1. 程式人生 > >Android6.0 AMS啟動Activity(六) AMS與PKMS關係(通過Intent獲取ActivityInfo)

Android6.0 AMS啟動Activity(六) AMS與PKMS關係(通過Intent獲取ActivityInfo)

之前幾篇部落格分析AMS中啟動Activity的時候,我們把主要流程理的差不多了。今天主要看下AMS中通過PKMS來獲取ActivityInfo。

一、AMS通過PKMS獲取ActivityInfo

之前我們知道startActivity流程,先是在AMS中呼叫startActivity然後呼叫startActivityMayWait函式,在這個函式中呼叫了resolveActivity來解析ActivityInfo資訊。後面這個函式繼續往後會呼叫startActivityLocked函式,在這個函式中會新建一個ActivityRecord物件,這個物件的processName和info.applicartionInfo.uid這兩個值在後續程序啟動的時候起到很關鍵的作用,用來判斷程序是否啟動,這個在之前的部落格中已經分析過了。而processName是利用ActivityInfo的processName。而info.applicationInfo.uid也是ActivityInfo中的ApplicationInfo的值。

  1. final int startActivityMayWait(IApplicationThread caller, int callingUid,  
  2.         String callingPackage, Intent intent, String resolvedType,  
  3.         IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,  
  4.         IBinder resultTo, String resultWho, int requestCode, int startFlags,  
  5.         ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,  
  6.         Bundle options, boolean ignoreTargetSecurity, int userId,  
  7.         IActivityContainer iContainer, TaskRecord inTask) {  
  8.     // Refuse possible leaked file descriptors
  9.     if (intent != null && intent.hasFileDescriptors()) {  
  10.         thrownew IllegalArgumentException("File descriptors passed in Intent");  
  11.     }  
  12.     boolean componentSpecified = intent.getComponent() != null;  
  13.     // Don't modify the client's object!
  14.     intent = new Intent(intent);  
  15.     // Collect information about the target of the Intent.
  16.     ActivityInfo aInfo =  
  17.             resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);  

那我們下面來看看這個resolveActivity函式,這個函式最終還是通過PKMS的resolveIntent函式來獲取ResolveInfo,而ActivityInfo是其中的一個變數。

  1. ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,  
  2.         ProfilerInfo profilerInfo, int userId) {  
  3.     // Collect information about the target of the Intent.
  4.     ActivityInfo aInfo;  
  5.     try {  
  6.         ResolveInfo rInfo =  
  7.             AppGlobals.getPackageManager().resolveIntent(  
  8.                     intent, resolvedType,  
  9.                     PackageManager.MATCH_DEFAULT_ONLY  
  10.                                 | ActivityManagerService.STOCK_PM_FLAGS, userId);  
  11.         aInfo = rInfo != null ? rInfo.activityInfo : null;  
  12.     } catch (RemoteException e) {  
  13.         aInfo = null;  
  14.     }  
  15.     if (aInfo != null) {  
  16.         // Store the found target back into the intent, because now that
  17.         // we have it we never want to do this again.  For example, if the
  18.         // user navigates back to this point in the history, we should
  19.         // always restart the exact same activity.
  20.         intent.setComponent(new ComponentName(  
  21.                 aInfo.applicationInfo.packageName, aInfo.name));  
  22.         // Don't debug things in the system process
  23.         if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) {  
  24.             if (!aInfo.processName.equals("system")) {  
  25.                 mService.setDebugApp(aInfo.processName, truefalse);  
  26.             }  
  27.         }  
  28.         if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) {  
  29.             if (!aInfo.processName.equals("system")) {  
  30.                 mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);  
  31.             }  
  32.         }  
  33.         if (profilerInfo != null) {  
  34.             if (!aInfo.processName.equals("system")) {  
  35.                 mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);  
  36.             }  
  37.         }  
  38.     }  
  39.     return aInfo;  
  40. }  

二、PKMS獲取ActivityInfo

