天天看點

Android 11 PackageManagerService源碼分析(一):PMS啟動的總體流程

本文并非從上帝視角來描述PMS的總體設計和運作邏輯,而是記錄本人閱讀源碼的一個過程。分析到後面才會出總結性的文章。

1、 PMS概述

PMS是Android系統中負責安裝包管理的服務,它的主要職責如下:

  1. 管理系統安裝的所有應用程式,包括更新、安裝、解除安裝
  2. 根據Intent比對相應的Activity、Service、Provider和BroadcastReceiver等,并提供相關資訊
  3. 解析應用權限,在App調用系統接口的時候,檢查App是否具有相應的權限
這裡所指的PMS包括PackageManagerService服務本身以及PackageManagerService服務運作時使用到的各種其他系統服務。也有人将PackageManagerService簡寫為PKMS,以和PowerManagerService區分。

2、 PMS的啟動流程

PMS服務是在SystemServer程序中啟動的,它屬于引導服務(Bootstrap service)

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    ...
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ...
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
   ...
}
           

看一下PackageManagerService#main

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    ...

    PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
    ...

    ServiceManager.addService("package", m);
    final PackageManagerNative pmn = m.new PackageManagerNative();
    ServiceManager.addService("package_native", pmn);
    return m;
}
           

這裡主要做了兩件事情:

  1. 建立PackageManagerService并向ServiceManager注冊
  2. 建立PackageManagerNative并向ServiceManager注冊

接下來看PackageManagerService的構造方法,PackageManagerService的構造方法非常龐大,但是我們可以把它分為幾個階段:

  1. 開始階段:BOOT_PROGRESS_PMS_START
  2. 系統掃描階段:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
  3. Data掃描階段:BOOT_PROGRESS_PMS_DATA_SCAN_START
  4. 掃描結束:BOOT_PROGRESS_PMS_SCAN_END
  5. 就緒階段:BOOT_PROGRESS_PMS_READY

2.1 BOOT_PROGRESS_PMS_START

接下來來看每個階段都做了寫什麼事情,首先是BOOT_PROGRESS_PMS_START

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
    PackageManager.disableApplicationInfoCache();
    PackageManager.disablePackageInfoCache();

    // Avoid invalidation-thrashing by preventing cache invalidations from causing property
    // writes if the cache isn't enabled yet.  We re-enable writes later when we're
    // done initializing.
    PackageManager.corkPackageInfoCache();

    // 開始階段日志
    final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
            Trace.TRACE_TAG_PACKAGE_MANAGER);
    mPendingBroadcasts = new PendingPackageBroadcasts();

    mInjector = injector;
    mInjector.bootstrap(this);
    mLock = injector.getLock();
    mInstallLock = injector.getInstallLock();
    LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
            SystemClock.uptimeMillis());

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

    mContext = injector.getContext();
    mFactoryTest = factoryTest;
    mOnlyCore = onlyCore;
    mMetrics = new DisplayMetrics();
    mInstaller = injector.getInstaller();

    // 建立提供服務或資料的子元件,注意建立的順序很重要
    t.traceBegin("createSubComponents");

    // 暴露私有服務供系統元件調用
    mPmInternal = new PackageManagerInternalImpl();
    LocalServices.addService(PackageManagerInternal.class, mPmInternal);
    mUserManager = injector.getUserManagerService();
    mComponentResolver = injector.getComponentResolver();
    mPermissionManager = injector.getPermissionManagerServiceInternal();

    // Settings是主要儲存設定和資訊的類
    mSettings = injector.getSettings();

    // 權限管理類
    mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
    mIncrementalManager =
            (IncrementalManager) mContext.getSystemService(Context.INCREMENTAL_SERVICE);
    PlatformCompat platformCompat = mInjector.getCompatibility();
    mPackageParserCallback = new PackageParser2.Callback() {
        @Override
        public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
            return platformCompat.isChangeEnabled(changeId, appInfo);
        }

        @Override
        public boolean hasFeature(String feature) {
            return PackageManagerService.this.hasSystemFeature(feature, 0);
        }
    };

    // CHECKSTYLE:ON IndentationCheck
    t.traceEnd();

    t.traceBegin("addSharedUsers");
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_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;
    }

    // Dex優化類
    mPackageDexOptimizer = new PackageDexOptimizer(mInstaller, mInstallLock, mContext,
            "*dexopt*");
    // Dex管理類
    mDexManager =
            new DexManager(mContext, this, mPackageDexOptimizer, mInstaller, mInstallLock);
    mArtManagerService = new ArtManagerService(mContext, this, mInstaller, mInstallLock);
    mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

    mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);

    ...

    synchronized (mInstallLock) {

    synchronized (mLock) {

        // 建立背景線程及其Handler
        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);
        }

        
        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();

        t.traceBegin("loadFallbacks");
        FallbackCategoryProvider.loadFallbacks();
        t.traceEnd();

        t.traceBegin("read user settings");
        // 這句很重要,解析系統配置檔案package.xml
        mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers(false));
        t.traceEnd();

        // 清理代碼路徑不存在的包,由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();
        }

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

        ....
    }
}
           

