主要遍历data/app system/app文件夹,然后通过线程解析apk中的androidMainfest.xml文件生产一个Package缓存对象(javabean)保持apk在manifest.xml配置应用相关内容,如版本号,包名,权限,四大组件等等
Android 9.0做的优化
1、PackageParser 增加缓存,有的话从缓存中读取
2、 ParallelPackageParser.java submit()中加入线程池进行解析
基于Android 30梳理
1. SystemServer.java 调起PackageManagerService.main(***)方法
//在main方法中实例化PackageManagerService
2598 PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
2. 在PackageManagerService构造函数中做了很多事情,初始化了PackageParser2对象,为解析做准备
3075行 PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
mMetrics, mCacheDir, mPackageParserCallback);
在3096行调用scanDirTracedLI扫描app目录
sAppInstallDir systemAppDir
android-29版本
2675行 scanDirTracedLI(systemAppDir,mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM,
0);
2921行 scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
android-30b版本 可能位置不太对 但是都是同一个方法
3096行 scanDirTracedLI(frameworkDir, systemParseFlags,
3225行 systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
3. 在scanDirLI()函数 开始去app目录解析.apk文件,如/system/app 、/data/app目录
9053行 private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser2 packageParser, ExecutorService executorService) {
}
3.1 在scanDirLI()方法中在9066行,通过parallelPackageParser开启线程来解析apk包
9066行 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);
fileCount++;
}
3.2 在ParallelPackageParser.java submit()方法中,将每个apk文件放入线程中解析,结果保存在ParseResult中,类似一个entity,保存一些参数。结果保存在mQueue队列中(这也是相对于Android7.0 8.0的优化点之一)
102行 public void submit(File scanFile, int parseFlags) {
mExecutorService.submit(() -> {
ParseResult pr = new ParseResult();
try {
pr.scanFile = scanFile;
pr.parsedPackage = parsePackage(scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
}
try {
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
3.3 在ParallelPackageParser.java submit()方法中,调用了parsePackage()函数去解析,实际是调用在构造方法传过来的mPackageParser.parsePackage()去解析,实际为PackageParser2.java
127行 protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
4. 在PackageParser2.java中开启真正的解析apk操作,141行 parsePackage()方法
4.1 首先,判断是否优先使用缓存和缓存是否为空,此为优化之一(缓存)
ParsedPackage实际为一个配置集合类,保存很多apk相关信息
143行 if (useCaches && mCacher != null) {
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
if (parsed != null) {
return parsed;
}
}
4.2 如果没有缓存的话,就开启解析
151行 ParseInput input = mSharedResult.get().reset();
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
if (result.isError()) {
throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
result.getException());
}
ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
//最后返回parsed
return parsed
5. 进入ParsingPackageUtils.java parsePackage()方法中进行解析, 根据判断file.isDirectory来进入不同解析函数
228行 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);
}
}
5.1 先瞧瞧parseClusterPackage()函数
它有两个重要的地方
1. 249行 ApkLiteParseUtils.parseClusterPackageLite()函数(主要解析AndroidManifest.xml文件中的一些信息)
2. parseBaseApk()函数
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
249行 ParseResult<PackageParser.PackageLite> liteResult =
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
...
278行 ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.codePath, assets, flags);
...
}
5.1.1 ApkLiteParseUtils.java中 104行parseClusterPackageLite()函数
它将轻量级解析单个包的详细信息。PackageParser.PackageLite
public static ParseResult<PackageParser.PackageLite> parseClusterPackageLite(ParseInput input,
File packageDir, int flags) {
123 行
判断是否是apk文件
for (File file : files) {
if (PackageParser.isApkFile(file)) {
ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags);
}
}
...
final String codePath = packageDir.getAbsolutePath();
return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames,
isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
splitRevisionCodes));
}
在123行 循环遍历文件夹判断是否是apk文件,是的话使用parseApkLite()函数进行解析,解析完了后,通过获取一些属性拼装new PackageParser.PackageLite返回
看看parseApkLite()函数, 其实真正调用了parseApkLiteInner()函数
public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, File apkFile,
int flags) {
return parseApkLiteInner(input, apkFile, null, null, flags);
}
//在parseApkLiteInner()函数中通过获取Mainifest.xml的XmlResourceParser,最终调用了parseApkLite(input, apkPath, parser, attrs, signingDetails)去解析
private static ParseResult<PackageParser.ApkLite> parseApkLiteInner(ParseInput input,
File apkFile, FileDescriptor fd, String debugPathName, int flags) {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
XmlResourceParser parser = null;
ApkAssets apkAssets = null;
...
237行 apkAssets = fd != null
? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */, null /* assets */)
: ApkAssets.loadFromPath(apkPath);
...
245行 parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME);
...
return parseApkLite(input, apkPath, parser, attrs, signingDetails);
在parseApkLiteInner()函数中通过获取Mainifest.xml的XmlResourceParser,最终调用了parseApkLite(input, apkPath, parser, attrs, signingDetails)去解析, 他通过一些标签获取一些属性,最终拼装成PackageParser.ApkLite 返回
5.1.2 看完了 ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);之后,再回过头来瞧瞧parseBaseApk()函数
ParsingPackageUtils.java
parseBaseApk(5个参数) --> 372行 parseBaseApk(6个参数) --> parseBaseApkTags() ---> parseBaseApplication()(后面还有parseBaseApkTag()函数)
372行 ParsingPackageUtils.parseBaseApk(6个参数)
372行 ParsingPackageUtils.parseBaseApk(6个参数)
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException, PackageParserException {
...
//没啥好看的,就是解析一些xml的标签
ParseResult<Pair<String, String>> packageSplitResult =
ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
...
//实际上就是回调了PackageParser2.java 多的startParsingPackage方法,其实就是new了一个PackageImpl对象,它继承至ParsingPackage
//PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
//调用parseBaseApkTags()
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
return input.success(pkg);
}
ParsingPackageUtils.parseBaseApkTags()函数
private ParseResult<ParsingPackage> parseBaseApkTags(...){
...
while (...) {
// 解析AndroidManifest.xml文件,的Application标签,不能有多个Application
743行 if (PackageParser.TAG_APPLICATION.equals(tagName)) {
if (foundApp) {
result = input.error("<manifest> has more than one <application>");
} else {
foundApp = true;
//解析
result = parseBaseApplication(input, pkg, res, parser, flags);
}
} else {
//解析不是Application标签的子标签
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
}
...
return input.success(pkg);
}
这下终于到了真正解析AndroidManifest.xml的地方了ParsingPackageUtils.parseBaseApplication()和ParsingPackageUtils.parseBaseApkTag()函数
就是解析xml,简单看看就行了~
private ParseResult<ParsingPackage> parseBaseApplication(...) {
...
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
switch (tagName) {
case "activity":
isActivity = true;
// fall-through
case "receiver":
ParseResult<ParsedActivity> activityResult =
ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
res, parser, flags, PackageParser.sUseRoundIcon, input);
...
result = activityResult;
break;
case "service":
ParseResult<ParsedService> serviceResult =
ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
flags, PackageParser.sUseRoundIcon, input);
...
result = serviceResult;
break;
case "provider":
ParseResult<ParsedProvider> providerResult =
ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
flags, PackageParser.sUseRoundIcon, input);
...
result = providerResult;
break;
case "activity-alias":
activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
parser, PackageParser.sUseRoundIcon, input);
...
result = activityResult;
break;
}
}
...
return input.success(pkg);
}
private ParseResult parseBaseApkTag(String tag, ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws IOException, XmlPullParserException {
switch (tag) {
case PackageParser.TAG_OVERLAY:
return parseOverlay(input, pkg, res, parser);
case PackageParser.TAG_KEY_SETS:
return parseKeySets(input, pkg, res, parser);
case "feature": // TODO moltmann: Remove
...
default:
return ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
}
}
5.2 回到最开始的ParsingPackageUtils.java 中的parsePackage()函数,我们上面走完了isDirectory()的分支,接下里走走parseMonolithicPackage()分支
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);
}
}
看了下parseMonolithicPackage()和parseClusterPackage()其实内部底层逻辑基本一致,所以这里就略过了 ~
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
ParseResult<PackageParser.PackageLite> liteResult =
ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
...
try {
ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
assetLoader.getBaseAssetManager(), flags);
return input.success(result.getResult()
.setUse32BitAbi(lite.use32bitAbi));
}
}
六、我们主标题3-5中把解析AndroidMainfest.xml走了一遍,接着PackageManagerService.java scanDirLI()函数 9083行往后走,在9078行parallelPackageParser.submit(file, parseFlags);解析完了之后,
#######PackageManagerService.scanDirLI()
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser2 packageParser, ExecutorService executorService) {
...
// Process results one by one
for (; fileCount > 0; fileCount--) {
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
9095行 addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
currentTime, null);
// Delete invalid userdata apps
if ((scanFlags & SCAN_AS_SYSTEM) == 0)){
...
removeCodePathLI(parseResult.scanFile);
}
}
}
9297行 PackageManagerService.addForInitLI()
这里我们就不用看这个方法了,通过描述得知
- 在平台init阶段,会想内部数据结构添加一个新的package
- 添加后系统就会知道,并且可以被查询到
- 对于app,需要进行一些额外检测,如签名、版本号等等
- 如与之前的包相同,如果package未通过签名检查,将会被removed,还有版本号小于当前安装的也会被remove掉
- Regardless of the package location, the results are applied to the internal structures and the package is made available to the rest of the system.
/**
* Adds a new package to the internal data structures during platform initialization.
* <p>After adding, the package is known to the system and available for querying.
* <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
* etc...], additional checks are performed. Basic verification [such as ensuring
* matching signatures, checking version codes, etc...] occurs if the package is
* identical to a previously known package. If the package fails a signature check,
* the version installed on /data will be removed. If the version of the new package
* is less than or equal than the version on /data, it will be ignored.
* <p>Regardless of the package location, the results are applied to the internal
* structures and the package is made available to the rest of the system.
* <p>NOTE: The return value should be removed. It's the passed in package object.
*/
@GuardedBy({"mInstallLock", "mLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
...
}
网友评论