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完成。匹配无非是一项查找工作而已,此处就不再深究细节了,建议读者在研究代码时以目的为导向,不宜深究其中的数据结构。