這裡主要是對一些屬性和子服務進行了建立或指派,其中比較重要的有mInstaller、mSettings、mPackageDexOptimizer等。在之前的有些版本,mSettings等有些屬性是在這裡直接new的,而現在采用傳入Injector的方式來擷取。另外、這裡還開啟了工作線程。

讓我們再來看看Settings#readLPw()都做了什麼吧

// Settins類的幾個重要屬性
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
private final File mPackageListFilename;
private final File mStoppedPackagesFilename;
private final File mBackupStoppedPackagesFilename;
/** The top level directory in configfs for sdcardfs to push the package->uid,userId mappings */
private final File mKernelMappingFilename;

/** 已經安裝的App的資訊 */
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();

/**
    * List of packages that were involved in installing other packages, i.e. are listed
    * in at least one app's InstallSource.
    */
private final ArraySet<String> mInstallerPackages = new ArraySet<>();

/** Map from package name to appId and excluded userids */
private final ArrayMap<String, KernelPackageState> mKernelMapping = new ArrayMap<>();

// Settings的構造方法
Settings(File dataDir, PermissionSettings permission,
        Object lock) {
    ...
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    mPackageListFilename = new File(mSystemDir, "packages.list");
    ...
}

boolean readLPw(@NonNull List<UserInfo> users) {
    FileInputStream str = null;
    // 判斷備份檔案是否存在
    if (mBackupSettingsFilename.exists()) {
        try {
            str = new FileInputStream(mBackupSettingsFilename);
            mReadMessages.append("Reading from backup settings file\n");
            PackageManagerService.reportSettingsProblem(Log.INFO,
                    "Need to read from backup settings file");
            if (mSettingsFilename.exists()) {
                // 如果備份檔案和正常檔案同時存在,忽略這個正常的檔案,因為就是在更新這個檔案的時候出現異常才會出現備份檔案沒有被删除的情況
                Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
                        + mSettingsFilename);
                mSettingsFilename.delete();
            }
        } catch (java.io.IOException e) {
            // We'll try for the normal settings file.
        }
    }

    // 把這些集合清空,為接下來的解析作準備
    mPendingPackages.clear();
    mPastSignatures.clear();
    mKeySetRefs.clear();
    mInstallerPackages.clear();

    try {
        if (str == null) { // str為null,則備份檔案不存在
            if (!mSettingsFilename.exists()) { // 兩者都不存在
                mReadMessages.append("No settings file found\n");
                PackageManagerService.reportSettingsProblem(Log.INFO,
                        "No settings file; creating initial state");
                // It's enough to just touch version details to create them
                // with default values
                findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
                findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
                return false;
            }
            str = new FileInputStream(mSettingsFilename);
        }
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(str, StandardCharsets.UTF_8.name());

        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG
                && type != XmlPullParser.END_DOCUMENT) {
            ;
        }

        // xml檔案不正常
        if (type != XmlPullParser.START_TAG) {
            mReadMessages.append("No start tag found in settings file\n");
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "No start tag found in package manager settings");
            Slog.wtf(PackageManagerService.TAG,
                    "No start tag found in package manager settings");
            return false;
        }

        int outerDepth = parser.getDepth();
        // 解析xml
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("package")) {
                readPackageLPw(parser);
            } else if (tagName.equals("permissions")) {
                mPermissions.readPermissions(parser);
            } else if (tagName.equals("permission-trees")) {
                mPermissions.readPermissionTrees(parser);
            } else if (tagName.equals("shared-user")) {
                readSharedUserLPw(parser);
            } else if ...
        }

        str.close();

    } catch ...

    ....

    return true;
}

