Android10_原理机制系列_PMS的启动及应用的安装过程

概述

这里主要介绍 PackageManagerService(简称PMS)的启动一个应用的安装过程。这里只是大致总结,供参考,不少地方同样需要进一步深入了解学习的。
该篇相关代码也是基于AndroidQ的。

PMS也是核心服务之一,管理包相关内容,解析AndroidManifest.xml、管理应用等,最常见的是应用的安装和卸载。
和AMS类似,PMS提供服务也是通过binder完成,也有相应的服务端和客户端。

PMS的几个相关类:
IPackageManager.aidl:接口,定义了服务端和客户端之间通信的函数方法。
PackageManagerService:服务端。继承IPackageManager.Stub,继承Binder。
PackageManager:抽象类,对外的接口(可调用,SDK)。可以通过Context#getPackageManager获取,可以看下下面源码中关于PackageManager的注释部分。
ApplicationPackageManager:客户端。PackageManager实现类,通过内部的mPM变量参与Binder通信。

//PackageManager.java
/**
 * Class for retrieving various kinds of information related to the application
 * packages that are currently installed on the device.
 *
 * You can find this class through {@link Context#getPackageManager}.
 */
public abstract class PackageManager {
    ......
}

//ApplicationPackageManager.java
protected ApplicationPackageManager(ContextImpl context,
                          IPackageManager pm) {
    mContext = context;
    mPM = pm;
}

PMS的启动

之前已经总结过 AMS的启动过程 以及 应用的第一次启动过程 ,比较详细,关于PMS的启动就容易理解了。
PMS启动过程 和 AMS启动过程 类似,都是在SystemServer启动之后完成的,若想详细了解可以先参考AMS的启动过程了解下,关于PMS的启动这里就大致说明下。

SystemServer中启动PMS

PMS的启动也是在SystemServer启动之后,也属于引导服务,在startBootstrapServices()中启动。

//SystemServer.java
private void startBootstrapServices() {
    ......
    //Installer服务,真正安装的服务,与installd交互
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ......
    //标记1
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    ......
    //标记2 
    mPackageManager = mSystemContext.getPackageManager();
}

private void startOtherServices() {
    ......
    //完成dex优化
    mPackageManagerService.updatePackagesIfNeeded();
    ......
    //清理磁盘,释放空间
    mPackageManagerService.performFstrimIfNeeded();
    ......
    //PMS准备就绪
    mPackageManagerService.systemReady();
    ......
}

可以看注释大致了解下。
这里主要看下标记1和标记2处,PackageManagerService.main()mSystemContext.getPackageManager()

标记1:mSystemContext.getPackageManager()

先看下mSystemContext.getPackageManager(),一路看下去,就看到如下代码。即Context#getPackageManager是创建了ApplicationPackageManager,mPM得到赋值 IPackageManager对象,可以通过mPm参与PMS通信。

//ContextImpl.java
@Override
public PackageManager getPackageManager() {
    if (mPackageManager != null) {
        return mPackageManager;
    }

    IPackageManager pm = ActivityThread.getPackageManager();
    if (pm != null) {
        // Doesn't matter if we make more than one instance.
        return (mPackageManager = new ApplicationPackageManager(this, pm));
    }

    return null;
}

标记2:PackageManagerService.main():

这是真正创建PMS服务,并启动。

//PackageManagerService.java
public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.
    PackageManagerServiceCompilerMapping.checkProperties();
    //初始化PMS
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    m.enableSystemUserPackages();
    //注册服务 package
    ServiceManager.addService("package", m);
    final PackageManagerNative pmn = m.new PackageManagerNative();
    //注册服务 package_native
    ServiceManager.addService("package_native", pmn);
    return m;
}

这里很简单,主要检查PMS环境,然创建并注册了两个服务package和package_native。
接下来主要看 创建PMS对象过程做了些什么。

PMS的创建

PMS的构造方法很长,下面折叠起来了,要了解可以打开

