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

Commit d7917c52 authored by Songchun Fan's avatar Songchun Fan
Browse files

Move more install-related code into InstallPackageHelper

The goal is to move code blocks that modify mPackages and mSettings into
one place (InstallPackageHelper).

+ Some clean up in InitAndSystemPackageHelper.

BUG: 198177734
BUG: 201815903
Test: manual
Change-Id: I965d59207d5d2963e76feeb6db72100ab7de0e82
parent 7582c4ac
Loading
Loading
Loading
Loading
+65 −315
Original line number Diff line number Diff line
@@ -16,13 +16,10 @@

package com.android.server.pm;

import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;

import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
@@ -33,23 +30,18 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;

import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.pm.parsing.PackageCacher;
@@ -69,13 +61,12 @@ import java.util.concurrent.ExecutorService;
 */
final class InitAndSystemPackageHelper {
    private final PackageManagerService mPm;
    private final RemovePackageHelper mRemovePackageHelper;
    private final AppDataHelper mAppDataHelper;

    private final List<ScanPartition> mDirsToScanAsSystem;
    private final int mScanFlags;
    private final int mSystemParseFlags;
    private final int mSystemScanFlags;
    private final InstallPackageHelper mInstallPackageHelper;

    /**
     * Tracks new system packages [received in an OTA] that we expect to
@@ -85,11 +76,9 @@ final class InitAndSystemPackageHelper {
    private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();

    // TODO(b/198166813): remove PMS dependency
    InitAndSystemPackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper,
            AppDataHelper appDataHelper) {
    InitAndSystemPackageHelper(PackageManagerService pm) {
        mPm = pm;
        mRemovePackageHelper = removePackageHelper;
        mAppDataHelper = appDataHelper;
        mInstallPackageHelper = new InstallPackageHelper(pm);
        mDirsToScanAsSystem = getSystemScanPartitions();
        // Set flag to monitor and not change apk file paths when scanning install directories.
        int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
@@ -158,61 +147,6 @@ final class InitAndSystemPackageHelper {
                consumer -> mPm.forEachPackage(
                        pkg -> consumer.accept(pkg, pkg.isSystem(),
                          apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
        cleanupSystemPackagesAndInstallStubs(packageParser, executorService, packageSettings,
                startTime, userIds);
        packageParser.close();
        return overlayConfig;
    }
    /**
     * First part of init dir scanning
     */
    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {
        File frameworkDir = new File(Environment.getRootDirectory(), "framework");

        // Collect vendor/product/system_ext overlay packages. (Do this before scanning
        // any apps.)
        // For security and version matching reason, only consider overlay packages if they
        // reside in the right directory.
        for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getOverlayFolder() == null) {
                continue;
            }
            scanDirTracedLI(partition.getOverlayFolder(), mSystemParseFlags,
                    mSystemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }

        scanDirTracedLI(frameworkDir, mSystemParseFlags,
                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                packageParser, executorService);
        if (!mPm.mPackages.containsKey("android")) {
            throw new IllegalStateException(
                    "Failed to load frameworks package; check log for warnings");
        }