// 讀xml的元素和屬性,擷取包資訊
private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
    String name = null;
    String realName = null;
    String idStr = null;
    String sharedIdStr = null;
    String codePathStr = null;
    String resourcePathStr = null;
    String legacyCpuAbiString = null;
    String legacyNativeLibraryPathStr = null;
    String primaryCpuAbiString = null;
    String secondaryCpuAbiString = null;
    String cpuAbiOverrideString = null;
    String systemStr = null;
    String installerPackageName = null;
    String isOrphaned = null;
    String installOriginatingPackageName = null;
    String installInitiatingPackageName = null;
    String installInitiatorUninstalled = null;
    String volumeUuid = null;
    String categoryHintString = null;
    String updateAvailable = null;
    int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
    String uidError = null;
    int pkgFlags = 0;
    int pkgPrivateFlags = 0;
    long timeStamp = 0;
    long firstInstallTime = 0;
    long lastUpdateTime = 0;
    PackageSetting packageSetting = null;
    String version = null;
    long versionCode = 0;
    String installedForceQueryable = null;
    try {
        name = parser.getAttributeValue(null, ATTR_NAME);
        realName = parser.getAttributeValue(null, "realName");
        idStr = parser.getAttributeValue(null, "userId");
        uidError = parser.getAttributeValue(null, "uidError");
        sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
        codePathStr = parser.getAttributeValue(null, "codePath");
        resourcePathStr = parser.getAttributeValue(null, "resourcePath");

        ...

        if (name == null) {
            ...
        } else if (codePathStr == null) {
            ...
        } else if (userId > 0) {
            packageSetting = addPackageLPw(/*省略一堆參數*/);
            ...
        } else if (sharedIdStr != null) {
            if (sharedUserId > 0) {
                packageSetting = new PackageSetting(/*省略一堆參數*/);
                ...
                mPendingPackages.add(packageSetting);
                ...
            } else {
                ...
            }
        } else {
            ...
        }
    } catch (NumberFormatException e) {
        ...
    }
    if (packageSetting != null) {
        
        packageSetting.uidError = "true".equals(uidError);
        InstallSource installSource = InstallSource.create(
                installInitiatingPackageName, installOriginatingPackageName,
                installerPackageName, "true".equals(isOrphaned),
                "true".equals(installInitiatorUninstalled));
        // 對packageSetting若幹屬性進行指派
        ...

    } else {
        XmlUtils.skipCurrentTag(parser);
    }
}

PackageSetting addPackageLPw(/*省略一堆參數*/) {
    PackageSetting p = mPackages.get(name);
    if (p != null) {
        if (p.appId == uid) {
            return p;
        }
        PackageManagerService.reportSettingsProblem(Log.ERROR,
                "Adding duplicate package, keeping first: " + name);
        return null;
    }
    p = new PackageSetting(name, realName, codePath, resourcePath,
            legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
            cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags,
            0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames,
            mimeGroups);
    p.appId = uid;
    if (registerExistingAppIdLPw(uid, p, name)) {
        mPackages.put(name, p);
        return p;
    }
    return null;
}
           

至此,我們知道,開始階段BOOT_PROGRESS_PMS_START的主要工作是:

  1. 初始化PMS的各個子元件/子服務以及相關屬性
  2. 解析package.xml,擷取已經安裝的App資訊,存儲到Settings的mPackages中
  3. 建立了背景工作線程及其Handler

2.2 BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

