Add block uninstall delegation in DPMS.
Implement the uninstall blocker delegation scope API in
DevicePolicyManagerSercice.
This feature gives a device owner or profile owner the ability to
delegate some of its privileges to another application.
Bug: 33105718
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.MixedDeviceOwnerTest#testDelegation
Change-Id: Ieb347ce3fb6219fe7f04cafbcd1e6b7359b31a10
diff --git a/api/current.txt b/api/current.txt
index 861a265..c1cb89a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6272,6 +6272,7 @@
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
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 int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
diff --git a/api/system-current.txt b/api/system-current.txt
index cdd5dab..cd57965 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6490,6 +6490,7 @@
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
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 int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
diff --git a/api/test-current.txt b/api/test-current.txt
index a23c8dc..a4218c6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6294,6 +6294,7 @@
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
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 int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f06d19c..abab6bf 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1224,6 +1224,12 @@
public static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
/**
+ * Delegation of application uninstall block. This scope grants access to the
+ * {@link #setUninstallBlocked} API.
+ */
+ public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
+
+ /**
* No management for current user in-effect. This is the default.
* @hide
*/
@@ -6127,19 +6133,25 @@
}
/**
- * Called by profile or device owners to change whether a user can uninstall a package.
+ * Change whether a user can uninstall a package. This function can be called by a device owner,
+ * profile owner, or by a delegate given the {@link #DELEGATION_BLOCK_UNINSTALL} 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 block uninstall delegate.
* @param packageName package to change.
* @param uninstallBlocked true if the user shouldn't be able to uninstall the package.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_BLOCK_UNINSTALL
*/
- public void setUninstallBlocked(@NonNull ComponentName admin, String packageName,
+ public void setUninstallBlocked(@Nullable ComponentName admin, String packageName,
boolean uninstallBlocked) {
throwIfParentInstance("setUninstallBlocked");
if (mService != null) {
try {
- mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
+ mService.setUninstallBlocked(admin, mContext.getPackageName(), packageName,
+ uninstallBlocked);
} 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 983de56..7e04016 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -227,7 +227,7 @@
void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userId);
- void setUninstallBlocked(in ComponentName admin, in String packageName, boolean uninstallBlocked);
+ void setUninstallBlocked(in ComponentName admin, in String callerPackage, in String packageName, boolean uninstallBlocked);
boolean isUninstallBlocked(in ComponentName admin, in String packageName);
void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d4d9483..587b032 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -34,6 +34,7 @@
import static android.app.admin.DevicePolicyManager.CODE_USER_NOT_RUNNING;
import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED;
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.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -264,7 +265,8 @@
// Comprehensive list of delegations.
private static final String DELEGATIONS[] = {
DELEGATION_CERT_INSTALL,
- DELEGATION_APP_RESTRICTIONS
+ DELEGATION_APP_RESTRICTIONS,
+ DELEGATION_BLOCK_UNINSTALL
};
/**
@@ -8304,12 +8306,13 @@
}
@Override
- public void setUninstallBlocked(ComponentName who, String packageName,
+ public void setUninstallBlocked(ComponentName who, String callerPackage, String packageName,
boolean uninstallBlocked) {
- Preconditions.checkNotNull(who, "ComponentName is null");
final int userId = UserHandle.getCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the caller is a DO/PO or a block uninstall delegate
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_BLOCK_UNINSTALL);
long id = mInjector.binderClearCallingIdentity();
try {