Merge "Handle archival for all users." into main
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 1f25fd0..451c0e5 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -80,7 +80,7 @@
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 c4bf18d..5df23c0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2362,8 +2362,8 @@
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 339b1e7..0bbad85 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.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,62 +183,76 @@
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);
Objects.requireNonNull(callerPackageName);
Objects.requireNonNull(intentSender);
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);
}
- snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
- "archiveApp");
+
+ 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");
+ }
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;
- }
+ final int deleteFlags = DELETE_ARCHIVE | DELETE_KEEP_DATA
+ | (deleteAllUsers ? DELETE_ALL_USERS : 0);
- 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;
- });
+ 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 @@
}
/** 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 @@
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 c6d448d..abea56b 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 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 5c9c8c6..81f9d1b 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 @@
private int runArchive() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
+ int flags = 0;
int userId = UserHandle.USER_ALL;
String opt;
@@ -4678,13 +4679,16 @@
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 bf00b75..4535ece 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 @@
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));
}