接下來看看第二階段:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
    
    ...
    
    mApexManager = ApexManager.getInstance();
    mAppsFilter = mInjector.getAppsFilter();

    // 找到要掃描的路徑
    final List<ScanPartition> scanPartitions = new ArrayList<>();
    final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
    for (int i = 0; i < activeApexInfos.size(); i++) {
        final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
        if (scanPartition != null) {
            scanPartitions.add(scanPartition);
        }
    }

    mDirsToScanAsSystem = new ArrayList<>();
    mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);
    mDirsToScanAsSystem.addAll(scanPartitions);

    ...

    synchronized (mInstallLock) {
    // writer
    synchronized (mLock) {
        
        ...

        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                startTime);

        ...

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

        final VersionInfo ver = mSettings.getInternalVersion();
        mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
        ...

        int scanFlags = SCAN_BOOTING | SCAN_INITIAL;

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

        final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
        final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;

        PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
                mMetrics, mCacheDir, mPackageParserCallback);

        ExecutorService executorService = ParallelPackageParser.makeExecutorService();
        // Prepare apex package info before scanning APKs, these information are needed when
        // scanning apk in apex.
        mApexManager.scanApexPackagesTraced(packageParser, executorService);
        // Collect vendor/product/system_ext overlay packages. (Do this before scanning
        // any apps.)
        // For security and version matching reason, only consider overlay packages if they
        // reside in the right directory.
        // 主要掃描代碼
        for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getOverlayFolder() == null) {
                continue;
            }
            scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
                    systemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }

        scanDirTracedLI(frameworkDir, systemParseFlags,
                systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                packageParser, executorService);
        if (!mPackages.containsKey("android")) {
            throw new IllegalStateException(
                    "Failed to load frameworks package; check log for warnings");
        }
        for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getPrivAppFolder() != null) {
                scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
                        systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                        packageParser, executorService);
            }
            scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
                    systemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }

        // Parse overlay configuration files to set default enable state, mutability, and
        // priority of system overlays.
        mOverlayConfig = OverlayConfig.initializeSystemInstance(
                consumer -> mPmInternal.forEachPackage(
                        pkg -> consumer.accept(pkg, pkg.isSystem())));

        // 收集可能不再存在的系統App
        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<AndroidPackage> pkgIterator = mPackages.values().iterator();
            while (pkgIterator.hasNext()) {
                final AndroidPackage pkg = pkgIterator.next();
                if (pkg.isStub()) {
                    stubSystemApps.add(pkg.getPackageName());
                }
            }

            final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
            // 這裡把mSettings.mPackages(也就是packages.xml檔案中讀取的記錄)和mPackages(實時掃描得到的記錄)做比較,看看有哪些變化
            // 有變化的情況往往是OTA更新
            while (psit.hasNext()) {
                PackageSetting ps = psit.next();

                // 非系統App跳過
                if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    continue;
                }

                /*
                * If the package is scanned, it's not erased.
                */
                final AndroidPackage 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");

                    // Assume package is truly gone and wipe residual permissions.
                    mPermissionManager.updatePermissions(ps.name, null);

                    // 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);
                    }
                }
            }
        }
        ...
    }
}
           

可以看出,這裡的主要工作是對系統區進行掃描,掃描順序是OverlayFolder -> frameworkDir -> PrivAppFolder -> AppFolder(),至于為什麼這麼設計,繼續看下去。

先看一下掃面的方法scanDirTracedLI():

private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
        long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
    try {
        // 這個方法幾乎沒有做其他的事情,除了日志,就是直接調用scanDirLI
        scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
        PackageParser2 packageParser, ExecutorService executorService) {
    final File[] files = scanDir.listFiles();
    // 空檔案夾直接傳回
    if (ArrayUtils.isEmpty(files)) {
        Log.d(TAG, "No files in app dir " + scanDir);
        return;
    }

    if (DEBUG_PACKAGE_SCANNING) {
        Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                + " flags=0x" + Integer.toHexString(parseFlags));
    }

    // 把傳進來的PackageParser2對象和線程池封裝成ParallelPackageParser對象
    ParallelPackageParser parallelPackageParser =
            new ParallelPackageParser(packageParser, executorService);

    int fileCount = 0;
    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }

        // 解析包的關鍵代碼
        parallelPackageParser.submit(file, parseFlags);
        fileCount++;
    }

    // 解析完成之後,取出結果挨個處理
    for (; fileCount > 0; fileCount--) {
        ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
        Throwable throwable = parseResult.throwable;
        int errorCode = PackageManager.INSTALL_SUCCEEDED;

        if (throwable == null) {
            // TODO(toddke): move lower in the scan chain
            // Static shared libraries have synthetic package names
            if (parseResult.parsedPackage.isStaticSharedLibrary()) {
                renameStaticSharedLibraryPackage(parseResult.parsedPackage);
            }
            try {
                addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                        currentTime, null);
            } catch (PackageManagerException e) {
                ...
            }
        } else ...


        // 删除無效的使用者App
        if ((scanFlags & SCAN_AS_SYSTEM) == 0
                && errorCode != PackageManager.INSTALL_SUCCEEDED) {
            logCriticalInfo(Log.WARN,
                    "Deleting invalid package at " + parseResult.scanFile);
            removeCodePathLI(parseResult.scanFile);
        }
    }
}
           