代码已折叠,点击显示PMS的完整构造方法
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = context;

        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mMetrics = new DisplayMetrics();
        mInstaller = installer;

        // Create sub-components that provide services / data. Order here is important.
        synchronized (mInstallLock) {
        synchronized (mPackages) {
            // Expose private service for system components to use.
            LocalServices.addService(
                    PackageManagerInternal.class, new PackageManagerInternalImpl());
            sUserManager = new UserManagerService(context, this,
                    new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
            mComponentResolver = new ComponentResolver(sUserManager,
                    LocalServices.getService(PackageManagerInternal.class),
                    mPackages);
            mPermissionManager = PermissionManagerService.create(context,
                    mPackages /*externalLock*/);
            mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
            mSettings = new Settings(Environment.getDataDirectory(),
                    mPermissionManager.getPermissionSettings(), mPackages);
        }
        }
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.se", SE_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

        String separateProcesses = SystemProperties.get("debug.separate_processes");
        if (separateProcesses != null && separateProcesses.length() > 0) {
            if ("*".equals(separateProcesses)) {
                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                mSeparateProcesses = null;
                Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
            } else {
                mDefParseFlags = 0;
                mSeparateProcesses = separateProcesses.split(",");
                Slog.w(TAG, "Running with debug.separate_processes: "
                        + separateProcesses);
            }
        } else {
            mDefParseFlags = 0;
            mSeparateProcesses = null;
        }

        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                "*dexopt*");
        mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock);
        mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

        mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);

        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                FgThread.get().getLooper());

        getDefaultDisplayMetrics(context, mMetrics);

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
        SystemConfig systemConfig = SystemConfig.getInstance();
        mAvailableFeatures = systemConfig.getAvailableFeatures();
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

        mProtectedPackages = new ProtectedPackages(mContext);

        mApexManager = new ApexManager(context);
        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            mProcessLoggingHandler = new ProcessLoggingHandler();
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
            mInstantAppRegistry = new InstantAppRegistry(this);

            ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig
                    = systemConfig.getSharedLibraries();
            final int builtInLibCount = libConfig.size();
            for (int i = 0; i < builtInLibCount; i++) {
                String name = libConfig.keyAt(i);
                SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
                addBuiltInSharedLibraryLocked(entry.filename, name);
            }

            // Now that we have added all the libraries, iterate again to add dependency
            // information IFF their dependencies are added.
            long undefinedVersion = SharedLibraryInfo.VERSION_UNDEFINED;
            for (int i = 0; i < builtInLibCount; i++) {
                String name = libConfig.keyAt(i);
                SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
                final int dependencyCount = entry.dependencies.length;
                for (int j = 0; j < dependencyCount; j++) {
                    final SharedLibraryInfo dependency =
                        getSharedLibraryInfoLPr(entry.dependencies[j], undefinedVersion);
                    if (dependency != null) {
                        getSharedLibraryInfoLPr(name, undefinedVersion).addDependency(dependency);
                    }
                }
            }

            SELinuxMMAC.readInstallPolicy();

            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
            FallbackCategoryProvider.loadFallbacks();
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

            // Clean up orphaned packages for which the code path doesn't exist
            // and they are an update to a system app - caused by bug/32321269
            final int packageSettingCount = mSettings.mPackages.size();
            for (int i = packageSettingCount - 1; i >= 0; i--) {
                PackageSetting ps = mSettings.mPackages.valueAt(i);
                if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
                        && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
                    mSettings.mPackages.removeAt(i);
                    mSettings.enableSystemPackageLPw(ps.name);
                }
            }

            if (!mOnlyCore && mFirstBoot) {
                requestCopyPreoptedFiles();
            }

            String customResolverActivityName = Resources.getSystem().getString(
                    R.string.config_customResolverActivity);
            if (!TextUtils.isEmpty(customResolverActivityName)) {
                mCustomResolverComponentName = ComponentName.unflattenFromString(
                        customResolverActivityName);
            }

            long startTime = SystemClock.uptimeMillis();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

            final String bootClassPath = System.getenv("BOOTCLASSPATH");
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

            if (bootClassPath == null) {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            if (systemServerClassPath == null) {
                Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
            }

            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            final VersionInfo ver = mSettings.getInternalVersion();
            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
            if (mIsUpgrade) {
                logCriticalInfo(Log.INFO,
                        "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
            }

            // when upgrading from pre-M, promote system app permissions from install to runtime
            mPromoteSystemApps =
                    mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

            // When upgrading from pre-N, we need to handle package extraction like first boot,
            // as there is no profiling data available.
            mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
            mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;

            int preUpgradeSdkVersion = ver.sdkVersion;

            // save off the names of pre-existing system packages prior to scanning; we don't
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);
                    }
                }
            }

            mCacheDir = preparePackageParserCache();

            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            int scanFlags = SCAN_BOOTING | SCAN_INITIAL;

            if (mIsUpgrade || mFirstBoot) {
                scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
            }

            // Collect vendor/product/product_services 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.
            scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);
            scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT,
                    0);
            scanDirTracedLI(new File(PRODUCT_SERVICES_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT_SERVICES,
                    0);
            scanDirTracedLI(new File(ODM_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_ODM,
                    0);
            scanDirTracedLI(new File(OEM_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_OEM,
                    0);

            mParallelPackageParserCallback.findStaticOverlayPackages();

            // Find base frameworks (resource packages without code).
            scanDirTracedLI(frameworkDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_NO_DEX
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRIVILEGED,
                    0);
            if (!mPackages.containsKey("android")) {
                throw new IllegalStateException(
                        "Failed to load frameworks package; check log for warnings");
            }

            // Collect privileged system packages.
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirTracedLI(privilegedAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary system packages.
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirTracedLI(systemAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM,
                    0);

            // Collect privileged vendor packages.
            File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
            try {
                privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(privilegedVendorAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary vendor packages.
            File vendorAppDir = new File(Environment.getVendorDirectory(), "app");
            try {
                vendorAppDir = vendorAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(vendorAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);

            // Collect privileged odm packages. /odm is another vendor partition
            // other than /vendor.
            File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
                        "priv-app");
            try {
                privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(privilegedOdmAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary odm packages. /odm is another vendor partition
            // other than /vendor.
            File odmAppDir = new File(Environment.getOdmDirectory(), "app");
            try {
                odmAppDir = odmAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(odmAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);

            // Collect all OEM packages.
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirTracedLI(oemAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_OEM,
                    0);

            // Collected privileged /product packages.
            File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
            try {
                privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(privilegedProductAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary /product packages.
            File productAppDir = new File(Environment.getProductDirectory(), "app");
            try {
                productAppDir = productAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(productAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT,
                    0);

            // Collected privileged /product_services packages.
            File privilegedProductServicesAppDir =
                    new File(Environment.getProductServicesDirectory(), "priv-app");
            try {
                privilegedProductServicesAppDir =
                        privilegedProductServicesAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(privilegedProductServicesAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT_SERVICES
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary /product_services packages.
            File productServicesAppDir = new File(Environment.getProductServicesDirectory(), "app");
            try {
                productServicesAppDir = productServicesAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(productServicesAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT_SERVICES,
                    0);

            // 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
            // partition or be disabled.
            final List<String> stubSystemApps = new ArrayList<>();
            if (!mOnlyCore) {
                // do this first before mucking with mPackages for the "expecting better" case
                final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
                while (pkgIterator.hasNext()) {
                    final PackageParser.Package pkg = pkgIterator.next();
                    if (pkg.isStub) {
                        stubSystemApps.add(pkg.packageName);
                    }
                }

                final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * 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 PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    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 (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            logCriticalInfo(Log.WARN,
                                    "Expecting better updated system app for " + ps.name
                                    + "; removing system app.  Last known"
                                    + " codePath=" + ps.codePathString
                                    + ", versionCode=" + ps.versionCode
                                    + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
                            removePackageLI(scannedPkg, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; it's data will be wiped");
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } 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.
                        final PackageSetting disabledPs =
                                mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()
                                || disabledPs.pkg == null) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        } 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.name, disabledPs.codePath);
                        }
                    }
                }
            }

            //delete tmp files
            deleteTempPackageFiles();

            final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();

            // Remove any shared userIDs that have no associated packages
            mSettings.pruneSharedUsersLPw();
            final long systemScanTime = SystemClock.uptimeMillis() - startTime;
            final int systemPackagesCount = mPackages.size();
            Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
                    + " ms, packageCount: " + systemPackagesCount
                    + " , timePerPackage: "
                    + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
                    + " , cached: " + cachedSystemApps);
            if (mIsUpgrade && systemPackagesCount > 0) {
                MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time",
                        ((int) systemScanTime) / systemPackagesCount);
            }
            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

                // 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 PackageParser.Package pkg = 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
                    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
                        removePackageLI(pkg, true);
                        try {
                            final File codePath = new File(pkg.applicationInfo.getCodePath());
                            scanPackageTracedLI(codePath, 0, scanFlags, 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 = mSettings.mPackages.get(packageName);
                    if (ps != null && mPackages.get(packageName) == null) {
                        removePackageDataLIF(ps, null, 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 (!mPackages.containsKey(packageName)) {
                        final File scanFile = mExpectingBetter.valueAt(i);

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

                        final @ParseFlags int reparseFlags;
                        final @ScanFlags int rescanFlags;
                        if (FileUtils.contains(privilegedAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_PRIVILEGED;
                        } else if (FileUtils.contains(systemAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM;
                        } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)
                                || FileUtils.contains(privilegedOdmAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_VENDOR
                                    | SCAN_AS_PRIVILEGED;
                        } else if (FileUtils.contains(vendorAppDir, scanFile)
                                || FileUtils.contains(odmAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_VENDOR;
                        } else if (FileUtils.contains(oemAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_OEM;
                        } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_PRODUCT
                                    | SCAN_AS_PRIVILEGED;
                        } else if (FileUtils.contains(productAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_PRODUCT;
                        } else if (FileUtils.contains(privilegedProductServicesAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_PRODUCT_SERVICES
                                    | SCAN_AS_PRIVILEGED;
                        } else if (FileUtils.contains(productServicesAppDir, scanFile)) {
                            reparseFlags =
                                    mDefParseFlags |
                                    PackageParser.PARSE_IS_SYSTEM_DIR;
                            rescanFlags =
                                    scanFlags
                                    | SCAN_AS_SYSTEM
                                    | SCAN_AS_PRODUCT_SERVICES;
                        } else {
                            Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                            continue;
                        }

                        mSettings.enableSystemPackageLPw(packageName);

                        try {
                            scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, "Failed to parse original system package: "
                                    + e.getMessage());
                        }
                    }
                }

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

                final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get()
                                - cachedSystemApps;

                final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
                final int dataPackagesCount = mPackages.size() - systemPackagesCount;
                Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
                        + " ms, packageCount: " + dataPackagesCount
                        + " , timePerPackage: "
                        + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
                        + " , cached: " + cachedNonSystemApps);
                if (mIsUpgrade && dataPackagesCount > 0) {
                    MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time",
                            ((int) dataScanTime) / dataPackagesCount);
                }
            }
            mExpectingBetter.clear();

            // Resolve the storage manager.
            mStorageManagerPackage = getStorageManagerPackageName();

            // Resolve protected action filters. Only the setup wizard is allowed to
            // have a high priority filter for these actions.
            mSetupWizardPackage = getSetupWizardPackageName();
            mComponentResolver.fixProtectedFilterPriorities();

            mSystemTextClassifierPackage = getSystemTextClassifierPackageName();

            mWellbeingPackage = getWellbeingPackageName();
            mDocumenterPackage = getDocumenterPackageName();
            mConfiguratorPackage = getDeviceConfiguratorPackageName();
            mAppPredictionServicePackage = getAppPredictionServicePackageName();
            mIncidentReportApproverPackage = getIncidentReportApproverPackageName();

            // Now that we know all of the shared libraries, update all clients to have
            // the correct library paths.
            updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));

            for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                // NOTE: We ignore potential failures here during a system scan (like
                // the rest of the commands above) because there's precious little we
                // can do about it. A settings error is reported, though.
                final List<String> changedAbiCodePath =
                        adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
                if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
                    for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                        final String codePathString = changedAbiCodePath.get(i);
                        try {
                            mInstaller.rmdex(codePathString,
                                    getDexCodeInstructionSet(getPreferredInstructionSet()));
                        } catch (InstallerException ignored) {
                        }
                    }
                }
                // Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
                // SELinux domain.
                setting.fixSeInfoLocked();
            }

            // Now that we know all the packages we are keeping,
            // read and update their last usage times.
            mPackageUsage.read(mPackages);
            mCompilerStats.read();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");

            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear.  This is really a hack, and means that apps can in some
            // cases get permissions that the user didn't initially explicitly
            // allow...  it would be nice to have some better way to handle
            // this situation.
            final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
            if (sdkUpdated) {
                Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
                        + mSdkVersion + "; regranting permissions for internal storage");
            }
            mPermissionManager.updateAllPermissions(
                    StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
                    mPermissionCallback);
            ver.sdkVersion = mSdkVersion;

            // If this is the first boot or an update from pre-M, and it is a normal
            // boot, then we need to initialize the default preferred apps across
            // all defined users.
            if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
                for (UserInfo user : sUserManager.getUsers(true)) {
                    mSettings.applyDefaultPreferredAppsLPw(user.id);
                    primeDomainVerificationsLPw(user.id);
                }
            }

            // Prepare storage for system user really early during boot,
            // since core system apps like SettingsProvider and SystemUI
            // can't wait for user to start
            final int storageFlags;
            if (StorageManager.isFileEncryptedNativeOrEmulated()) {
                storageFlags = StorageManager.FLAG_STORAGE_DE;
            } else {
                storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
            }
            List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
                    UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
                    true /* onlyCoreApps */);
            mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(() -> {
                TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
                        Trace.TRACE_TAG_PACKAGE_MANAGER);
                traceLog.traceBegin("AppDataFixup");
                try {
                    mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
                            StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
                } catch (InstallerException e) {
                    Slog.w(TAG, "Trouble fixing GIDs", e);
                }
                traceLog.traceEnd();

                traceLog.traceBegin("AppDataPrepare");
                if (deferPackages == null || deferPackages.isEmpty()) {
                    return;
                }
                int count = 0;
                for (String pkgName : deferPackages) {
                    PackageParser.Package pkg = null;
                    synchronized (mPackages) {
                        PackageSetting ps = mSettings.getPackageLPr(pkgName);
                        if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
                            pkg = ps.pkg;
                        }
                    }
                    if (pkg != null) {
                        synchronized (mInstallLock) {
                            prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags,
                                    true /* maybeMigrateAppData */);
                        }
                        count++;
                    }
                }
                traceLog.traceEnd();
                Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
            }, "prepareAppData");

            // If this is first boot after an OTA, and a normal boot, then
            // we need to clear code cache directories.
            // Note that we do *not* clear the application profiles. These remain valid
            // across OTAs and are used to drive profile verification (post OTA) and
            // profile compilation (without waiting to collect a fresh set of profiles).
            if (mIsUpgrade && !onlyCore) {
                Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                for (int i = 0; i < mSettings.mPackages.size(); i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                        // No apps are running this early, so no need to freeze
                        clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                                FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
                                        | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            // Grandfather existing (installed before Q) non-system apps to hide
            // their icons in launcher.
            if (!onlyCore && mIsPreQUpgrade) {
                Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
                int size = mSettings.mPackages.size();
                for (int i = 0; i < size; i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                        continue;
                    }
                    ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
                            UserHandle.USER_SYSTEM);
                }
            }

            // clear only after permissions and other defaults have been updated
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // All the changes are done during package scanning.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // can downgrade to reader
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings");
            mSettings.writeLPr();
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            if (!mOnlyCore) {
                mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
                mRequiredInstallerPackage = getRequiredInstallerLPr();
                mRequiredUninstallerPackage = getRequiredUninstallerLPr();
                mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
                if (mIntentFilterVerifierComponent != null) {
                    mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                            mIntentFilterVerifierComponent);
                } else {
                    mIntentFilterVerifier = null;
                }
                mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES,
                        SharedLibraryInfo.VERSION_UNDEFINED);
                mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
                        SharedLibraryInfo.VERSION_UNDEFINED);
            } else {
                mRequiredVerifierPackage = null;
                mRequiredInstallerPackage = null;
                mRequiredUninstallerPackage = null;
                mIntentFilterVerifierComponent = null;
                mIntentFilterVerifier = null;
                mServicesSystemSharedLibraryPackageName = null;
                mSharedSystemSharedLibraryPackageName = null;
            }
            // PermissionController hosts default permission granting and role management, so it's a
            // critical part of the core system.
            mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();

            // Initialize InstantAppRegistry's Instant App list for all users.
            final int[] userIds = UserManagerService.getInstance().getUserIds();
            for (PackageParser.Package pkg : mPackages.values()) {
                if (pkg.isSystem()) {
                    continue;
                }
                for (int userId : userIds) {
                    final PackageSetting ps = (PackageSetting) pkg.mExtras;
                    if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
                        continue;
                    }
                    mInstantAppRegistry.addInstantAppLPw(userId, ps.appId);
                }
            }

            mInstallerService = new PackageInstallerService(context, this, mApexManager);
            final Pair<ComponentName, String> instantAppResolverComponent =
                    getInstantAppResolverLPr();
            if (instantAppResolverComponent != null) {
                if (DEBUG_INSTANT) {
                    Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
                }
                mInstantAppResolverConnection = new InstantAppResolverConnection(
                        mContext, instantAppResolverComponent.first,
                        instantAppResolverComponent.second);
                mInstantAppResolverSettingsComponent =
                        getInstantAppResolverSettingsLPr(instantAppResolverComponent.first);
            } else {
                mInstantAppResolverConnection = null;
                mInstantAppResolverSettingsComponent = null;
            }
            updateInstantAppInstallerLocked(null);

            // Read and update the usage of dex files.
            // Do this at the end of PM init so that all the packages have their
            // data directory reconciled.
            // At this point we know the code paths of the packages, so we can validate
            // the disk file and build the internal cache.
            // The usage file is expected to be small so loading and verifying it
            // should take a fairly small time compare to the other activities (e.g. package
            // scanning).
            final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
            for (int userId : userIds) {
                userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
            }
            mDexManager.load(userPackages);
            if (mIsUpgrade) {
                MetricsLogger.histogram(null, "ota_package_manager_init_time",
                        (int) (SystemClock.uptimeMillis() - startTime));
            }
        } // synchronized (mPackages)
        } // synchronized (mInstallLock)

        mModuleInfoProvider = new ModuleInfoProvider(mContext, this);

        // Now after opening every single application zip, make sure they
        // are all flushed.  Not really needed, but keeps things nice and
        // tidy.
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "GC");
        Runtime.getRuntime().gc();
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

        // The initial scanning above does many calls into installd while
        // holding the mPackages lock, but we're mostly interested in yelling
        // once we have a booted system.
        mInstaller.setWarnIfHeld(mPackages);

        PackageParser.readConfigUseRoundIcon(mContext.getResources());

        mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);

        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }

从构造方法中的EventLogTags的标记,大致分为5个阶段,根据这个大致了解下。

  1. BOOT_PROGRESS_PMS_START
    创建和保存需要使用的相关对象,下面列出一些比较重要的:
  • mInstaller:Installer对象,系统服务,与installd交互,管理包的安装、卸载、数据、迁移等。
  • sUserManager:UserManagerService,用户管理服务。
  • mPermissionManager:PermissionManagerServiceInternal,权限管理相关。
  • mSettings:Settings,保存动态设置信息。这里通过addSharedUserLPw设置shared uid到Settings中(有8种:system、phone、log、nfc、bluetooth、shell、se、networkstack)。这里的Settings是frameworks/base/services/core/java/com/android/server/pm/Settings.java而不是frameworks/base/core/java/android/provider/Settings.java下的。
  • mPackageDexOptimizer:PackageDexOptimizer,助手工具类,进行dex优化等,dexopt。
  • mDexManager:DexManager,dex管理类,跟踪dex文件的使用等。
  • SystemConfig:用于获取系统的全局配置信息。
  • mApexManager:ApexManager,apex管理类,处理与apex服务通信。
  1. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
    扫描系统目录中的app等,通过scanDirTracedLI()方法。
    这个阶段主要扫描的路径是:/vendor/overlay;/product/overlay;/product_services/overlay;/odm/overlay;/oem/overlay;/system/framework;/system/priv-app;/system/app;/vendor/priv-app;/vendor/app;/odm/priv-app;/odm/app;/oem/app;/product/priv-app;/product/app;/product_services/priv-app;/product_services/app;
    概括起来,就是vendor/product/product_services/odm/oem下的overlay目录;/system/framework/;system/vendor/odm/oem/product/product_services下的priv-app和app目录(没有/oem/priv-app)。

  2. BOOT_PROGRESS_PMS_DATA_SCAN_START
    扫描非系统目录app等。
    这个阶段主要扫描目录:/data/app;

  3. BOOT_PROGRESS_PMS_SCAN_END
    扫描完成,将结果写入文件中。
    通过mSettings.writeLPr();方法。写入到文件:/data/system/packages.xml和/data/system/packages.list。
    安装、卸载等都会更新这个目录。

  4. BOOT_PROGRESS_PMS_READY
    PMS准备完成,创建PackageInstallerService服务。mInstallerService = new PackageInstallerService(context, this, mApexManager);

