PKMS的queryIntentActivities分析
PKMS除了负责Android系统中Package安装、升级、卸载外,还有一个重要的职责,就是对外提供统一的信息查询功能,其中包括查询系统中匹配某Intent的Activity,BroadcastReceiver或Service等。
一、Activity信息的管理
前面在介绍PKMS扫描APK时提到,PKMS将解析得到的Package私有的Activity信息加入到自己的数据结构mActivities中保存。下面是相关代码:
1 N = pkg.activities.size();//去除该APK中包含的Activity信息 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");//加入mActivities保存
先要理解mActivities则个数据类型,mActivities为ActivityIntentResolver类型,是PKMS的成员变量,用于保存系统中所有与Activity相关的信息,它以ComponetName为key,保存PackageParser.Activity对象。由addActivity代码可以看出:
1 public final void addActivity(PackageParser.Activity a, String type) { 2 final boolean systemApp = isSystemApp(a.info.applicationInfo); 3 mActivities.put(a.getComponentName(), a); 4 ... 5 final int NI = a.intents.size(); 6 for (int j=0; j<NI; j++) { 7 //ActivityIntentInfo存储的就是xml中声明的IntentFilter信息 8 PackageParser.ActivityIntentInfo intent = a.intents.get(j); 9 if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) { 10 intent.setPriority(0);//非系统APK的Priority必须为0 11 Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " 12 + a.className + " with priority > 0, forcing to 0"); 13 } 14 ... 15 addFilter(intent);//接下来是分析这个函数,和IntentFilter有关 16 } 17 }
addFilter代码:
1 public void addFilter(F f) { 2 ... 3 mFilters.add(f);//mFilters保存所有IntentFilter信息 4 //除此之外,为了加快匹配工作的速度,还需要分类保存IntentFilter信息 5 int numS = register_intent_filter(f, f.schemesIterator(), 6 mSchemeToFilter, " Scheme: "); 7 int numT = register_mime_types(f, " Type: "); 8 if (numS == 0 && numT == 0) { 9 register_intent_filter(f, f.actionsIterator(), 10 mActionToFilter, " Action: "); 11 } 12 if (numT != 0) { 13 register_intent_filter(f, f.actionsIterator(), 14 mTypedActionToFilter, " TypedAction: "); 15 } 16 }
自此所有Activity的Intent信息都已保存,下面看看Intent匹配查询
二、Intent匹配查询分析
1、客户端查询
客户端通过ApplicationPackageManager输出的queryIntentActivities函数向PKMS发起一起查询请求,代码如下:
1 try { 2 return mPM.queryIntentActivities( 3 intent, 4 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 5 flags, 6 userId); 7 }
2、queryIntentActivities分析
1 @Override 2 public List<ResolveInfo> queryIntentActivities(Intent intent, 3 String resolvedType, int flags, int userId) { 4 ... 5 ComponentName comp = intent.getComponent(); 6 ... 7 if (comp != null) { 8 final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); 9 final ActivityInfo ai = getActivityInfo(comp, flags, userId); 10 if (ai != null) { 11 final ResolveInfo ri = new ResolveInfo(); 12 ri.activityInfo = ai; 13 list.add(ri); 14 } 15 return list; 16 } 17 18 // reader 19 synchronized (mPackages) { 20 final String pkgName = intent.getPackage(); 21 if (pkgName == null) { 22 List<CrossProfileIntentFilter> matchingFilters = 23 getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); 24 // Check for results that need to skip the current profile. 25 ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, 26 resolvedType, flags, userId); 27 if (resolveInfo != null) { 28 List<ResolveInfo> result = new ArrayList<ResolveInfo>(1); 29 result.add(resolveInfo); 30 return result; 31 } 32 // Check for cross profile results. 33 resolveInfo = queryCrossProfileIntents( 34 matchingFilters, intent, resolvedType, flags, userId); 35 36 // Check for results in the current profile. 37 List<ResolveInfo> result = mActivities.queryIntent( 38 intent, resolvedType, flags, userId); 39 if (resolveInfo != null) { 40 result.add(resolveInfo); 41 Collections.sort(result, mResolvePrioritySorter); 42 } 43 return result; 44 } 45 final PackageParser.Package pkg = mPackages.get(pkgName); 46 if (pkg != null) { 47 return mActivities.queryIntentForPackage(intent, resolvedType, flags, 48 pkg.activities, userId); 49 } 50 return new ArrayList<ResolveInfo>(); 51 } 52 }
上述代码分3种情况:
1、如果Intent指明了Component,则直接查询该Component对应的ActivityInfo。
2、如果指明了Package名,则从该Package包含的Activities中进行匹配查询。
3、若没有上述限定,则在全系统范围内进行匹配查询,就是queryIntent的工作。
1 public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, 2 int userId) { 3 String scheme = intent.getScheme(); 4 5 ArrayList<R> finalList = new ArrayList<R>(); 6 ... 7 F[] firstTypeCut = null; 8 F[] secondTypeCut = null; 9 F[] thirdTypeCut = null; 10 F[] schemeCut = null; 11 12 // If the intent includes a MIME type, then we want to collect all of 13 // the filters that match that MIME type. 14 if (resolvedType != null) { 15 int slashpos = resolvedType.indexOf('/'); 16 if (slashpos > 0) { 17 final String baseType = resolvedType.substring(0, slashpos); 18 if (!baseType.equals("*")) { 19 if (resolvedType.length() != slashpos+2 20 || resolvedType.charAt(slashpos+1) != '*') { 21 // Not a wild card, so we can just look for all filters that 22 // completely match or wildcards whose base type matches. 23 firstTypeCut = mTypeToFilter.get(resolvedType); 24 if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut)); 25 secondTypeCut = mWildTypeToFilter.get(baseType); 26 if (debug) Slog.v(TAG, "Second type cut: " 27 + Arrays.toString(secondTypeCut)); 28 } 29 ... 30 } 31 } 32 33 // If the intent includes a data URI, then we want to collect all of 34 // the filters that match its scheme (we will further refine matches 35 // on the authority and path by directly matching each resulting filter). 36 if (scheme != null) { 37 schemeCut = mSchemeToFilter.get(scheme); 38 if (debug) Slog.v(TAG, "Scheme list: " + Arrays.toString(schemeCut)); 39 } 40 41 // If the intent does not specify any data -- either a MIME type or 42 // a URI -- then we will only be looking for matches against empty 43 // data. 44 if (resolvedType == null && scheme == null && intent.getAction() != null) { 45 firstTypeCut = mActionToFilter.get(intent.getAction()); 46 if (debug) Slog.v(TAG, "Action list: " + Arrays.toString(firstTypeCut)); 47 } 48 //FastImmutableArraySet是战役中特殊的数据结构,用于保存该Intent中携带的category相关信息 49 FastImmutableArraySet<String> categories = getFastIntentCategories(intent); 50 if (firstTypeCut != null) { 51 buildResolveList(intent, categories, debug, defaultOnly, 52 resolvedType, scheme, firstTypeCut, finalList, userId); 53 } 54 if (secondTypeCut != null) { 55 buildResolveList(intent, categories, debug, defaultOnly, 56 resolvedType, scheme, secondTypeCut, finalList, userId); 57 } 58 if (thirdTypeCut != null) { 59 buildResolveList(intent, categories, debug, defaultOnly, 60 resolvedType, scheme, thirdTypeCut, finalList, userId); 61 } 62 if (schemeCut != null) { 63 buildResolveList(intent, categories, debug, defaultOnly, 64 resolvedType, scheme, schemeCut, finalList, userId); 65 } 66 sortResults(finalList);//将匹配结果按priority大小排序 67 ... 68 return finalList; 69 }
queryIntentActivities功能简单粗暴,数据结构较多,目的性强,不难分析