這裡主要操作如下:

  1. 通過ParallelPackageParser解析掃描目錄下的包
  2. 取出解析結果,執行addForInitLI
  3. 删除無效的使用者App

我們先不關心包解析的細節,隻關注主流程,如果我們每個細節都關注的話就沒完沒了了。後面的文章再專門分析包的解析。解析的結果是ParsedPackage對象,它是一個繼承自AndroidPackage的接口,實作類是PackageImpl。

看一下addForInitLI的邏輯

private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
        @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
        @Nullable UserHandle user)
                throws PackageManagerException {

    ...

    final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
    if (scanResult.success) {
        synchronized (mLock) {
            boolean appIdCreated = false;
            try {
                final String pkgName = scanResult.pkgSetting.name;
                final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
                        new ReconcileRequest(
                                Collections.singletonMap(pkgName, scanResult),
                                mSharedLibraries,
                                mPackages,
                                Collections.singletonMap(
                                        pkgName, getSettingsVersionForPackage(parsedPackage)),
                                Collections.singletonMap(pkgName,
                                        getSharedLibLatestVersionSetting(scanResult))),
                        mSettings.mKeySetManagerService);
                appIdCreated = optimisticallyRegisterAppId(scanResult);
                commitReconciledScanResultLocked(
                        reconcileResult.get(pkgName), mUserManager.getUserIds());
            } catch (PackageManagerException e) {
                if (appIdCreated) {
                    cleanUpAppIdCreation(scanResult);
                }
                throw e;
            }
        }
    }

    if (shouldHideSystemApp) {
        synchronized (mLock) {
            mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
        }
    }
    return scanResult.pkgSetting.pkg;
}
           

這裡調用了scanPackageNewLI擷取一個ScanResult對象,雖然它也是掃描的意思,但是我們關心的真正的掃描和解析的工作已經在ParallelPackageParser#submit()完成了,是以這裡先跳過。

随後又調用了reconcilePackagesLocked方法擷取一個Map對象,這裡不明白為什麼這麼做,也打不算去深究。但是不要緊,對主流程沒有影響。

最後調用了commitReconciledScanResultLocked()方法,這個方法看名字是送出掃描和解析的結果。看看它的流程吧

