diff options
| author | 2024-02-02 03:14:35 +0000 | |
|---|---|---|
| committer | 2024-02-02 03:14:35 +0000 | |
| commit | a09617041de099d25708913b91d9e28d32e17cbc (patch) | |
| tree | 653553f9fb0afe4a0cb071bd0aeac4b5a4e32c20 | |
| parent | 828e80cecbb3637e909a4004c8ca3733e9b1c3ea (diff) | |
| parent | 2b9b9215b7118d20af3f8b8240a5069763017777 (diff) | |
Merge "Handle archival for all users." into main
6 files changed, 68 insertions, 46 deletions
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 1f25fd039dd8..451c0e5e079a 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -80,7 +80,7 @@ interface IPackageInstaller { long timeout); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES,android.Manifest.permission.REQUEST_DELETE_PACKAGES})") - void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); + void requestArchive(String packageName, String callerPackageName, int flags, in IntentSender statusReceiver, in UserHandle userHandle); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})") void requestUnarchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index c4bf18d70242..5df23c0ff44a 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -2362,8 +2362,8 @@ public class PackageInstaller { public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver) throws PackageManager.NameNotFoundException { try { - mInstaller.requestArchive(packageName, mInstallerPackageName, statusReceiver, - new UserHandle(mUserId)); + mInstaller.requestArchive(packageName, mInstallerPackageName, /*flags=*/ 0, + statusReceiver, new UserHandle(mUserId)); } catch (ParcelableException e) { e.maybeRethrow(PackageManager.NameNotFoundException.class); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index 339b1e71c091..0bbad85aebcd 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -28,6 +28,7 @@ import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; import static android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; +import static android.content.pm.PackageManager.DELETE_ALL_USERS; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; @@ -182,9 +183,19 @@ public class PackageArchiver { return Flags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false); } + @VisibleForTesting + void requestArchive( + @NonNull String packageName, + @NonNull String callerPackageName, + @NonNull IntentSender intentSender, + @NonNull UserHandle userHandle) { + requestArchive(packageName, callerPackageName, /*flags=*/ 0, intentSender, userHandle); + } + void requestArchive( @NonNull String packageName, @NonNull String callerPackageName, + int flags, @NonNull IntentSender intentSender, @NonNull UserHandle userHandle) { Objects.requireNonNull(packageName); @@ -193,51 +204,55 @@ public class PackageArchiver { Objects.requireNonNull(userHandle); Computer snapshot = mPm.snapshotComputer(); - int userId = userHandle.getIdentifier(); + int binderUserId = userHandle.getIdentifier(); int binderUid = Binder.getCallingUid(); int binderPid = Binder.getCallingPid(); if (!PackageManagerServiceUtils.isSystemOrRootOrShell(binderUid)) { - verifyCaller(snapshot.getPackageUid(callerPackageName, 0, userId), binderUid); + verifyCaller(snapshot.getPackageUid(callerPackageName, 0, binderUserId), binderUid); + } + + final boolean deleteAllUsers = (flags & PackageManager.DELETE_ALL_USERS) != 0; + final int[] users = deleteAllUsers ? mPm.mInjector.getUserManagerInternal().getUserIds() + : new int[]{binderUserId}; + for (int userId : users) { + snapshot.enforceCrossUserPermission(binderUid, userId, + /*requireFullPermission=*/ true, /*checkShell=*/ true, + "archiveApp"); } - snapshot.enforceCrossUserPermission(binderUid, userId, true, true, - "archiveApp"); verifyUninstallPermissions(); - CompletableFuture<ArchiveState> archiveStateFuture; + CompletableFuture<Void>[] archiveStateStored = new CompletableFuture[users.length]; try { - archiveStateFuture = createArchiveState(packageName, userId); + for (int i = 0, size = users.length; i < size; ++i) { + archiveStateStored[i] = createAndStoreArchiveState(packageName, users[i]); + } } catch (PackageManager.NameNotFoundException e) { Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s", packageName, e.getMessage())); throw new ParcelableException(e); } - archiveStateFuture - .thenAccept( - archiveState -> { - // TODO(b/282952870) Should be reverted if uninstall fails/cancels - try { - storeArchiveState(packageName, archiveState, userId); - } catch (PackageManager.NameNotFoundException e) { - sendFailureStatus(intentSender, packageName, e.getMessage()); - return; - } - - mPm.mInstallerService.uninstall( - new VersionedPackage(packageName, - PackageManager.VERSION_CODE_HIGHEST), - callerPackageName, - DELETE_ARCHIVE | DELETE_KEEP_DATA, - intentSender, - userId, - binderUid, - binderPid); - }) - .exceptionally( - e -> { - sendFailureStatus(intentSender, packageName, e.getMessage()); - return null; - }); + final int deleteFlags = DELETE_ARCHIVE | DELETE_KEEP_DATA + | (deleteAllUsers ? DELETE_ALL_USERS : 0); + + CompletableFuture.allOf(archiveStateStored).thenAccept(ignored -> + mPm.mInstallerService.uninstall( + new VersionedPackage(packageName, + PackageManager.VERSION_CODE_HIGHEST), + callerPackageName, + deleteFlags, + intentSender, + binderUserId, + binderUid, + binderPid) + ).exceptionally( + e -> { + Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s", + packageName, e.getMessage())); + sendFailureStatus(intentSender, packageName, e.getMessage()); + return null; + } + ); } /** @@ -384,7 +399,7 @@ public class PackageArchiver { } /** Creates archived state for the package and user. */ - private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) + private CompletableFuture<Void> createAndStoreArchiveState(String packageName, int userId) throws PackageManager.NameNotFoundException { Computer snapshot = mPm.snapshotComputer(); PackageStateInternal ps = getPackageState(packageName, snapshot, @@ -399,17 +414,18 @@ public class PackageArchiver { List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps.getPackageName(), userId); - final CompletableFuture<ArchiveState> archiveState = new CompletableFuture<>(); + final CompletableFuture<Void> archiveStateStored = new CompletableFuture<>(); mPm.mHandler.post(() -> { try { - archiveState.complete( - createArchiveStateInternal(packageName, userId, mainActivities, - installerInfo.loadLabel(mContext.getPackageManager()).toString())); - } catch (IOException e) { - archiveState.completeExceptionally(e); + var archiveState = createArchiveStateInternal(packageName, userId, mainActivities, + installerInfo.loadLabel(mContext.getPackageManager()).toString()); + storeArchiveState(packageName, archiveState, userId); + archiveStateStored.complete(null); + } catch (IOException | PackageManager.NameNotFoundException e) { + archiveStateStored.completeExceptionally(e); } }); - return archiveState; + return archiveStateStored; } @Nullable diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index c6d448d97673..abea56bfa433 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -1672,9 +1672,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements public void requestArchive( @NonNull String packageName, @NonNull String callerPackageName, + int flags, @NonNull IntentSender intentSender, @NonNull UserHandle userHandle) { - mPackageArchiver.requestArchive(packageName, callerPackageName, intentSender, userHandle); + mPackageArchiver.requestArchive(packageName, callerPackageName, flags, intentSender, + userHandle); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 5c9c8c6d249a..81f9d1b68438 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -4651,6 +4651,7 @@ class PackageManagerShellCommand extends ShellCommand { private int runArchive() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); + int flags = 0; int userId = UserHandle.USER_ALL; String opt; @@ -4678,13 +4679,16 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } + if (userId == UserHandle.USER_ALL) { + flags |= PackageManager.DELETE_ALL_USERS; + } final int translatedUserId = translateUserId(userId, UserHandle.USER_SYSTEM, "runArchive"); final LocalIntentReceiver receiver = new LocalIntentReceiver(); try { mInterface.getPackageInstaller().requestArchive(packageName, - /* callerPackageName= */ "", receiver.getIntentSender(), + /* callerPackageName= */ "", flags, receiver.getIntentSender(), new UserHandle(translatedUserId)); } catch (Exception e) { pw.println("Failure [" + e.getMessage() + "]"); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java index bf00b75e9f7b..4535ecee8097 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java @@ -270,7 +270,7 @@ public class PackageArchiverTest { assertThat(value.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)).isEqualTo(PACKAGE); assertThat(value.getIntExtra(PackageInstaller.EXTRA_STATUS, 0)).isEqualTo( PackageInstaller.STATUS_FAILURE); - assertThat(value.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)).isEqualTo( + assertThat(value.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)).contains( String.format("Package %s not found.", PACKAGE)); } |