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

Commit d0db470f authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Set AndroidPackage to null for archived installs.

Bug: 313720942
Test: presubmit

Change-Id: I1d43cd9a56d8c4d7f0a5a70103e5d2336256d228
parent 1dfd11dd
Loading
Loading
Loading
Loading
+80 −84
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.pm;

import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;

import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
@@ -49,7 +50,6 @@ import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SELinuxUtil;

@@ -93,25 +93,27 @@ public class AppDataHelper {
     */
    @GuardedBy("mPm.mInstallLock")
    public void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
        prepareAppDataPostCommitLIF(pkg, 0 /* previousAppId */);
        final PackageSetting ps;
        synchronized (mPm.mLock) {
            ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
        }
        prepareAppDataPostCommitLIF(ps, 0 /* previousAppId */);
    }

    /**
     * For more details about data verification and previousAppId, check
     * {@link #prepareAppData(Installer.Batch, AndroidPackage, int, int, int)}
     * @see #prepareAppDataAfterInstallLIF(AndroidPackage)
     * {@link #prepareAppData}
     * @see #prepareAppDataAfterInstallLIF
     */
    @GuardedBy("mPm.mInstallLock")
    public void prepareAppDataPostCommitLIF(AndroidPackage pkg, int previousAppId) {
        final PackageSetting ps;
    public void prepareAppDataPostCommitLIF(PackageSetting ps, int previousAppId) {
        synchronized (mPm.mLock) {
            ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
            mPm.mSettings.writeKernelMappingLPr(ps);
        }

        // TODO(b/211761016): should we still create the profile dirs?
        if (!shouldHaveAppStorage(pkg)) {
            Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
        if (ps.getPkg() != null && !shouldHaveAppStorage(ps.getPkg())) {
            Slog.w(TAG, "Skipping preparing app data for " + ps.getPackageName());
            return;
        }

@@ -132,15 +134,15 @@ public class AppDataHelper {

            if (ps.getInstalled(user.id)) {
                // TODO: when user data is locked, mark that we're still dirty
                prepareAppData(batch, pkg, previousAppId, user.id, flags).thenRun(() -> {
                prepareAppData(batch, ps, 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()
                    if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                        // Prepare app data on external storage; currently this is used to
                        // setup any OBB dirs that were created by the installer correctly.
                        int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid()));
                        smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid);
                        int uid = UserHandle.getUid(user.id, ps.getAppId());
                        smInternal.prepareAppDataAfterInstall(ps.getPackageName(), uid);
                    }
                });
            }
@@ -156,73 +158,70 @@ public 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:
     * <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, app data owned by previousAppId will be migrated to the new app ID
     * </ul>
     */
    private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
            @Nullable AndroidPackage pkg, int previousAppId, int userId,
            @StorageManager.StorageFlags int flags) {
    private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
            @NonNull AndroidPackage pkg, @UserIdInt int userId,
            @StorageManager.StorageFlags int flags, boolean maybeMigrateAppData) {
        if (pkg == null) {
            Slog.wtf(TAG, "Package was null!", new Throwable());
            return CompletableFuture.completedFuture(null);
            return;
        }
        if (!shouldHaveAppStorage(pkg)) {
            Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
            return CompletableFuture.completedFuture(null);
            return;
        }
        return prepareAppDataLeaf(batch, pkg, previousAppId, userId, flags);
        final PackageSetting ps;
        synchronized (mPm.mLock) {
            ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
        }

    private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
            @NonNull PackageState packageState, @NonNull AndroidPackage pkg, @UserIdInt int userId,
            @StorageManager.StorageFlags int flags, boolean maybeMigrateAppData) {
        prepareAppData(batch, pkg, Process.INVALID_UID, userId, flags).thenRun(() -> {
        prepareAppData(batch, ps, 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()
            if (maybeMigrateAppData && maybeMigrateAppDataLIF(packageState, pkg, userId)) {
            if (maybeMigrateAppData && maybeMigrateAppDataLIF(ps, userId)) {
                // 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, Process.INVALID_UID, userId, flags);
                prepareAppData(batchInner, ps, Process.INVALID_UID, userId, flags);
                executeBatchLI(batchInner);
            }
        });
    }

    private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch,
            @NonNull AndroidPackage pkg, int previousAppId, int userId, int flags) {
    /**
     * 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:
     * <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, app data owned by previousAppId will be migrated to the new app ID
     * </ul>
     */
    private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
            @NonNull PackageSetting ps, int previousAppId, int userId, int flags) {
        final String packageName = ps.getPackageName();

        if (DEBUG_APP_DATA) {
            Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
            Slog.v(TAG, "prepareAppData for " + packageName + " u" + userId + " 0x"
                    + Integer.toHexString(flags));
        }

        final PackageSetting ps;
        final String seInfoUser;
        synchronized (mPm.mLock) {
            ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
            seInfoUser = SELinuxUtil.getSeinfoUser(ps.readUserState(userId));
        }
        final String volumeUuid = pkg.getVolumeUuid();
        final String packageName = pkg.getPackageName();

        final int appId = UserHandle.getAppId(pkg.getUid());
        final AndroidPackage pkg = ps.getPkg();
        final String volumeUuid = ps.getVolumeUuid();
        final int appId = ps.getAppId();

        String pkgSeInfo = ps.getSeInfo();

        Preconditions.checkNotNull(pkgSeInfo);

        final String seInfo = pkgSeInfo + seInfoUser;
        final int targetSdkVersion = pkg.getTargetSdkVersion();
        final boolean usesSdk = !pkg.getUsesSdkLibraries().isEmpty();
        final int targetSdkVersion = ps.getTargetSdkVersion();
        final boolean usesSdk = ps.getUsesSdkLibraries().length > 0;
        final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(volumeUuid, packageName,
                userId, flags, appId, seInfo, targetSdkVersion, usesSdk);
        args.previousAppId = previousAppId;
@@ -234,7 +233,7 @@ public class AppDataHelper {
            if (e != null) {
                logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName
                        + ", but trying to recover: " + e);
                destroyAppDataLeafLIF(pkg, userId, flags);
                destroyAppDataLeafLIF(packageName, volumeUuid, userId, flags);
                try {
                    createAppDataResult = mInstaller.createAppData(args);
                    logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
@@ -267,8 +266,8 @@ public class AppDataHelper {
                // #performDexOptUpgrade. When we do that we should have a
                // more granular check here and only update the existing
                // profiles.
                if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()
                        || (userId != UserHandle.USER_SYSTEM)) {
                if (pkg != null && (mPm.isDeviceUpgrading() || mPm.isFirstBoot()
                        || (userId != UserHandle.USER_SYSTEM))) {
                    try {
                        mArtManagerService.prepareAppProfiles(pkg, userId,
                                /* updateReferenceProfileContent= */ false);
@@ -292,7 +291,9 @@ public class AppDataHelper {
                }
            }

            if (pkg != null) {
                prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
            }
        });
    }

@@ -336,18 +337,17 @@ public class AppDataHelper {
     * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
     * requested by the app.
     */
    private boolean maybeMigrateAppDataLIF(@NonNull PackageState packageState,
            @NonNull AndroidPackage pkg, @UserIdInt int userId) {
        if (packageState.isSystem() && !StorageManager.isFileEncrypted()
    private boolean maybeMigrateAppDataLIF(@NonNull PackageSetting ps, @UserIdInt int userId) {
        if (ps.isSystem() && !StorageManager.isFileEncrypted()
                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
            final int storageTarget = pkg.isDefaultToDeviceProtectedStorage()
            final int storageTarget = ps.isDefaultToDeviceProtectedStorage()
                    ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
            try {
                mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId,
                mInstaller.migrateAppData(ps.getVolumeUuid(), ps.getPackageName(), userId,
                        storageTarget);
            } catch (Installer.InstallerException e) {
                logCriticalInfo(Log.WARN,
                        "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage());
                        "Failed to migrate " + ps.getPackageName() + ": " + e.getMessage());
            }
            return true;
        } else {
@@ -471,7 +471,7 @@ public class AppDataHelper {
            }

            if (ps.getUserStateOrDefault(userId).isInstalled()) {
                prepareAppDataAndMigrate(batch, ps, ps.getPkg(), userId, flags, migrateAppData);
                prepareAppDataAndMigrate(batch, ps.getPkg(), userId, flags, migrateAppData);
                preparedCount++;
            }
        }
@@ -550,7 +550,7 @@ public class AppDataHelper {
                        && packageStateInternal.getUserStateOrDefault(
                                UserHandle.USER_SYSTEM).isInstalled()) {
                    AndroidPackage pkg = packageStateInternal.getPkg();
                    prepareAppDataAndMigrate(batch, packageStateInternal, pkg,
                    prepareAppDataAndMigrate(batch, pkg,
                            UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */);
                    count++;
                }
@@ -568,22 +568,22 @@ public class AppDataHelper {
        if (pkg == null) {
            return;
        }
        clearAppDataLeafLIF(pkg, userId, flags);
        clearAppDataLeafLIF(pkg.getPackageName(), pkg.getVolumeUuid(), userId, flags);

        if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
            clearAppProfilesLIF(pkg);
        }
    }

    private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
    void clearAppDataLeafLIF(String packageName, String volumeUuid, int userId, int flags) {
        final Computer snapshot = mPm.snapshotComputer();
        final PackageStateInternal packageStateInternal =
                snapshot.getPackageStateInternal(pkg.getPackageName());
                snapshot.getPackageStateInternal(packageName);
        for (int realUserId : mPm.resolveUserIds(userId)) {
            final long ceDataInode = (packageStateInternal != null)
                    ? packageStateInternal.getUserStateOrDefault(realUserId).getCeDataInode() : 0;
            try {
                mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
                mInstaller.clearAppData(volumeUuid, packageName, realUserId,
                        flags, ceDataInode);
            } catch (Installer.InstallerException e) {
                Slog.w(TAG, String.valueOf(e));
@@ -597,7 +597,7 @@ public class AppDataHelper {
            return;
        }
        if (DexOptHelper.useArtService()) {
            destroyAppProfilesWithArtService(pkg);
            destroyAppProfilesWithArtService(pkg.getPackageName());
        } else {
            try {
                mArtManagerService.clearAppProfiles(pkg);
@@ -612,41 +612,37 @@ public class AppDataHelper {
            Slog.wtf(TAG, "Package was null!", new Throwable());
            return;
        }
        destroyAppDataLeafLIF(pkg, userId, flags);
        destroyAppDataLeafLIF(pkg.getPackageName(), pkg.getVolumeUuid(), userId, flags);
    }

    private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
    private void destroyAppDataLeafLIF(
            String packageName, String volumeUuid, int userId, int flags) {
        final Computer snapshot = mPm.snapshotComputer();
        final PackageStateInternal packageStateInternal =
                snapshot.getPackageStateInternal(pkg.getPackageName());
                snapshot.getPackageStateInternal(packageName);
        for (int realUserId : mPm.resolveUserIds(userId)) {
            final long ceDataInode = (packageStateInternal != null)
                    ? packageStateInternal.getUserStateOrDefault(realUserId).getCeDataInode() : 0;
            try {
                mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
                mInstaller.destroyAppData(volumeUuid, packageName, realUserId,
                        flags, ceDataInode);
            } catch (Installer.InstallerException e) {
                Slog.w(TAG, String.valueOf(e));
            }
            mPm.getDexManager().notifyPackageDataDestroyed(pkg.getPackageName(), userId);
            mPm.getDynamicCodeLogger().notifyPackageDataDestroyed(pkg.getPackageName(), userId);
        }
            mPm.getDexManager().notifyPackageDataDestroyed(packageName, userId);
            mPm.getDynamicCodeLogger().notifyPackageDataDestroyed(packageName, userId);
        }

    public void destroyAppProfilesLIF(AndroidPackage pkg) {
        if (pkg == null) {
            Slog.wtf(TAG, "Package was null!", new Throwable());
            return;
        }
        destroyAppProfilesLeafLIF(pkg);
    }

    private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
    /**
     * Destroy ART app profiles for the package.
     */
    void destroyAppProfilesLIF(String packageName) {
        if (DexOptHelper.useArtService()) {
            destroyAppProfilesWithArtService(pkg);
            destroyAppProfilesWithArtService(packageName);
        } else {
            try {
                mInstaller.destroyAppProfiles(pkg.getPackageName());
                mInstaller.destroyAppProfiles(packageName);
            } catch (LegacyDexoptDisabledException e) {
                throw new RuntimeException(e);
            } catch (Installer.InstallerException e) {
@@ -655,7 +651,7 @@ public class AppDataHelper {
        }
    }

    private void destroyAppProfilesWithArtService(AndroidPackage pkg) {
    private void destroyAppProfilesWithArtService(String packageName) {
        if (!DexOptHelper.artManagerLocalIsInitialized()) {
            // This function may get called while PackageManagerService is constructed (via e.g.
            // InitAppsHelper.initSystemApps), and ART Service hasn't yet been started then (it
@@ -668,7 +664,7 @@ public class AppDataHelper {
        try (PackageManagerLocal.FilteredSnapshot snapshot =
                        getPackageManagerLocal().withFilteredSnapshot()) {
            try {
                DexOptHelper.getArtManagerLocal().clearAppProfiles(snapshot, pkg.getPackageName());
                DexOptHelper.getArtManagerLocal().clearAppProfiles(snapshot, packageName);
            } catch (IllegalArgumentException e) {
                // Package isn't found, but that should only happen due to race.
                Slog.w(TAG, e);
+10 −8
Original line number Diff line number Diff line
@@ -1500,14 +1500,15 @@ public class ComputerEngine implements Computer {
                    state.getFirstInstallTimeMillis(), ps.getLastUpdateTime(), installedPermissions,
                    grantedPermissions, state, userId, ps);

            if (packageInfo != null) {
            if (packageInfo == null) {
                return null;
            }

            packageInfo.packageName = packageInfo.applicationInfo.packageName =
                    resolveExternalPackageName(p);

            return packageInfo;
            }
        }
        // TODO(b/314808978): Set ps.setPkg to null during install-archived.
        if ((flags & (MATCH_UNINSTALLED_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0
        } else if ((flags & (MATCH_UNINSTALLED_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0
                && PackageUserStateUtils.isAvailable(state, flags)) {
            PackageInfo pi = new PackageInfo();
            pi.packageName = ps.getPackageName();
@@ -1539,9 +1540,10 @@ public class ComputerEngine implements Computer {
                        + ps.getPackageName() + "]. Provides a minimum info.");
            }
            return pi;
        }
        } else {
            return null;
        }
    }

    public final PackageInfo getPackageInfo(String packageName,
            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+13 −10
Original line number Diff line number Diff line
@@ -732,7 +732,8 @@ final class InstallPackageHelper {

                    synchronized (mPm.mInstallLock) {
                        // We don't need to freeze for a brand new install
                        mAppDataHelper.prepareAppDataAfterInstallLIF(pkgSetting.getPkg());
                        mAppDataHelper.prepareAppDataPostCommitLIF(
                                pkgSetting, /* previousAppId= */0);
                    }
                }
                // TODO(b/278553670) Store archive state for the user.
@@ -2435,9 +2436,9 @@ final class InstallPackageHelper {
            final boolean instantApp = ((installRequest.getScanFlags() & SCAN_AS_INSTANT_APP) != 0);
            final boolean isApex = ((installRequest.getScanFlags() & SCAN_AS_APEX) != 0);
            final PackageSetting ps = installRequest.getScannedPackageSetting();
            final String packageName = ps.getPackageName();
            final String codePath = ps.getPathString();
            final AndroidPackage pkg = ps.getPkg();
            final String packageName = pkg.getPackageName();
            final String codePath = pkg.getPath();
            final boolean onIncremental = mIncrementalManager != null
                    && isIncrementalPath(codePath);
            if (onIncremental) {
@@ -2450,18 +2451,19 @@ final class InstallPackageHelper {
            }

            // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
            mAppDataHelper.prepareAppDataPostCommitLIF(pkg, 0);
            mAppDataHelper.prepareAppDataPostCommitLIF(ps, 0);
            if (installRequest.isClearCodeCache()) {
                mAppDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
                        FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
                                | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                mAppDataHelper.clearAppDataLeafLIF(packageName, ps.getVolumeUuid(),
                        UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                        | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
            }
            if (installRequest.isInstallReplace()) {
                mDexManager.notifyPackageUpdated(pkg.getPackageName(),
            if (installRequest.isInstallReplace() && pkg != null) {
                mDexManager.notifyPackageUpdated(packageName,
                        pkg.getBaseApkPath(), pkg.getSplitCodePaths());
            }

            if (!useArtService()) { // ART Service handles this on demand instead.
            // ART Service handles this on demand instead.
            if (!useArtService() && pkg != null) {
                // Prepare the application profiles for the new code paths.
                // This needs to be done before invoking dexopt so that any install-time profile
                // can be used for optimizations.
@@ -2526,6 +2528,7 @@ final class InstallPackageHelper {
                    (!instantApp || android.provider.Settings.Global.getInt(
                            mContext.getContentResolver(),
                            android.provider.Settings.Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                            && pkg != null
                            && !pkg.isDebuggable()
                            && (!onIncremental)
                            && dexoptOptions.isCompilationEnabled()
+1 −0
Original line number Diff line number Diff line
@@ -1540,6 +1540,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                continue;
            }
            pkgSetting
                    .setPkg(null)
                    .modifyUserState(userId)
                    .setInstalled(false)
                    .setArchiveState(archiveState);
+2 −2
Original line number Diff line number Diff line
@@ -261,7 +261,7 @@ final class RemovePackageHelper {
            sus = mPm.mSettings.getSharedUserSettingLPr(ps);
        }

        mAppDataHelper.destroyAppProfilesLIF(pkg);
        mAppDataHelper.destroyAppProfilesLIF(ps.getPackageName());

        final List<AndroidPackage> sharedUserPkgs =
                sus != null ? sus.getPackages() : Collections.emptyList();
@@ -354,7 +354,7 @@ final class RemovePackageHelper {
            }
            mAppDataHelper.destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
                    FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
            mAppDataHelper.destroyAppProfilesLIF(resolvedPkg);
            mAppDataHelper.destroyAppProfilesLIF(resolvedPkg.getPackageName());
            if (outInfo != null) {
                outInfo.mDataRemoved = true;
            }