private AndroidPackage commitReconciledScanResultLocked(
        @NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
    ....
    commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
            (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
    
    ...

    return pkg;
}

private void commitPackageSettings(AndroidPackage pkg,
            @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting,
        final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
    final String pkgName = pkg.getPackageName();
    // 判斷是不是自定義的ResolverComponentName,這個ResolverComponentName後面再分析
    if (mCustomResolverComponentName != null &&
            mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
        setUpCustomResolverActivity(pkg, pkgSetting);
    }

    if (pkg.getPackageName().equals("android")) {
        synchronized (mLock) {
            // Set up information for our fall-back user intent resolution activity.
            mPlatformPackage = pkg;

            // The instance stored in PackageManagerService is special cased to be non-user
            // specific, so initialize all the needed fields here.
            mAndroidApplication = pkg.toAppInfoWithoutState();
            mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
            mAndroidApplication.privateFlags =
                    PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
            mAndroidApplication.initForUser(UserHandle.USER_SYSTEM);

            if (!mResolverReplaced) {
                mResolveActivity.applicationInfo = mAndroidApplication;
                mResolveActivity.name = ResolverActivity.class.getName();
                mResolveActivity.packageName = mAndroidApplication.packageName;
                mResolveActivity.processName = "system:ui";
                mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
                mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
                mResolveActivity.exported = true;
                mResolveActivity.enabled = true;
                mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
                mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
                        | ActivityInfo.CONFIG_SCREEN_LAYOUT
                        | ActivityInfo.CONFIG_ORIENTATION
                        | ActivityInfo.CONFIG_KEYBOARD
                        | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
                mResolveInfo.activityInfo = mResolveActivity;
                mResolveInfo.priority = 0;
                mResolveInfo.preferredOrder = 0;
                mResolveInfo.match = 0;
                mResolveComponentName = new ComponentName(
                        mAndroidApplication.packageName, mResolveActivity.name);
            }
        }
    }

    ...

    // writer
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");

    synchronized (mLock) {
        // We don't expect installation to fail beyond this point

        // 更新mSettings中相關包的資料
        mSettings.insertPackageSettingLPw(pkgSetting, pkg);
        // 把包的資訊存儲到mPackages裡面
        mPackages.put(pkg.getPackageName(), pkg);
        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
            mApexManager.registerApkInApex(pkg);
        }

        // 把KeySets添加到KeySetManagerService
        KeySetManagerService ksms = mSettings.mKeySetManagerService;
        ksms.addScannedPackageLPw(pkg);

        // 向mComponentResolver注冊
        mComponentResolver.addAllComponents(pkg, chatty);
        final boolean isReplace =
                reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
        // 向mAppsFilter注冊
        mAppsFilter.addPackage(pkgSetting, isReplace);

        // 不允許臨時應用程式定義新的權限組
        if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
            Slog.w(TAG, "Permission groups from package " + pkg.getPackageName()
                    + " ignored: instant apps cannot define new permission groups.");
        } else {
            // 權限組相關處理
            mPermissionManager.addAllPermissionGroups(pkg, chatty);
        }

        // 不允許臨時應用程式定義新的權限
        if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
            Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
                    + " ignored: instant apps cannot define new permissions.");
        } else {
            // 權限相關處理
            mPermissionManager.addAllPermissions(pkg, chatty);
        }

        int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
        StringBuilder r = null;
        int i;
        for (i = 0; i < collectionSize; i++) {
            ParsedInstrumentation a = pkg.getInstrumentations().get(i);
            a.setPackageName(pkg.getPackageName());
            // 向mInstrumentation注冊
            mInstrumentation.put(a.getComponentName(), a);
            if (chatty) {
                if (r == null) {
                    r = new StringBuilder(256);
                } else {
                    r.append(' ');
                }
                r.append(a.getName());
            }
        }
        if (r != null) {
            if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
        }

        if (!pkg.getProtectedBroadcasts().isEmpty()) {
            synchronized (mProtectedBroadcasts) {
                mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
            }
        }

        if (oldPkg != null) {
            // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
            // revoke callbacks from this method might need to kill apps which need the
            // mPackages lock on a different thread. This would dead lock.
            //
            // Hence create a copy of all package names and pass it into
            // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
            // revoked. If a new package is added before the async code runs the permission
            // won't be granted yet, hence new packages are no problem.
            final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());

            AsyncTask.execute(() ->
                    mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
                            allPackageNames));
        }
    }

    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

           

這裡就比較重要了,它把解析的結果存儲到了PMS的各個相關的變量中,後續我們會分析這些變量都用在哪些地方。

我們總結一下BOOT_PROGRESS_PMS_SYSTEM_SCAN_START階段所做的事情:

  1. 掃描各個系統分區的的App
  2. 解析系統App資訊
  3. 把解析結果存儲起來,存儲在PMS的相關屬性和mSettings裡

2.3 BOOT_PROGRESS_PMS_DATA_SCAN_START

接下來是BOOT_PROGRESS_PMS_DATA_SCAN_START階段,掃描/data/app下的App,也就是使用者安裝的App

if (!mOnlyCore) {
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
            SystemClock.uptimeMillis());
    // 掃描使用者安裝的App,/data/app目錄
    scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
            packageParser, executorService);

}

// 關閉packageParser,那麼接下來應該就不會用它來做包的解析了
packageParser.close();

List<Runnable> unfinishedTasks = executorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
    throw new IllegalStateException("Not all tasks finished before calling close: "
            + unfinishedTasks);
}

