前面我们介绍过Android AMS服务,今天我们看一下PKMS(PackageManagerService)服务,PKMS也是android系统中核心服务之一,负责应用程序的安装,卸载,信息查询等工作。
PKMS的启动
首先启动创建PKMS:
private void startBootstrapServices() { ... // code 1 启动Installer // 我们需要在初始化其他服务之前完成此任务。 Installer installer = mSystemServiceManager.startService(Installer.class);...mActivityManagerService.setInstaller(installer);... // code 2 获取设备是否加密(手机设置密码),如果加密了,则只解析"core"应用,mOnlyCore = true,后面会频繁使用该变量进行条件判断 (android 14已去除)String cryptState = VoldProperties.decrypt().orElse("");if (ENCRYPTING_STATE.equals(cryptState)) {Slog.w(TAG, "Detected encryption in progress - only parsing core apps");mOnlyCore = true;} else if (ENCRYPTED_STATE.equals(cryptState)) {Slog.w(TAG, "Device encrypted - only parsing core apps");mOnlyCore = true;}// code 3 调用main方法初始化PackageManagerService mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);// PKMS是否是第一次启动mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager();// code 4 如果设备没有加密,执行OtaDexoptService.main。 if (!mOnlyCore) {boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false); OtaDexoptService.main(mSystemContext, mPackageManagerService); }...
}private void startOtherServices() {...//检查system app是否需要更新,需要则更新mPackageManagerService.updatePackagesIfNeeded();...//检查system app是否需要fs裁剪mPackageManagerService.performFstrimIfNeeded();...//最后system Ready通知其他服务ready设置相关信息mPackageManagerService.systemReady();...
}
在startBootstrpServices中,会做以下几件事情:
- 启动Installer服务
- 获取设备是否加密(手机设置密码),如果设备加密了,则只解析"core"应用(在android14中被删除)
- 调用PKMS main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
- 如果设备没有加密,执行OtaDexoptService.main。
我们继续看PackageManagerService.main:
public static PackageManagerService main(Context context,Installer installer, @NonNull DomainVerificationService domainVerificationService,boolean factoryTest) {// code 1 检查Package编译相关系统属性PackageManagerServiceCompilerMapping.checkProperties();...// code 2 调用PackageManagerService构造方法PackageManagerService m = new PackageManagerService(injector, factoryTest,PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);...m.installAllowlistedSystemPackages();IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();// code 3 往ServiceManager中注册”package”和”package_native”ServiceManager.addService("package", iPackageManager);final PackageManagerNative pmn = new PackageManagerNative(m);ServiceManager.addService("package_native", pmn);return m;
}
在构造方法中会处理很多的逻辑:
初始化Settings
扫描各个系统目录下APP相关信息
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {PackageManager.disableApplicationInfoCache();PackageManager.disablePackageInfoCache();...//code 1 setting保存系统中安装APP包名,权限,四大组件等相关信息的存储mSettings = injector.getSettings();...// CHECKSTYLE:OFF IndentationChecksynchronized (mInstallLock) {// writersynchronized (mLock) {...// 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);}...if (!mOnlyCore) {EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,packageParser, executorService);}packageParser.close();...}}
}
继续执行scanDirTraceLI
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(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}
}
继续执行scanDirLI
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));}ParallelPackageParser parallelPackageParser =new ParallelPackageParser(packageParser, executorService);// Submit files for parsing in parallelint 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++;}// Process results one by onefor (; 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) {errorCode = e.error;Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());}} else if (throwable instanceof PackageParserException) {PackageParserException e = (PackageParserException)throwable;errorCode = e.error;Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());} 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());}// Delete invalid userdata appsif ((scanFlags & SCAN_AS_SYSTEM) == 0&& errorCode != PackageManager.INSTALL_SUCCEEDED) {logCriticalInfo(Log.WARN,"Deleting invalid package at " + parseResult.scanFile);removeCodePathLI(parseResult.scanFile);}}
}
扫描路径的顺序
/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app
PKMS安装APK
Binder.execTransact->
Binder.execTransactInternal->
PackageManagerService.onTransact->
IPackageManager$Stub.onTransact->
Binder.onTransact->
Binder.shellCommand->
PackageManagerService.onShellCommand->
ShellCommand.exec->
PackageManagerShellCommand.onCommand->
PackageManagerShellCommand.runInstall->
PackageManagerShellCommand.doRunInstall->
PackageManagerShellCommand.doCommitSession->
PackageInstaller$Session.commit->
PackageInstallerSession.commit->
PackageInstallerSession.dispatchStreamValidateAndCommit->(mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT))
PackageInstallerSession.handleStreamValidateAndCommit->mHandler.obtainMessage(MSG_INSTALL)
PackageInstallerSession.handleInstall->
PackageInstallerSession.installNonStagedLocked->
PackageManagerService.installStage->mHandler.obtainMessage(INIT_COPY)
PackageManagerService$HandlerParams.startCopy
我们通过上面的代码可以看到,最终会执行到PackageManagerService$HandlerParams.startCopy:
final void startCopy() {if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);handleStartCopy();handleReturnCode();
}
继续执行handleReturnCode,最终会调用ParsingPackageUtils.parsePackage:
PackageManagerService$HandlerParams.startCopy->
PackageManagerService.handleReturnCode->
PackageManagerService.processPendingInstall->
PackageManagerService.processInstallRequestsAsync->
PackageManagerService.installPackagesTracedLI->
PackageManagerService.installPackagesLI->
PackageManagerService.scanPackageTracedLI->
PackageManagerService.scanPackageLI->
PackageParser2.parsePackage->
ParsingPackageUtils.parsePackage
我们看一下parsePackage的逻辑:
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,int flags)throws PackageParserException {if (packageFile.isDirectory()) {return parseClusterPackage(input, packageFile, flags);} else {return parseMonolithicPackage(input, packageFile, flags);}
}
上面代码中,如果参数是packageFile 是一个目录,就会执行parseClusterPackage(),否则执行 parseMonolithicPackage() 来处理。对于关联的多个apk 会放到一个目录下,来查看parseClusterPackage():
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,int flags) {//获取应用目录的PackageLite 对象,这个对象中分开保存了目录下的核心应用名称以及其他非核心应用的名称ParseResult<PackageParser.PackageLite> liteResult =ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);if (liteResult.isError()) {return input.error(liteResult);}final PackageParser.PackageLite lite = liteResult.getResult();if (mOnlyCoreApps && !lite.coreApp) {return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,"Not a coreApp: " + packageDir);}// Build the split dependency tree.SparseArray<int[]> splitDependencies = null;final SplitAssetLoader assetLoader;if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {try {splitDependencies =SplitAssetDependencyLoader.createDependenciesFromPackage(lite);assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);} catch (SplitAssetDependencyLoader.IllegalDependencyException e) {return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());}} else {assetLoader = new DefaultSplitAssetLoader(lite, flags);}try {//需要AssetManager 对象final AssetManager assets = assetLoader.getBaseAssetManager();final File baseApk = new File(lite.baseCodePath);ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,lite.codePath, assets, flags);if (result.isError()) {return input.error(result);}//对于apk 进行分析,得到Package 对象ParsingPackage pkg = result.getResult();if (!ArrayUtils.isEmpty(lite.splitNames)) {pkg.asSplit(lite.splitNames,lite.splitCodePaths,lite.splitRevisionCodes,splitDependencies);final int num = lite.splitNames.length;for (int i = 0; i < num; i++) {final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);parseSplitApk(input, pkg, i, splitAssets, flags);}}pkg.setUse32BitAbi(lite.use32bitAbi);return input.success(pkg);} catch (PackageParserException e) {return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,"Failed to load assets: " + lite.baseCodePath, e);} finally {IoUtils.closeQuietly(assetLoader);}
}
parseClusterPackage() 方法中先执行parseClusterPackageLite() 方法对目录下的apk 文件进行初步分析,主要是区分出核心应用和非核心应用。核心应用只有一个,非核心应用可以没有或者多个,非核心应用的作用是用来保存资源和代码。
接下来调用parseBaseApk() 方法对核心应用进行分析,并生成Package 对象,对非核心的应用调用 parseSpliteApk() 方法来分析,分析的结果会放到前面的 Package 对象中。 parseBaseApk() 方法实际上是主要是分析AndroidManifest.xml 文件:
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,String codePath, AssetManager assets, int flags) {final String apkPath = apkFile.getAbsolutePath();...final int cookie = assets.findCookieForPath(apkPath);...try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,PackageParser.ANDROID_MANIFEST_FILENAME)) { // code 1final Resources res = new Resources(assets, mDisplayMetrics, null);ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,parser, flags);...final ParsingPackage pkg = result.getResult();...pkg.setVolumeUuid(volumeUuid);...return input.success(pkg);} catch(Exception e){return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,"Failed to read manifest from "+apkPath,e);}
}
在code1处主要分析XmlResourceParser对象,也就是获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
查看PackageParser文件可知,这个地方的ANDROID_MANIFEST_FILENAME 为
public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
继续执行parseBaseApk:
ParsingPackageUtils.parsePackage->
ParsingPackageUtils.parseClusterPackage->
ParsingPackageUtils.parseBaseApk->
ParsingPackageUtils.parseBaseApk->
ParsingPackageUtils.parseBaseApkTags->
ParsingPackageUtils.parseBaseApplication->
ParsedActivityUtils.parseActivityOrReceiver
最终会执行到ParsingPackageUtils.parseBaseApplication:
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)throws XmlPullParserException, IOException {...switch (tagName) {case "activity":isActivity = true;// fall-throughcase "receiver":ParseResult<ParsedActivity> activityResult =ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,res, parser, flags, PackageParser.sUseRoundIcon, input);if (activityResult.isSuccess()) {ParsedActivity activity = activityResult.getResult();if (isActivity) {hasActivityOrder |= (activity.getOrder() != 0);pkg.addActivity(activity);} else {hasReceiverOrder |= (activity.getOrder() != 0);pkg.addReceiver(activity);}}result = activityResult;break;case "service":ParseResult<ParsedService> serviceResult =ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,flags, PackageParser.sUseRoundIcon, input);if (serviceResult.isSuccess()) {ParsedService service = serviceResult.getResult();hasServiceOrder |= (service.getOrder() != 0);pkg.addService(service);}result = serviceResult;break;case "provider":ParseResult<ParsedProvider> providerResult =ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,flags, PackageParser.sUseRoundIcon, input);if (providerResult.isSuccess()) {pkg.addProvider(providerResult.getResult());}result = providerResult;break;case "activity-alias":activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,parser, PackageParser.sUseRoundIcon, input);if (activityResult.isSuccess()) {ParsedActivity activity = activityResult.getResult();hasActivityOrder |= (activity.getOrder() != 0);pkg.addActivity(activity);}result = activityResult;break;default:result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);break;}...
}
在这个地方就完成了activity,service,receiver等四大组件的注册。
总结
- 清单文件的解析过程,一般是由PKMS来完成,触发PKMS的执行的分为两个部分:
- 在系统启动的过程中,会启动 SystemServer 进程,而SystemServer进程会启动各种服务,这些服务包括PKMS,在启动PKMS的时候就会扫码apk 安装路径下面的apk,然后解析AndroidManifest文件,并做持久化存储;
- app 安装的过程中,也会触发PKMS对 apk进行检测,调用类似的流程解析 AndroidManifest文件。Receiver的解析,都只是整个AndroidManifest解析过 程中的一个环节。
- android系统启动之后会解析系统特定目录下的apk文件,并执行解析;
- 解析Manifest流程:Zygote进程 –> SystemServer进程 –> PackgeManagerService服务 –> scanPackageLI方法 –> PackageParser2.parserPackage方法;
- 解析完成Manifest之后会将apk的Manifest信息保存在Settings对象中并持久化,删除软件时,信息会被删除,新安装的apk会重复调用scanPackageLI。