题外话:
apex是 AndroidQ开始提出的mainline计划后 而有的一种新格式,google将framework也分成一个个小模块,最终希望通过play store对system的核心内容的进行更新,不需要odm、oem干预。而这一个个模块与apk应用不同,因此有了apex这种格式。其实google在Android O开始就再弄的Treble计划,一步步将system与vendor分开了独立,最终整个系统可以直接使用一套公共的system.img即GSI(Generic System Image)。在Android R开始,kernel部分也开始使用这套,弄一套通用内核镜像GKI(Generic Kernel Image)。 Android各个版本之间变动是非常大的,可能用户感受不到。为了实现这些,引入了很多新的概念和技术。

/data/system/packages.xml,在 Android调试非常有用的命令集 总结中也提到过,这里就是该文件内容是什么,怎么来的。
所以预置应用越多,扫描时间会越长,影响开机时间。

一个应用的安装

应用的安装,最常见的是点击apk后的有界面的安装 和 开发中通过adb命令的静默安装。
下面关于这两种安装方式,简单说明下。

点击安装(有界面)


1.点击安装,PackageInstaller.apk处理过程

这个过程通过系统预置的PackageInstaller.apk或类似应用完成。

点击apk,进行一些验证后跳转到了PackageInstallerActivity,即弹出的”是否安装此应用“的确认安装界面。点击确认安装后,进入了InstallInstalling。
点击apk进行安装,PackageInstaller.apk是从InstallStart->PackageInstallerActivity->InstallInstalling。

