天天看点

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优化、磁盘清理等等一些列额外操作。

继续阅读