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)- PackageParserhtml
關鍵類 | 路徑 |
---|---|
PackageParser.java | frameworks/base/core/java/android/content/pm/PackageParser.java |
PackageManagerService.java | frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java |
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); } ... ... }
在分析 PackageParser 解析 APK 以前,咱們先要了解一下 Split APK 機制!java
Split APK 是 Google 爲解決 65536 上限,以及 APK 安裝包愈來愈大等問題,在 Android L 中引入的機制。
Split APK 能夠將一個龐大的 APK,按屏幕密度,ABI 等形式拆分紅多個獨立的 APK,在應用程序更新時,沒必要下載整個 APK,只需單獨下載某個模塊便可安裝更新。
Split APK 將原來一個 APK 中多個模塊共享同一份資源的模型分離成多個 APK 使用各自的資源,而且能夠繼承 Base APK 中的資源,多個 APK 有相同的 data,cache 目錄。android
在引入了 Split APK 機制後,APK 有兩種分類 :segmentfault
Single APK:安裝文件爲一個完整的 APK,即 Base APK。Android 稱其爲 Monolithic。
Mutiple APK:安裝文件在一個文件目錄中,其內部有多個被拆分的 APK,這些 APK 由一個 Base APK 和一個或多個Split APK組成。Android 稱其爲 Cluster。cookie
/** * 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 參數:app
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 的分析天然更簡單了。ide
一塊兒來瞅瞅源碼:函數
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); } }
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); }
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。ui
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 方法,這個方法主要用來解析APK的AndroidManifest中的各個標籤,好比 application、permission、uses-sdk、feature-group 等等。spa
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 方法很長,咱們這裏只截取了解析四大組件相關的代碼。 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方法主要的解析結構能夠理解爲如下簡圖: