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

Commit a0961704 authored by Alex Buynytskyy's avatar Alex Buynytskyy Committed by Android (Google) Code Review
Browse files

Merge "Handle archival for all users." into main

parents 828e80ce 2b9b9215
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
@@ -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);
        }
        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;
                        });
                }
        );
    }

    /**
@@ -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
+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