Allow app protection role to uninstall packages
Bug: 361776825
Test: End-to-end
Flag: android.content.pm.delete_packages_silently_backport
Change-Id: I288a95ec9084e5acfac333de88d2741122a39386
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 60b409a..160cbdf 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -301,4 +301,11 @@
description: "Feature flag to remove hack code of using PackageManager.MATCH_ANY_USER flag without cross user permission."
bug: "332664521"
is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+ name: "delete_packages_silently_backport"
+ namespace: "package_manager_service"
+ description: "Feature flag to enable the holder of SYSTEM_APP_PROTECTION_SERVICE role to silently delete packages. To be deprecated by delete_packages_silently."
+ bug: "361776825"
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 1316df1..b1b1637 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -50,6 +50,7 @@
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -201,6 +202,9 @@
Manifest.permission.USE_FULL_SCREEN_INTENT
);
+ private static final String ROLE_SYSTEM_APP_PROTECTION_SERVICE =
+ "android.app.role.SYSTEM_APP_PROTECTION_SERVICE";
+
final PackageArchiver mPackageArchiver;
private final Context mContext;
@@ -1454,6 +1458,12 @@
.createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE)
.setAdmin(callerPackageName)
.write();
+ } else if (isSystemAppProtectionRoleHolder(snapshot, userId, callingUid)) {
+ // Allow the SYSTEM_APP_PROTECTION_SERVICE role holder to silently uninstall, with a
+ // clean calling identity to get DELETE_PACKAGES permission
+ Binder.withCleanCallingIdentity(() ->
+ mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags)
+ );
} else {
ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId);
if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
@@ -1475,6 +1485,29 @@
}
}
+ private Boolean isSystemAppProtectionRoleHolder(
+ @NonNull Computer snapshot, int userId, int callingUid) {
+ if (!Flags.deletePackagesSilentlyBackport()) {
+ return false;
+ }
+ String holderPackageName = Binder.withCleanCallingIdentity(() -> {
+ RoleManager roleManager = mPm.mContext.getSystemService(RoleManager.class);
+ if (roleManager == null) {
+ return null;
+ }
+ List<String> holders = roleManager.getRoleHoldersAsUser(
+ ROLE_SYSTEM_APP_PROTECTION_SERVICE, UserHandle.of(userId));
+ if (holders.isEmpty()) {
+ return null;
+ }
+ return holders.get(0);
+ });
+ if (holderPackageName == null) {
+ return false;
+ }
+ return snapshot.getPackageUid(holderPackageName, /* flags= */ 0, userId) == callingUid;
+ }
+
@Override
public void uninstallExistingPackage(VersionedPackage versionedPackage,
String callerPackageName, IntentSender statusReceiver, int userId) {