我們來看下PKMS的resolveIntent函式,先看下是否有許可權,然後呼叫queryIntentActivities來獲取滿足條件的ResolveInfo,然後呼叫chooseBestActivity挑選最合適的。

  1. @Override  
  2. public ResolveInfo resolveIntent(Intent intent, String resolvedType,  
  3.         int flags, int userId) {  
  4.     if (!sUserManager.exists(userId)) return null;  
  5.     enforceCrossUserPermission(Binder.getCallingUid(), userId, falsefalse"resolve intent");  
  6.     List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);  
  7.     return chooseBestActivity(intent, resolvedType, flags, query, userId);  
  8. }  

所以這裡我們主要看下queryIntentActivities函式,先會檢查許可權。然後獲取ComponentName,如果不為空,那麼Intent是指定了模組,只有一個匹配項。如果沒有指定模組,還要區分是否指定了包名。

  1. public List<ResolveInfo> queryIntentActivities(Intent intent,  
  2.         String resolvedType, int flags, int userId) {  
  3.     if (!sUserManager.exists(userId)) return Collections.emptyList();  
  4.     enforceCrossUserPermission(Binder.getCallingUid(), userId, falsefalse"query intent activities");  
  5.     ComponentName comp = intent.getComponent();  
  6.     if (comp == null) {  
  7.         if (intent.getSelector() != null) {  
  8.             intent = intent.getSelector();  
  9.             comp = intent.getComponent();  
  10.         }  
  11.     }  
  12.     if (comp != null) {//如果Intent中指定了模組,只會有一個匹配項
  13.         final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);  
  14.         final ActivityInfo ai = getActivityInfo(comp, flags, userId);  
  15.         if (ai != null) {  
  16.             final ResolveInfo ri = new ResolveInfo();  
  17.             ri.activityInfo = ai;  
  18.             list.add(ri);  
  19.         }  
  20.         return list;  
  21.     }  
  22.     // reader
  23.     synchronized (mPackages) {  
  24.         final String pkgName = intent.getPackage();  
  25.         if (pkgName == null) {//intent沒有指定包名,在系統所有包中查詢
  26.             List<CrossProfileIntentFilter> matchingFilters =  
  27.                     getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);//獲取所有匹配的intent filter
  28.             // Check for results that need to skip the current profile.
  29.             ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,  
  30.                     resolvedType, flags, userId);  
  31.             if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {  
  32.                 List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);  
  33.                 result.add(xpResolveInfo);  
  34.                 return filterIfNotPrimaryUser(result, userId);  
  35.             }  
  36.             // Check for results in the current profile.
  37.             List<ResolveInfo> result = mActivities.queryIntent(  
  38.                     intent, resolvedType, flags, userId);  
  39.             // Check for cross profile results.
  40.             xpResolveInfo = queryCrossProfileIntents(  
  41.                     matchingFilters, intent, resolvedType, flags, userId);  
  42.             if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {  
  43.                 result.add(xpResolveInfo);  
  44.                 Collections.sort(result, mResolvePrioritySorter);  
  45.             }  
  46.             result = filterIfNotPrimaryUser(result, userId);  
  47.             if (hasWebURI(intent)) {  
  48.                 CrossProfileDomainInfo xpDomainInfo = null;  
  49.                 final UserInfo parent = getProfileParent(userId);  
  50.                 if (parent != null) {  
  51.                     xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,  
  52.                             flags, userId, parent.id);  
  53.                 }  
  54.                 if (xpDomainInfo != null) {  
  55.                     if (xpResolveInfo != null) {  
  56.                         // If we didn't remove it, the cross-profile ResolveInfo would be twice
  57.                         // in the result.
  58.                         result.remove(xpResolveInfo);  
  59.                     }  
  60.                     if (result.size() == 0) {  
  61.                         result.add(xpDomainInfo.resolveInfo);  
  62.                         return result;  
  63.                     }  
  64.                 } elseif (result.size() <= 1) {  
  65.                     return result;  
  66.                 }  
  67.                 result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,  
  68.                         xpDomainInfo, userId);  
  69.                 Collections.sort(result, mResolvePrioritySorter);  
  70.             }  
  71.             return result;  
  72.         }  
  73.         final PackageParser.Package pkg = mPackages.get(pkgName);  
  74.         if (pkg != null) {//如果Intent中有包名,就在指定包中查詢
  75.             return filterIfNotPrimaryUser(  
  76.                     mActivities.queryIntentForPackage(  
  77.                             intent, resolvedType, flags, pkg.activities, userId),  
  78.                     userId);  
  79.         }  
  80.         returnnew ArrayList<ResolveInfo>();  
  81.     }  
  82. }  

