-
概述
前面兩篇博文分析了apk安裝的流程,我們換個角度,從apk啟動來看安裝的信息是如何使用的,這個過程也可能會發(fā)現(xiàn)安裝流程中忽視掉的邏輯,從而使頭尾相連,把整個安裝原理搞明白。
整個思路就是根據(jù)Activity的啟動流程,看看過程中是如何檢索包信息來實現(xiàn)啟動的,根據(jù)已知原理,我們到ActivityStarter的execute中開始尋找,我們發(fā)現(xiàn)啟動的所有信息,包括ActivityInfo等都是通過ActicityStarter.Request來指定的,顯然這是我們需要關(guān)注的重點,追蹤一下它的信息都是怎么來的。
-
mRequest.resolveActivity(mSupervisor)
在execute方法中有一句:
if (mRequest.activityInfo == null) { mRequest.resolveActivity(mSupervisor); }因為經(jīng)查找,我們并沒有發(fā)現(xiàn)activityInfo被設(shè)置了,因此這里會執(zhí)行mRequest.resolveActivity方法。
void resolveActivity(ActivityTaskSupervisor supervisor) { ... resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId, 0 /* matchFlags */, computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid)); ... activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags, profilerInfo); ... }mSupervisor是ActivityTaskSupervisor,它的resolveActivity方法中:
mService.getPackageManagerInternalLocked().resolveIntent( intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true, filterCallingUid);mService是ActivityTaskManagerService,它的getPackageManagerInternalLocked方法如下:
PackageManagerInternal getPackageManagerInternalLocked() { if (mPmInternal == null) { mPmInternal = LocalServices.getService(PackageManagerInternal.class); } return mPmInternal; }全局搜索“LocalServices.addService(PackageManagerInternal”會在PackageManagerService的構(gòu)造方法中找到:
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());PackageManagerInternalImpl的resolveIntent方法在其父類PackageManagerInternalBase中定義:
public final ResolveInfo resolveIntent(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid) { return getResolveIntentHelper().resolveIntentInternal(snapshot(), intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart, filterCallingUid); }ResolveIntentHelper的resolveIntentInternal方法如下:
public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid) { try { ... final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent, resolvedType, flags, privateResolveFlags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/); ... final ResolveInfo bestChoice = chooseBestActivity(computer, intent, resolvedType, flags, privateResolveFlags, query, userId, queryMayBeFiltered); ... return bestChoice; } ... }computer是前面snapshot()方法返回的對象:
@Override public final Computer snapshot() { return mService.snapshotComputer(); }mService是PackageManagerService,它的snapshotComputer方法會返回一個ComputerEngine對象,computer就是它。
ComputerEngine的queryIntentActivitiesInternal方法如下:
public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { ... ComponentName comp = intent.getComponent(); ... List<ResolveInfo> list = Collections.emptyList(); //顯示啟動,指定目標(biāo)Activity類名形式的跳轉(zhuǎn) if (comp != null) { final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai != null) { ... final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; //可見這里最終返回只含有一個ResolveInfo的集合 list = new ArrayList<>(1); list.add(ri); PackageManagerServiceUtils.applyEnforceIntentFilterMatching( mInjector.getCompatibility(), mComponentResolver, list, false, intent, resolvedType, filterCallingUid); } } else { //隱式啟動,匹配action、type、data等形式的跳轉(zhuǎn),這種方式下list可能有多個匹配的 ... //queryIntentActivitiesInternalBody開始查找匹配項 //tip:解析匹配uri、action的邏輯在IntentResolver的queryIntent方法中 QueryIntentActivitiesResult lockedResult = queryIntentActivitiesInternalBody( intent, resolvedType, flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName); ... if (lockedResult.sortResult) { //按照優(yōu)先級排序,優(yōu)先級越高越靠前 lockedResult.result.sort(RESOLVE_PRIORITY_SORTER); } list = lockedResult.result; } } ... return list; }這里根據(jù)Intent的查找方式分成了兩種,一種是Intent(this, destActivity.class) 這種指定了具體目標(biāo)Activity的顯示啟動,另一種是類似intent.setAction() 這種泛化匹配的隱式啟動,對于前者來說只會查到一個ActivityInfo,因此返回的集合中只會有一個ResolveInfo;后者可能會匹配到多個ActivityInfo,返回的集合中可能會有多個ResolveInfo。
回到resolveIntentInternal方法,接下來會調(diào)用chooseBestActivity方法:
private ResolveInfo chooseBestActivity(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, List<ResolveInfo> query, int userId, boolean queryMayBeFiltered) { if (query != null) { final int n = query.size(); //對于顯示啟動來說只是取出list中唯一的ResolveInfo if (n == 1) { return query.get(0); } else if (n > 1) { //對于隱式啟動 final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); //如果第一個匹配項有著更高且唯一的優(yōu)先級,也就是說第二個匹配項必須低于第一個(之前排好序了) ResolveInfo r0 = query.get(0); ResolveInfo r1 = query.get(1); ... if (r0.priority != r1.priority || r0.preferredOrder != r1.preferredOrder || r0.isDefault != r1.isDefault) { return query.get(0); } //如果優(yōu)先級篩選沒有決出唯一的一個ResolveInfo則先嘗試獲取首選項(本地保存記錄) ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(computer, intent, resolvedType, flags, query, true, false, debug, userId, queryMayBeFiltered); if (ri != null) { return ri; } ... //mResolveInfoSupplier.get()會獲取一個默認(rèn)的(ResolverActivity)或者自定義的Activity用于讓用戶選擇哪一個Activity ri = new ResolveInfo(mResolveInfoSupplier.get()); ri.activityInfo = new ActivityInfo(ri.activityInfo); ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction()); final String intentPackage = intent.getPackage(); //如果所有的目標(biāo)Activity都來自同一個package的話則直接使用第一個的ApplicationInfo if (!TextUtils.isEmpty(intentPackage) && allHavePackage(query, intentPackage)) { final ApplicationInfo appi = query.get(0).activityInfo.applicationInfo; ri.resolvePackageName = intentPackage; if (mUserNeedsBadging.get(userId)) { ri.noResourceId = true; } else { ri.icon = appi.icon; } ri.iconResourceId = appi.icon; ri.labelRes = appi.labelRes; } //如果多個目標(biāo)Activity來自不同的包則使用mResolveInfoSupplier.get()的ApplicationInfo ri.activityInfo.applicationInfo = new ApplicationInfo( ri.activityInfo.applicationInfo); if (userId != 0) { ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); } //汽車應(yīng)用相關(guān) // Make sure that the resolver is displayable in car mode if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle(); ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true); return ri; } } return null; }首選項是用戶之前選擇過的默認(rèn)項,mPreferredActivityHelper.findPreferredActivityNotLocked最終是從pm.Settings中的mPreferredActivities中根據(jù)userId來獲取PreferredIntentResolver實例,如果沒取到則使用mResolveInfoSupplier.get()獲取,來源邏輯如下:
//PackageManagerService: //倒數(shù)第二個參數(shù),所以get()獲取的是mResolveInfo mResolveIntentHelper = new ResolveIntentHelper(mContext, mPreferredActivityHelper, injector.getCompatibility(), mUserManager, mDomainVerificationManager, mUserNeedsBadging, () -> mResolveInfo, () -> mInstantAppInstallerActivity);mResolveInfo有兩個途徑賦值,一個是在setPlatformPackage方法中:
void setPlatformPackage(AndroidPackage pkg, PackageSetting pkgSetting) { synchronized (mLock) { // Set up information for our fall-back user intent resolution activity. mPlatformPackage = pkg; // The instance stored in PackageManagerService is special cased to be non-user // specific, so initialize all the needed fields here. mAndroidApplication = PackageInfoUtils.generateApplicationInfo(pkg, 0, PackageUserStateInternal.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting); if (!mResolverReplaced) { mResolveActivity.applicationInfo = mAndroidApplication; mResolveActivity.name = ResolverActivity.class.getName(); ...//mResolveActivity的其他信息設(shè)置 mResolveInfo.activityInfo = mResolveActivity; ... mResolveComponentName = new ComponentName( mAndroidApplication.packageName, mResolveActivity.name); } PackageManagerService.onChanged(); } applyUpdatedSystemOverlayPaths(); }setPlatformPackage方法是在InstallPackageHelper的commitPackageSettings方法中調(diào)用,而commitPackageSettings方法是在之前的安裝流程中通過commitPackagesLocked -> commitReconciledScanResultLocked方法中調(diào)用的:
if (pkg.getPackageName().equals("android")) { mPm.setPlatformPackage(pkg, pkgSetting); }可見,這是系統(tǒng)包的默認(rèn)配置,也就是說對于多個匹配目標(biāo)的情況下系統(tǒng)默認(rèn)會提供一個可供用戶選擇的Activity,而在setPlatformPackage方法中我們可以看到,這個Activity就是
ResolverActivity。mResolveInfo的另一個途徑是自定義途徑,提供一個可供廠商自定義此Activity的入口,通過setUpCustomResolverActivity方法賦值:
void setUpCustomResolverActivity(AndroidPackage pkg, PackageSetting pkgSetting) { synchronized (mLock) { ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0, PackageUserStateInternal.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting); // Set up information for custom user intent resolution activity. mResolveActivity.applicationInfo = appInfo; mResolveActivity.name = mCustomResolverComponentName.getClassName(); mResolveActivity.packageName = pkg.getPackageName(); mResolveActivity.processName = pkg.getProcessName(); mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; mResolveInfo.activityInfo = mResolveActivity; ... } }可以看到,mResolveActivity.name的值來自mCustomResolverComponentName。setUpCustomResolverActivity方法同樣是在commitPackageSettings方法中調(diào)用的:
final String pkgName = pkg.getPackageName(); if (mPm.mCustomResolverComponentName != null && mPm.mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) { mPm.setUpCustomResolverActivity(pkg, pkgSetting); }mCustomResolverComponentName是在PackageManagerService構(gòu)造方法中賦值的:
String customResolverActivityName = Resources.getSystem().getString( R.string.config_customResolverActivity); if (!TextUtils.isEmpty(customResolverActivityName)) { mCustomResolverComponentName = ComponentName.unflattenFromString( customResolverActivityName); }可見,廠商是通過配置config_customResolverActivity屬性來設(shè)置自定義的“ResolverActivity”。
因為系統(tǒng)package的安裝要優(yōu)先于其他package,因此setPlatformPackage會優(yōu)先設(shè)置,之后廠商package如果符合條件時setUpCustomResolverActivity才會被調(diào)用,他們都是設(shè)置的mResolveInfo,所以如果廠商設(shè)置了自定義“ResolverActivity”的話則會覆蓋掉系統(tǒng)默認(rèn)的ResolverActivity。
那ResolverActivity是如何發(fā)揮作用的,因為也沒看到把查詢到的所有匹配的ActivityInfo數(shù)據(jù)傳遞給它???我們?nèi)?strong>ResolverActivity(用的是9.0的源碼)中去看看有沒有答案。
通過查看其布局文件resolver_list_with_default.xml(其中之一的情況,無所謂這里只需要了解個大概界面)得知,它含有一個ListView來盛放所有匹配的app項,我們找到了它的adapter設(shè)置的內(nèi)部類ItemClickListener,在其onItemClick方法中會調(diào)用startSelected方法:
public void startSelected(int which, boolean always, boolean hasIndexBeenFiltered) { ... //從其data中取出TargetInfo TargetInfo target = mAdapter.targetInfoForPosition(which, hasIndexBeenFiltered); if (target == null) { return; } if (onTargetSelected(target, always)) { ... finish(); } }onTargetSelected方法如下:
protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { final ResolveInfo ri = target.getResolveInfo(); final Intent intent = target != null ? target.getResolvedIntent() : null; //保存本次選中的啟動首選項 if (intent != null && (mSupportsAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mUnfilteredResolveList != null) { IntentFilter filter = new IntentFilter(); ...//根據(jù)intent的action、data、category等生成intentFilter //IntentFilter在這里就是用于本次啟動的匹配信息的,以便再次啟動時復(fù)用 if (filter != null) { ...//一些保存信息的生成 //保存選擇記錄 //tip:IPackageManager的實現(xiàn)類是IPackageManagerBase if (alwaysCheck) { ... //即調(diào)用IPackageManager的addPreferredActivity final PackageManager pm = getPackageManager(); pm.addPreferredActivity(filter, bestMatch, set, intent.getComponent()); ... } else { //最終也是調(diào)用IPackageManager的addPreferredActivity //tip:ResolveListController.setLastChosen方法中調(diào)用AppGlobals.getPackageManager().setLastChosenActivity方法,AppGlobals.getPackageManager()獲取的是IPackageManager mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch); } } } //啟動本次選中的目標(biāo)Activity if (target != null) { safelyStartActivity(target); } return true; }這個方法里會先保存本次選中的啟動首選項,還記得之前chooseBestActivity中的PreferredActivityHelper.findPreferredActivityNotLocked操作嗎?這里的PackageManager的addPreferredActivity操作與之呼應(yīng)上了。最后啟動選中的目標(biāo)Activity。流程對上了,我們的重點來到了target是怎么來的,它來自targetInfoForPosition方法,這個方法只是根據(jù)index從ResolverListAdapter的mDisplayList中返回,mDisplayList是怎么來的呢?它通過addResolveInfo方法添加,這個方法是由onCreate->configureContentView->mAdapter.rebuildList()->finishRebuildingListWithFilteredResults->processSortedList(currentResolveList)調(diào)用的:
private void processSortedList(List<ResolvedComponentInfo> sortedComponents) { for (int i = 1; i < sortedComponents.size(); i++) { ... ResolvedComponentInfo rci = sortedComponents.get(i); ... processGroup(sortedComponents, start, (i - 1), rci, r0Label); ... start = i; } }processGroup是去除重復(fù)的項,并且調(diào)用addResolveInfoWithAlternates方法,這個方法里再調(diào)用addResolveInfo方法添加到mDisplayList中:
private void addResolveInfoWithAlternates(ResolvedComponentInfo rci, CharSequence extraInfo, CharSequence roLabel) { ... final Intent intent = rci.getIntentAt(0); final ResolveInfo add = rci.getResolveInfoAt(0); final Intent replaceIntent = getReplacementIntent(add.activityInfo, intent); final DisplayResolveInfo dri = new DisplayResolveInfo(intent, add, roLabel, extraInfo, replaceIntent); ... addResolveInfo(dri); ... }繼續(xù)看上面processSortedList方法的sortedComponents方法的來源,它來自finishRebuildingListWithFilteredResults方法的傳入?yún)?shù)?;氐絉esolverListAdapter的rebuildList方法:
protected boolean rebuildList(boolean doPostProcessing) { mDisplayList.clear(); List<ResolvedComponentInfo> currentResolveList = getInitialRebuiltResolveList(); ... boolean result = finishRebuildingListWithFilteredResults(currentResolveList, doPostProcessing); return result; }可以看到,傳入?yún)?shù)是currentResolveList,由getInitialRebuiltResolveList方法返回:
List<ResolvedComponentInfo> getInitialRebuiltResolveList() { if (mBaseResolveList != null) { List<ResolvedComponentInfo> currentResolveList = new ArrayList<>(); mResolverListController.addResolveListDedupe(currentResolveList, mResolverListCommunicator.getTargetIntent(), mBaseResolveList); return currentResolveList; } else { return mResolverListController.getResolversForIntent( /* shouldGetResolvedFilter= */ true, mResolverListCommunicator.shouldGetActivityMetadata(), mIntents); } }mResolverListController.getResolversForIntent最底層是調(diào)用了mpm.queryIntentActivitiesAsUser方法,mpm查看來源發(fā)現(xiàn)是通過ContextImpl的getPackageManager返回的ApplicationPackageManager對象,ApplicationPackageManager的queryIntentActivitiesAsUser方法調(diào)用了IPackageManagerBase的queryIntentActivities方法拿到一個ParceledListSlice<ResolveInfo>,然后調(diào)用它的getList()把它的mList返回了,所以我們的重點來到了queryIntentActivities方法:
public final @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { return new ParceledListSlice<>(snapshot().queryIntentActivitiesInternal(intent, resolvedType, flags, userId)); }傳給ParceledListSlice構(gòu)造方法的正是賦值給它的mList的,snapshot()我們之前已經(jīng)知道它是ComputerEngine,它的queryIntentActivitiesInternal方法熟悉吧,正是我們開啟這一切的起點,終于真相大白了,之所以chooseBestActivity方法中針對多匹配的情況時沒有把所有的匹配項都傳給ResolverActivity,是因為在ResolverActivity中會再次調(diào)用queryIntentActivitiesInternal查詢匹配項。
Ok!順帶著我們已經(jīng)搞明白了啟動Activity時對于隱式啟動的處理邏輯,我們下面要回到主任務(wù)中,畢竟我們的目標(biāo)是分析啟動信息是怎么獲取的。
-
getActivityInfo
上面的邏輯只是針對ActivityInfo的處理邏輯,那么ActivityInfo是怎么來的呢?
ComputerEngine的getActivityInfo方法最終調(diào)用了getActivityInfoInternalBody方法:
protected ActivityInfo getActivityInfoInternalBody(ComponentName component, @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) { ParsedActivity a = mComponentResolver.getActivity(component); AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName()); if (pkg != null && mSettings.isEnabledAndMatch(pkg, a, flags, userId)) { PackageStateInternal ps = mSettings.getPackage(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplication( ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) { return null; } return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.getUserStateOrDefault(userId), userId, ps); } //如果上面沒返回,則看是否是“ResolverActivity” if (resolveComponentName().equals(component)) { return PackageInfoWithoutStateUtils.generateDelegateActivityInfo(mResolveActivity, flags, PackageUserStateInternal.DEFAULT, userId); } //都不是則返回null return null; }mComponentResolver類型是ComponentResolverApi,我們到PackageManagerService的main方法中的injector的構(gòu)造邏輯中找到了它的實現(xiàn)類ComponentResolver,它的getActivity方法定義在其父類ComponentResolverLocked中,內(nèi)部又是調(diào)用了super的getActivity方法,也就是ComponentResolverBase:
//ComponentResolverBase: @Override public ParsedActivity getActivity(@NonNull ComponentName component) { return mActivities.mActivities.get(component); }mActivities中的數(shù)據(jù)是怎么來的?第一個mActivities是ComponentResolver.ActivityIntentResolver,它的mActivities是ArrayMap<ComponentName, ParsedActivity>,這個ArrayMap通過它的addActivity方法添加數(shù)據(jù),這個addActivity方法又是被ComponentResolver.ActivityIntentResolver的addActivitiesLocked調(diào)用的:
private void addActivitiesLocked(AndroidPackage pkg, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) { final int activitiesSize = ArrayUtils.size(pkg.getActivities()); ... for (int i = 0; i < activitiesSize; i++) { ParsedActivity a = pkg.getActivities().get(i); mActivities.addActivity(a, "activity", newIntents); ... } ... }該方法又被ComponentResolver的addAllComponents方法調(diào)用,而addAllComponents又在PackageManagerService的commitPackageSettings方法中被調(diào)用,這正是我們之前分析的安裝流程中的一個必執(zhí)行方法。
獲取到ParsedActivity之后,再根據(jù)它的packageName去mPackages中獲取AndroidPackage,而mPackages是在InstallPackageHelper的commitPackageSettings方法中通過mPm.mPackages直接添加數(shù)據(jù)的:
mPm.mPackages.put(pkg.getPackageName(), pkg);AndroidPackage中的activity信息是怎么來的呢?
那我們得再回到之前安裝流程中找一下AndroidPackage是怎么來的,AndroidPackage通過parsedPackage.hideAsFinal()獲取,parsedPackage又通過PackageParser2的parsePackage方法獲?。?/p>
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches, List<File> frameworkSplits) throws PackageManagerException { ... ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags, frameworkSplits); ... ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed(); return parsed; }public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags, List<File> frameworkSplits) { if (((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0) && frameworkSplits.size() > 0 && packageFile.getAbsolutePath().endsWith("/framework-res.apk")) { return parseClusterPackage(input, packageFile, frameworkSplits, flags); } else if (packageFile.isDirectory()) { return parseClusterPackage(input, packageFile, /* frameworkSplits= */null, flags); } else { return parseMonolithicPackage(input, packageFile, flags); } }private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir, List<File> frameworkSplits, int flags) { ... final ParseResult<PackageLite> liteResult = ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, frameworkSplits, liteParseFlags); ... try { final File baseApk = new File(lite.getBaseApkPath()); final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk, lite.getPath(), assetLoader, flags); if (result.isError()) { return input.error(result); } ParsingPackage pkg = result.getResult(); ... return input.success(pkg); } ... }parseClusterPackage中會調(diào)用ApkLiteParseUtils.parseClusterPackageLite方法,該方法中會遍歷apkDirectory下的所有apk文件,對每個apk文件調(diào)用parseApkLite方法,最終是調(diào)用parseApkLiteInner方法:
private static ParseResult<ApkLite> parseApkLiteInner(ParseInput input, File apkFile, FileDescriptor fd, String debugPathName, int flags) { final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath(); XmlResourceParser parser = null; //這里會使用ApkAssets加載apk文件 ApkAssets apkAssets = null; try { try { apkAssets = fd != null ? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */, null /* assets */) : ApkAssets.loadFromPath(apkPath); } ... //ANDROID_MANIFEST_FILENAME是AndroidManifest.xml parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME); ... return parseApkLite(input, apkPath, parser, signingDetails, flags); } ... }調(diào)用parseApkLite方法來解析AndroidManifest.xml配置,下面只貼部分代碼以明白大概做了什么即可:
private static ParseResult<ApkLite> parseApkLite(ParseInput input, String codePath, XmlResourceParser parser, SigningDetails signingDetails, int flags) throws IOException, XmlPullParserException { //解析manifest標(biāo)簽下的split屬性、package屬性 ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser); ... Pair<String, String> packageSplit = result.getResult(); ... //安裝位置 int installLocation = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "installLocation", PARSE_DEFAULT_INSTALL_LOCATION); //versionCode int versionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "versionCode", 0); ... int type; final int searchDepth = parser.getDepth() + 1; final List<VerifierInfo> verifiers = new ArrayList<>(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { ... if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) { ... } else if (TAG_APPLICATION.equals(parser.getName())) { ...//解析application標(biāo)簽 } else if... } else if (TAG_USES_SDK.equals(parser.getName())) { //sdk版本相關(guān) String minSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "minSdkVersion"); String targetSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "targetSdkVersion"); ... } } ... return input.success(new ApkLite(codePath, ...)); }parseApkLite主要是解析出一些大方面的配置,和系統(tǒng)相關(guān)的,比如安裝位置、版本號、sdk信息等,而像應(yīng)用本身的name、label、icon等其他特性信息會在隨后的parseBaseApk方法中解析:
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath, String codePath, Resources res, XmlResourceParser parser, int flags) throws XmlPullParserException, IOException { ... final String pkgName; ... final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); try { final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/, "coreApp",false); final ParsingPackage pkg = mCallback.startParsingPackage( pkgName, apkPath, codePath, manifestArray, isCoreApp); final ParseResult<ParsingPackage> result = parseBaseApkTags(input, pkg, manifestArray, res, parser, flags); if (result.isError()) { return result; } return input.success(pkg); } finally { manifestArray.recycle(); } }mCallback.startParsingPackage返回的是PackageImpl,是AndroidPackage的子類,這也就是最終要返回的的AndroidPackage對象。parseBaseApkTags方法中會解析出和應(yīng)用本身相關(guān)的信息:private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg, TypedArray sa, Resources res, XmlResourceParser parser, int flags) throws XmlPullParserException, IOException { ... final int depth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > depth)) { if (type != XmlPullParser.START_TAG) { continue; } String tagName = parser.getName(); final ParseResult result; if (TAG_APPLICATION.equals(tagName)) { ... //解析<application>信息以及子標(biāo)簽信息,比如注冊的四大組件<activity>、<service>等 result = parseBaseApplication(input, pkg, res, parser, flags); ... } else { //解析和application同級的其他標(biāo)簽,比如<uses-permission>等 result = parseBaseApkTag(tagName, input, pkg, res, parser, flags); } ... } ... return input.success(pkg); }parseBaseApplication方法如下:
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) throws XmlPullParserException, IOException { final String pkgName = pkg.getPackageName(); int targetSdk = pkg.getTargetSdkVersion(); TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); ...//application標(biāo)簽的信息解析,比如name、label等 //子標(biāo)簽信息的解析 final int depth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > depth)) { if (type != XmlPullParser.START_TAG) { continue; } final ParseResult result; String tagName = parser.getName(); switch (tagName) { case "activity": isActivity = true; case "receiver": ParseResult<ParsedActivity> activityResult = ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg, res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/, input); if (activityResult.isSuccess()) { //拿到的是ParsedActivityImpl ParsedActivity activity = activityResult.getResult(); //添加到ParsingPackageImpl中的activities集合中 pkg.addActivity(activity); } result = activityResult; break; case "service": ParseResult<ParsedService> serviceResult = ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/, input); if (serviceResult.isSuccess()) { ParsedService service = serviceResult.getResult(); hasServiceOrder |= (service.getOrder() != 0); pkg.addService(service); } result = serviceResult; break; ... default: result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags); break; } ... } ... return input.success(pkg); }可以看到,activity和receiver組件都是通過ParsedActivityUtils.parseActivityOrReceiver方法解析的,具體邏輯就不看了,沒什么特別的。
總結(jié)一下,在安裝過程中會解析apk的AndroidManifest.xml文件,然后把解析的activity信息保存到AndroidPackage(實際類型是其子類PackageImpl)的activities集合(在其父類ParsingPackageImpl中定義)中,然后在隨后的commitPackageSettings方法流程中調(diào)用addAllComponents方法將所有的activity信息交給PackageManagerService中的mComponentResolver(ComponentResolver),之后在啟動Activity時調(diào)用getActivity方法就會使用mComponentResolver獲取AndroidPackage(也就是PackageImpl),最后調(diào)用PackageInfoUtils.generateActivityInfo方法生成ActivityInfo。
Apk安裝的源碼分析(三)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 在Android中,我們經(jīng)常需要使用到Intent類,它用于跳轉(zhuǎn)Activity、啟動Service、發(fā)布廣播等功...
- 1、動態(tài)注冊過程源碼分析: 在Activity中動態(tài)注冊廣播室,在注冊方法之前其實省略了Context,也就是實際...
- Activity的工作原理-android9.0 startActivityForResult 方法當(dāng)開啟一個頁面...
- 一、本文需要解決的問題 本文并不是非常詳細(xì)地解釋startActivity()源碼每行代碼的具體作用(實際上也根本...