summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Robert Horvath <robhor@google.com> 2020-04-08 17:05:05 +0200
committer Robert Horvath <robhor@google.com> 2020-05-12 09:18:56 +0000
commit77880fa8607856571711cf3330a3bee77d91d106 (patch)
treeea3117516faf9a4c1e4b479bbc5960ed8675574a
parentc8f22beefece1cafccd46683a8ec4ecf543512a0 (diff)
Add PackageInstaller#uninstallExistingPackage
This new API allows an app to be uninstalled silently by any app holding the DELETE_PACKAGES permission, as long as the app is installed in another user so won't be fully removed from the device. Bug: 149601842 Test: atest UninstallExistingPackageTest Merged-In: I69fe4d1dd4e9da83574b431257f7be6d1ac8b2bb Change-Id: I69fe4d1dd4e9da83574b431257f7be6d1ac8b2bb
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl3
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl10
-rw-r--r--core/java/android/content/pm/PackageInstaller.java21
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java39
5 files changed, 88 insertions, 0 deletions
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 37baae35734b..010589617e09 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -51,6 +51,9 @@ interface IPackageInstaller {
void uninstall(in VersionedPackage versionedPackage, String callerPackageName, int flags,
in IntentSender statusReceiver, int userId);
+ void uninstallExistingPackage(in VersionedPackage versionedPackage, String callerPackageName,
+ in IntentSender statusReceiver, int userId);
+
void installExistingPackage(String packageName, int installFlags, int installReason,
in IntentSender statusReceiver, int userId, in List<String> whiteListedPermissions);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 8bebafff37f0..f257326904fd 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -235,6 +235,16 @@ interface IPackageManager {
void deletePackageVersioned(in VersionedPackage versionedPackage,
IPackageDeleteObserver2 observer, int userId, int flags);
+ /**
+ * Delete a package for a specific user.
+ *
+ * @param versionedPackage The package to delete.
+ * @param observer a callback to use to notify when the package deletion in finished.
+ * @param userId the id of the user for whom to delete the package
+ */
+ void deleteExistingPackageAsUser(in VersionedPackage versionedPackage,
+ IPackageDeleteObserver2 observer, int userId);
+
@UnsupportedAppUsage
String getInstallerPackageName(in String packageName);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 85a3986a65f9..ed75504529b9 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -720,6 +720,27 @@ public class PackageInstaller {
}
}
+ /**
+ * Uninstall the given package for the user for which this installer was created if the package
+ * will still exist for other users on the device.
+ *
+ * @param packageName The package to install.
+ * @param statusReceiver Where to deliver the result.
+ *
+ * {@hide}
+ */
+ @RequiresPermission(Manifest.permission.DELETE_PACKAGES)
+ public void uninstallExistingPackage(@NonNull String packageName,
+ @Nullable IntentSender statusReceiver) {
+ Objects.requireNonNull(packageName, "packageName cannot be null");
+ try {
+ mInstaller.uninstallExistingPackage(
+ new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+ mInstallerPackageName, statusReceiver, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/** {@hide} */
@SystemApi
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 3367cd556b2b..0462a1990df4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -933,6 +933,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
@Override
+ public void uninstallExistingPackage(VersionedPackage versionedPackage,
+ String callerPackageName, IntentSender statusReceiver, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
+ mAppOps.checkPackage(callingUid, callerPackageName);
+ }
+
+ final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
+ statusReceiver, versionedPackage.getPackageName(), false, userId);
+ mPm.deleteExistingPackageAsUser(versionedPackage, adapter.getBinder(), userId);
+ }
+
+ @Override
public void installExistingPackage(String packageName, int installFlags, int installReason,
IntentSender statusReceiver, int userId, List<String> whiteListedPermissions) {
mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8b191dda5590..a9842ee37739 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17811,8 +17811,46 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.DELETE_PACKAGES, null);
+ Preconditions.checkNotNull(versionedPackage);
+ Preconditions.checkNotNull(observer);
+ final String packageName = versionedPackage.getPackageName();
+ final long versionCode = versionedPackage.getLongVersionCode();
+
+ int installedForUsersCount = 0;
+ synchronized (mLock) {
+ // Normalize package name to handle renamed packages and static libs
+ final String internalPkgName = resolveInternalPackageNameLPr(packageName, versionCode);
+ final PackageSetting ps = mSettings.getPackageLPr(internalPkgName);
+ if (ps != null) {
+ int[] installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
+ installedForUsersCount = installedUsers.length;
+ }
+ }
+
+ if (installedForUsersCount > 1) {
+ deletePackageVersionedInternal(versionedPackage, observer, userId, 0, true);
+ } else {
+ try {
+ observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_INTERNAL_ERROR,
+ null);
+ } catch (RemoteException re) {
+ }
+ }
+ }
+
+ @Override
public void deletePackageVersioned(VersionedPackage versionedPackage,
final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
+ deletePackageVersionedInternal(versionedPackage, observer, userId, deleteFlags, false);
+ }
+
+ private void deletePackageVersionedInternal(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags,
+ final boolean allowSilentUninstall) {
final int callingUid = Binder.getCallingUid();
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
@@ -17833,6 +17871,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int uid = Binder.getCallingUid();
if (!isOrphaned(internalPackageName)
+ && !allowSilentUninstall
&& !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
mHandler.post(() -> {
try {