• 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安装的过程是 进入的哪,进一步跟踪了解。

  • 相关阅读:
    Postgresql10离线安装
    Clickhouse集群安装部署
    Clickhouse建表语法、视图语法、数据表DDL(数据定义语言)、数据DML(数据操作语言)
    Clickhouse基础语法、数据类型、数据表引擎学习
    Spring4.0+Mybatis整合时占位符无法读取jdbc.properties的问题
    Code: 210. DB::NetException: Connection refused (localhost:9000)
    使用Jdbc的方式连接Clickhouse列式数据库
    Dbeaver连接不上远程服务器部署的Clickhouse问题
    Clickhouse入门学习、单机、集群安装部署
    Another Redis DeskTop Manage一款免费的Redis可视化工具
  • 原文地址:https://www.cnblogs.com/fanglongxiang/p/13817369.html
Copyright © 2020-2023  润新知