if (!mOnlyCore) {
    // 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.
    // 删除OTA更新中移除的系統App,如果OTA對這個App的操作是“删除”,則完全删除App相關的東西,否則剝奪它的“系統App”身份/權限
    for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
        final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
        final AndroidPackage 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
        // 從disabled清單删除
        mSettings.removeDisabledSystemPackageLPw(packageName);

        if (pkg == null) {
            // should have found an update, but, we didn't; remove everything
            // pkg
            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.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");

            @ParseFlags int reparseFlags = 0;
            @ScanFlags int rescanFlags = 0;
            for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
                final ScanPartition partition = mDirsToScanAsSystem.get(i1);
                if (partition.containsPrivApp(scanFile)) {
                    reparseFlags = systemParseFlags;
                    rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
                            | partition.scanFlag;
                    break;
                }
                if (partition.containsApp(scanFile)) {
                    reparseFlags = systemParseFlags;
                    rescanFlags = systemScanFlags | partition.scanFlag;
                    break;
                }
            }
            if (rescanFlags == 0) {
                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 = PackageCacher.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) {
        //CHECKSTYLE:OFF IndentationCheck
        FrameworkStatsLog.write(
            FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
            BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
            dataScanTime / dataPackagesCount);
        //CHECKSTYLE:OFF IndentationCheck
    }
}
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 = getSetupWizardPackageNameImpl();
mComponentResolver.fixProtectedFilterPriorities();

mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName();
mSystemTextClassifierPackageName = getSystemTextClassifierPackageName();
mWellbeingPackage = getWellbeingPackageName();
mDocumenterPackage = getDocumenterPackageName();
mConfiguratorPackage = getDeviceConfiguratorPackageName();
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mRetailDemoPackage = getRetailDemoPackageName();

// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLocked(null, 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 =
            applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
            mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
                    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();
    setting.updateProcesses();
}

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

這裡就是對/data/app進行了掃描,主要工作與掃描系統App目錄是一樣的,隻是細節處理上有些不同。初次之外還做了一些掃尾工作。

另外關于這個“disabled system list”後續分析Settings和packages.xml會講到。

2.4 BOOT_PROGRESS_PMS_SCAN_END

接下來看

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.
// 如果SDK版本發生了變化(更新系統),重新對App進行授權
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);
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.
// 如果是首次啟動或者從6.0以前的系統更新,初始化使用者首選App
if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
    for (UserInfo user : mInjector.getUserManagerInternal().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
// 為系統使用者準備存儲空間,因為SettingsProvider和SystemUI等核心系統App不可能等使用者去啟動
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.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) {
        AndroidPackage pkg = null;
        synchronized (mLock) {
            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 && !mOnlyCore) {
    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
                            | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
        }
    }
    ver.fingerprint = Build.FINGERPRINT;
}

// Grandfather existing (installed before Q) non-system apps to hide
// their icons in launcher.
if (!mOnlyCore && 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
mPromoteSystemApps = false;

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

// can downgrade to reader
t.traceBegin("write settings");
// 把更新後的mSettings中更新後的相關資訊寫入packages.xml等對應檔案中
mSettings.writeLPr();
t.traceEnd();
           

這裡主要做了如下幾件事情:

  1. 如果SDK版本發生了變化(更新系統),重新對App進行授權
  2. 為系統核心服務準備存儲空間
  3. 如果是更新後第一次正常啟動,需要清除代碼緩存,但不是會清除應用的配置檔案
  4. 把更新後的資訊寫回對應的xml檔案中

2.5 BOOT_PROGRESS_PMS_READY

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
    ...
    synchronized (mInstallLock) {
    // writer
    synchronized (mLock) {
        ...

        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;
            }
            mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr();
            mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                    PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
                    SharedLibraryInfo.VERSION_UNDEFINED);
        } else {
            mRequiredVerifierPackage = null;
            mRequiredInstallerPackage = null;
            mRequiredUninstallerPackage = null;
            mIntentFilterVerifierComponent = null;
            mIntentFilterVerifier = null;
            mServicesExtensionPackageName = null;
            mSharedSystemSharedLibraryPackageName = null;
        }

        // PermissionController hosts default permission granting and role management, so it's a
        // critical part of the core system.
        mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();

        mSettings.setPermissionControllerVersion(
                getPackageInfo(mRequiredPermissionControllerPackage, 0,
                        UserHandle.USER_SYSTEM).getLongVersionCode());

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

        // Prepare a supplier of package parser for the staging manager to parse apex file
        // during the staging installation.
        final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2(
                mSeparateProcesses, mOnlyCore, mMetrics, null /* cacheDir */,
                mPackageParserCallback);
        // 初始化PackageInstallerService
        mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);
        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).
        // 讀取并更新dex檔案的使用情況

        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) {
            FrameworkStatsLog.write(
                    FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
                    SystemClock.uptimeMillis() - startTime);
        }
    } // synchronized (mLock)
    } // synchronized (mInstallLock)
    // CHECKSTYLE:ON IndentationCheck

    mModuleInfoProvider = new ModuleInfoProvider(mContext, this);

    // Uncork cache invalidations and allow clients to cache package information.
    PackageManager.uncorkPackageInfoCache();

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

    // 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(mLock);

    PackageParser.readConfigUseRoundIcon(mContext.getResources());

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

