我是靠谱客的博主 懦弱芒果,最近开发中收集的这篇文章主要介绍 Framework 核心服务之 PackageManagerService 钻研(7)- PackageParser开篇PackageParserparseClusterPackage参考,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

开篇

PackageManagerService 系列文章如下(基于 Android 9.0 源码)

         ?   Framework 核心服务之 PackageManagerService 钻研(1)- 启动流程                          
         ?   Framework 核心服务之 PackageManagerService 钻研(2)- 构造函数
         ?   Framework 核心服务之 PackageManagerService 钻研(3)- PackageManager
         ?   Framework 核心服务之 PackageManagerService 钻研(4)- PackageInstaller
         ?   Framework 核心服务之 PackageManagerService 钻研(5)- APK 安装流程(PackageInstaller)
         ?   Framework 核心服务之 PackageManagerService 钻研(6)- APK 安装流程(PMS)
         ?   Framework 核心服务之 PackageManagerService 钻研(7)- PackageParser

核心源码

关键类路径
PackageParser.javaframeworks/base/core/java/android/content/pm/PackageParser.java
PackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

PackageParser

创建解析器


private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
... ...
PackageParser pp = new PackageParser();
// 创建 PackageParser
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
// 解析APK
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
... ...
}

解析APK

在分析 PackageParser 解析 APK 之前,我们先要了解一下 Split APK 机制!

Split APK机制

Split APK 是 Google 为解决 65536 上限,以及 APK 安装包越来越大等问题,在 Android L 中引入的机制。
Split APK 可以将一个庞大的 APK,按屏幕密度,ABI 等形式拆分成多个独立的 APK,在应用程序更新时,不必下载整个 APK,只需单独下载某个模块即可安装更新。
Split APK 将原来一个 APK 中多个模块共享同一份资源的模型分离成多个 APK 使用各自的资源,并且可以继承 Base APK 中的资源,多个 APK 有相同的 data,cache 目录。

在引入了 Split APK 机制后,APK 有两种分类

Single APK:安装文件为一个完整的 APK,即 Base APK。Android 称其为 Monolithic。
Mutiple APK:安装文件在一个文件目录中,其内部有多个被拆分的 APK,这些 APK 由一个 Base APK 和一个或多个Split APK组成。Android 称其为 Cluster。

parsePackage


/**
* Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
*/
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
return parsePackage(packageFile, flags, false /* useCaches */);
}

新增一个 useCaches 参数:


public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
// 如果解析的 packageFile 是一个目录,则调用 parseClusterPackage
if (packageFile.isDirectory()) {
parsed = parseClusterPackage(packageFile, flags);
} else {
// 如果是单个 APK 文件,则调用 parseMonolithicPackage
parsed = parseMonolithicPackage(packageFile, flags);
}
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
cacheResult(packageFile, flags, parsed);
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime - parseTime;
cacheTime = SystemClock.uptimeMillis() - cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ "ms, update_cache=" + cacheTime + " ms");
}
}
return parsed;
}

我们这边选取 parseClusterPackage 作为分析的分支,当你搞懂这个方法的具体逻辑,单个 APK 的分析自然更简单了。

parseClusterPackage

一起来瞅瞅源码:


private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
/*
* 调用 parseClusterPackageLite 方法用于轻量级解析目录文件,
* 之所以要轻量级解析是因为解析APK是一个复杂耗时的操作,这里的逻辑并不需要APK所有的信息。
*/
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
/*
* mOnlyCoreApps 用来指示 PackageParser 是否只解析“核心”应用,
* “核心”应用指的是 AndroidManifest 中属性 coreApp 值为 true,只解析“核心”应用是为了创建一个极简的启动环境,
* 可以通过 PackageParser 的 setOnlyCoreApps 方法来设置 mOnlyCoreApps 的值。
*
* lite.coreApp 表示当前包是否包含“核心”应用,如果不满足条件就会抛出异常。
*/
if (mOnlyCoreApps && !lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"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) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
}
} else {
assetLoader = new DefaultSplitAssetLoader(lite, flags);
}
try {
final AssetManager assets = assetLoader.getBaseAssetManager();
final File baseApk = new File(lite.baseCodePath);
// 解析 base APK
final Package pkg = parseBaseApk(baseApk, assets, flags);
if (pkg == null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse base APK: " + baseApk);
}
if (!ArrayUtils.isEmpty(lite.splitNames)) {
// 获取 split APK 的数量
final int num = lite.splitNames.length;
pkg.splitNames = lite.splitNames;
pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
pkg.splitPrivateFlags = new int[num];
pkg.applicationInfo.splitNames = pkg.splitNames;
pkg.applicationInfo.splitDependencies = splitDependencies;
pkg.applicationInfo.splitClassLoaderNames = new String[num];
for (int i = 0; i < num; i++) {
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
// 解析每个 split APK
parseSplitApk(pkg, i, splitAssets, flags);
}
}
pkg.setCodePath(packageDir.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + lite.baseCodePath, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}

parseClusterPackageLite


static PackageLite parseClusterPackageLite(File packageDir, int flags)
throws PackageParserException {
... ...
for (File file : files) {
if (isApkFile(file)) {
// 通过 parseApkLite 方法解析每个 Mutiple APK,得到每个 Mutiple APK 对应的 ApkLite(轻量级 APK 信息)
final ApkLite lite = parseApkLite(file, flags);
... ...
}
}
... ...
final String codePath = packageDir.getAbsolutePath();
// 将这些 ApkLite 封装为一个 PackageLite(轻量级包信息)并返回
return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
configForSplits, splitCodePaths, splitRevisionCodes);
}