注:这里以aosp中的PackageInstaller.apk说明(com.android.packageinstaller),在外单中 一般预置的是GMS包中的GooglePackageInstaller。

下面是大致的代码过程的关键代码:

//InstallStart.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
    Intent nextActivity = new Intent(intent);
    .....
    if (isSessionInstall) {
        nextActivity.setClass(this, PackageInstallerActivity.class);
    }
    ......
    if (nextActivity != null) {
        startActivity(nextActivity);
    }
}

//PackageInstallerActivity.java
protected void onCreate(Bundle icicle) {
    .......
    bindUi();
}

private void bindUi() {
    ......
    mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
            (ignored, ignored2) -> {
                if (mOk.isEnabled()) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        finish();
                    } else {
                        startInstall();
                    }
                }
            }, null);
    ......
}

private void startInstall() {
    Intent newIntent = new Intent();
    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
            mPkgInfo.applicationInfo);
    newIntent.setData(mPackageURI);
    newIntent.setClass(this, InstallInstalling.class);
    ......
    startActivity(newIntent);
    finish();
}

可以清晰看到,点击确认安装后,通过startInstall()方法进入了InstallInstalling。
接着看InstallInstalling的处理:

//InstallInstalling.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
    ......
    mPackageURI = getIntent().getData();

    if ("package".equals(mPackageURI.getScheme())) {
        .......
    } else {
        ......
        if (savedInstanceState != null) {
            ......  
        } else {
            ......
            try {
                mInstallId = InstallEventReceiver
                        .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                this::launchFinishBasedOnResult);
            } catch (EventResultPersister.OutOfIdsException e) {
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }

            try {
                mSessionId = getPackageManager().getPackageInstaller().createSession(params);
            } catch (IOException e) {
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }
        }

        mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);

        mSessionCallback = new InstallSessionCallback();
    }
}

@Override
protected void onResume() {
    super.onResume();

    // This is the first onResume in a single life of the activity
    if (mInstallingTask == null) {
        PackageInstaller installer = getPackageManager().getPackageInstaller();
        PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

        if (sessionInfo != null && !sessionInfo.isActive()) {
            mInstallingTask = new InstallingAsyncTask();
            mInstallingTask.execute();
        } else {
            // we will receive a broadcast when the install is finished
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        }
    }
}

onCreate()中创建了一个安装会话并返回获得一个sessionId。onResume()中进行进一步安装。

2.创建安装的会话

先看onCreate()中创建安装会话,返回的sessionId很重要。

InstallEventReceiver是一个BroadcastReceiver,接收安装事件并回调给EventResultPersister。mSessionId是安装的会话id。
添加log可以看到,mPackageURI.getScheme()的值是"file"。最后关键执行到的是getPackageManager().getPackageInstaller().createSession(params)这句。