這裡又對一些屬性進行了指派,最重要的是初始化PackageInstallerService。

2.6 總結

PMS的建立過程分為以下幾個階段

  1. 開始階段:BOOT_PROGRESS_PMS_START。這個階段的主要工作:
    • 初始化PMS的各個子元件/子服務以及相關屬性
    • 解析package.xml,擷取已經安裝的App資訊,存儲到Settings的mPackages中
    • 建立了背景工作線程及其Handler
  2. 系統掃描階段:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START。這個階段的主要工作:
    • 掃描各個系統分區的的App
    • 解析系統App資訊
    • 把解析結果存儲起來,存儲在PMS的相關屬性和mSettings裡
  3. Data掃描階段:BOOT_PROGRESS_PMS_DATA_SCAN_START。這個階段對/data/app進行了掃描,主要工作與掃描系統App目錄是一樣的,隻是細節處理上有些不同。初次之外還做了一些掃尾工作。
  4. 掃描結束:BOOT_PROGRESS_PMS_SCAN_END。這個階段主要工作:
    • 如果SDK版本發生了變化(更新系統),重新對App進行授權
    • 為系統核心服務準備存儲空間
    • 如果是更新後第一次正常啟動,需要清除代碼緩存,但不是會清除應用的配置檔案
    • 把更新後的資訊寫回對應的xml檔案中
  5. 就緒階段:BOOT_PROGRESS_PMS_READY。這個階段又對一些屬性進行了指派,最重要的是初始化PackageInstallerService。

這是PMS的主流程,其中有非常多的細節這裡沒有提及,比如多使用者的處理等等。不過有一些細節我也不打算繼續深究了,後續會挑一些重要的深入分析。

3、PMS建構完成之後

在SystemServer中,PMS建構完成之後,仍然後一些額外的操作(通過查找mPackageManagerService看它在哪些地方用到了)

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    t.traceBegin("startOtherServices");

    ...

    if (!mOnlyCore) {
        ...
        // 優化Dex
        mPackageManagerService.updatePackagesIfNeeded();
        ...
    }

    t.traceBegin("PerformFstrimIfNeeded");
    try {
        // 磁盤清理
        mPackageManagerService.performFstrimIfNeeded();
    } catch (Throwable e) {
        reportWtf("performing fstrim", e);
    }
    t.traceEnd();

    ...

    t.traceBegin("MakePackageManagerServiceReady");
    // 通知mPackageManagerService及其子元件系統已就緒
    mPackageManagerService.systemReady();
    t.traceEnd();

    ...

    // We now tell the activity manager it is okay to run third party
    // code.  It will call back into us once it has gotten to the state
    // where third party code can really run (but before it has actually
    // started launching the initial applications), for us to complete our
    // initialization.
    mActivityManagerService.systemReady(() -> {
        ...

        // 等待PMS中為App的啟動做好準備工作
        mPackageManagerService.waitForAppDataPrepared();

        ...
    }, t);

    t.traceEnd(); // startOtherServices
}
           

在startOtherServices中,PMS做了幾件事情:

  1. 在需要的情況下進行dex優化
  2. 在需要的情況下進行磁盤清理
  3. 通知PMS及其子元件系統已就緒
  4. ActivityManagerService啟動Launcher之前等待PMS中為App的啟動做好準備工作

這裡每一項都可以寫一篇文章來介紹,是以這裡就暫時略過,隻了解大概流程,細節後續再議。

4、總結

本文分析了PMS建立的主流程,未對分支流程進行太多的探究。總的來說,PMS在SystemServer裡面建立,并向ServiceManager注冊。其建立過程分為五個階段,在此過程中會從packages.xml等相關檔案中讀取上次儲存的包清單和實時掃描的清單進行比較和更新,處理更新事宜,最後把更新後的包清單重新持久化。另外,建立完成之後還進行了一些dex優化、磁盤清理等等一些列額外操作。

繼續閱讀