diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 63b56e0f92d4d..81de29c4ee4dd 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -983,4 +983,9 @@ public abstract class PackageManagerInternal { * Returns if a package name is a valid system package. */ public abstract boolean isSystemPackage(@NonNull String packageName); + + /** + * Unblocks uninstall for all packages for the user. + */ + public abstract void clearBlockUninstallForUser(@UserIdInt int userId); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5447bcb246e04..7adafe3ed658d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -24721,6 +24721,14 @@ public class PackageManagerService extends IPackageManager.Stub return packageName.equals( PackageManagerService.this.ensureSystemPackageName(packageName)); } + + @Override + public void clearBlockUninstallForUser(@UserIdInt int userId) { + synchronized (mLock) { + mSettings.clearBlockUninstallLPw(userId); + mSettings.writePackageRestrictionsLPr(userId); + } + } } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 44a61d895be54..ddeab29c5b78d 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1833,6 +1833,10 @@ public final class Settings { } } + void clearBlockUninstallLPw(int userId) { + mBlockUninstallPackages.remove(userId); + } + boolean getBlockUninstallLPr(int userId, String packageName) { ArraySet packages = mBlockUninstallPackages.get(userId); if (packages == null) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index fc70af4e7bd41..c716fce8a86d3 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3153,13 +3153,17 @@ public class UserManagerService extends IUserManager.Stub { /** * Removes the app restrictions file for a specific package and user id, if it exists. + * + * @return whether there were any restrictions. */ - private static void cleanAppRestrictionsForPackageLAr(String pkg, @UserIdInt int userId) { - File dir = Environment.getUserSystemDirectory(userId); - File resFile = new File(dir, packageToRestrictionsFileName(pkg)); + private static boolean cleanAppRestrictionsForPackageLAr(String pkg, @UserIdInt int userId) { + final File dir = Environment.getUserSystemDirectory(userId); + final File resFile = new File(dir, packageToRestrictionsFileName(pkg)); if (resFile.exists()) { resFile.delete(); + return true; } + return false; } /** @@ -4003,17 +4007,24 @@ public class UserManagerService extends IUserManager.Stub { if (restrictions != null) { restrictions.setDefusable(true); } + final boolean changed; synchronized (mAppRestrictionsLock) { if (restrictions == null || restrictions.isEmpty()) { - cleanAppRestrictionsForPackageLAr(packageName, userId); + changed = cleanAppRestrictionsForPackageLAr(packageName, userId); } else { // Write the restrictions to XML writeApplicationRestrictionsLAr(packageName, restrictions, userId); + // TODO(b/154323615): avoid unnecessary broadcast when there is no change. + changed = true; } } + if (!changed) { + return; + } + // Notify package of changes via an intent - only sent to explicitly registered receivers. - Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); + final Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); changeIntent.setPackage(packageName); changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(userId)); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2c0d4c0c92087..22b0b62a819d1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2703,7 +2703,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final ComponentName doAdminReceiver = doAdmin.info.getComponent(); clearDeviceOwnerLocked(doAdmin, doUserId); Slog.i(LOG_TAG, "Removing admin artifacts..."); - // TODO(b/149075700): Clean up application restrictions in UserManager. removeAdminArtifacts(doAdminReceiver, doUserId); Slog.i(LOG_TAG, "Migration complete."); @@ -8766,6 +8765,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { saveSettingsLocked(UserHandle.USER_SYSTEM); clearUserPoliciesLocked(userId); clearOverrideApnUnchecked(); + clearApplicationRestrictions(userId); + mInjector.getPackageManagerInternal().clearBlockUninstallForUser(userId); mOwners.clearDeviceOwner(); mOwners.writeDeviceOwner(); @@ -8779,6 +8780,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { toggleBackupServiceActive(UserHandle.USER_SYSTEM, true); } + private void clearApplicationRestrictions(int userId) { + // Changing app restrictions involves disk IO, offload it to the background thread. + mBackgroundHandler.post(() -> { + final List installedPackageInfos = mInjector.getPackageManager(userId) + .getInstalledPackages(MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE); + final UserHandle userHandle = UserHandle.of(userId); + for (final PackageInfo packageInfo : installedPackageInfos) { + mInjector.getUserManager().setApplicationRestrictions( + packageInfo.packageName, null /* restrictions */, userHandle); + } + }); + } + @Override public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) { if (!mHasFeature) { @@ -8898,6 +8912,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { policyData.mOwnerInstalledCaCerts.clear(); saveSettingsLocked(userId); clearUserPoliciesLocked(userId); + clearApplicationRestrictions(userId); mOwners.removeProfileOwner(userId); mOwners.writeProfileOwner(userId); deleteTransferOwnershipBundleLocked(userId); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index 74e7f8c44d1a4..a0b9d9d2a8751 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -62,6 +62,10 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { mContext = getContext(); + // Make createContextAsUser to work. + mContext.packageName = "com.android.frameworks.servicestests"; + getServices().addPackageContext(UserHandle.of(0), mContext); + when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) .thenReturn(true); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 09d1d3a270bac..57039e53429ed 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -196,6 +196,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { anyInt(), any(UserHandle.class)); + // Make createContextAsUser to work. + mContext.packageName = "com.android.frameworks.servicestests"; + getServices().addPackageContext(UserHandle.of(0), mContext); + getServices().addPackageContext(UserHandle.of(DpmMockContext.CALLER_USER_HANDLE), mContext); + // By default, pretend all users are running and unlocked. when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 8625a1ed9fdae..20716ab501df9 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -459,6 +459,15 @@ public class DpmMockContext extends MockContext { return mMockSystemServices.createPackageContextAsUser(packageName, flags, user); } + @Override + public Context createContextAsUser(UserHandle user, int flags) { + try { + return mMockSystemServices.createPackageContextAsUser(packageName, flags, user); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalStateException(e); + } + } + @Override public ContentResolver getContentResolver() { return mMockSystemServices.contentResolver;