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功能简单粗暴,数据结构较多,目的性强,不难分析

posted @ 2015-05-05 14:52  Simba.Chen  阅读(1628)  评论(0编辑  收藏  举报