這個函式會根據Intent中的資訊來分別處理。如果Intent有包名和Activity資訊(指定了模組)直接返回ActivityInfo,這是最快的方式。如果只有包名,呼叫queryIntentForPackage在指定的安裝包中查詢Activity。如果包名也沒有,只能呼叫queryIntent來搜尋所有安裝包了,這是最慢的一種查詢方式了。

我們這裡就看最直接的方式,我們看上面函式是直接呼叫了getActivityInfo方法來獲取ActivityInfo的。直接通過mActivities.mActivities中的component來獲取Activity,然後通過PackageParser.generateActivityInfo來產生一個ActivityInfo

  1. public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {  
  2.     if (!sUserManager.exists(userId)) return null;  
  3.     enforceCrossUserPermission(Binder.getCallingUid(), userId, falsefalse"get activity info");//檢查許可權
  4.     synchronized (mPackages) {  
  5.         PackageParser.Activity a = mActivities.mActivities.get(component);//獲取到Activity
  6.         if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);  
  7.         if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {  
  8.             PackageSetting ps = mSettings.mPackages.get(component.getPackageName());  
  9.             if (ps == null) return null;  
  10.             return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),//得到ActivityInfo
  11.                     userId);  
  12.         }  
  13.         if (mResolveComponentName.equals(component)) {  
  14.             return PackageParser.generateActivityInfo(mResolveActivity, flags,  
  15.                     new PackageUserState(), userId);  
  16.         }  
  17.     }  
  18.     return null;  
  19. }  

我們來看下這個generateActivityInfo函式,其實就是利用Activity的成員變數info來重新構造了一個ActivityInfo,然後再賦值ApplicationInfo等。

  1. publicstatic final ActivityInfo generateActivityInfo(Activity a, int flags,  
  2.         PackageUserState state, int userId) {  
  3.     if (a == null) return null;  
  4.     if (!checkUseInstalledOrHidden(flags, state)) {  
  5.         return null;  
  6.     }  
  7.     if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {  
  8.         return a.info;  
  9.     }  
  10.     // Make shallow copies so we can store the metadata safely
  11.     ActivityInfo ai = new ActivityInfo(a.info);  
  12.     ai.metaData = a.metaData;  
  13.     ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);  
  14.     return ai;  
  15. }  

這裡最關鍵的就是mActivities成員變量了,它是ActivityIntentResolver物件

  1. final ActivityIntentResolver mActivities =  
  2.         new ActivityIntentResolver();  

還是就是ActivityIntentResolver的成員變數mActivities是一個map key就是ComponentName,通過ComponentName來找到Activity的。

  1. // Keys are String (activity class name), values are Activity.
  2. private final ArrayMap<ComponentName, PackageParser.Activity> mActivities  
  3.         = new ArrayMap<ComponentName, PackageParser.Activity>();  



三、mActivities變數中的Activity新增

3.1 開機掃描和安裝應用大致流程

之前的部落格講PKMS的時候分析過無論是開機掃描各個目錄的apk檔案,還是安裝新的apk最後都會呼叫scanPackageDirtyLI方法。

我們來簡單回顧下,開機掃描各個目錄的時候是呼叫scanDirLI函式,然後呼叫scanPackageLI函式這個函式第一個引數是File,這個函式會新建一個PackageParser物件,來解析檔案。最後也會呼叫另一個scanPackageLI方法這個引數是Packageparser.Package類。而在這個scanPackageLI方法中最後呼叫了scanPackageDirtyLI方法。

在安裝一個新應用的時候先copy apk檔案到指定目錄,後面會呼叫installPackageLI,這個函式也會建立一個PackageParser物件來解析apk檔案,後面會呼叫installNewPackageLI繼續處理,最後會發送廣播通知其他應用,比如Launcher增加圖示等。在installNewPackageLI函式中也會呼叫scanPackageLI函式,是引數是Packageparser.Package類。而最後就會呼叫scanPackageDirtyLI方法。