        for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getPrivAppFolder() != null) {
                scanDirTracedLI(partition.getPrivAppFolder(), mSystemParseFlags,
                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                        packageParser, executorService);
            }
            scanDirTracedLI(partition.getAppFolder(), mSystemParseFlags,
                    mSystemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }
    }

    /**
     * Second part of init dir scanning
     */
    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private void cleanupSystemPackagesAndInstallStubs(PackageParser2 packageParser,
            ExecutorService executorService,
            WatchedArrayMap<String, PackageSetting> packageSettings,
            long startTime, int[] userIds) {
        // Prune any system packages that no longer exist.
        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
        // Stub packages must either be replaced with full versions in the /data
@@ -221,77 +155,9 @@ final class InitAndSystemPackageHelper {

        if (!mPm.isOnlyCoreApps()) {
            // do this first before mucking with mPackages for the "expecting better" case
            final int numPackages = mPm.mPackages.size();
            for (int index = 0; index < numPackages; index++) {
                final AndroidPackage pkg = mPm.mPackages.valueAt(index);
                if (pkg.isStub()) {
                    stubSystemApps.add(pkg.getPackageName());
                }
            }

            // Iterates PackageSettings in reversed order because the item could be removed
            // during the iteration.
            for (int index = packageSettings.size() - 1; index >= 0; index--) {
                final PackageSetting ps = packageSettings.valueAt(index);

                /*
                 * If this is not a system app, it can't be a
                 * disable system app.
                 */
                if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    continue;
                }

                /*
                 * If the package is scanned, it's not erased.
                 */
                final AndroidPackage scannedPkg = mPm.mPackages.get(ps.getPackageName());
                final PackageSetting disabledPs =
                        mPm.mSettings.getDisabledSystemPkgLPr(ps.getPackageName());
                if (scannedPkg != null) {
                    /*
                     * If the system app is both scanned and in the
                     * disabled packages list, then it must have been
                     * added via OTA. Remove it from the currently
                     * scanned package so the previously user-installed
                     * application can be scanned.
                     */
                    if (disabledPs != null) {
                        logCriticalInfo(Log.WARN,
                                "Expecting better updated system app for "
                                        + ps.getPackageName()
                                        + "; removing system app.  Last known"
                                        + " codePath=" + ps.getPathString()
                                        + ", versionCode=" + ps.getVersionCode()
                                        + "; scanned versionCode="
                                        + scannedPkg.getLongVersionCode());
                        mRemovePackageHelper.removePackageLI(scannedPkg, true);
                        mExpectingBetter.put(ps.getPackageName(), ps.getPath());
                    }

                    continue;
                }

                if (disabledPs == null) {
                    logCriticalInfo(Log.WARN, "System package " + ps.getPackageName()
                            + " no longer exists; its data will be wiped");
                    mRemovePackageHelper.removePackageDataLIF(ps, userIds, null, 0, false);
                } else {
                    // we still have a disabled system package, but, it still might have
                    // been removed. check the code path still exists and check there's
                    // still a package. the latter can happen if an OTA keeps the same
                    // code path, but, changes the package name.
                    if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
                            || disabledPs.getPkg() == null) {
                        possiblyDeletedUpdatedSystemApps.add(ps.getPackageName());
                    } else {
                        // We're expecting that the system app should remain disabled, but add
                        // it to expecting better to recover in case the data version cannot
                        // be scanned.
                        mExpectingBetter.put(disabledPs.getPackageName(), disabledPs.getPath());
                    }
                }
            }
            updateStubSystemAppsList(stubSystemApps);
            mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
                    possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
        }

        final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
