本文并非从上帝视角来描述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() {@Overridepublic boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {return platformCompat.isChangeEnabled(changeId, appInfo);}@Overridepublic boolean hasFeature(String feature) {return PackageManagerService.this.hasSystemFeature(feature, 0);}};// CHECKSTYLE:ON IndentationCheckt.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) {// 创建后台线程及其HandlermHandlerThread = 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.xmlmFirstBoot = !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();}// 自定义mCustomResolverComponentNameString 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 valuesfindOrCreateVersion(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();// 解析xmlwhile ((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) {// writersynchronized (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())));// 收集可能不再存在的系统Appfinal 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" casefinal 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 {// 这个方法几乎没有做其他的事情,除了日志,就是直接调用scanDirLIscanDirLI(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 packagescontinue;}// 解析包的关键代码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 namesif (parseResult.parsedPackage.isStaticSharedLibrary()) {renameStaticSharedLibraryPackage(parseResult.parsedPackage);}try {addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,currentTime, null);} catch (PackageManagerException e) {...}} else ...// 删除无效的用户Appif ((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);}}}...// writerTrace.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添加到KeySetManagerServiceKeySetManagerService 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// pkgmsg = "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 privilegesmsg = "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 privilegesremovePackageLI(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 IndentationCheckFrameworkStatsLog.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 freezeclearAppDataLIF(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) {// writersynchronized (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);// 初始化PackageInstallerServicemInstallerService = 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 IndentationCheckmModuleInfoProvider = 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) {...// 优化DexmPackageManagerService.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优化、磁盘清理等等一些列额外操作。

Android 11 PackageManagerService源码分析(一):PMS启动的总体流程相关推荐

  1. CTS(11)---android自动化测试CTS源码分析之一

    android自动化测试CTS源码分析之一 1, 概述 CTS(Compatibility Test Suite)全名兼容性测试,主要目的就是让Android设备开发商能够开发出兼容性更好的andro ...

  2. Android 系统(78)---《android framework常用api源码分析》之 app应用安装流程

    <android framework常用api源码分析>之 app应用安装流程 <android framework常用api源码分析>android生态在中国已经发展非常庞大 ...

  3. android agps,Android应用开发Android GPS ——AGPS源码分析及配置

    本文将带你了解Android应用开发Android GPS --AGPS源码分析及配置,希望本文对大家学Android有所帮助. " Android Framework GPS --AGPS ...

  4. android gps源码分析,Android编程之Android GPS ——AGPS源码分析及配置

    本文主要介绍了Android编程的Android GPS --AGPS源码分析及配置,通过具体的分析以及源码,向大家展示了这些,希望对大家学习Android编程有所帮助. 1:冷启动指令: locat ...

  5. live555 源码分析:播放启动

    本文分析 live555 中,流媒体播放启动,数据开始通过 RTP/RTCP 传输的过程. 如我们在 live555 源码分析:子会话 SETUP 中看到的,一个流媒体子会话的播放启动,由 Strea ...

  6. srs源码分析3-srs的启动

    本文分析的srs版本是0.6.0 srs源码分析1-搭建环境 srs源码分析2-浅析state_threads srs源码分析3-srs的启动 srs源码分析4-客户端的连接 srs源码分析5-han ...

  7. Android之AsyncTask源码分析(第五篇:execute方法只能执行一次的原因)

    (注意:本文基于API 28的源码分析,API 29上或其他平台的源码略有不同) 前言 当你调用AsyncTask对象的execute()方法时,突然发生崩溃--内心充满不解:java.lang.Il ...

  8. android(cm11)状态栏源码分析(一)

    版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/50216563 (一):写在前面 最近由于工 ...

  9. Android 7.0 源码分析项目一期竣工啦

    从 Android 入行开始,因为工作需求和解决疑难bug的原因陆陆续续的看过一些源码,但都不成系统,从2016年年底开始,在Github上建了一个Android Open Source Projec ...

最新文章

  1. Ubuntu 14.04 64bit上查看网页中的cookies
  2. C# 浅拷贝与深拷贝区别 解惑篇
  3. debstack 安装 openstack
  4. 20分钟打造你的Bootstrap站点
  5. Effective C++ 阅读笔记(一)透彻了解inline以及降低编译依存关系
  6. 笔记本计算机无法开机怎么办,笔记本开机没反应,教您笔记本电脑开不了机怎么处理...
  7. 大数据— Hadoop
  8. 崇尚个人当前状态的社会
  9. 10 月全国程序员工资统计,一半以上的职位 5 个月没招到人!
  10. 利用Nginx对不同的域名进行解析
  11. SegmentFault D-Day 2015 武汉站回顾
  12. 高精度目标检测算法-RFBNet
  13. 信息安全工程师考试大纲(含pdf)
  14. FastJNI导致的Android系统死机问题分析
  15. idea使用maven私服时下载源码
  16. 运动控制加减速算法(一)
  17. 如何定义用户模型(persona)
  18. STM32——PWM知识详解
  19. Python-小游戏-乌龟吃鱼
  20. 【机器学习】P20 模型的诊断 - 验证集

热门文章

  1. 微信小程序收款手续费_为什么有人做的小程序交易手续费是0.38%而不是0.6%?
  2. Flutter从0到1自定义日历
  3. 搞个大点的 某团购App mtgsig
  4. Godaddy出售域名收益/收款提现探究——待续
  5. 学成在线-第13天-讲义-在线学习 HLS
  6. 【集合论】序关系 ( 偏序关系中八种特殊元素 | ① 最大元 | ② 最小元 | ③ 极大元 | ④ 极小元 | ⑤ 上界 | ⑥ 下界 | ⑦ 最小上界 上确界 | ⑧ 最小下界 下确界 )
  7. Thingworx - 导航
  8. [1025]python地理处理包shapely
  9. S.M.A.R.T原则:目标管理概念 - 让你的管理规范化
  10. Base64编码理解