所以其實無論開機掃描還是安裝應用其實流程差不多。

3.2 scanPackageDirtyLI方法處理mActivities

我們再來看下scanPackageDirtyLI方法中的一段程式碼,首先從PackageParser.Package中遍歷其Activity,然後制定其info.processName最後把Activity放入到mActivities中。

  1. N = pkg.activities.size();  
  2. r = null;  
  3. for (i=0; i<N; i++) {  
  4.     PackageParser.Activity a = pkg.activities.get(i);  
  5.     a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  6.             a.info.processName, pkg.applicationInfo.uid);  
  7.     mActivities.addActivity(a, "activity");  
  8.     if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  9.         if (r == null) {  
  10.             r = new StringBuilder(256);  
  11.         } else {  
  12.             r.append(' ');  
  13.         }  
  14.         r.append(a.info.name);  
  15.     }  
  16. }  

再來看fixProcessName函式,結合上面的引數當a.info.processName有的話processName就是這個值,沒有的話才是pkg.applicationInfo.processName。

  1. privatestatic String fixProcessName(String defProcessName,  
  2.         String processName, int uid) {  
  3.     if (processName == null) {  
  4.         return defProcessName;  
  5.     }  
  6.     return processName;  
  7. }  

下面我們再來看ActivityIntentResolver類的addActivity函式,其實主要就是放入了mActivities變數中,其key就是ComponentName。

  1. public final void addActivity(PackageParser.Activity a, String type) {  
  2.     final boolean systemApp = a.info.applicationInfo.isSystemApp();  
  3.     mActivities.put(a.getComponentName(), a);  
  4.     final int NI = a.intents.size();  
  5.     for (int j=0; j<NI; j++) {  
  6.         PackageParser.ActivityIntentInfo intent = a.intents.get(j);  
  7.         if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {  
  8.             intent.setPriority(0);  
  9.             Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
  10.                     + a.className + " with priority > 0, forcing to 0");  
  11.         }  
  12.         if (DEBUG_SHOW_INFO) {  
  13.             Log.v(TAG, "    IntentFilter:");  
  14.             intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");  
  15.         }  
  16.         if (!intent.debugCheck()) {  
  17.             Log.w(TAG, "==> For Activity " + a.info.name);  
  18.         }  
  19.         addFilter(intent);  
  20.     }  
  21. }  

我們回過頭來看下,其實ActivityIntentResolver中mActivities中的值也是從PackageParser.Package中遍歷其Activity,稍微修改下在add到mActivities中的。所以還是主要看PackageParser.Package中的Activity的由來。

四、PackageParser.Package的activities的ComponentName & info.processName

而PackageParser.Package的值無論是開機掃描還是新安裝應用都是新建一個PackageParser,然後解析檔案得到的。

只是開機掃描是在scanPackageLI函式中呼叫:

  1. private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,  
  2.         long currentTime, UserHandle user) throws PackageManagerException {  
  3.     if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);  
  4.     parseFlags |= mDefParseFlags;  
  5.     PackageParser pp = new PackageParser();  
  6.     pp.setSeparateProcesses(mSeparateProcesses);  
  7.     pp.setOnlyCoreApps(mOnlyCore);  
  8.     pp.setDisplayMetrics(mMetrics);  
  9.     if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {  
  10.         parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;  
  11.     }  
  12.     final PackageParser.Package pkg;  
  13.     try {  
  14.         pkg = pp.parsePackage(scanFile, parseFlags);  
  15.     } catch (PackageParserException e) {  
  16.         throw PackageManagerException.from(e);  
  17.     }  
  18. ..  

