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

Commit 27bb37e0 authored by John Wu's avatar John Wu Committed by Android (Google) Code Review
Browse files

Merge "Migrate data when apps leave sharedUserId"

parents fe023a7d c71ba54c
Loading
Loading
Loading
Loading
+79 −70
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.SELinuxUtil;
import android.content.pm.UserInfo;
import android.os.CreateAppDataArgs;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
@@ -86,12 +88,20 @@ final class AppDataHelper {
     * <p>
     * Verifies that directories exist and that ownership and labeling is
     * correct for all installed apps. If there is an ownership mismatch, it
     * will try recovering system apps by wiping data; third-party app data is
     * left intact.
     * will wipe and recreate the data.
     * <p>
     * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
     */
    public void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
        prepareAppDataPostCommitLIF(pkg, 0 /* previousAppId */);
    }

    /**
     * For more details about data verification and previousAppId, check
     * {@link #prepareAppData(Installer.Batch, AndroidPackage, int, int, int)}
     * @see #prepareAppDataAfterInstallLIF(AndroidPackage)
     */
    public void prepareAppDataPostCommitLIF(AndroidPackage pkg, int previousAppId) {
        final PackageSetting ps;
        synchronized (mPm.mLock) {
            ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -113,13 +123,9 @@ final class AppDataHelper {
                continue;
            }

            // TODO@ashfall check ScanResult.mNeedsNewAppId, and if true instead
            // of creating app data, migrate / change ownership of existing
            // data.

            if (ps.getInstalled(user.id)) {
                // TODO: when user data is locked, mark that we're still dirty
                prepareAppData(batch, pkg, user.id, flags).thenRun(() -> {
                prepareAppData(batch, pkg, previousAppId, user.id, flags).thenRun(() -> {
                    // Note: this code block is executed with the Installer lock
                    // already held, since it's invoked as a side-effect of
                    // executeBatchLI()
@@ -147,22 +153,26 @@ final class AppDataHelper {
     * Prepare app data for the given app.
     * <p>
     * Verifies that directories exist and that ownership and labeling is
     * correct for all installed apps. If there is an ownership mismatch, this
     * will try recovering system apps by wiping data; third-party app data is
     * left intact.
     * correct for all installed apps. If there is an ownership mismatch:
     * <ul>
     * <li>If previousAppId < 0, app data will be migrated to the new app ID
     * <li>If previousAppId == 0, no migration will happen and data will be wiped and recreated
     * <li>If previousAppId > 0, it will migrate all data owned by previousAppId
     *     to the new app ID
     * </ul>
     */
    private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
            @Nullable AndroidPackage pkg, int userId, int flags) {
            @Nullable AndroidPackage pkg, int previousAppId, int userId, int flags) {
        if (pkg == null) {
            Slog.wtf(TAG, "Package was null!", new Throwable());
            return CompletableFuture.completedFuture(null);
        }
        return prepareAppDataLeaf(batch, pkg, userId, flags);
        return prepareAppDataLeaf(batch, pkg, previousAppId, userId, flags);
    }

    private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
            @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) {
        prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
        prepareAppData(batch, pkg, Process.INVALID_UID, userId, flags).thenRun(() -> {
            // Note: this code block is executed with the Installer lock
            // already held, since it's invoked as a side-effect of
            // executeBatchLI()
@@ -170,14 +180,14 @@ final class AppDataHelper {
                // We may have just shuffled around app data directories, so
                // prepare them one more time
                final Installer.Batch batchInner = new Installer.Batch();
                prepareAppData(batchInner, pkg, userId, flags);
                prepareAppData(batchInner, pkg, Process.INVALID_UID, userId, flags);
                executeBatchLI(batchInner);
            }
        });
    }

    private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch,
            @NonNull AndroidPackage pkg, int userId, int flags) {
            @NonNull AndroidPackage pkg, int previousAppId, int userId, int flags) {
        if (DEBUG_APP_DATA) {
            Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
                    + Integer.toHexString(flags));
@@ -200,9 +210,11 @@ final class AppDataHelper {

        final String seInfo = pkgSeInfo + seInfoUser;
        final int targetSdkVersion = pkg.getTargetSdkVersion();
        final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(volumeUuid, packageName,
                userId, flags, appId, seInfo, targetSdkVersion);
        args.previousAppId = previousAppId;

        return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo,
                targetSdkVersion).whenComplete((ceDataInode, e) -> {
        return batch.createAppData(args).whenComplete((ceDataInode, e) -> {
            // Note: this code block is executed with the Installer lock
            // already held, since it's invoked as a side-effect of
            // executeBatchLI()
@@ -211,8 +223,7 @@ final class AppDataHelper {
                        + ", but trying to recover: " + e);
                destroyAppDataLeafLIF(pkg, userId, flags);
                try {
                            ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
                                    flags, appId, seInfo, pkg.getTargetSdkVersion());
                    ceDataInode = mInstaller.createAppData(args).ceDataInode;
                    logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
                } catch (Installer.InstallerException e2) {
                    logCriticalInfo(Log.DEBUG, "Recovery failed!");
@@ -251,11 +262,9 @@ final class AppDataHelper {
            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
                // TODO: mark this structure as dirty so we persist it!
                synchronized (mPm.mLock) {
                            if (ps != null) {
                    ps.setCeDataInode(ceDataInode, userId);
                }
            }
                    }

            prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
        });
+6 −1
Original line number Diff line number Diff line
@@ -2433,7 +2433,12 @@ final class InstallPackageHelper {
                }
                incrementalStorages.add(storage);
            }
            appDataHelper.prepareAppDataAfterInstallLIF(pkg);
            int previousAppId = 0;
            if (reconciledPkg.mScanResult.needsNewAppId()) {
                // Only set previousAppId if the app is migrating out of shared UID
                previousAppId = reconciledPkg.mScanResult.mPreviousAppId;
            }
            appDataHelper.prepareAppDataPostCommitLIF(pkg, previousAppId);
            if (reconciledPkg.mPrepareResult.mClearCodeCache) {
                appDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
                        FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
+12 −35
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.os.Build;
import android.os.CreateAppDataArgs;
import android.os.CreateAppDataResult;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.IInstalld;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -148,12 +147,9 @@ public class Installer extends SystemService {
        IBinder binder = ServiceManager.getService("installd");
        if (binder != null) {
            try {
                binder.linkToDeath(new DeathRecipient() {
                    @Override
                    public void binderDied() {
                binder.linkToDeath(() -> {
                    Slog.w(TAG, "installd died; reconnecting");
                    connect();
                    }
                }, 0);
            } catch (RemoteException e) {
                binder = null;
@@ -168,9 +164,7 @@ public class Installer extends SystemService {
            }
        } else {
            Slog.w(TAG, "installd not found; trying again");
            BackgroundThread.getHandler().postDelayed(() -> {
                connect();
            }, DateUtils.SECOND_IN_MILLIS);
            BackgroundThread.getHandler().postDelayed(this::connect, DateUtils.SECOND_IN_MILLIS);
        }
    }

@@ -192,7 +186,9 @@ public class Installer extends SystemService {
        }
    }

    private static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName,
    // We explicitly do NOT set previousAppId because the default value should always be 0.
    // Manually override previousAppId after building CreateAppDataArgs for specific behaviors.
    static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName,
            int userId, int flags, int appId, String seInfo, int targetSdkVersion) {
        final CreateAppDataArgs args = new CreateAppDataArgs();
        args.uuid = uuid;
@@ -213,23 +209,6 @@ public class Installer extends SystemService {
        return result;
    }

    /**
     * @deprecated callers are encouraged to migrate to using {@link Batch} to
     *             more efficiently handle operations in bulk.
     */
    @Deprecated
    public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
            String seInfo, int targetSdkVersion) throws InstallerException {
        final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags,
                appId, seInfo, targetSdkVersion);
        final CreateAppDataResult result = createAppData(args);
        if (result.exceptionCode == 0) {
            return result.ceDataInode;
        } else {
            throw new InstallerException(result.exceptionMessage);
        }
    }

    public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
            throws InstallerException {
        if (!checkBeforeRemote()) {
@@ -284,13 +263,11 @@ public class Installer extends SystemService {
         * Callers of this method are not required to hold a monitor lock on an
         * {@link Installer} object.
         */
        public synchronized @NonNull CompletableFuture<Long> createAppData(String uuid,
                String packageName, int userId, int flags, int appId, String seInfo,
                int targetSdkVersion) {
            if (mExecuted) throw new IllegalStateException();

            final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags,
                    appId, seInfo, targetSdkVersion);
        @NonNull
        public synchronized CompletableFuture<Long> createAppData(CreateAppDataArgs args) {
            if (mExecuted) {
                throw new IllegalStateException();
            }
            final CompletableFuture<Long> future = new CompletableFuture<>();
            mArgs.add(args);
            mFutures.add(future);
+4 −1
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import android.content.pm.pkg.PackageUserStateUtils;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.CreateAppDataArgs;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -4016,9 +4017,11 @@ public final class Settings implements Watchable, Snappable {
                    // Accumulate all required args and call the installer after mPackages lock
                    // has been released
                    final String seInfo = AndroidPackageUtils.getSeInfo(ps.getPkg(), ps);
                    batch.createAppData(ps.getVolumeUuid(), ps.getPackageName(), userHandle,
                    final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(
                            ps.getVolumeUuid(), ps.getPackageName(), userHandle,
                            StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE,
                            ps.getAppId(), seInfo, ps.getPkg().getTargetSdkVersion());
                    batch.createAppData(args);
                } else {
                    // Make sure the app is excluded from storage mapping for this user
                    writeKernelMappingLPr(ps);