Andriod PKMS启动及扫描流程
本文分析了Android 15中PackageManagerService(PKMS)的启动流程。PKMS作为系统包管理服务,在SystemServer进程启动时被初始化。主要流程包括:1)SystemServer调用startOtherServices()启动PKMS;2)PKMS.main()方法创建后台线程,初始化依赖注入器,构建PKMS实例;3)PKMS构造函数执行应用扫描、解析和安装等核
本文基于 Android 15
一、启动流程
PKMS 是一个负责包管理的系统服务,是在 SystemServer 进程中进行启动的,在开机阶段中 SystemServer 中执行 startOtherService()
1.1 SystemServer.startOtherServices()
t.traceBegin("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main( // PKMS 的创建和注册过程
mSystemContext, installer, domainVerificationService,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
t.traceEnd();
这里调用 PKMS 的 main 方法来进行 PKMS 的初始化,服务注册,应用扫描、解析和安装等操作
1.1 PKMS.main()
/** Starts PackageManagerService. */
public static PackageManagerService main(Context context,
Installer installer, @NonNull DomainVerificationService domainVerificationService,
boolean factoryTest) {
HandlerThread backgroundThread = new ServiceThread("PackageManagerBg", // 创建 PackageManagerBg 线程
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
backgroundThread.start();
Handler backgroundHandler = new Handler(backgroundThread.getLooper(),
BACKGROUND_HANDLER_CALLBACK); // 创建 PackageManagerBg 后台线程的 Handler
// 先创建 PackageManagerServiceInjector 注入器对象,获取使用的一些对象都可以从里面进行获取,这里使用的是 lambda 表达式
PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
...
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, backgroundHandler,
lock),
...
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
i.getContext(), "*dexopt*"),
(i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
i.getDynamicCodeLogger()),
...
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), // 获取包解析器,重要的
new PackageCacher(pm.mCacheDir, pm.mPackageParserCallback),
pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* scanningPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* preparingPackageParserProducer */,
// Prepare a supplier of package parser for the staging manager to parse apex file
// during the staging installation.
(i, pm) -> new PackageInstallerService( // 创建 PackageInstallerService
i.getContext(), pm, i::getScanningPackageParser),
...);
// 这里才会创建 PKMS 对象
PackageManagerService m = new PackageManagerService(injector, factoryTest,
PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,
Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);
t.traceEnd(); // "create package manager"
...
m.installAllowlistedSystemPackages();
IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl(); // 获取的是 PackageManagerService 本身,因为这里调用是在 PKMS 的本地进程中
ServiceManager.addService("package", iPackageManager); // 将 PKMS 注册到 ServiceManager 中,发布服务
final PackageManagerNative pmn = new PackageManagerNative(m); // 相当于是同时注册两个独立的服务,注册 PackageManagerNative 对象之后,客户端可与 Native 直接通信,不必再传递到 Java 层来
ServiceManager.addService("package_native", pmn); // 再使用 JNI 初始化 Native 层对应的 PKMS 服务,然后同时发布到 ServiceManager 中进行注册
// 服务的发布必须进行注册到 ServiceManager 中,客户端才能获取到服务的代理类
return m;
}
-
创建并启动 PackageManagerBg 线程
-
初始化 PackageManagerServiceInjector 注入器对象,再初始化 PackageManagerService 对象
-
将 PKMS 注册到 ServiceManager 中
-
将 PKMS 的 Native 对象注册到 ServiceManager 中
创建 PackageManagerBg 线程,后续有一些操作可通过 Handler 投递到该线程进行执行,依赖的初始化是通过 PackageManagerServiceInjector 来进行,将 PKMS 所以来的对象维护在 Injector 中,后续 PKMS 需要使用就直接从注入器中获取
创建 Injector 对象之后,调用 PKMS 的构造方法来进行 PKMS 初始化,其中会进行应用扫描、解析和安装等等一系列繁琐的操作,后文就一直围绕着构造方法中具体的一些重要步骤在讲述
最后会将 PKMS 发布到 ServiceManager 中进行服务的注册,后续其他进程想要使用该服务的使用才能调用到,这是 binder 通信的必要操作
还会通过 JNI 初始化一个 PackageManagerNative 的 Native 层对象,这是 PKMS 在 Native 的对应表示,将其也注册到 ServiceManager 中
1.2 new PackageManagerService()
public PackageManagerService(PackageManagerServiceInjector injector, boolean factoryTest,
final String partitionsFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
mPendingBroadcasts = new PendingPackageBroadcasts();
...
// PKMS 初始化的第一个阶段 BOOT_PROGRESS_PMS_START
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
// 添加 PackageManagerInternal 到 LocalServices 中供 SystemServer 进程内部使用
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
LocalManagerRegistry.addManager(PackageManagerLocal.class,
new PackageManagerLocalImpl(this));
LocalServices.addService(TestUtilityService.class, this);
mTestUtilityService = LocalServices.getService(TestUtilityService.class);
mUserManager = injector.getUserManagerService();
mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
mComponentResolver = injector.getComponentResolver();
mPermissionManager = injector.getPermissionManagerServiceInternal(); // PermissionManagerService 对象
mSettings = injector.getSettings(); // 属于 pm 包下的维护着一些配置的 Settings 类
mIncrementalManager = mInjector.getIncrementalManager();
mDefaultAppProvider = mInjector.getDefaultAppProvider();
mLegacyPermissionManager = mInjector.getLegacyPermissionManagerInternal();
PlatformCompat platformCompat = mInjector.getCompatibility();
t.traceBegin("addSharedUsers"); // 进行 SharedUserId 的初始化,为系统关键组件添加 SharedUserId
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
final ArrayMap<String, Integer> oemDefinedUids = systemConfig.getOemDefinedUids();
final int numOemDefinedUids = oemDefinedUids.size();
for (int i = 0; i < numOemDefinedUids; i++) {
mSettings.addOemSharedUserLPw(oemDefinedUids.keyAt(i), oemDefinedUids.valueAt(i),
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
}
...
// 这里进行读取历史持久化配置,顺便可以通过是否存在历史持久化配置来判断是否首次开机启动
mFirstBoot = !mSettings.readLPw(computer, // LPw 表示需要持有锁并且需要执行写操作
mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ false,
/* excludePreCreated= */ false));
t.traceEnd();
mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); // 读取之前的权限信息
mPermissionManager.readLegacyPermissionStateTEMP(); // 读取了之后存储起来
if (mFirstBoot) {
DexOptHelper.requestCopyPreoptedFiles();
}
// 开始 PKMS 扫描阶段
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
// 获取 InitAppsHelper 类,负责应用扫描安装
mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
mInjector.getSystemPartitions());
final int[] userIds = mUserManager.getUserIds();
// 初始化 PackageParser 对象(包解析器)
PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
// 进行系统应用的扫描安装
mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
startTime);
// 进行三方应用扫描安装
mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
packageParser.close();
// PKMS 应用扫描结束
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
...
// PKMS ready 阶段
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
...
}
-
进行一些依赖服务的绑定,PackageManagerService 初始化
-
进行 SharedUserId 的初始化,为系统关键组件添加 SharedUserId
-
通过 com.android.server.pm.Settings 类来读取持久化配置并保存起来,顺便判断是否手次开机启动
-
通过 mInitAppsHelper 进行系统应用和三方应用的扫描安装
二、应用扫描
针对构造方法中的应用扫描、解析和安装来进一步详细说明,这也是 PKMS 启动的核心流程
这里就使用系统应用的安装来举例
2.1 InitAppsHelper.initSystemApps()
/**
* Install apps from system dirs.
* 安装系统应用
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public OverlayConfig initSystemApps(PackageParser2 packageParser,
WatchedArrayMap<String, PackageSetting> packageSettings,
int[] userIds, long startTime) {
// 这里先扫描 apex 包,解析为 ApexManager.ScanResult 对象
final List<ApexManager.ScanResult> apexScanResults = scanApexPackagesTraced(packageParser);
mApexManager.notifyScanResult(apexScanResults);
scanSystemDirs(packageParser, mExecutorService);
...
logSystemAppsScanningTime(startTime);
return overlayConfig;
}
-
这里 SystemApp 包括 system、system_ext、product、vendor、odm、oem、apex 分区下的/app 和/priv-app 目录下的 apk,也包括 apex 包
-
先进行 apex 包的扫描
-
进行系统目录的扫描和应用安装,包括 system、system_ext、product、vendor、odm、oem、apex 分区
-
apex 包启用和 overlay 配置
2.2 InitAppsHelper.scanSystemDirs()
/**
* First part of init dir scanning
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {
File frameworkDir = new File(Environment.getRootDirectory(), "framework"); // /system/framework 目录
// mDirsToScanAsSystem 包括 system、system_ext、product、vendor、odm、oem 分区以及包括 apex 包所在的分区(如 apex)
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), // 这里先扫描每个分区中 overlay 包并进行安装
mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService, partition.apexInfo);
}
scanDirTracedLI(frameworkDir, // 扫描/system/framework/目录并进行安装
mSystemParseFlags, mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
packageParser, executorService, null);
if (!mPm.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) { // 扫描每个系统分区中的/priv-app 目录并安装
scanDirTracedLI(partition.getPrivAppFolder(),
mSystemParseFlags,
mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
packageParser, executorService, partition.apexInfo);
}
scanDirTracedLI(partition.getAppFolder(), // 扫描每个系统分区中的/app 目录并安装
mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService, partition.apexInfo);
}
}
-
遍历扫描系统分区中(system、system_ext、product、vendor、odm、oem、apex)的 overlay 包并安装
-
扫描/system/framework/目录
-
遍历扫描系统分区中的/priv-app 目录安装包并安装
-
遍历扫描系统分区中的/app 目录安装包并安装
2.3 InitAppsHelper.scanDirTracedLI()
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,
PackageParser2 packageParser, ExecutorService executorService,
@Nullable ApexManager.ActiveApexInfo apexInfo) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
// when scanning apk in apexes, we want to check the maxSdkVersion
parseFlags |= PARSE_APK_IN_APEX;
}
mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags,
scanFlags, packageParser, executorService, apexInfo);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
参数:
扫描路径:scanDir
包解析器:packageParser
packageParser(包解析器)会进行 apk 的解析,apk 包的基本信息获取,包名、版本号和证书等等,解析 AndroidManifest.xml 中的各个标签,、等标签,解析标签,四大组件的解析,最后封装为 Parsedpackage 类来表示解析结果
2.4 InstallPackageHelper.installPackagesFromDir()
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, int parseFlags,
int scanFlags, PackageParser2 packageParser, ExecutorService executorService,
@Nullable ApexManager.ActiveApexInfo apexInfo) {
final File[] files = scanDir.listFiles(); // 获取待安装目录下的所有文件
// 并行解析器(多线程)
ParallelPackageParser parallelPackageParser =
new ParallelPackageParser(packageParser, executorService);
// Submit files for parsing in parallel
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); // 提交该 apk 给解析器,调用 PackageParser2.parsePackage()进行解析
fileCount++;
}
// Process results one by one 开始依次解析
for (; fileCount > 0; fileCount--) {
// 这里一次处理解析后的结果
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;
String errorMsg = null;
if (throwable == null) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "addForInitLI");
addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
new UserHandle(UserHandle.USER_SYSTEM), apexInfo);
} catch (PackageManagerException e) {
errorCode = e.error;
errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
Slog.w(TAG, errorMsg);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
} else if (throwable instanceof PackageManagerException) {
PackageManagerException e = (PackageManagerException) throwable;
errorCode = e.error;
errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
Slog.w(TAG, errorMsg);
} else {
throw new IllegalStateException("Unexpected exception occurred while parsing "
+ parseResult.scanFile, throwable);
}
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
}
// Delete invalid userdata apps 解析出错将会删除 app
if ((scanFlags & SCAN_AS_SYSTEM) == 0
&& errorCode != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
mRemovePackageHelper.removeCodePath(parseResult.scanFile);
}
}
}
三、应用解析
3.1 PackageParser2.parsePackage()
@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
...
// 下面调用工具类 ParsingPackageUtils.parsePackage 进行解析
ParseResult<ParsingPackage> result = mParsingUtils.parsePackage(input, packageFile, flags);
if (result.isError()) {
throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
result.getException());
}
...
ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
...
return parsed; // 返回解析结果
}
3.2 ParsingPackageUtils.parsePackage()
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags); // 如果是目录,这是一个 apk 集群
} else {
return parseMonolithicPackage(input, packageFile, flags); // 是单个文件,解析 Monolithic 单个 package
}
}
分为两种情况,apk 分包和单包的情况
**分包:**parseClusterPacakge,扫描目录下面所有 apk,合并清单文件,代码、资源和权限信息,最终生成一个完整的 ParsingPackage 对象
**单包:**parseMonolithicPackage,直接解析这个 apk,生成 ParsingPackage 对象
3.3 ParsingPackageUtils.parseClusterPackage()
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
...
// 先进行最基础的信息解析(轻量级信息)
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags);
...
try {
final File baseApk = new File(lite.getBaseApkPath());
// parseBaseApk,进行最主要的解析步骤
final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.getPath(), assetLoader, flags, shouldSkipComponents);
ParsingPackage pkg = result.getResult();
return input.success(pkg); // 返回 ParsingPackage 解析结果
} catch (IllegalArgumentException e) {
...
}
}
解析分包的情况
3.4 ParsingPackageUtils.parseMonolithicPackage()
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) {
...
// 也是先进行轻量级的解析,解析一些包的基本信息
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, liteParseFlags);
...
try {
// 重要的步骤,进行主要的解析
final ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
assetLoader, flags, shouldSkipComponents);
return input.success(result.getResult()
.set32BitAbiPreferred(lite.isUse32bitAbi()));
} catch (IOException e) {
...
}
}
解析单包的情况
3.3 ParsingPackageUtils.parseBaseApk()
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags,
boolean shouldSkipComponents) {
...
// 获取 xml 解析器来解析 AndroidManifest.xml 文件,这是应用解析最重要的步骤
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags, shouldSkipComponents);
...
return input.success(pkg);
}
3.4 ParsingPackageUtils.parseBaseApk()
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags,
boolean shouldSkipComponents)
throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
ParseResult<Pair<String, String>> packageSplitResult =
ApkLiteParseUtils.parsePackageSplitNames(input, parser);
Pair<String, String> packageSplit = packageSplitResult.getResult();
pkgName = packageSplit.first;
splitName = packageSplit.second;
try {
final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/,
"coreApp", false); // 是否是 core app
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
// 这里进行 AndroidManifest.xml 中标签的解析
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags,
shouldSkipComponents);
return input.success(pkg);
...
}
重要的步骤,牢记 parseBaseApk 进行 AndroidManifest.xml 的解析
3.5 ParsingPackageUtils.parseBaseApkTags()
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags,
boolean shouldSkipComponents) throws XmlPullParserException, IOException {
// 解析 sharedUserId 属性
ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
final boolean updatableSystem = parser.getAttributeBooleanValue(null /*namespace*/,
"updatableSystem", true); // 是否为可更新的系统应用
final String emergencyInstaller = parser.getAttributeValue(null /*namespace*/,
"emergencyInstaller"); // 指定的紧急安装器
...
boolean foundApp = false;
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
String tagName = parser.getName();
final ParseResult result;
// <application> has special logic, so it's handled outside the general method
if (TAG_APPLICATION.equals(tagName)) { // 解析<application>标签,因为 application 有特殊的逻辑,所以单独拿出来
if (foundApp) {
if (RIGID_PARSER) {
result = input.error("<manifest> has more than one <application>");
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
result = input.success(null);
}
} else {
foundApp = true;
// 解析<applicaiton 标签>,会进行四大组件的解析
result = parseBaseApplication(input, pkg, res, parser, flags,
shouldSkipComponents);
}
} else {
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
}
return validateBaseApkTags(input, pkg, flags);
}
在这里解析的解析,解析四大组件标签
3.6 ParsingPackageUtils.parseBaseApplication()
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
boolean shouldSkipComponents) throws XmlPullParserException, IOException {
...
ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
pkgName, pkgName, taskAffinity, input);
pkg.setTaskAffinity(taskAffinityResult.getResult());
...
// 下面解析四大组件
boolean hasActivityOrder = false;
boolean hasReceiverOrder = false;
boolean hasServiceOrder = false;
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
...
switch (tagName) {
case "activity":
...
case "receiver":
...
case "service":
...
case "provider":
...
case "activity-alias":
...
case "apex-system-service":
...
default:
...
}
return input.success(pkg);
}
解析四大组件,最后将解析结果保存到解析结果 ParsingPacakge 对象里面去
3.6 ParsingPackageUtils.parseBaseApkTag()
private ParseResult parseBaseApkTag(String tag, ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws IOException, XmlPullParserException {
switch (tag) {
case TAG_OVERLAY:
return parseOverlay(input, pkg, res, parser);
case TAG_KEY_SETS:
return parseKeySets(input, pkg, res, parser);
case "feature": // TODO moltmann: Remove
case TAG_ATTRIBUTION:
return parseAttribution(input, pkg, res, parser);
case TAG_PERMISSION_GROUP:
return parsePermissionGroup(input, pkg, res, parser);
case TAG_PERMISSION:
return parsePermission(input, pkg, res, parser, flags);
case TAG_PERMISSION_TREE:
return parsePermissionTree(input, pkg, res, parser);
case TAG_USES_PERMISSION:
case TAG_USES_PERMISSION_SDK_M:
case TAG_USES_PERMISSION_SDK_23:
return parseUsesPermission(input, pkg, res, parser);
case TAG_USES_CONFIGURATION:
return parseUsesConfiguration(input, pkg, res, parser);
case TAG_USES_FEATURE:
return parseUsesFeature(input, pkg, res, parser);
case TAG_FEATURE_GROUP:
return parseFeatureGroup(input, pkg, res, parser);
case TAG_USES_SDK:
return parseUsesSdk(input, pkg, res, parser, flags);
case TAG_SUPPORT_SCREENS:
return parseSupportScreens(input, pkg, res, parser);
case TAG_PROTECTED_BROADCAST:
return parseProtectedBroadcast(input, pkg, res, parser);
case TAG_INSTRUMENTATION:
return parseInstrumentation(input, pkg, res, parser);
case TAG_ORIGINAL_PACKAGE:
return parseOriginalPackage(input, pkg, res, parser);
case TAG_ADOPT_PERMISSIONS:
return parseAdoptPermissions(input, pkg, res, parser);
case TAG_USES_GL_TEXTURE:
case TAG_COMPATIBLE_SCREENS:
case TAG_SUPPORTS_INPUT:
case TAG_EAT_COMMENT:
// Just skip this tag
XmlUtils.skipCurrentTag(parser);
return input.success(pkg);
case TAG_RESTRICT_UPDATE:
return parseRestrictUpdateHash(flags, input, pkg, res, parser);
case TAG_INSTALL_CONSTRAINTS:
return parseInstallConstraints(input, pkg, res, parser,
mCallback.getInstallConstraintsAllowlist());
case TAG_QUERIES:
return parseQueries(input, pkg, res, parser);
default:
return ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
}
}
四、应用安装
4.1 InstallPackageHelper.addForInitLI()
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user, @Nullable ApexManager.ActiveApexInfo activeApexInfo)
throws PackageManagerException {
PackageSetting disabledPkgSetting;
synchronized (mPm.mLock) {
...
// 解析后的结果
final Pair<ScanResult, Boolean> scanResultPair = scanPackageForInitLI(
parsedPackage, parseFlags, scanFlags, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
// 构建一个安装请求 InstallRequest 对象
final InstallRequest installRequest = new InstallRequest(
parsedPackage, parseFlags, scanFlags, user, scanResult, disabledPkgSetting);
synchronized (mPm.mLock) {
...
commitReconciledScanResultLocked(reconcileResult.get(0),
mPm.mUserManager.getUserIds());
}
return scanResult.mPkgSetting.getPkg();
}
对于单独的一个 ParsedPackage 解析结果对象,会为其构建一个 InstallRequest 安装请求对象,进行安装
4.2 InstallPackageHelper.commitReconciledScanResultLocked()
/**
* Commits the package scan and modifies system state.
* <p><em>WARNING:</em> The method may throw an exception in the middle
* of committing the package, leaving the system in an inconsistent state.
* This needs to be fixed so, once we get to this point, no errors are
* possible and the system is not left in an inconsistent state.
*/
@GuardedBy("mPm.mLock")
private AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
final InstallRequest request = reconciledPkg.mInstallRequest;
// TODO(b/135203078): Move this even further away
ParsedPackage parsedPackage = request.getParsedPackage();
...
// Modify state for the given package setting 最后将
commitPackageSettings(pkg, pkgSetting, oldPkgSetting, reconciledPkg);
...
return pkg;
}
-
取出 ReconciledPackage 对象中的 InstallRequest 对象和 parsedPackage 对象
-
commitPackageSettings() 将应用包信息写入到 Settings 中(PKMS 的核心配置管理类),并且会将应用包信息持久化到/data/system/packages.xml 中,是通过 Settings 类完成内存更新和持久化触发
4.3 InstallPackageHelper.commitPackageSettings()
/**
* Adds a scanned package to the system. When this method is finished, the package will
* be available for query, resolution, etc...
* 添加扫描后的 package 到系统中,这个方法结束后,package 就可以被查询、解析等等,应用就安装完成了
*/
private void commitPackageSettings(@NonNull AndroidPackage pkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
ReconciledPackage reconciledPkg) {
...
synchronized (mPm.mLock) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
mPm.mSettings.insertPackageSettingLPw(pkgSetting, pkg); // 这里将 package 信息写入到 pkms 的配置管理类 Settings 中
// Add the new setting to mPackages
mPm.mPackages.put(pkg.getPackageName(), pkg);
final List<String> protectedBroadcasts = pkg.getProtectedBroadcasts();
if (!protectedBroadcasts.isEmpty()) {
synchronized (mPm.mProtectedBroadcasts) {
mPm.mProtectedBroadcasts.addAll(protectedBroadcasts); // 进行受保护广播的添加
}
}
// 触发 PermissionManagerService 的回调方法来进行权限的更新
mPm.mPermissionManager.onPackageAdded(pkgSetting,
(scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg);
}
...
}
-
最终进行 package 信息更新到 mSettings(PKMS 的核心配置管理类)中
-
触发 PermissionManagerService 的 onPackageAdded 的回调,进行权限更新
五、总结
到此,PKMS 的开机启动流程就完成了,主要做了以下步骤:
-
服务初始化:在 SystemServer 中进行启动,进行 PackageManagerService 的初始化,注册 AIDL 服务到 ServiceManager 中,供夸进程调用
-
mSettings(PKMS 中核心配置管理类)读取文件系统中的持久化文件(如/data/system/packages.xml),来加载和恢复 PKMS 的配置和应用包信息到内存中,还可以判断是否是第一次启动
-
应用扫描:扫描分区(system、system_ext、product、vendor、odm、oem 和 apex 等分区)中的 apex 或 apk 包,读取进行解析应用包
-
分别解析系统应用和三方应用,进行应用 apk 的解析,解析包名、版本号、签名等等,解析 AndroidManifest.xml 中的各个标签,、等标签,解析标签,四大组件的解析,最后封装为 Parsedpackage 类来表示解析结果
-
应用安装,依次遍历处理后的结果,创建 InstallRequest 对象,交给 InstallPackageHelper 进行应用安装,将 package 的信息保存到(内存)mSettings 中,并触发 mSettings 来持久化写入文件中,最后触发 PermissionManagerService 的回调来进行应用权限信息的更新
PKMS 的核心价值:管理应用全生命周期(安装、更新、卸载、查询),保障应用安装的安全性、系统的稳定性,以及跨进程应用交互的可行性
流程图

更多推荐



所有评论(0)