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的值。
- final int startActivityMayWait(IApplicationThread caller, int callingUid,
- String callingPackage, Intent intent, String resolvedType,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- IBinder resultTo, String resultWho, int requestCode, int startFlags,
- ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
- Bundle options, boolean ignoreTargetSecurity, int userId,
- IActivityContainer iContainer, TaskRecord inTask) {
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- thrownew IllegalArgumentException("File descriptors passed in Intent");
- }
- boolean componentSpecified = intent.getComponent() != null;
- // Don't modify the client's object!
- intent = new Intent(intent);
- // Collect information about the target of the Intent.
- ActivityInfo aInfo =
- resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
那我們下面來看看這個resolveActivity函式,這個函式最終還是通過PKMS的resolveIntent函式來獲取ResolveInfo,而ActivityInfo是其中的一個變數。
- ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
- ProfilerInfo profilerInfo, int userId) {
- // Collect information about the target of the Intent.
- ActivityInfo aInfo;
- try {
- ResolveInfo rInfo =
- AppGlobals.getPackageManager().resolveIntent(
- intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
- aInfo = rInfo != null ? rInfo.activityInfo : null;
- } catch (RemoteException e) {
- aInfo = null;
- }
- if (aInfo != null) {
- // Store the found target back into the intent, because now that
- // we have it we never want to do this again. For example, if the
- // user navigates back to this point in the history, we should
- // always restart the exact same activity.
- intent.setComponent(new ComponentName(
- aInfo.applicationInfo.packageName, aInfo.name));
- // Don't debug things in the system process
- if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) {
- if (!aInfo.processName.equals("system")) {
- mService.setDebugApp(aInfo.processName, true, false);
- }
- }
- if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) {
- if (!aInfo.processName.equals("system")) {
- mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
- }
- }
- if (profilerInfo != null) {
- if (!aInfo.processName.equals("system")) {
- mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
- }
- }
- }
- return aInfo;
- }
二、PKMS獲取ActivityInfo
我們來看下PKMS的resolveIntent函式,先看下是否有許可權,然後呼叫queryIntentActivities來獲取滿足條件的ResolveInfo,然後呼叫chooseBestActivity挑選最合適的。
- @Override
- public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- int flags, int userId) {
- if (!sUserManager.exists(userId)) return null;
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
- List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
- return chooseBestActivity(intent, resolvedType, flags, query, userId);
- }
所以這裡我們主要看下queryIntentActivities函式,先會檢查許可權。然後獲取ComponentName,如果不為空,那麼Intent是指定了模組,只有一個匹配項。如果沒有指定模組,還要區分是否指定了包名。
- public List<ResolveInfo> queryIntentActivities(Intent intent,
- String resolvedType, int flags, int userId) {
- if (!sUserManager.exists(userId)) return Collections.emptyList();
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
- ComponentName comp = intent.getComponent();
- if (comp == null) {
- if (intent.getSelector() != null) {
- intent = intent.getSelector();
- comp = intent.getComponent();
- }
- }
- if (comp != null) {//如果Intent中指定了模組,只會有一個匹配項
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- final ActivityInfo ai = getActivityInfo(comp, flags, userId);
- if (ai != null) {
- final ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = ai;
- list.add(ri);
- }
- return list;
- }
- // reader
- synchronized (mPackages) {
- final String pkgName = intent.getPackage();
- if (pkgName == null) {//intent沒有指定包名,在系統所有包中查詢
- List<CrossProfileIntentFilter> matchingFilters =
- getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);//獲取所有匹配的intent filter
- // Check for results that need to skip the current profile.
- ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
- resolvedType, flags, userId);
- if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
- List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
- result.add(xpResolveInfo);
- return filterIfNotPrimaryUser(result, userId);
- }
- // Check for results in the current profile.
- List<ResolveInfo> result = mActivities.queryIntent(
- intent, resolvedType, flags, userId);
- // Check for cross profile results.
- xpResolveInfo = queryCrossProfileIntents(
- matchingFilters, intent, resolvedType, flags, userId);
- if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
- result.add(xpResolveInfo);
- Collections.sort(result, mResolvePrioritySorter);
- }
- result = filterIfNotPrimaryUser(result, userId);
- if (hasWebURI(intent)) {
- CrossProfileDomainInfo xpDomainInfo = null;
- final UserInfo parent = getProfileParent(userId);
- if (parent != null) {
- xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
- flags, userId, parent.id);
- }
- if (xpDomainInfo != null) {
- if (xpResolveInfo != null) {
- // If we didn't remove it, the cross-profile ResolveInfo would be twice
- // in the result.
- result.remove(xpResolveInfo);
- }
- if (result.size() == 0) {
- result.add(xpDomainInfo.resolveInfo);
- return result;
- }
- } elseif (result.size() <= 1) {
- return result;
- }
- result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
- xpDomainInfo, userId);
- Collections.sort(result, mResolvePrioritySorter);
- }
- return result;
- }
- final PackageParser.Package pkg = mPackages.get(pkgName);
- if (pkg != null) {//如果Intent中有包名,就在指定包中查詢
- return filterIfNotPrimaryUser(
- mActivities.queryIntentForPackage(
- intent, resolvedType, flags, pkg.activities, userId),
- userId);
- }
- returnnew ArrayList<ResolveInfo>();
- }
- }
這個函式會根據Intent中的資訊來分別處理。如果Intent有包名和Activity資訊(指定了模組)直接返回ActivityInfo,這是最快的方式。如果只有包名,呼叫queryIntentForPackage在指定的安裝包中查詢Activity。如果包名也沒有,只能呼叫queryIntent來搜尋所有安裝包了,這是最慢的一種查詢方式了。
我們這裡就看最直接的方式,我們看上面函式是直接呼叫了getActivityInfo方法來獲取ActivityInfo的。直接通過mActivities.mActivities中的component來獲取Activity,然後通過PackageParser.generateActivityInfo來產生一個ActivityInfo
- public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
- if (!sUserManager.exists(userId)) return null;
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");//檢查許可權
- synchronized (mPackages) {
- PackageParser.Activity a = mActivities.mActivities.get(component);//獲取到Activity
- if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
- PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
- if (ps == null) return null;
- return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),//得到ActivityInfo
- userId);
- }
- if (mResolveComponentName.equals(component)) {
- return PackageParser.generateActivityInfo(mResolveActivity, flags,
- new PackageUserState(), userId);
- }
- }
- return null;
- }
我們來看下這個generateActivityInfo函式,其實就是利用Activity的成員變數info來重新構造了一個ActivityInfo,然後再賦值ApplicationInfo等。
- publicstatic final ActivityInfo generateActivityInfo(Activity a, int flags,
- PackageUserState state, int userId) {
- if (a == null) return null;
- if (!checkUseInstalledOrHidden(flags, state)) {
- return null;
- }
- if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
- return a.info;
- }
- // Make shallow copies so we can store the metadata safely
- ActivityInfo ai = new ActivityInfo(a.info);
- ai.metaData = a.metaData;
- ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
- return ai;
- }
這裡最關鍵的就是mActivities成員變量了,它是ActivityIntentResolver物件
- final ActivityIntentResolver mActivities =
- new ActivityIntentResolver();
還是就是ActivityIntentResolver的成員變數mActivities是一個map key就是ComponentName,通過ComponentName來找到Activity的。
- // Keys are String (activity class name), values are Activity.
- private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
- = 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中。
- N = pkg.activities.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
- a.info.processName = fixProcessName(pkg.applicationInfo.processName,
- a.info.processName, pkg.applicationInfo.uid);
- mActivities.addActivity(a, "activity");
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
- }
- }
再來看fixProcessName函式,結合上面的引數當a.info.processName有的話processName就是這個值,沒有的話才是pkg.applicationInfo.processName。
- privatestatic String fixProcessName(String defProcessName,
- String processName, int uid) {
- if (processName == null) {
- return defProcessName;
- }
- return processName;
- }
下面我們再來看ActivityIntentResolver類的addActivity函式,其實主要就是放入了mActivities變數中,其key就是ComponentName。
- public final void addActivity(PackageParser.Activity a, String type) {
- final boolean systemApp = a.info.applicationInfo.isSystemApp();
- mActivities.put(a.getComponentName(), a);
- final int NI = a.intents.size();
- for (int j=0; j<NI; j++) {
- PackageParser.ActivityIntentInfo intent = a.intents.get(j);
- if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
- intent.setPriority(0);
- Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
- + a.className + " with priority > 0, forcing to 0");
- }
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
- }
- if (!intent.debugCheck()) {
- Log.w(TAG, "==> For Activity " + a.info.name);
- }
- addFilter(intent);
- }
- }
我們回過頭來看下,其實ActivityIntentResolver中mActivities中的值也是從PackageParser.Package中遍歷其Activity,稍微修改下在add到mActivities中的。所以還是主要看PackageParser.Package中的Activity的由來。
四、PackageParser.Package的activities的ComponentName & info.processName
而PackageParser.Package的值無論是開機掃描還是新安裝應用都是新建一個PackageParser,然後解析檔案得到的。
只是開機掃描是在scanPackageLI函式中呼叫:
- private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
- long currentTime, UserHandle user) throws PackageManagerException {
- if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
- parseFlags |= mDefParseFlags;
- PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setOnlyCoreApps(mOnlyCore);
- pp.setDisplayMetrics(mMetrics);
- if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
- parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
- }
- final PackageParser.Package pkg;
- try {
- pkg = pp.parsePackage(scanFile, parseFlags);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
- }
- ..
而安裝應用是在installPackageLI函式中呼叫:
- privatevoid installPackageLI(InstallArgs args, PackageInstalledInfo res) {
- final int installFlags = args.installFlags;
- final String installerPackageName = args.installerPackageName;
- final String volumeUuid = args.volumeUuid;
- final File tmpPackageFile = new File(args.getCodePath());
- final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
- final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
- || (args.volumeUuid != null));
- boolean replace = false;
- int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
- if (args.move != null) {
- // moving a complete application; perfom an initial scan on the new install location
- scanFlags |= SCAN_INITIAL;
- }
- // Result object to be returned
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
- if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
- // Retrieve PackageSettings and parse package
- final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
- | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
- | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
- PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setDisplayMetrics(mMetrics);
- final PackageParser.Package pkg;
- try {
- pkg = pp.parsePackage(tmpPackageFile, parseFlags);
- } catch (PackageParserException e) {
- res.setError("Failed parse during installPackageLI", e);
- return;
- }
- ..
我們來看PackageParser的parsePackage函式,這裡是否是目錄的話呼叫的函式不一樣。
- public Package parsePackage(File packageFile, int flags) throws PackageParserException {
- if (packageFile.isDirectory()) {
- return parseClusterPackage(packageFile, flags);
- } else {
- return parseMonolithicPackage(packageFile, flags);
- }
- }
我們先來看下如果是目錄的話呼叫parseClusterPackage函式,而在這個函式先呼叫parseBaseApk,然後遍歷所有的split,呼叫函式parseSplitApk函式。
- private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
- final PackageLite lite = parseClusterPackageLite(packageDir, 0);
- if (mOnlyCoreApps && !lite.coreApp) {
- thrownew PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Not a coreApp: " + packageDir);
- }
- final AssetManager assets = new AssetManager();
- try {
- // Load the base and all splits into the AssetManager
- // so that resources can be overriden when parsing the manifests.
- loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
- if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
- for (String path : lite.splitCodePaths) {
- loadApkIntoAssetManager(assets, path, flags);
- }
- }
- final File baseApk = new File(lite.baseCodePath);
- final Package pkg = parseBaseApk(baseApk, assets, flags);
- if (pkg == null) {
- thrownew PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Failed to parse base APK: " + baseApk);
- }
- if (!ArrayUtils.isEmpty(lite.splitNames)) {
- final int num = lite.splitNames.length;
- pkg.splitNames = lite.splitNames;
- pkg.splitCodePaths = lite.splitCodePaths;
- pkg.splitRevisionCodes = lite.splitRevisionCodes;
- pkg.splitFlags = newint[num];
- pkg.splitPrivateFlags = newint[num];
- for (int i = 0; i < num; i++) {
- parseSplitApk(pkg, i, assets, flags);
- }
- }
- pkg.codePath = packageDir.getAbsolutePath();
- return pkg;
- } finally {
- IoUtils.closeQuietly(assets);
- }
- }
而我們再看下parseMonolithicPackage函式,因為不是目錄,所以只有一個apk,直接呼叫了parseBaseApk。
- public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
- if (mOnlyCoreApps) {
- final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
- if (!lite.coreApp) {
- thrownew PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Not a coreApp: " + apkFile);
- }
- }
- final AssetManager assets = new AssetManager();
- try {
- final Package pkg = parseBaseApk(apkFile, assets, flags);
- pkg.codePath = apkFile.getAbsolutePath();
- return pkg;
- } finally {
- IoUtils.closeQuietly(assets);
- }
- }
那我們來看下這個parseBaseApk函式,在這個函式中呼叫了另一個parseBaseApk函式,在這個函式新建了一個Package物件。然後遍歷xml中各個節點,這裡我們只關心application。在這個節點解析的時候直接呼叫了parseBaseApplication函式。
- private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
- String[] outError) throws XmlPullParserException, IOException {
- ......
- final Package pkg = new Package(pkgName);
- boolean foundApp = false;
- TypedArray sa = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.AndroidManifest);
- pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
- com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
- 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();
- }
- ......
- int outerDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
- String tagName = parser.getName();
- if (tagName.equals("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;
- if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
- return null;
- }
- }
我們再來看下parseBaseApplication函式,先獲取了ApplicationInfo後面會修改器processName,再後面就開始就是xml中的application下的各個節點了。我們主要看下關於Activities的。是呼叫了parseActivity,然後儲存在activities變數中。
- private boolean parseBaseApplication(Package owner, Resources res,
- XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
- throws XmlPullParserException, IOException {
- final ApplicationInfo ai = owner.applicationInfo;
- final String pkgName = owner.applicationInfo.packageName;
- ......
- ai.processName = buildProcessName(ai.packageName, null, pname,
- flags, mSeparateProcesses, outError);
- ......
- 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")) {
- Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
- owner.baseHardwareAccelerated);
- if (a == null) {
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- returnfalse;
- }
- owner.activities.add(a);
- }
parseActivity新建了一個Activity物件,然後解析各種資料儲存在info等變數中。但是仔細看沒有我們想要的東西。
1.沒有看到Activity的info.processName
2.沒有看到Activity的ComponentName
- private Activity parseActivity(Package owner, Resources res,
- XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
- boolean receiver, boolean hardwareAccelerated)
- throws XmlPullParserException, IOException {
- TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity);
- if (mParseActivityArgs == null) {
- mParseActivityArgs = new ParseComponentArgs(owner, outError,
- R.styleable.AndroidManifestActivity_name,
- R.styleable.AndroidManifestActivity_label,
- R.styleable.AndroidManifestActivity_icon,
- R.styleable.AndroidManifestActivity_logo,
- R.styleable.AndroidManifestActivity_banner,
- mSeparateProcesses,
- R.styleable.AndroidManifestActivity_process,
- R.styleable.AndroidManifestActivity_description,
- R.styleable.AndroidManifestActivity_enabled);
- }
- mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
- mParseActivityArgs.sa = sa;
- mParseActivityArgs.flags = flags;
- Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
- public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
- super(args, _info);
- info = _info;
- info.applicationInfo = args.owner.applicationInfo;
- }
我們看其父類的函式,也沒有看到起關於ComponentName的設定,但是會對outInfo的processName進行設定,也就是Activity的info的processName。那這裡解了我們第一個疑惑info的processName。
- public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
- this(args, (PackageItemInfo)outInfo);
- if (args.outError[0] != null) {
- return;
- }
- if (args.processRes != 0) {
- CharSequence pname;
- if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
- pname = args.sa.getNonConfigurationString(args.processRes,
- Configuration.NATIVE_CONFIG_VERSION);
- } else {
- // Some older apps have been seen to use a resource reference
- // here that on older builds was ignored (with a warning). We
- // need to continue to do this for them so they don't break.
- pname = args.sa.getNonResourceString(args.processRes);
- }
- outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
- owner.applicationInfo.processName, pname,
- args.flags, args.sepProcesses, args.outError);
- }
- if (args.descriptionRes != 0) {
- outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
- }
- outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
- }
那麼第二個ComponentName呢,我再來看上面這個函式第一句話是呼叫了另一個建構函式,在這裡我們構造了className。當然這裡獲取className的方式有點複雜,和一些資源相關。
- public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
- owner = args.owner;
- intents = new ArrayList<II>(0);
- String name = args.sa.getNonConfigurationString(args.nameRes, 0);
- if (name == null) {
- className = null;
- args.outError[0] = args.tag + " does not specify android:name";
- return;
- }
- outInfo.name
- = buildClassName(owner.applicationInfo.packageName, name, args.outError);
- if (outInfo.name == null) {
- className = null;
- args.outError[0] = args.tag + " does not have valid android:name";
- return;
- }
- className = outInfo.name;
而我們再看下Activity的getComponentName函式,只要有className就會新建一個ComponentName物件。
- public ComponentName getComponentName() {
- if (componentName != null) {
- return componentName;
- }
- if (className != null) {
- componentName = new ComponentName(owner.applicationInfo.packageName,
- className);
- }
- return componentName;
- }
ComponentName的建構函式也就是儲存兩個變數。
- public ComponentName(String pkg, String cls) {
- if (pkg == null) thrownew NullPointerException("package name is null");
- if (cls == null) thrownew NullPointerException("class name is null");
- mPackage = pkg;
- mClass = cls;
- }
那麼這樣ComponentName和processName的問題都解決了。
五、uid值由來
給AMS傳遞的ActivityInfo,還有一個重要的資訊就是uid,是在ApplicationInfo中的。我們來看下在哪裡賦值的。
在scanPackageDirtyLI函式中有一句
- pkg.applicationInfo.uid = pkgSetting.appId;
我們再看下Activity的建構函式,info.applicationInfo就是Package的applicationinfo。因此上面給uid賦值,就