而安裝應用是在installPackageLI函式中呼叫:

  1. privatevoid installPackageLI(InstallArgs args, PackageInstalledInfo res) {  
  2.     final int installFlags = args.installFlags;  
  3.     final String installerPackageName = args.installerPackageName;  
  4.     final String volumeUuid = args.volumeUuid;  
  5.     final File tmpPackageFile = new File(args.getCodePath());  
  6.     final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);  
  7.     final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)  
  8.             || (args.volumeUuid != null));  
  9.     boolean replace = false;  
  10.     int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;  
  11.     if (args.move != null) {  
  12.         // moving a complete application; perfom an initial scan on the new install location
  13.         scanFlags |= SCAN_INITIAL;  
  14.     }  
  15.     // Result object to be returned
  16.     res.returnCode = PackageManager.INSTALL_SUCCEEDED;  
  17.     if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);  
  18.     // Retrieve PackageSettings and parse package
  19.     final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY  
  20.             | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)  
  21.             | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);  
  22.     PackageParser pp = new PackageParser();  
  23.     pp.setSeparateProcesses(mSeparateProcesses);  
  24.     pp.setDisplayMetrics(mMetrics);  
  25.     final PackageParser.Package pkg;  
  26.     try {  
  27.         pkg = pp.parsePackage(tmpPackageFile, parseFlags);  
  28.     } catch (PackageParserException e) {  
  29.         res.setError("Failed parse during installPackageLI", e);  
  30.         return;  
  31.     }  
  32. ..  

我們來看PackageParser的parsePackage函式,這裡是否是目錄的話呼叫的函式不一樣。

  1. public Package parsePackage(File packageFile, int flags) throws PackageParserException {  
  2.     if (packageFile.isDirectory()) {  
  3.         return parseClusterPackage(packageFile, flags);  
  4.     } else {  
  5.         return parseMonolithicPackage(packageFile, flags);  
  6.     }  
  7. }  

我們先來看下如果是目錄的話呼叫parseClusterPackage函式,而在這個函式先呼叫parseBaseApk,然後遍歷所有的split,呼叫函式parseSplitApk函式。

  1. private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {  
  2.     final PackageLite lite = parseClusterPackageLite(packageDir, 0);  
  3.     if (mOnlyCoreApps && !lite.coreApp) {  
  4.         thrownew PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,  
  5.                 "Not a coreApp: " + packageDir);  
  6.     }  
  7.     final AssetManager assets = new AssetManager();  
  8.     try {  
  9.         // Load the base and all splits into the AssetManager
  10.         // so that resources can be overriden when parsing the manifests.
  11.         loadApkIntoAssetManager(assets, lite.baseCodePath, flags);  
  12.         if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {  
  13.             for (String path : lite.splitCodePaths) {  
  14.                 loadApkIntoAssetManager(assets, path, flags);  
  15.             }  
  16.         }  
  17.         final File baseApk = new File(lite.baseCodePath);  
  18.         final Package pkg = parseBaseApk(baseApk, assets, flags);  
  19.         if (pkg == null) {  
  20.             thrownew PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,  
  21.                     "Failed to parse base APK: " + baseApk);  
  22.         }  
  23.         if (!ArrayUtils.isEmpty(lite.splitNames)) {  
  24.             final int num = lite.splitNames.length;  
  25.             pkg.splitNames = lite.splitNames;  
  26.             pkg.splitCodePaths = lite.splitCodePaths;  
  27.             pkg.splitRevisionCodes = lite.splitRevisionCodes;  
  28.             pkg.splitFlags = newint[num];  
  29.             pkg.splitPrivateFlags = newint[num];  
  30.             for (int i = 0; i < num; i++) {  
  31.                 parseSplitApk(pkg, i, assets, flags);  
  32.             }  
  33.         }  
  34.         pkg.codePath = packageDir.getAbsolutePath();  
  35.         return pkg;  
  36.     } finally {  
  37.         IoUtils.closeQuietly(assets);  
  38.     }  
  39. }  

而我們再看下parseMonolithicPackage函式,因為不是目錄,所以只有一個apk,直接呼叫了parseBaseApk。

  1. public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {  
  2.     if (mOnlyCoreApps) {  
  3.         final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);  
  4.         if (!lite.coreApp) {  
  5.             thrownew PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,  
  6.                     "Not a coreApp: " + apkFile);  
  7.         }  
  8.     }  
  9.     final AssetManager assets = new AssetManager();  
  10.     try {  
  11.         final Package pkg = parseBaseApk(apkFile, assets, flags);  
  12.         pkg.codePath = apkFile.getAbsolutePath();  
  13.         return pkg;  
  14.     } finally {  
  15.         IoUtils.closeQuietly(assets);  
  16.     }  
  17. }  

