diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index ee56a18e71a5f..4e53914a3c681 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -44,7 +44,6 @@ public class PackageUserState { public boolean notLaunched; public boolean hidden; // Is the app restricted by owner / admin public boolean suspended; - public boolean blockUninstall; public boolean instantApp; public int enabled; public String lastDisableAppCaller; @@ -75,7 +74,6 @@ public class PackageUserState { notLaunched = o.notLaunched; hidden = o.hidden; suspended = o.suspended; - blockUninstall = o.blockUninstall; instantApp = o.instantApp; enabled = o.enabled; lastDisableAppCaller = o.lastDisableAppCaller; @@ -193,9 +191,6 @@ public class PackageUserState { if (suspended != oldState.suspended) { return false; } - if (blockUninstall != oldState.blockUninstall) { - return false; - } if (instantApp != oldState.instantApp) { return false; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index cfcd0a51a3283..121ae07edd821 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18514,11 +18514,6 @@ public class PackageManagerService extends IPackageManager.Stub mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_PACKAGES, null); synchronized (mPackages) { - PackageSetting ps = mSettings.mPackages.get(packageName); - if (ps == null) { - Log.i(TAG, "Package doesn't exist in set block uninstall " + packageName); - return false; - } // Cannot block uninstall of static shared libs as they are // considered a part of the using app (emulating static linking). // Also static libs are installed always on internal storage. @@ -18528,12 +18523,7 @@ public class PackageManagerService extends IPackageManager.Stub + " providing static shared library: " + pkg.staticSharedLibName); return false; } - if (!ps.getInstalled(userId)) { - // Can't block uninstall for an app that is not installed or enabled. - Log.i(TAG, "Package not installed in set block uninstall " + packageName); - return false; - } - ps.setBlockUninstall(blockUninstall, userId); + mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall); mSettings.writePackageRestrictionsLPr(userId); } return true; @@ -18542,12 +18532,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean getBlockUninstallForUser(String packageName, int userId) { synchronized (mPackages) { - PackageSetting ps = mSettings.mPackages.get(packageName); - if (ps == null) { - Log.i(TAG, "Package doesn't exist in get block uninstall " + packageName); - return false; - } - return ps.getBlockUninstall(userId); + return mSettings.getBlockUninstallLPr(userId, packageName); } } @@ -18754,7 +18739,6 @@ public class PackageManagerService extends IPackageManager.Stub null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, - false /*blockUninstall*/, ps.readUserState(nextUserId).domainVerificationStatus, 0, PackageManager.INSTALL_REASON_UNKNOWN); } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index dfed72fa9b61f..14f65eb485f4b 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -402,14 +402,6 @@ abstract class PackageSettingBase extends SettingBase { modifyUserState(userId).suspended = suspended; } - boolean getBlockUninstall(int userId) { - return readUserState(userId).blockUninstall; - } - - void setBlockUninstall(boolean blockUninstall, int userId) { - modifyUserState(userId).blockUninstall = blockUninstall; - } - boolean getInstantApp(int userId) { return readUserState(userId).instantApp; } @@ -421,8 +413,8 @@ abstract class PackageSettingBase extends SettingBase { void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped, boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp, String lastDisableAppCaller, ArraySet enabledComponents, - ArraySet disabledComponents, boolean blockUninstall, - int domainVerifState, int linkGeneration, int installReason) { + ArraySet disabledComponents, int domainVerifState, + int linkGeneration, int installReason) { PackageUserState state = modifyUserState(userId); state.ceDataInode = ceDataInode; state.enabled = enabled; @@ -434,7 +426,6 @@ abstract class PackageSettingBase extends SettingBase { state.lastDisableAppCaller = lastDisableAppCaller; state.enabledComponents = enabledComponents; state.disabledComponents = disabledComponents; - state.blockUninstall = blockUninstall; state.domainVerificationStatus = domainVerifState; state.appLinkGeneration = linkGeneration; state.installReason = installReason; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index cea031eec9f50..44bcff25b53c3 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -186,6 +186,8 @@ final class Settings { private static final String TAG_PERMISSIONS = "perms"; private static final String TAG_CHILD_PACKAGE = "child-package"; private static final String TAG_USES_STATIC_LIB = "uses-static-lib"; + private static final String TAG_BLOCK_UNINSTALL_PACKAGES = "block-uninstall-packages"; + private static final String TAG_BLOCK_UNINSTALL = "block-uninstall"; private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES = "persistent-preferred-activities"; @@ -215,6 +217,8 @@ final class Settings { // New name for the above attribute. private static final String ATTR_HIDDEN = "hidden"; private static final String ATTR_SUSPENDED = "suspended"; + // Legacy, uninstall blocks are stored separately. + @Deprecated private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall"; private static final String ATTR_ENABLED = "enabled"; private static final String ATTR_ENABLED_CALLER = "enabledCaller"; @@ -271,6 +275,9 @@ final class Settings { private final ArrayMap mDisabledSysPackages = new ArrayMap(); + /** List of packages that are blocked for uninstall for specific users */ + private final SparseArray> mBlockUninstallPackages = new SparseArray<>(); + // Set of restored intent-filter verification states private final ArrayMap mRestoredIntentFilterVerifications = new ArrayMap(); @@ -756,7 +763,6 @@ final class Settings { null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, - false /*blockUninstall*/, INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0, PackageManager.INSTALL_REASON_UNKNOWN); } @@ -1614,6 +1620,34 @@ final class Settings { } } + void readBlockUninstallPackagesLPw(XmlPullParser parser, int userId) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + ArraySet packages = new ArraySet<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String tagName = parser.getName(); + if (tagName.equals(TAG_BLOCK_UNINSTALL)) { + String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); + packages.add(packageName); + } else { + String msg = "Unknown element under " + TAG_BLOCK_UNINSTALL_PACKAGES + ": " + + parser.getName(); + PackageManagerService.reportSettingsProblem(Log.WARN, msg); + XmlUtils.skipCurrentTag(parser); + } + } + if (packages.isEmpty()) { + mBlockUninstallPackages.remove(userId); + } else { + mBlockUninstallPackages.put(userId, packages); + } + } + void readPackageRestrictionsLPr(int userId) { if (DEBUG_MU) { Log.i(TAG, "Reading package restrictions for user=" + userId); @@ -1662,7 +1696,6 @@ final class Settings { null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, - false /*blockUninstall*/, INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0, PackageManager.INSTALL_REASON_UNKNOWN); } @@ -1768,9 +1801,12 @@ final class Settings { } } + if (blockUninstall) { + setBlockUninstallLPw(userId, name, true); + } ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched, hidden, suspended, instantApp, enabledCaller, enabledComponents, - disabledComponents, blockUninstall, verifState, linkGeneration, + disabledComponents, verifState, linkGeneration, installReason); } else if (tagName.equals("preferred-activities")) { readPreferredActivitiesLPw(parser, userId); @@ -1780,6 +1816,8 @@ final class Settings { readCrossProfileIntentFiltersLPw(parser, userId); } else if (tagName.equals(TAG_DEFAULT_APPS)) { readDefaultAppsLPw(parser, userId); + } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) { + readBlockUninstallPackagesLPw(parser, userId); } else { Slog.w(PackageManagerService.TAG, "Unknown element under : " + parser.getName()); @@ -1806,6 +1844,30 @@ final class Settings { } } + void setBlockUninstallLPw(int userId, String packageName, boolean blockUninstall) { + ArraySet packages = mBlockUninstallPackages.get(userId); + if (blockUninstall) { + if (packages == null) { + packages = new ArraySet(); + mBlockUninstallPackages.put(userId, packages); + } + packages.add(packageName); + } else if (packages != null) { + packages.remove(packageName); + if (packages.isEmpty()) { + mBlockUninstallPackages.remove(userId); + } + } + } + + boolean getBlockUninstallLPr(int userId, String packageName) { + ArraySet packages = mBlockUninstallPackages.get(userId); + if (packages == null) { + return false; + } + return packages.contains(packageName); + } + private ArraySet readComponentsLPr(XmlPullParser parser) throws IOException, XmlPullParserException { ArraySet components = null; @@ -1976,6 +2038,20 @@ final class Settings { serializer.endTag(null, TAG_DEFAULT_APPS); } + void writeBlockUninstallPackagesLPr(XmlSerializer serializer, int userId) + throws IOException { + ArraySet packages = mBlockUninstallPackages.get(userId); + if (packages != null) { + serializer.startTag(null, TAG_BLOCK_UNINSTALL_PACKAGES); + for (int i = 0; i < packages.size(); i++) { + serializer.startTag(null, TAG_BLOCK_UNINSTALL); + serializer.attribute(null, ATTR_PACKAGE_NAME, packages.valueAt(i)); + serializer.endTag(null, TAG_BLOCK_UNINSTALL); + } + serializer.endTag(null, TAG_BLOCK_UNINSTALL_PACKAGES); + } + } + void writePackageRestrictionsLPr(int userId) { if (DEBUG_MU) { Log.i(TAG, "Writing package restrictions for user=" + userId); @@ -2038,9 +2114,6 @@ final class Settings { if (ustate.suspended) { serializer.attribute(null, ATTR_SUSPENDED, "true"); } - if (ustate.blockUninstall) { - serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true"); - } if (ustate.instantApp) { serializer.attribute(null, ATTR_INSTANT_APP, "true"); } @@ -2091,6 +2164,7 @@ final class Settings { writePersistentPreferredActivitiesLPr(serializer, userId); writeCrossProfileIntentFiltersLPr(serializer, userId); writeDefaultAppsLPr(serializer, userId); + writeBlockUninstallPackagesLPr(serializer, userId); serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 3b4afa1ca353b..5e4ba7bec7138 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -535,7 +535,6 @@ public class PackageManagerSettingsTests { private void verifyUserState(PackageUserState userState, PackageUserState oldUserState, boolean userStateChanged, boolean notLaunched, boolean stopped, boolean installed) { - assertThat(userState.blockUninstall, is(false)); assertThat(userState.enabled, is(0)); assertThat(userState.hidden, is(false)); assertThat(userState.installed, is(installed)); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java index bf05f21f32d54..50be8dbd16a89 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java @@ -48,10 +48,6 @@ public class PackageUserStateTest { oldUserState.appLinkGeneration = 6; assertThat(testUserState.equals(oldUserState), is(false)); - oldUserState = new PackageUserState(); - oldUserState.blockUninstall = true; - assertThat(testUserState.equals(oldUserState), is(false)); - oldUserState = new PackageUserState(); oldUserState.ceDataInode = 4000L; assertThat(testUserState.equals(oldUserState), is(false));