@@ -312,6 +178,7 @@ final class InitAndSystemPackageHelper {
                    systemScanTime / systemPackagesCount);
            //CHECKSTYLE:ON IndentationCheck
        }

        if (!mPm.isOnlyCoreApps()) {
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                    SystemClock.uptimeMillis());
@@ -327,110 +194,14 @@ final class InitAndSystemPackageHelper {
        }

        if (!mPm.isOnlyCoreApps()) {
            final ScanPackageHelper scanPackageHelper = new ScanPackageHelper(mPm);
            // Remove disable package settings for updated system apps that were
            // removed via an OTA. If the update is no longer present, remove the
            // app completely. Otherwise, revoke their system privileges.
            for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
                final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
                final AndroidPackage pkg = mPm.mPackages.get(packageName);
                final String msg;

                // remove from the disabled system list; do this first so any future
                // scans of this package are performed without this state
                mPm.mSettings.removeDisabledSystemPackageLPw(packageName);

                if (pkg == null) {
                    // should have found an update, but, we didn't; remove everything
                    msg = "Updated system package " + packageName
                            + " no longer exists; removing its data";
                    // Actual deletion of code and data will be handled by later
                    // reconciliation step
                } else {
                    // found an update; revoke system privileges
                    msg = "Updated system package " + packageName
                            + " no longer exists; rescanning package on data";

                    // NOTE: We don't do anything special if a stub is removed from the
                    // system image. But, if we were [like removing the uncompressed
                    // version from the /data partition], this is where it'd be done.

                    // remove the package from the system and re-scan it without any
                    // special privileges
                    mRemovePackageHelper.removePackageLI(pkg, true);
                    try {
                        final File codePath = new File(pkg.getPath());
                        scanPackageHelper.scanPackageTracedLI(codePath, 0, mScanFlags, 0, null);
                    } catch (PackageManagerException e) {
                        Slog.e(TAG, "Failed to parse updated, ex-system package: "
                                + e.getMessage());
                    }
                }

                // one final check. if we still have a package setting [ie. it was
                // previously scanned and known to the system], but, we don't have
                // a package [ie. there was an error scanning it from the /data
                // partition], completely remove the package data.
                final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
                if (ps != null && mPm.mPackages.get(packageName) == null) {
                    mRemovePackageHelper.removePackageDataLIF(ps, userIds, null, 0, false);

                }
                logCriticalInfo(Log.WARN, msg);
            }

            /*
             * Make sure all system apps that we expected to appear on
             * the userdata partition actually showed up. If they never
             * appeared, crawl back and revive the system version.
             */
            for (int i = 0; i < mExpectingBetter.size(); i++) {
                final String packageName = mExpectingBetter.keyAt(i);
                if (!mPm.mPackages.containsKey(packageName)) {
                    final File scanFile = mExpectingBetter.valueAt(i);

                    logCriticalInfo(Log.WARN, "Expected better " + packageName
                            + " but never showed up; reverting to system");

                    @ParsingPackageUtils.ParseFlags int reparseFlags = 0;
                    @PackageManagerService.ScanFlags int rescanFlags = 0;
                    for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
                        final ScanPartition partition = mDirsToScanAsSystem.get(i1);
                        if (partition.containsPrivApp(scanFile)) {
                            reparseFlags = mSystemParseFlags;
                            rescanFlags = mSystemScanFlags | SCAN_AS_PRIVILEGED
                                    | partition.scanFlag;
                            break;
                        }
                        if (partition.containsApp(scanFile)) {
                            reparseFlags = mSystemParseFlags;
                            rescanFlags = mSystemScanFlags | partition.scanFlag;
                            break;
                        }
                    }
                    if (rescanFlags == 0) {
                        Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                        continue;
                    }
                    mPm.mSettings.enableSystemPackageLPw(packageName);

                    try {
                        final AndroidPackage newPkg = scanPackageHelper.scanPackageTracedLI(
                                scanFile, reparseFlags, rescanFlags, 0, null);
                        // We rescanned a stub, add it to the list of stubbed system packages
                        if (newPkg.isStub()) {
                            stubSystemApps.add(packageName);
                        }
                    } catch (PackageManagerException e) {
                        Slog.e(TAG, "Failed to parse original system package: "
                                + e.getMessage());
                    }
                }
            }
            mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
                    userIds, mScanFlags);
            mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
                    stubSystemApps, mSystemScanFlags, mSystemParseFlags);

            // Uncompress and install any stubbed system applications.
            // This must be done last to ensure all stubs are replaced or disabled.
            new InstallPackageHelper(mPm).installSystemStubPackages(stubSystemApps, mScanFlags);
            mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);

            final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
                    - cachedSystemApps;
