Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b9b9215 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Handle archival for all users.

Fixes: 321988220
Test: atest PackageManagerTest
Test: atest --user-type secondary_user PackageManagerTest
Change-Id: I512e5c04542a10d6d7312aaa10cb469e4db1e8b2
parent 028d0c4a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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) {
+56 −40
Original line number Diff line number Diff line
@@ -29,6 +29,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;
@@ -183,9 +184,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);
@@ -194,51 +205,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);
        }
        snapshot.enforceCrossUserPermission(binderUid, userId, true, true,

        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);

        CompletableFuture.allOf(archiveStateStored).thenAccept(ignored ->
                mPm.mInstallerService.uninstall(
                        new VersionedPackage(packageName,
                                PackageManager.VERSION_CODE_HIGHEST),
                        callerPackageName,
                                    DELETE_ARCHIVE | DELETE_KEEP_DATA,
                        deleteFlags,
                        intentSender,
                                    userId,
                        binderUserId,
                        binderUid,
                                    binderPid);
                        })
                .exceptionally(
                        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;
                        });
                }
        );
    }

    /**
@@ -379,7 +394,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,
@@ -394,17 +409,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
+3 −1
Original line number Diff line number Diff line
@@ -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
+5 −1
Original line number Diff line number Diff line
@@ -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() + "]");
Loading