Add DPMS delegation scopes.
Implement the permission grant, package access, enable system app, and
keep uninstalled packages delegation scope APIs in the
DevicePolicyManagerService.
This feature gives a device owner or profile owner the ability to
delegate some of its privileges to another application.
Bug: 33105287, 33105284, 33105719
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.MixedDeviceOwnerTest#testDelegation
Change-Id: I50d2903eb73ae7844ec1f6fe07e41101ea2760ea
diff --git a/api/current.txt b/api/current.txt
index c1cb89a..9538253 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6274,6 +6274,9 @@
field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+ field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+ field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
diff --git a/api/system-current.txt b/api/system-current.txt
index cd57965..c649c23 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6492,6 +6492,9 @@
field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+ field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+ field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
diff --git a/api/test-current.txt b/api/test-current.txt
index a4218c6..ab421ce 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6296,6 +6296,9 @@
field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+ field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+ field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+ field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index abab6bf..72daade 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1230,6 +1230,34 @@
public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
/**
+ * Delegation of permission policy and permission grant state. This scope grants access to the
+ * {@link #setPermissionPolicy}, {@link #getPermissionGrantState},
+ * and {@link #setPermissionGrantState} APIs.
+ */
+ public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
+
+ /**
+ * Delegation of package access state. This scope grants access to the
+ * {@link #isApplicationHidden}, {@link #setApplicationHidden}, {@link #isPackageSuspended}, and
+ * {@link #setPackagesSuspended} APIs.
+ */
+ public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+
+ /**
+ * Delegation for enabling system apps. This scope grants access to the {@link #enableSystemApp}
+ * API.
+ */
+ public static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+
+ /**
+ * Delegation of management of uninstalled packages. This scope grants access to the
+ * {@code #setKeepUninstalledPackages} and {@code #getKeepUninstalledPackages} APIs.
+ * @hide
+ */
+ public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES =
+ "delegation-keep-uninstalled-packages";
+
+ /**
* No management for current user in-effect. This is the default.
* @hide
*/
@@ -4573,7 +4601,9 @@
}
/**
- * Called by device or profile owners to suspend packages for this user.
+ * Called by device or profile owners to suspend packages for this user. This function can be
+ * called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_PACKAGE_ACCESS} scope via {@link #setDelegatedScopes}.
* <p>
* A suspended package will not be able to start activities. Its notifications will be hidden,
* it will not show up in recents, will not be able to show toasts or dialogs or ring the
@@ -4583,20 +4613,24 @@
* package will no longer be suspended. The admin can block this by using
* {@link #setUninstallBlocked}.
*
- * @param admin The name of the admin component to check.
+ * @param admin The name of the admin component to check, or {@code null} if the caller is a
+ * package access delegate.
* @param packageNames The package names to suspend or unsuspend.
* @param suspended If set to {@code true} than the packages will be suspended, if set to
* {@code false} the packages will be unsuspended.
* @return an array of package names for which the suspended status is not set as requested in
* this method.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public @NonNull String[] setPackagesSuspended(@NonNull ComponentName admin,
@NonNull String[] packageNames, boolean suspended) {
throwIfParentInstance("setPackagesSuspended");
if (mService != null) {
try {
- return mService.setPackagesSuspended(admin, packageNames, suspended);
+ return mService.setPackagesSuspended(admin, mContext.getPackageName(), packageNames,
+ suspended);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -4605,21 +4639,26 @@
}
/**
- * Called by device or profile owners to determine if a package is suspended.
+ * Determine if a package is suspended. This function can be called by a device owner, profile
+ * owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to retrieve the suspended status of.
* @return {@code true} if the package is suspended or {@code false} if the package is not
* suspended, could not be found or an error occurred.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @throws NameNotFoundException if the package could not be found.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
throws NameNotFoundException {
throwIfParentInstance("isPackageSuspended");
if (mService != null) {
try {
- return mService.isPackageSuspended(admin, packageName);
+ return mService.isPackageSuspended(admin, mContext.getPackageName(), packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (IllegalArgumentException ex) {
@@ -5489,19 +5528,24 @@
}
/**
- * Called by a device owner to get the list of apps to keep around as APKs even if no user has
- * currently installed it.
+ * Get the list of apps to keep around as APKs even if no user has currently installed it. This
+ * function can be called by a device owner or by a delegate given the
+ * {@link #DELEGATION_KEEP_UNINSTALLED_PACKAGES} scope via {@link #setDelegatedScopes}.
+ * <p>
+ * Please note that packages returned in this method are not automatically pre-cached.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a keep uninstalled packages delegate.
* @return List of package names to keep cached.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES
* @hide
*/
- public @Nullable List<String> getKeepUninstalledPackages(@NonNull ComponentName admin) {
+ public @Nullable List<String> getKeepUninstalledPackages(@Nullable ComponentName admin) {
throwIfParentInstance("getKeepUninstalledPackages");
if (mService != null) {
try {
- return mService.getKeepUninstalledPackages(admin);
+ return mService.getKeepUninstalledPackages(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5510,23 +5554,27 @@
}
/**
- * Called by a device owner to set a list of apps to keep around as APKs even if no user has
- * currently installed it.
+ * Set a list of apps to keep around as APKs even if no user has currently installed it. This
+ * function can be called by a device owner or by a delegate given the
+ * {@link #DELEGATION_KEEP_UNINSTALLED_PACKAGES} scope via {@link #setDelegatedScopes}.
*
* <p>Please note that setting this policy does not imply that specified apps will be
* automatically pre-cached.</p>
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a keep uninstalled packages delegate.
* @param packageNames List of package names to keep cached.
* @throws SecurityException if {@code admin} is not a device owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES
* @hide
*/
- public void setKeepUninstalledPackages(@NonNull ComponentName admin,
+ public void setKeepUninstalledPackages(@Nullable ComponentName admin,
@NonNull List<String> packageNames) {
throwIfParentInstance("setKeepUninstalledPackages");
if (mService != null) {
try {
- mService.setKeepUninstalledPackages(admin, packageNames);
+ mService.setKeepUninstalledPackages(admin, mContext.getPackageName(), packageNames);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5779,22 +5827,28 @@
}
/**
- * Called by profile or device owners to hide or unhide packages. When a package is hidden it is
- * unavailable for use, but the data and actual package file remain.
+ * Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and
+ * actual package file remain. This function can be called by a device owner, profile owner, or
+ * by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to hide or unhide.
* @param hidden {@code true} if the package should be hidden, {@code false} if it should be
* unhidden.
* @return boolean Whether the hidden setting of the package was successfully updated.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
boolean hidden) {
throwIfParentInstance("setApplicationHidden");
if (mService != null) {
try {
- return mService.setApplicationHidden(admin, packageName, hidden);
+ return mService.setApplicationHidden(admin, mContext.getPackageName(), packageName,
+ hidden);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5803,18 +5857,23 @@
}
/**
- * Called by profile or device owners to determine if a package is hidden.
+ * Determine if a package is hidden. This function can be called by a device owner, profile
+ * owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
+ * {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to retrieve the hidden status of.
* @return boolean {@code true} if the package is hidden, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
throwIfParentInstance("isApplicationHidden");
if (mService != null) {
try {
- return mService.isApplicationHidden(admin, packageName);
+ return mService.isApplicationHidden(admin, mContext.getPackageName(), packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5823,18 +5882,22 @@
}
/**
- * Called by profile or device owners to re-enable a system app that was disabled by default
- * when the user was initialized.
+ * Re-enable a system app that was disabled by default when the user was initialized. This
+ * function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_ENABLE_SYSTEM_APP} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is an enable system app delegate.
* @param packageName The package to be re-enabled in the calling profile.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public void enableSystemApp(@NonNull ComponentName admin, String packageName) {
throwIfParentInstance("enableSystemApp");
if (mService != null) {
try {
- mService.enableSystemApp(admin, packageName);
+ mService.enableSystemApp(admin, mContext.getPackageName(), packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5842,20 +5905,24 @@
}
/**
- * Called by profile or device owners to re-enable system apps by intent that were disabled by
- * default when the user was initialized.
+ * Re-enable system apps by intent that were disabled by default when the user was initialized.
+ * This function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_ENABLE_SYSTEM_APP} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if the caller is an enable system app delegate.
* @param intent An intent matching the app(s) to be installed. All apps that resolve for this
* intent will be re-enabled in the calling profile.
* @return int The number of activities that matched the intent and were installed.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PACKAGE_ACCESS
*/
public int enableSystemApp(@NonNull ComponentName admin, Intent intent) {
throwIfParentInstance("enableSystemApp");
if (mService != null) {
try {
- return mService.enableSystemAppWithIntent(admin, intent);
+ return mService.enableSystemAppWithIntent(admin, mContext.getPackageName(), intent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6437,12 +6504,14 @@
}
/**
- * Called by profile or device owners to set the default response for future runtime permission
- * requests by applications. The policy can allow for normal operation which prompts the user to
- * grant a permission, or can allow automatic granting or denying of runtime permission requests
- * by an application. This also applies to new permissions declared by app updates. When a
- * permission is denied or granted this way, the effect is equivalent to setting the permission
- * grant state via {@link #setPermissionGrantState}.
+ * Set the default response for future runtime permission requests by applications. This
+ * function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
+ * The policy can allow for normal operation which prompts the user to grant a permission, or
+ * can allow automatic granting or denying of runtime permission requests by an application.
+ * This also applies to new permissions declared by app updates. When a permission is denied or
+ * granted this way, the effect is equivalent to setting the permission * grant state via
+ * {@link #setPermissionGrantState}.
* <p/>
* As this policy only acts on runtime permission requests, it only applies to applications
* built with a {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#M} or later.
@@ -6452,11 +6521,13 @@
* {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @see #setPermissionGrantState
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PERMISSION_GRANT
*/
public void setPermissionPolicy(@NonNull ComponentName admin, int policy) {
throwIfParentInstance("setPermissionPolicy");
try {
- mService.setPermissionPolicy(admin, policy);
+ mService.setPermissionPolicy(admin, mContext.getPackageName(), policy);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -6465,6 +6536,7 @@
/**
* Returns the current runtime permission policy set by the device or profile owner. The
* default is {@link #PERMISSION_POLICY_PROMPT}.
+ *
* @param admin Which profile or device owner this request is associated with.
* @return the current policy for future permission requests.
*/
@@ -6484,7 +6556,8 @@
* cannot manage it through the UI, and {@link #PERMISSION_GRANT_STATE_GRANTED granted} in which
* the permission is granted and the user cannot manage it through the UI. This might affect all
* permissions in a group that the runtime permission belongs to. This method can only be called
- * by a profile or device owner.
+ * by a profile owner, device owner, or a delegate given the
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
* <p/>
* Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not revoke
* the permission. It retains the previous grant, if any.
@@ -6503,21 +6576,27 @@
* @see #PERMISSION_GRANT_STATE_DENIED
* @see #PERMISSION_GRANT_STATE_DEFAULT
* @see #PERMISSION_GRANT_STATE_GRANTED
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PERMISSION_GRANT
*/
public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName,
String permission, int grantState) {
throwIfParentInstance("setPermissionGrantState");
try {
- return mService.setPermissionGrantState(admin, packageName, permission, grantState);
+ return mService.setPermissionGrantState(admin, mContext.getPackageName(), packageName,
+ permission, grantState);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
- * Returns the current grant state of a runtime permission for a specific application.
+ * Returns the current grant state of a runtime permission for a specific application. This
+ * function can be called by a device owner, profile owner, or by a delegate given the
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which profile or device owner this request is associated with.
+ * @param admin Which profile or device owner this request is associated with, or {@code null}
+ * if the caller is a permission grant delegate.
* @param packageName The application to check the grant state for.
* @param permission The permission to check for.
* @return the current grant state specified by device policy. If the profile or device owner
@@ -6532,12 +6611,15 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @see #setPermissionGrantState(ComponentName, String, String, int)
* @see PackageManager#checkPermission(String, String)
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_PERMISSION_GRANT
*/
public int getPermissionGrantState(@Nullable ComponentName admin, String packageName,
String permission) {
throwIfParentInstance("getPermissionGrantState");
try {
- return mService.getPermissionGrantState(admin, packageName, permission);
+ return mService.getPermissionGrantState(admin, mContext.getPackageName(), packageName,
+ permission);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7e04016..7604af8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -150,8 +150,8 @@
void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
CharSequence getDeviceOwnerLockScreenInfo();
- String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
- boolean isPackageSuspended(in ComponentName admin, String packageName);
+ String[] setPackagesSuspended(in ComponentName admin, in String callerPackage, in String[] packageNames, boolean suspended);
+ boolean isPackageSuspended(in ComponentName admin, in String callerPackage, String packageName);
boolean installCaCert(in ComponentName admin, String callerPackage, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, String callerPackage, in String[] aliases);
@@ -201,15 +201,15 @@
List getPermittedInputMethodsForCurrentUser();
boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId);
- boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden);
- boolean isApplicationHidden(in ComponentName admin, in String packageName);
+ boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden);
+ boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName);
UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
boolean switchUser(in ComponentName who, in UserHandle userHandle);
- void enableSystemApp(in ComponentName admin, in String packageName);
- int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
+ void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
+ int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
String[] getAccountTypesWithManagementDisabled();
@@ -271,15 +271,15 @@
void notifyPendingSystemUpdate(in SystemUpdateInfo info);
SystemUpdateInfo getPendingSystemUpdate(in ComponentName admin);
- void setPermissionPolicy(in ComponentName admin, int policy);
+ void setPermissionPolicy(in ComponentName admin, in String callerPackage, int policy);
int getPermissionPolicy(in ComponentName admin);
- boolean setPermissionGrantState(in ComponentName admin, String packageName,
+ boolean setPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName,
String permission, int grantState);
- int getPermissionGrantState(in ComponentName admin, String packageName, String permission);
+ int getPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName, String permission);
boolean isProvisioningAllowed(String action, String packageName);
int checkProvisioningPreCondition(String action, String packageName);
- void setKeepUninstalledPackages(in ComponentName admin,in List<String> packageList);
- List<String> getKeepUninstalledPackages(in ComponentName admin);
+ void setKeepUninstalledPackages(in ComponentName admin, in String callerPackage, in List<String> packageList);
+ List<String> getKeepUninstalledPackages(in ComponentName admin, in String callerPackage);
boolean isManagedProfile(in ComponentName admin);
boolean isSystemOnlyUser(in ComponentName admin);
String getWifiMacAddress(in ComponentName admin);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 587b032..3082e8b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -36,6 +36,10 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -266,7 +270,11 @@
private static final String DELEGATIONS[] = {
DELEGATION_CERT_INSTALL,
DELEGATION_APP_RESTRICTIONS,
- DELEGATION_BLOCK_UNINSTALL
+ DELEGATION_BLOCK_UNINSTALL,
+ DELEGATION_ENABLE_SYSTEM_APP,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES,
+ DELEGATION_PACKAGE_ACCESS,
+ DELEGATION_PERMISSION_GRANT
};
/**
@@ -6287,32 +6295,38 @@
}
@Override
- public void setKeepUninstalledPackages(ComponentName who, List<String> packageList) {
+ public void setKeepUninstalledPackages(ComponentName who, String callerPackage,
+ List<String> packageList) {
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
Preconditions.checkNotNull(packageList, "packageList is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (this) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- admin.keepUninstalledPackages = packageList;
+ // Ensure the caller is a DO or a keep uninstalled packages delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES);
+ // Get the device owner
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ // Set list of packages to be kept even if uninstalled.
+ deviceOwner.keepUninstalledPackages = packageList;
+ // Save settings.
saveSettingsLocked(userHandle);
+ // Notify package manager.
mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList);
}
}
@Override
- public List<String> getKeepUninstalledPackages(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public List<String> getKeepUninstalledPackages(ComponentName who, String callerPackage) {
if (!mHasFeature) {
return null;
}
// TODO In split system user mode, allow apps on user 0 to query the list
synchronized (this) {
- // Check if this is the device owner who is calling
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ // Ensure the caller is a DO or a keep uninstalled packages delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES);
return getKeepUninstalledPackagesLocked();
}
}
@@ -7987,12 +8001,13 @@
}
@Override
- public String[] setPackagesSuspended(ComponentName who, String[] packageNames,
- boolean suspended) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public String[] setPackagesSuspended(ComponentName who, String callerPackage,
+ String[] packageNames, boolean suspended) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8009,10 +8024,12 @@
}
@Override
- public boolean isPackageSuspended(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
long id = mInjector.binderClearCallingIdentity();
@@ -8124,12 +8141,13 @@
}
@Override
- public boolean setApplicationHidden(ComponentName who, String packageName,
+ public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
boolean hidden) {
- Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8146,11 +8164,13 @@
}
@Override
- public boolean isApplicationHidden(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public boolean isApplicationHidden(ComponentName who, String callerPackage,
+ String packageName) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a package access delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PACKAGE_ACCESS);
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8167,12 +8187,11 @@
}
@Override
- public void enableSystemApp(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public void enableSystemApp(ComponentName who, String callerPackage, String packageName) {
synchronized (this) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or an enable system app delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_ENABLE_SYSTEM_APP);
int userId = UserHandle.getCallingUserId();
long id = mInjector.binderClearCallingIdentity();
@@ -8202,12 +8221,11 @@
}
@Override
- public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ public int enableSystemAppWithIntent(ComponentName who, String callerPackage, Intent intent) {
synchronized (this) {
- // This API can only be called by an active device admin,
- // so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or an enable system app delegate.
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_ENABLE_SYSTEM_APP);
int userId = UserHandle.getCallingUserId();
long id = mInjector.binderClearCallingIdentity();
@@ -9139,10 +9157,13 @@
}
@Override
- public void setPermissionPolicy(ComponentName admin, int policy) throws RemoteException {
+ public void setPermissionPolicy(ComponentName admin, String callerPackage, int policy)
+ throws RemoteException {
int userId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a permission grant state delegate.
+ enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PERMISSION_GRANT);
DevicePolicyData userPolicy = getUserData(userId);
if (userPolicy.mPermissionPolicy != policy) {
userPolicy.mPermissionPolicy = policy;
@@ -9161,11 +9182,13 @@
}
@Override
- public boolean setPermissionGrantState(ComponentName admin, String packageName,
- String permission, int grantState) throws RemoteException {
+ public boolean setPermissionGrantState(ComponentName admin, String callerPackage,
+ String packageName, String permission, int grantState) throws RemoteException {
UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a permission grant state delegate.
+ enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PERMISSION_GRANT);
long ident = mInjector.binderClearCallingIdentity();
try {
if (getTargetSdk(packageName, user.getIdentifier())
@@ -9205,13 +9228,16 @@
}
@Override
- public int getPermissionGrantState(ComponentName admin, String packageName,
- String permission) throws RemoteException {
+ public int getPermissionGrantState(ComponentName admin, String callerPackage,
+ String packageName, String permission) throws RemoteException {
PackageManager packageManager = mInjector.getPackageManager();
UserHandle user = mInjector.binderGetCallingUserHandle();
enforceProfileOwnerOrSystemUser(admin);
synchronized (this) {
+ // Ensure the caller is a DO/PO or a permission grant state delegate.
+ enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_PERMISSION_GRANT);
long ident = mInjector.binderClearCallingIdentity();
try {
int granted = mIPackageManager.checkPermission(permission,