@@ -454,93 +225,72 @@ final class InitAndSystemPackageHelper {
        mExpectingBetter.clear();

        mPm.mSettings.pruneRenamedPackagesLPw();
        packageParser.close();
        return overlayConfig;
    }

    /**
     * First part of init dir scanning
     */
    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
        try {
            scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {
        File frameworkDir = new File(Environment.getRootDirectory(), "framework");

        // Collect vendor/product/system_ext overlay packages. (Do this before scanning
        // any apps.)
        // For security and version matching reason, only consider overlay packages if they
        // reside in the right directory.
        for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getOverlayFolder() == null) {
                continue;
            }
            scanDirTracedLI(partition.getOverlayFolder(), mSystemParseFlags,
                    mSystemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }

    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
            PackageParser2 packageParser, ExecutorService executorService) {
        final File[] files = scanDir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + scanDir);
            return;
        scanDirTracedLI(frameworkDir, mSystemParseFlags,
                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                packageParser, executorService);
        if (!mPm.mPackages.containsKey("android")) {
            throw new IllegalStateException(
                    "Failed to load frameworks package; check log for warnings");
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getPrivAppFolder() != null) {
                scanDirTracedLI(partition.getPrivAppFolder(), mSystemParseFlags,
                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                        packageParser, executorService);
            }

        ParallelPackageParser parallelPackageParser =
                new ParallelPackageParser(packageParser, executorService);

        // Submit files for parsing in parallel
        int fileCount = 0;
        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            scanDirTracedLI(partition.getAppFolder(), mSystemParseFlags,
                    mSystemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }
            parallelPackageParser.submit(file, parseFlags);
            fileCount++;
    }

        final ScanPackageHelper scanPackageHelper = new ScanPackageHelper(mPm);
        // Process results one by one
        for (; fileCount > 0; fileCount--) {
            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
            Throwable throwable = parseResult.throwable;
            int errorCode = PackageManager.INSTALL_SUCCEEDED;
            String errorMsg = null;

            if (throwable == null) {
                // TODO(b/194319951): move lower in the scan chain
                // Static shared libraries have synthetic package names
                if (parseResult.parsedPackage.isStaticSharedLibrary()) {
                    PackageManagerService.renameStaticSharedLibraryPackage(
                            parseResult.parsedPackage);
    @GuardedBy("mPm.mLock")
    private void updateStubSystemAppsList(List<String> stubSystemApps) {
        final int numPackages = mPm.mPackages.size();
        for (int index = 0; index < numPackages; index++) {
            final AndroidPackage pkg = mPm.mPackages.valueAt(index);
            if (pkg.isStub()) {
                stubSystemApps.add(pkg.getPackageName());
            }
                try {
                    scanPackageHelper.addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                            currentTime, null);
                } catch (PackageManagerException e) {
                    errorCode = e.error;
                    errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
                    Slog.w(TAG, errorMsg);
                }
            } else if (throwable instanceof PackageManagerException) {
                PackageManagerException e = (PackageManagerException) throwable;
                errorCode = e.error;
                errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
                Slog.w(TAG, errorMsg);
            } else {
                throw new IllegalStateException("Unexpected exception occurred while parsing "
                        + parseResult.scanFile, throwable);
        }

            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
                mPm.mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
    }

            // Delete invalid userdata apps
            if ((scanFlags & SCAN_AS_SYSTEM) == 0
                    && errorCode != PackageManager.INSTALL_SUCCEEDED) {
                logCriticalInfo(Log.WARN,
                        "Deleting invalid package at " + parseResult.scanFile);
                mRemovePackageHelper.removeCodePathLI(parseResult.scanFile);
            }
    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
        try {
            mInstallPackageHelper.installSystemPackagesFromDir(scanDir, parseFlags, scanFlags,
                    currentTime, packageParser, executorService);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

+399 −11

File changed.

Preview size limit exceeded, changes collapsed.

+30 −8

File changed.

Preview size limit exceeded, changes collapsed.

+8 −143

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ public final class StorageEventHelper extends StorageEventListener {

        final Settings.VersionInfo ver;
        final List<PackageSetting> packages;
        final ScanPackageHelper scanPackageHelper = new ScanPackageHelper(mPm);
        final InstallPackageHelper installPackageHelper = new InstallPackageHelper(mPm);
        synchronized (mPm.mLock) {
            ver = mPm.mSettings.findOrCreateVersion(volumeUuid);
            packages = mPm.mSettings.getVolumePackagesLPr(volumeUuid);
@@ -147,7 +147,7 @@ public final class StorageEventHelper extends StorageEventListener {
            synchronized (mPm.mInstallLock) {
                final AndroidPackage pkg;
                try {
                    pkg = scanPackageHelper.scanPackageTracedLI(
                    pkg = installPackageHelper.scanSystemPackageTracedLI(
                            ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
                    loaded.add(pkg);