getPackageManager()获取PM对象,然后调用实现类ApplicationPackageManager中getPackageInstaller()得到的是PackageInstaller对象。最终调用的是PackageInstaller中的createSession()创建安装会话并返回sessionId。这里不列出代码,直接看createSession()方法。

//PackageInstaller.java
//frameworks/base/core/java/android/content/pm/PackageInstaller.java
private final IPackageInstaller mInstaller;
public int createSession(@NonNull SessionParams params) throws IOException {
    try {
        final String installerPackage;
        ......
        return mInstaller.createSession(params, installerPackage, mUserId);
    }
    ......
}

注意,这里调用的是mInstaller.createSession()。mInstaller是IPackageInstaller,一看就知道这也是通过binder调用的一个服务,这个服务是PackageInstallerService,即最终调用的是PackageInstallerService的createSession()方法创建了一个安装会话 并 返回了sessionId。
这里不细述创建安装会话的过程了。

3.安装会话创建后,进一步安装

接着看onResume()。这里主要是看mInstallingTask.execute()

/**
 * Send the package to the package installer and then register a event result observer that
 * will call {@link #launchFinishBasedOnResult(int, int, String)}
 */
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
        PackageInstaller.Session> {
    volatile boolean isDone;

    @Override
    protected PackageInstaller.Session doInBackground(Void... params) {
        PackageInstaller.Session session;
        try {
            session = getPackageManager().getPackageInstaller().openSession(mSessionId);
        } catch (IOException e) {
            return null;
        }

        session.setStagingProgress(0);

        try {
            File file = new File(mPackageURI.getPath());

            try (InputStream in = new FileInputStream(file)) {
                long sizeBytes = file.length();
                try (OutputStream out = session
                        .openWrite("PackageInstaller", 0, sizeBytes)) {
                    byte[] buffer = new byte[1024 * 1024];
                    while (true) {
                        int numRead = in.read(buffer);

                        if (numRead == -1) {
                            session.fsync(out);
                            break;
                        }

                        if (isCancelled()) {
                            session.close();
                            break;
                        }

                        out.write(buffer, 0, numRead);
                        if (sizeBytes > 0) {
                            float fraction = ((float) numRead / (float) sizeBytes);
                            session.addProgress(fraction);
                        }
                    }
                }
            }

            return session;
        } catch (IOException | SecurityException e) {
            Log.e(LOG_TAG, "Could not write package", e);

            session.close();

            return null;
        } finally {
            synchronized (this) {
                isDone = true;
                notifyAll();
            }
        }
    }

    @Override
    protected void onPostExecute(PackageInstaller.Session session) {
        if (session != null) {
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            broadcastIntent.setPackage(getPackageName());
            broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallInstalling.this,
                    mInstallId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);

            session.commit(pendingIntent.getIntentSender());
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        } else {
            getPackageManager().getPackageInstaller().abandonSession(mSessionId);

            if (!isCancelled()) {
                launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
            }
        }
    }
}

InstallingAsyncTask是个异步任务。
doInBackground中,apk的信息(通过URI获取)通过IO流写入到PackageInstaller.Session中。在onPostExecute中,通过session.commit()发送安装。
Session就是通过sessionId获取打开的。
接下来主要看发送安装。

PackageInstaller.Session.commit()发送安装

//frameworks/base/core/java/android/content/pm/PackageInstaller.java
public static class Session implements Closeable {
    protected final IPackageInstallerSession mSession;

    public void commit(@NonNull IntentSender statusReceiver) {
        try {
            mSession.commit(statusReceiver, false);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

//PackageInstallerSession.java
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        @Override
    public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
        ......
        if (!markAsCommitted(statusReceiver, forTransfer)) {
            return;
        }
        if (isMultiPackage()) {
            final SparseIntArray remainingSessions = mChildSessionIds.clone();
            final IntentSender childIntentSender =
                    new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
                            .getIntentSender();
            RuntimeException commitException = null;
            boolean commitFailed = false;
            for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
                final int childSessionId = mChildSessionIds.keyAt(i);
                try {
                    // commit all children, regardless if any of them fail; we'll throw/return
                    // as appropriate once all children have been processed
                    if (!mSessionProvider.getSession(childSessionId)
                            .markAsCommitted(childIntentSender, forTransfer)) {
                        commitFailed = true;
                    }
                } catch (RuntimeException e) {
                    commitException = e;
                }
            }
            if (commitException != null) {
                throw commitException;
            }
            if (commitFailed) {
                return;
            }
        }
        mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
    }
}

最终调用到PackageInstallerSession中的commit()。主要看mHandler.obtainMessage(MSG_COMMIT).sendToTarget(); ,即通过Handler发送了MSG_COMMIT的消息,进程间通信。

接着看消息处理代码:

//PackageInstallerSession.java
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_COMMIT:
                handleCommit();
                break;
            ......
        }

        return true;
    }
};

private void handleCommit() {
    ......
    // For a multiPackage session, read the child sessions
    // outside of the lock, because reading the child
    // sessions with the lock held could lead to deadlock
    // (b/123391593).
    List<PackageInstallerSession> childSessions = getChildSessions();

    try {
        synchronized (mLock) {
            commitNonStagedLocked(childSessions);
        }
    } catch (PackageManagerException e) {
        ......
    }
}

@GuardedBy("mLock")
private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
        throws PackageManagerException {
    final PackageManagerService.ActiveInstallSession committingSession =
            makeSessionActiveLocked();
    if (committingSession == null) {
        return;
    }
    if (isMultiPackage()) {
        List<PackageManagerService.ActiveInstallSession> activeChildSessions =
                new ArrayList<>(childSessions.size());
        boolean success = true;
        PackageManagerException failure = null;
        for (int i = 0; i < childSessions.size(); ++i) {
            final PackageInstallerSession session = childSessions.get(i);
            try {
                final PackageManagerService.ActiveInstallSession activeSession =
                        session.makeSessionActiveLocked();
                if (activeSession != null) {
                    activeChildSessions.add(activeSession);
                }
            } catch (PackageManagerException e) {
                failure = e;
                success = false;
            }
        }
        if (!success) {
            try {
                mRemoteObserver.onPackageInstalled(
                        null, failure.error, failure.getLocalizedMessage(), null);
            } catch (RemoteException ignored) {
            }
            return;
        }
        mPm.installStage(activeChildSessions);
    } else {
        mPm.installStage(committingSession);
    }
}

