開篇
核心源碼
關鍵類 | 路徑 |
---|---|
PackageParser.java | frameworks/base/core/java/android/content/pm/PackageParser.java |
PackageManagerService.java | frameworks/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方法主要的解析結構可以理解爲以下簡圖: