之前几篇博客分析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) {
-
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- boolean componentSpecified = intent.getComponent() != null;
-
-
- intent = new Intent(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) {
-
- 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) {
-
-
-
-
- intent.setComponent(new ComponentName(
- aInfo.applicationInfo.packageName, aInfo.name));
-
-
- 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 query = queryIntentActivities(intent, resolvedType, flags, userId);
- return chooseBestActivity(intent, resolvedType, flags, query, userId);
- }
所以这里我们主要看下queryIntentActivities函数,先会检查权限。然后获取ComponentName,如果不为空,那么Intent是指定了模块,只有一个匹配项。如果没有指定模块,还要区分是否指定了包名。
- public List 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) {
- final List list = new ArrayList(1);
- final ActivityInfo ai = getActivityInfo(comp, flags, userId);
- if (ai != null) {
- final ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = ai;
- list.add(ri);
- }
- return list;
- }
-
-
- synchronized (mPackages) {
- final String pkgName = intent.getPackage();
- if (pkgName == null) {
- List matchingFilters =
- getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
-
- ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
- resolvedType, flags, userId);
- if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
- List result = new ArrayList(1);
- result.add(xpResolveInfo);
- return filterIfNotPrimaryUser(result, userId);
- }
-
-
- List result = mActivities.queryIntent(
- intent, resolvedType, flags, userId);
-
-
- 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) {
-
-
- result.remove(xpResolveInfo);
- }
- if (result.size() == 0) {
- result.add(xpDomainInfo.resolveInfo);
- return result;
- }
- } else if (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) {
- return filterIfNotPrimaryUser(
- mActivities.queryIntentForPackage(
- intent, resolvedType, flags, pkg.activities, userId),
- userId);
- }
- return new ArrayList();
- }
- }
这个函数会根据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);
-
- 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),
- userId);
- }
- if (mResolveComponentName.equals(component)) {
- return PackageParser.generateActivityInfo(mResolveActivity, flags,
- new PackageUserState(), userId);
- }
- }
- return null;
- }
我们来看下这个generateActivityInfo函数,其实就是利用Activity的成员变量info来重新构造了一个ActivityInfo,然后再赋值ApplicationInfo等。
- public static 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;
- }
-
- 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的。
-
- private final ArrayMap mActivities
- = new ArrayMap();
三、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
- 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。
- private static 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
- 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函数中调用:
- private void 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) {
-
- scanFlags |= SCAN_INITIAL;
- }
-
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
-
- if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
-
- 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) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Not a coreApp: " + packageDir);
- }
-
- final AssetManager assets = new AssetManager();
- try {
-
-
- 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) {
- throw new 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 = new int[num];
- pkg.splitPrivateFlags = new int[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) {
- throw new 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] = " has more than one ";
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
- } else {
- Slog.w(TAG, " has more than one ");
- 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;
- return false;
- }
-
- 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 ? "" : "";
- mParseActivityArgs.sa = sa;
- mParseActivityArgs.flags = flags;
-
- Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
我们先看下Activity的构造函数,其父类是public static class Component
- 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 {
-
-
-
- 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(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) throw new NullPointerException("package name is null");
- if (cls == null) throw new 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赋值,就是ActivityInfo的applicationInfo的uid赋值。
- public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
- super(args, _info);
- info = _info;
- info.applicationInfo = args.owner.applicationInfo;
- }
那我们再看看pkgSetting.appId的由来,同样在scanPackageDirtyLI函数中有如下代码,创建一个pkgSetting。
- pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
- destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
- pkg.applicationInfo.primaryCpuAbi,
- pkg.applicationInfo.secondaryCpuAbi,
- pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
- user, false);
我们来看下这个函数,它调用了另一个getPackageLPw函数
- PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
- int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add) {
- final String name = pkg.packageName;
- PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
- resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
- pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user, add, true );
- return p;
- }
我们来看下这个函数,首先我们现在在mPackages没有值,所以直接从p==null分支看,然后也没有origPackage,没有sharedUser,我们就直接看newUserIdLPw函数产生一个新的uid。
- private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbiString,
- String secondaryCpuAbiString, int vc, int pkgFlags, int pkgPrivateFlags,
- UserHandle installUser, boolean add, boolean allowInstall) {
- PackageSetting p = mPackages.get(name);
- UserManagerService userManager = UserManagerService.getInstance();
- if (p != null) {
- ......
- }
- if (p == null) {
- if (origPackage != null) {
- ......
- } else {
- p = new PackageSetting(name, realName, codePath, resourcePath,
- legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- null , vc, pkgFlags, pkgPrivateFlags);
- p.setTimeStamp(codePath.lastModified());
- p.sharedUser = sharedUser;
-
- if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- if (DEBUG_STOPPED) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.i(PackageManagerService.TAG, "Stopping package " + name, e);
- }
- List users = getAllUsers();
- final int installUserId = installUser != null ? installUser.getIdentifier() : 0;
- if (users != null && allowInstall) {
- for (UserInfo user : users) {
-
-
-
-
-
-
- final boolean installed = installUser == null
- || (installUserId == UserHandle.USER_ALL
- && !isAdbInstallDisallowed(userManager, user.id))
- || installUserId == user.id;
- p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,
- installed,
- true,
- true,
- false,
- null, null, null,
- false,
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
- writePackageRestrictionsLPr(user.id);
- }
- }
- }
- if (sharedUser != null) {
- p.appId = sharedUser.userId;
- } else {
-
- PackageSetting dis = mDisabledSysPackages.get(name);
- if (dis != null) {
-
-
-
-
- if (dis.signatures.mSignatures != null) {
- p.signatures.mSignatures = dis.signatures.mSignatures.clone();
- }
- p.appId = dis.appId;
-
- p.getPermissionsState().copyFrom(dis.getPermissionsState());
-
- List users = getAllUsers();
- if (users != null) {
- for (UserInfo user : users) {
- int userId = user.id;
- p.setDisabledComponentsCopy(
- dis.getDisabledComponents(userId), userId);
- p.setEnabledComponentsCopy(
- dis.getEnabledComponents(userId), userId);
- }
- }
-
- addUserIdLPw(p.appId, p, name);
- } else {
-
- p.appId = newUserIdLPw(p);
- }
- }
- }
- if (p.appId < 0) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Package " + name + " could not be assigned a valid uid");
- return null;
- }
- if (add) {
-
-
- addPackageSettingLPw(p, name, sharedUser);
- }
- } else {
- .....
- }
- return p;
- }
newUserIdLPw函数先遍历所有的uid。看哪个uid对应的对象空了,就重新用这个uid。如果都不为空,而且不超过最大uid值,用当前最大值的uid+1,作为新的uid。
- private int newUserIdLPw(Object obj) {
-
- final int N = mUserIds.size();
- for (int i = mFirstAvailableUid; i < N; i++) {
- if (mUserIds.get(i) == null) {
- mUserIds.set(i, obj);
- return Process.FIRST_APPLICATION_UID + i;
- }
- }
-
-
- if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
- return -1;
- }
-
- mUserIds.add(obj);
- return Process.FIRST_APPLICATION_UID + N;
- }
六、成员变量mSettings mPackages保存数据
在scanPackageDirtyLI函数后面会保存mSettings和mPackages,主要是把PackageSetting保存在mSetting中,把Package保存在mPackages中。mPackages直接put了,我们就不分析了。我们看下mSettings保存PackageSetting。
- synchronized (mPackages) {
-
-
-
- mSettings.insertPackageSettingLPw(pkgSetting, pkg);
-
- mPackages.put(pkg.applicationInfo.packageName, pkg);
insertPackageSettingLPw函数先把pkg赋给了PackageSetting 的pkg,最后调用了addPackageSettingLPw函数保存PackageSetting 对象。
- void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
- p.pkg = pkg;
-
-
- final String volumeUuid = pkg.applicationInfo.volumeUuid;
- final String codePath = pkg.applicationInfo.getCodePath();
- final String resourcePath = pkg.applicationInfo.getResourcePath();
- final String legacyNativeLibraryPath = pkg.applicationInfo.nativeLibraryRootDir;
-
- if (!Objects.equals(volumeUuid, p.volumeUuid)) {
- Slog.w(PackageManagerService.TAG, "Volume for " + p.pkg.packageName +
- " changing from " + p.volumeUuid + " to " + volumeUuid);
- p.volumeUuid = volumeUuid;
- }
-
- if (!Objects.equals(codePath, p.codePathString)) {
- Slog.w(PackageManagerService.TAG, "Code path for " + p.pkg.packageName +
- " changing from " + p.codePathString + " to " + codePath);
- p.codePath = new File(codePath);
- p.codePathString = codePath;
- }
-
- if (!Objects.equals(resourcePath, p.resourcePathString)) {
- Slog.w(PackageManagerService.TAG, "Resource path for " + p.pkg.packageName +
- " changing from " + p.resourcePathString + " to " + resourcePath);
- p.resourcePath = new File(resourcePath);
- p.resourcePathString = resourcePath;
- }
-
- if (!Objects.equals(legacyNativeLibraryPath, p.legacyNativeLibraryPathString)) {
- p.legacyNativeLibraryPathString = legacyNativeLibraryPath;
- }
-
-
- p.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
- p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
- p.cpuAbiOverrideString = pkg.cpuAbiOverride;
-
- if (pkg.mVersionCode != p.versionCode) {
- p.versionCode = pkg.mVersionCode;
- }
-
- if (p.signatures.mSignatures == null) {
- p.signatures.assignSignatures(pkg.mSignatures);
- }
-
- if (pkg.applicationInfo.flags != p.pkgFlags) {
- p.pkgFlags = pkg.applicationInfo.flags;
- }
-
-
- if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
- p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
- }
- addPackageSettingLPw(p, pkg.packageName, p.sharedUser);
- }
addPackageSettingLPw主要把PackageSetting 放在了mSettings的成员变量mPackages中。
- private void addPackageSettingLPw(PackageSetting p, String name,
- SharedUserSetting sharedUser) {
- mPackages.put(name, p);
- ..
这里只是保存了这两个成员变量,而在每次开机的时候都会重新扫描各个目录的apk,然后重新把各个PackageSetting放入mSettings中,最后也会把mSettings中的数据写入packages.xml文件中。
七、总结
在AMS中我们从PKMS中通过Intent参数获取ActivityInfo对象,并且其processName和uid这两个变量在后续启动进程的时候很重要。而PKMS通过Intent查询Activity,如果Intent有ComponentName我们可以直接找到对应的Activity,并且把ActivityInfo传给AMS。如果没有ComponentName,就要通过包名或者全局查找了。