parseBaseApk


private static final String MNT_EXPAND = "/mnt/expand/";
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
// 如果 APK 的路径以 /mnt/expand/ 开头,就截取该路径获取 volumeUuid
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
XmlResourceParser parser = null;
try {
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
// 再次调用 parseBaseApk 方法
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.setVolumeUuid(volumeUuid);
// 用于以后标识这个解析后的 Package
pkg.setApplicationVolumeUuid(volumeUuid);
// 用于标识该 App 所在的存储卷 UUID
pkg.setBaseCodePath(apkPath);
pkg.setSigningDetails(SigningDetails.UNKNOWN);
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}

我们发现,上面代码中再次调用了 parseBaseApk 的重载方法,可以看出当前的 parseBaseApk 方法主要是为了获取和设置 volumeUuid。

parseBaseApk重载


private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
... ...
// 创建 Package 对象
final Package pkg = new Package(pkgName);
//从资源中提取自定义属性集 com.android.internal.R.styleable.AndroidManifest 得到 TypedArray
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
// 使用 typedarray 获取 AndroidManifest 中的 versionCode 赋值给 Package 的对应属性
pkg.mVersionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
pkg.mVersionCodeMajor = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0);
pkg.applicationInfo.setVersionCode(pkg.getLongVersionCode());
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
// 读取 APK 的 AndroidManifest 中的 coreApp 的值
pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
pkg.mCompileSdkVersion = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_compileSdkVersion, 0);
pkg.applicationInfo.compileSdkVersion = pkg.mCompileSdkVersion;
pkg.mCompileSdkVersionCodename = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_compileSdkVersionCodename, 0);
if (pkg.mCompileSdkVersionCodename != null) {
pkg.mCompileSdkVersionCodename = pkg.mCompileSdkVersionCodename.intern();
}
pkg.applicationInfo.compileSdkVersionCodename = pkg.mCompileSdkVersionCodename;
// 获取资源后要回收
sa.recycle();
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}

parseBaseApkCommon

最终调用了 parseBaseApkCommon 方法,这个方法主要用来解析APK的AndroidManifest中的各个标签,比如 application、permission、uses-sdk、feature-group 等等。


private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
... ...
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
... ...
// private static final String TAG_APPLICATION = "application";
if (tagName.equals(TAG_APPLICATION)) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}
foundApp = true;
// 其中四大组件的标签在 application 标签下,解析 application 标签的方法为 parseBaseApplication。
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
return null;
}
} else if (tagName.equals(TAG_OVERLAY)) {
... ...
}
... ...
}

parseBaseApplication


// parseBaseApplication 方法很长,我们这里只截取了解析四大组件相关的代码。
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
... ...
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {
// 调用 parseActivity 方法解析 activity 标签并得到一个 Activity 对象(PackageParser 的静态内部类)
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasActivityOrder |= (a.order != 0);
// 将解析得到的 Activity 对象保存在 Package 的列表 activities 中
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasReceiverOrder |= (a.order != 0);
owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasServiceOrder |= (s.order != 0);
owner.services.add(s);
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.providers.add(p);
}
... ...
}
... ...
}

PackageParser 解析 APK 的代码逻辑非常庞大,基本了解本文所讲的就足够了,如果有兴趣可以自行看源码。

parseBaseApk方法主要的解析结构可以理解为以下简图:
1417629-1a9039e0ad81bf21.png

参考

 01. http://liuwangshu.cn/framewor...

最后

以上就是懦弱芒果为你收集整理的 Framework 核心服务之 PackageManagerService 钻研(7)- PackageParser开篇PackageParserparseClusterPackage参考的全部内容,希望文章能够帮你解决 Framework 核心服务之 PackageManagerService 钻研(7)- PackageParser开篇PackageParserparseClusterPackage参考所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部