那我們來看下這個parseBaseApk函式,在這個函式中呼叫了另一個parseBaseApk函式,在這個函式新建了一個Package物件。然後遍歷xml中各個節點,這裡我們只關心application。在這個節點解析的時候直接呼叫了parseBaseApplication函式。

  1. private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,  
  2.         String[] outError) throws XmlPullParserException, IOException {  
  3.     ......  
  4.     final Package pkg = new Package(pkgName);  
  5.     boolean foundApp = false;  
  6.     TypedArray sa = res.obtainAttributes(attrs,  
  7.             com.android.internal.R.styleable.AndroidManifest);  
  8.     pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(  
  9.             com.android.internal.R.styleable.AndroidManifest_versionCode, 0);  
  10.     pkg.baseRevisionCode = sa.getInteger(  
  11.             com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);  
  12.     pkg.mVersionName = sa.getNonConfigurationString(  
  13.             com.android.internal.R.styleable.AndroidManifest_versionName, 0);  
  14.     if (pkg.mVersionName != null) {  
  15.         pkg.mVersionName = pkg.mVersionName.intern();  
  16.     }  
  17.     ......  
  18.     int outerDepth = parser.getDepth();  
  19.     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT  
  20.             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {  
  21.         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {  
  22.             continue;  
  23.         }  
  24.         String tagName = parser.getName();  
  25.         if (tagName.equals("application")) {  
  26.             if (foundApp) {  
  27.                 if (RIGID_PARSER) {  
  28.                     outError[0] = "<manifest> has more than one <application>";  
  29.                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;  
  30.                     return null;  
  31.                 } else {  
  32.                     Slog.w(TAG, "<manifest> has more than one <application>");  
  33.                     XmlUtils.skipCurrentTag(parser);  
  34.                     continue;  
  35.                 }  
  36.             }  
  37.             foundApp = true;  
  38.             if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {  
  39.                 return null;  
  40.             }  
  41.         }   

我們再來看下parseBaseApplication函式,先獲取了ApplicationInfo後面會修改器processName,再後面就開始就是xml中的application下的各個節點了。我們主要看下關於Activities的。是呼叫了parseActivity,然後儲存在activities變數中。

  1. private boolean parseBaseApplication(Package owner, Resources res,  
  2.         XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)  
  3.     throws XmlPullParserException, IOException {  
  4.     final ApplicationInfo ai = owner.applicationInfo;  
  5.     final String pkgName = owner.applicationInfo.packageName;  
  6.     ......  
  7.                 ai.processName = buildProcessName(ai.packageName, null, pname,  
  8.                 flags, mSeparateProcesses, outError);  
  9.     ......  
  10.     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT  
  11.             && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {  
  12.         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {  
  13.             continue;  
  14.         }  
  15.         String tagName = parser.getName();  
  16.         if (tagName.equals("activity")) {  
  17.             Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,  
  18.                     owner.baseHardwareAccelerated);  
  19.             if (a == null) {  
  20.                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;  
  21.                 returnfalse;  
  22.             }  
  23.             owner.activities.add(a);  
  24.         }  

parseActivity新建了一個Activity物件,然後解析各種資料儲存在info等變數中。但是仔細看沒有我們想要的東西。

1.沒有看到Activity的info.processName

2.沒有看到Activity的ComponentName

  1. private Activity parseActivity(Package owner, Resources res,  
  2.         XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,  
  3.         boolean receiver, boolean hardwareAccelerated)  
  4.         throws XmlPullParserException, IOException {  
  5.     TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity);  
  6.     if (mParseActivityArgs == null) {  
  7.         mParseActivityArgs = new ParseComponentArgs(owner, outError,  
  8.                 R.styleable.AndroidManifestActivity_name,  
  9.                 R.styleable.AndroidManifestActivity_label,  
  10.                 R.styleable.AndroidManifestActivity_icon,  
  11.                 R.styleable.AndroidManifestActivity_logo,  
  12.                 R.styleable.AndroidManifestActivity_banner,  
  13.                 mSeparateProcesses,  
  14.                 R.styleable.AndroidManifestActivity_process,  
  15.                 R.styleable.AndroidManifestActivity_description,  
  16.                 R.styleable.AndroidManifestActivity_enabled);  
  17.     }  
  18.     mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";  
  19.     mParseActivityArgs.sa = sa;  
  20.     mParseActivityArgs.flags = flags;  
  21.     Activity a = new Activity(mParseActivityArgs, new ActivityInfo());  
我們先看下Activity的建構函式,其父類是public static class Component<II extends IntentInfo>
  1. public Activity(final ParseComponentArgs args, final ActivityInfo _info) {  
  2.     super(args, _info);  
  3.     info = _info;  
  4.     info.applicationInfo = args.owner.applicationInfo;  
  5. }  

我們看其父類的函式,也沒有看到起關於ComponentName的設定,但是會對outInfo的processName進行設定,也就是Activity的info的processName。那這裡解了我們第一個疑惑info的processName。

  1. public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {  
  2.     this(args, (PackageItemInfo)outInfo);  
  3.     if (args.outError[0] != null) {  
  4.         return;  
  5.     }  
  6.     if (args.processRes != 0) {  
  7.         CharSequence pname;  
  8.         if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {  
  9.             pname = args.sa.getNonConfigurationString(args.processRes,  
  10.                     Configuration.NATIVE_CONFIG_VERSION);  
  11.         } else {  
  12.             // Some older apps have been seen to use a resource reference
  13.             // here that on older builds was ignored (with a warning).  We
  14.             // need to continue to do this for them so they don't break.
  15.             pname = args.sa.getNonResourceString(args.processRes);  
  16.         }  
  17.         outInfo.processName = buildProcessName(owner.applicationInfo.packageName,  
  18.                 owner.applicationInfo.processName, pname,  
  19.                 args.flags, args.sepProcesses, args.outError);  
  20.     }  
  21.     if (args.descriptionRes != 0) {  
  22.         outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);  
  23.     }  
  24.     outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);  
  25. }  

那麼第二個ComponentName呢,我再來看上面這個函式第一句話是呼叫了另一個建構函式,在這裡我們構造了className。當然這裡獲取className的方式有點複雜,和一些資源相關。

  1. public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {  
  2.     owner = args.owner;  
  3.     intents = new ArrayList<II>(0);  
  4.     String name = args.sa.getNonConfigurationString(args.nameRes, 0);  
  5.     if (name == null) {  
  6.         className = null;  
  7.         args.outError[0] = args.tag + " does not specify android:name";  
  8.         return;  
  9.     }  
  10.     outInfo.name  
  11.         = buildClassName(owner.applicationInfo.packageName, name, args.outError);  
  12.     if (outInfo.name == null) {  
  13.         className = null;  
  14.         args.outError[0] = args.tag + " does not have valid android:name";  
  15.         return;  
  16.     }  
  17.     className = outInfo.name;  

而我們再看下Activity的getComponentName函式,只要有className就會新建一個ComponentName物件。

  1. public ComponentName getComponentName() {  
  2.     if (componentName != null) {  
  3.         return componentName;  
  4.     }  
  5.     if (className != null) {  
  6.         componentName = new ComponentName(owner.applicationInfo.packageName,  
  7.                 className);  
  8.     }  
  9.     return componentName;  
  10. }  

ComponentName的建構函式也就是儲存兩個變數。

  1. public ComponentName(String pkg, String cls) {  
  2.     if (pkg == null) thrownew NullPointerException("package name is null");  
  3.     if (cls == null) thrownew NullPointerException("class name is null");  
  4.     mPackage = pkg;  
  5.     mClass = cls;  
  6. }  

那麼這樣ComponentName和processName的問題都解決了。

五、uid值由來

給AMS傳遞的ActivityInfo,還有一個重要的資訊就是uid,是在ApplicationInfo中的。我們來看下在哪裡賦值的。

在scanPackageDirtyLI函式中有一句

  1. pkg.applicationInfo.uid = pkgSetting.appId;  

我們再看下Activity的建構函式,info.applicationInfo就是Package的applicationinfo。因此上面給uid賦值,就