很清晰,最终通过mPm.installStage() 进入PMS进行处理。

4.安装进入PMS

直接看PMS的installStage()。

//PackageManagerService.java
void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
        }
    }
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    final InstallParams params = new InstallParams(activeInstallSession);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;

    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));

    mHandler.sendMessage(msg);
}

class PackageHandler extends Handler {
   void doHandleMessage(Message msg) {
        switch (msg.what) {
            case INIT_COPY: {
                HandlerParams params = (HandlerParams) msg.obj;
                if (params != null) {
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                            System.identityHashCode(params));
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                    params.startCopy();
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                break;
            }
            ......
        }
   }
}

通过Handler发送了INIT_COPY消息,开始拷贝apk到执行地方进行进一步安装。

5.拷贝APK

看startCopy():

//PackageManagerService.java
private abstract class HandlerParams {
    final void startCopy() {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        handleStartCopy();
        handleReturnCode();
    }
    abstract void handleStartCopy();
    abstract void handleReturnCode();
}

class InstallParams extends HandlerParams {
    @Override
    public void handleStartCopy() {
        int ret = PackageManager.INSTALL_SUCCEEDED;

        // If we're already staged, we've firmly committed to an install location
        ......

        /*
         * If we have too little free space, try to free cache
         * before giving up.
         */
        ......

        if (ret == PackageManager.INSTALL_SUCCEEDED) {
            int loc = pkgLite.recommendedInstallLocation;
            if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
            } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                ret = PackageManager.INSTALL_FAILED_INVALID_APK;
            } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                ret = PackageManager.INSTALL_FAILED_INVALID_URI;
            } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
            } else {
                // Override with defaults if needed.
                ......
            }
        }
        final InstallArgs args = createInstallArgs(this);
        mVerificationCompleted = true;
        mEnableRollbackCompleted = true;
        Args = args;
        ......
        mRet = ret;
    }
    
    @Override
    void handleReturnCode() {
        if (mVerificationCompleted && mEnableRollbackCompleted) {
            ......
            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                mRet = mArgs.copyApk();
            }
            processPendingInstall(mArgs, mRet);
        }
    }
}

startCopy()只有两个方法,handleStartCopy()和handleReturnCode()。
handleStartCopy()中进行安装前的各种验证,检查文件、空间、发送给所有sufficientVerifiers进行验证。 验证成功,即mRet == PackageManager.INSTALL_SUCCEEDED,在handleReturnCode()中进行apk拷贝工作。

拷贝apk目标路径

接着看下handleReturnCode()中的拷贝apk操作:mArgs.copyApk()
mArgs这里是FileInstallArgs。

//PackageManagerService.java
private InstallArgs createInstallArgs(InstallParams params) {
    if (params.move != null) {
        return new MoveInstallArgs(params);
    } else {
        return new FileInstallArgs(params);
    }
}

//PackageManagerService.java
class FileInstallArgs extends InstallArgs {
   int copyApk() {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
        try {
            return doCopyApk();
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

    private int doCopyApk() {
        ......
        final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
        final File tempDir =
                mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
        codeFile = tempDir;
        resourceFile = tempDir;
        ......
        int ret = PackageManagerServiceUtils.copyPackage(
                origin.file.getAbsolutePath(), codeFile);
        ......
        return ret;
    }
}

//PackageManagerServiceUtils.java
public static int copyPackage(String packagePath, File targetDir) {
    if (packagePath == null) {
        return PackageManager.INSTALL_FAILED_INVALID_URI;
    }

    try {
        final File packageFile = new File(packagePath);
        final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
        copyFile(pkg.baseCodePath, targetDir, "base.apk");
        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
            for (int i = 0; i < pkg.splitNames.length; i++) {
                copyFile(pkg.splitCodePaths[i], targetDir,
                        "split_" + pkg.splitNames[i] + ".apk");
            }
        }
        return PackageManager.INSTALL_SUCCEEDED;
    } catch (PackageParserException | IOException | ErrnoException e) {
        Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }
}

拷贝到的目标文件是:/data/app/vmdl[sessionId].tmp/base.apk。若是多个,/data/app/vmdl[sessionId].tmp/split_[pkgname].apk。

例如:如我的一次安装 /data/app/vmdl1101585668.tmp/base.apk,这次安装的sessionId是1101585668。
注:用userdebug软件,安装抓取的log也能看出大致安装过程的信息,可以辅助。如搜索TAG为 PackageManager(PMS类的TAG)。

下面是路径相关代码:

//PackageInstallerService.java
public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
    synchronized (mSessions) {
        ......
            final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
        ......
    }
}

private File buildTmpSessionDir(int sessionId, String volumeUuid) {
    final File sessionStagingDir = getTmpSessionDir(volumeUuid);
    return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
}

private File getTmpSessionDir(String volumeUuid) {
    return Environment.getDataAppDirectory(volumeUuid);
}

6.真正安装

copyFile完成拷贝后,回头看handleReturnCode(),mArgs.copyApk();后执行processPendingInstall(mArgs, mRet);开始真正的安装。

//PackageManagerService.java
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    if (args.mMultiPackageInstallParams != null) {
        args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
    } else {
        //安装参数
        PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    mHandler.post(() -> {
        if (success) {
            for (InstallRequest request : installRequests) {
                //如果之前安装失败,清理无用信息
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                //进行安装
                installPackagesTracedLI(installRequests);
            }
            for (InstallRequest request : installRequests) {
                //安装失败,清理无用信息
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : installRequests) {
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });
}

private PackageInstalledInfo createPackageInstalledInfo(
        int currentStatus) {
    PackageInstalledInfo res = new PackageInstalledInfo();
    res.setReturnCode(currentStatus);
    res.uid = -1;
    res.pkg = null;
    res.removedInfo = null;
    return res;
}

看上述注释大致了解下,我们接着看installPackagesTracedLI()。

//PMS
@GuardedBy({"mInstallLock", "mPackages"})
private void installPackagesTracedLI(List<InstallRequest> requests) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
        installPackagesLI(requests);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private void installPackagesLI(List<InstallRequest> requests) {
    ......
    try {
        for (InstallRequest request : requests) {
            // TODO(b/109941548): remove this once we've pulled everything from it and into
            //                    scan, reconcile or commit.
            final PrepareResult prepareResult;
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                //分析安装状态、分析包并检查验证
                //检查包并分析完整性;检查SDK版本、静态库等;检查签名;设置权限;
                prepareResult = preparePackageLI(request.args, request.installResult);
            }
            ......
            try {
                //扫描apk
                final List<ScanResult> scanResults = scanPackageTracedLI(
                        prepareResult.packageToScan, prepareResult.parseFlags,
                        prepareResult.scanFlags, System.currentTimeMillis(),
                        request.args.user);
            } 
            ......
        }
        executePostCommitSteps(commitRequest);
    } finally {
        ......
    }
}

installPackagesLI()方法很复杂,这里也不细述了。
installPackagesLI()对安装包本身以及安装环境等进行一些相关的检查验证。检查包的完整性、SDK版本、签名、共享库、设置权限等等,检查安装环境是否满足等。可以大致看下方法中这几个方法:

prepareResult = preparePackageLI(request.args, request.installResult);
final List<ScanResult> scanResults = scanPackageTracedLI(
                        prepareResult.packageToScan, prepareResult.parseFlags,
                        prepareResult.scanFlags, System.currentTimeMillis(),
                        request.args.user);
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,

最后执行executePostCommitSteps()进一步进行安装,最终通过binder进入installd进程完成安装。这个过程也很复杂,本人也需进一步阅读。executePostCommitSteps()后续简单参考过程:

PackageManagerService.java
installPackagesLI()->executePostCommitSteps()->prepareAppDataAfterInstallLIF()->prepareAppDataLIF()->prepareAppDataLeafLIF()->mInstaller.createAppData()。      
Installer.java:
createAppData()->mInstalld.createAppData()。      

关于过程中一些路径操作多说一点:
在preparePackageLI()中有个rename的过程,将前面拷贝的文件目录重命名了下,所以安装后能在手机中看到的是重命名后的目录。
重命名规则:/data/app/[packagename]-[suffix]。
例如我的安装:PackageManager: Renaming /data/app/vmdl1101585668.tmp to /data/app/[packagename]-RDISkz-0p77Yh-pAwNtfFA==
相关代码:

private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
    ......
    if (!args.doRename(res.returnCode, pkg)) {
        throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
    }
    ......
}

class FileInstallArgs extends InstallArgs {
    boolean doRename(int status, PackageParser.Package pkg) {
        .....
        final File targetDir = codeFile.getParentFile();
        final File beforeCodeFile = codeFile;
        final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
        if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
        .....
        Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
        .....
    }
}

private File getNextCodePath(File targetDir, String packageName) {
    File result;
    SecureRandom random = new SecureRandom();
    byte[] bytes = new byte[16];
    do {
        random.nextBytes(bytes);
        String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
        result = new File(targetDir, packageName + "-" + suffix);
    } while (result.exists());
    return result;
}

一点总结

点击安装,通过类似PackageInstaller.apk处理。
确认安装后,拷贝apk到/data/app/vmdl[sessionId].tmp/base.apk下。
进一步安装中,重命名路径为 /data/app/[packagename]-[suffix]。

如我的安装:拷贝到/data/app/vmdl1101585668.tmp/base.apk。重命名后是:/data/app/[packagename]-RDISkz-0p77Yh-pAwNtfFA==。

查看/data/app/[packagename]-RDISkz-0p77Yh-pAwNtfFA==目录,有base.apk lib/ oat/,安装后的apk、库、odex、vdex都在这个目录下。
系统预置的还在预置目录下,如/system/priv-app。
/data/data/[packagename]存放应用数据,一般有cache code_cache lib。

adb安装(无界面 静默安装)

这也是一个简单参考,不完整。
使用adb命令进行安装,下面大致可以参考:

//system/core/adb/client/commandline.cpp
int adb_commandline(int argc, const char** argv) {
    ......
    else if (!strcmp(argv[0], "install")) {
        if (argc < 2) error_exit("install requires an argument");
        return install_app(argc, argv);
    }
    ......
}

//system/core/adb/client/adb_install.cpp
int install_app(int argc, const char** argv) {
    ......
    switch (installMode) {
        case INSTALL_PUSH:
            return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
                                      use_fastdeploy, use_localagent);
        case INSTALL_STREAM:
            return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(),
                                        use_fastdeploy, use_localagent);
        case INSTALL_DEFAULT:
        default:
            return 1;
    }
}

static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy,
                              bool use_localagent) {
    ......
    result = pm_command(argc, argv);
    ......
}

static int pm_command(int argc, const char** argv) {
    std::string cmd = "pm";

    while (argc-- > 0) {
        cmd += " " + escape_arg(*argv++);
    }

    return send_shell_command(cmd);
}

在AndroidO时,还有源码frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java。AndroidO最终Pm.java执行mInstaller.createSession()进入PMS。

AndroidQ中,frameworks/base/cmds/pm/src/com/android/commands/pm只有一个Andoird.mk了,pm是system/bin下的一个可执行文件了system/bin/pm
不过应该是和O类似的(AndoridP中也没有Pm.java的源码了),最终也是进入的PMS中方法,回归到类似点击安装的过程。
我们可以在上面点击安装过程中的PMS方法中添加调用栈或log等,了解adb安装的过程是 进入的哪,进一步跟踪了解。

posted @ 2020-10-18 21:52  流浪_归家  阅读(2127)  评论(0编辑  收藏  举报