diff --git a/api/current.txt b/api/current.txt index 861a2654b0f51..c1cb89a23c15b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6272,6 +6272,7 @@ package android.app.admin { 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 cdd5dab88a600..cd579650bdeaf 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6490,6 +6490,7 @@ package android.app.admin { 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 a23c8dc7d0866..a4218c6a63338 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6294,6 +6294,7 @@ package android.app.admin { 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 f06d19ce87400..abab6bf0eb14f 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1223,6 +1223,12 @@ public class DevicePolicyManager { */ 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 @@ public class DevicePolicyManager { } /** - * 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 983de56f84175..7e04016d9c21e 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -227,7 +227,7 @@ interface IDevicePolicyManager { 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 d4d94839f016e..587b032cc17b7 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_HAS_PROFILE_OWNER; 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @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 {