4.5.3 Intent匹配查询分析
1.客户端查询
客户端通过ApplicationPackageManager输出的queryIntentActivities函数向PKMS发起一次查询请求,代码如下:
[—>ApplicationPackageManager.java:queryIntentActivities]
public List<ResolveInfo>queryIntentActivities(Intent intent, int flags){
try{
return mPM.queryIntentActivities(
intent,//下面这句话很重要
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags);
}……
}
如果Intent的Data包含一个uri,那么就需要查询该uri的提供者(即Content-Provider)以取得该数据的数据类型。读者可自行阅读resolveTypeIfNeeded函数的代码。
另外,flags参数目前有3个可选值,分别是MATCH_DEFAULT_ONLY、GET_INTENT_FILTERS和GET_RESOLVED_FILTER。详细信息读者可查询SDK相关文档。
下面来看PKMS对匹配查询的处理。
2.queryIntentActivities分析
该函数代码如下:
[—>PackageManagerService.java:queryIntentActivities]
public List<ResolveInfo>queryIntentActivities(Intent intent,
String resolvedType, int flags){
final ComponentName comp=intent.getComponent();
if(comp!=null){
//Explicit的Intent,直接根据component得到对应的ActivityInfo
final List<ResolveInfo>list=new ArrayList<ResolveInfo>(1);
final ActivityInfo ai=getActivityInfo(comp, flags);
if(ai!=null){
final ResolveInfo ri=new ResolveInfo();
//ResovlerInfo的activityInfo指向查询得到的ActivityInfo
ri.activityInfo=ai;
list.add(ri);
}
return list;
}
synchronized(mPackages){
final String pkgName=intent.getPackage();
if(pkgName==null){
//Implicit Intents,我们重点分析此情况
return mActivities.queryIntent(intent, resolvedType, flags);
}
//Intent指明了PackageName,比Explicit Intents情况差一点
final PackageParser.Package pkg=mPackages.get(pkgName);
if(pkg!=null){
//其实是从该Package包含的Activities中进行匹配查询
return mActivities.queryIntentForPackage(intent, resolvedType,
flags, pkg.activities);
}
return new ArrayList<ResolveInfo>();
}
}
上边代码分3种情况:
如果Intent指明了Component,则直接查询该Component对应的ActivityInfo。
如果Intent指明了Package名,则根据Package名找到该Package,然后再从该Package包含的Activities中进行匹配查询。
如果上面条件都不满足,则需要在全系统范围内进行匹配查询,这就是queryIntent的工作。
queryIntent函数的代码如下:
public List<ResolveInfo>queryIntent(Intent intent, String resolvedType,
int flags){
mFlags=flags;
//调用基类的queryIntent函数
return super.queryIntent(intent, resolvedType,
(flags&PackageManager.MATCH_DEFAULT_ONLY)!=0);
}
[—>IntentResolver.java:queryIntent]
public List<R>queryIntent(Intent intent, String resolvedType,
boolean defaultOnly){
String scheme=intent.getScheme();
ArrayList<R>finalList=new ArrayList<R>();
//最多有4轮匹配工作要做
ArrayList<F>firstTypeCut=null;
ArrayList<F>secondTypeCut=null;
ArrayList<F>thirdTypeCut=null;
ArrayList<F>schemeCut=null;
//下面将设置各轮校验者
if(resolvedType!=null){
int slashpos=resolvedType.indexOf('/');
if(slashpos>0){
final String baseType=resolvedType.substring(0,slashpos);
if(!baseType.equals("*")){
if(resolvedType.length()!=slashpos+2
||resolvedType.charAt(slashpos+1)!='*'){
firstTypeCut=mTypeToFilter.get(resolvedType);
secondTypeCut=mWildTypeToFilter.get(baseType);
}……//略去一部分内容
}
}
if(scheme!=null){
schemeCut=mSchemeToFilter.get(scheme);
}
if(resolvedType==null&&scheme==null&&intent.getAction()!=null)
{
//看来action的filter优先级最低
firstTypeCut=mActionToFilter.get(intent.getAction());
}
//FastImmutableArraySet是一种特殊的数据结构,用于保存该Intent中携带的
//Category相关的信息
FastImmutableArraySet<String>categories=getFastIntentCategories(intent);
if(firstTypeCut!=null){
//第一轮匹配查询
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, firstTypeCut, finalList);
}
if(secondTypeCut!=null){
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, secondTypeCut, finalList);
}
if(thirdTypeCut!=null){
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, thirdTypeCut, finalList);
}
if(schemeCut!=null){
//生成符合schemeCut条件的finalList
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, schemeCut, finalList);
}
//将匹配结果按Priority的大小排序
sortResults(finalList);
return finalList;
}
在以上代码中设置了最多4轮匹配关卡,然后逐一执行匹配工作。具体的匹配工作由buildResolveList完成。匹配无非是一项查找工作而已,此处就不再深究细节了,建议读者在研究代码时以目的为导向,不宜深究其中的数据结构。