深入PMS源码(三)—— PMS中intent-filter的匹配架构

1、简介

由前面深入PMS源码(一)—— PMS的启动过程和执行流程深入PMS源码(二)—— APK的安装和卸载源码分析两篇文章知道,无论是Android系统启动后执行的PMS启动,还是使用PackageInstaller安装APK的过程,最终都会使用PackageParser扫描相应的apk文件,将扫描提取的信息保在Package对象中,扫描完成后会回调PMS中方法将扫描获取的四大组件信息转换保存在PMS属性中,主要使用ActivityIntentResolver、ServiceIntentResolver、ProviderIntentResolver保存信息,这里会有两个问题:

  1. 系统是按照何种方式保存这些属性的对应关系?保存这些属性又是如何使用的?
  2. 我们启动Activity只是创建了Intent对象,然后调用Context中的启动方法而已,那系统是如何查找到目标活动的信息的呢?

2、PMS保存IntentFilter

下面带着这两个问题,从源码的角度探讨下PMS中的intent-filter的匹配架构,接着PMS的启动过程中分析,对四大组件处理代码如下,这里已对Activity的处理为例分析

N = pkg.activities.size();
3503            r = null;
3504            for (i=0; i<N; i++) {
3505                PackageParser.Activity a = pkg.activities.get(i);
3506                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
3507                        a.info.processName, pkg.applicationInfo.uid);
3508                mActivities.addActivity(a, "activity"); //调用ActivityIntentResolver.addActivity()
}

// ActivityIntentResolver.addActivity()
public final void addActivity(PackageParser.Activity a, String type) {
    mActivities.put(a.getComponentName(), a); // 1、获取内部的Component对象,在Activity会自动创建Component对象
    final int NI = a.intents.size();
    for (int j=0; j<NI; j++) {
        PackageParser.ActivityIntentInfo intent = a.intents.get(j); // 获取Activity中设置的intent
        addFilter(intent); // 添加Intent过滤
    }
}

从解析得到的Package对象中获取每个创建的Activity对象,然后调用ActivityIntentResolver.addActivity()方法将Activity对象保存在ActivityIntentResolver.mActivities集合中,在程序的最后几行代码中会遍历a.intents的集合,取出每个ActivityIntentInfo信息调用addFilter()添加Intent过滤信息,这里的ActivityIntentInfo是在PackageParser解析标签中创建的对象并添加到a.intents的集合中,也就是说每个Activity标签下定义的标签都对应一个ActivityIntentInfo对象,且所有的对象都保存在a.intents的集合中,在介绍addFilter()方法前先介绍下IntentResolver类;

  • IntentResolver
  1. 作用:IntentResolver主要用于保存程序中设置的和相应的ActivityRecord的对应关系,并在使用时提供查找机制
  2. 实现原理:IntentResolver会按照中的每个特性(如action、type)等分别创建HashMap,并在解析时保存相应的对象,在查找时取出要匹配的Component对象的action、type,然后再各自的ArrayMap中获取其保存对象的集合,此时获取到的是多个集合其中包含重复信息,然后对所有的集合取交集并去重,最终得到完全匹配的对象;
  3. IntentResolver属性如下:
public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
private final ArraySet<F> mFilters = new ArraySet<F>(); //保存所有的intent对应的匹配对象
private final ArrayMap<String, F[]> mTypeToFilter = new ArrayMap<String, F[]>(); //保存Type 匹配的Intent集合
private final ArrayMap<String, F[]> mBaseTypeToFilter = new ArrayMap<String, F[]>();
private final ArrayMap<String, F[]> mWildTypeToFilter = new ArrayMap<String, F[]>();// 保存所有带“*”通配符类型
private final ArrayMap<String, F[]> mSchemeToFilter = new ArrayMap<String, F[]>(); //已注册所有Uri方案
private final ArrayMap<String, F[]> mActionToFilter = new ArrayMap<String, F[]>();//保存所有指定Action 的Intent集合
private final ArrayMap<String, F[]> mTypedActionToFilter = new ArrayMap<String, F[]>(); // 匹配已注册且指定Mime Type类型Intent
}

上面的IntentResolver是一个范型,内部储存者IntentFilter的子类,而ActivityIntentInfo继承IntentInfo,IntentInfo又继承于IntentFilter类,所以此处直接保存的就是ActivityIntentInfo对象,在IntentFilter中保存着设置的多个属性

private int mPriority; // 优先级
private int mOrder; // 层级
private final ArrayList<String> mActions;  // 设置的actions集合
private ArrayList<String> mCategories = null; // 设置categories集合
private ArrayList<String> mDataSchemes = null; // 数据集合
private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
private ArrayList<AuthorityEntry> mDataAuthorities = null; // 匹配权限
private ArrayList<PatternMatcher> mDataPaths = null; // 匹配数据path
private ArrayList<String> mDataTypes = null; // 数据类型
  • addFilter():添加匹配意图

添加PMS扫描获得的可匹配的IntentFilter对象,在PMS解析时将每个Activity中设置的标签中信息保存在一个IntentFilter对象中,在IntentFilter中保存着标签下所有的action、type、scheme、categories的集合,在addFilter()时将这些集合中数据取出作为Key,将包含相同Key的Intent-Filter保存在数组中,然后以Key为键将这些集合存储在Intent-Resolve的ArrayMap中;

public void addFilter(F f) {
    mFilters.add(f); // 在总的Filter中保存数据
    int numS = register_intent_filter(f, f.schemesIterator(),
            mSchemeToFilter, "      Scheme:); // 判断数据uri,保存在mSchemeToFilter集合中
    int numT = register_mime_types(f, "      Type:); //判断baseType 和 mWildType 类型
    if (numS == 0 && numT == 0) { 
        register_intent_filter(f, f.actionsIterator(),
                mActionToFilter, "      Action:); // 判断匹配action对应的
    }
    if (numT != 0) {
        register_intent_filter(f, f.actionsIterator(),
                mTypedActionToFilter, "      TypedAction:); // 添加mTypedActionToFilter集合
    }
}

在addFilter()中首先将传入的intent-filter对象保存在mFilters中,也就是说mFilters中保存着所有的匹配对象,然后依次调用register_intent_filter()、register_mime_types()、register_intent_filter()、register_intent_filter()方法分别解析IntentFilter对象中的属性信息,并保存在相应的HashMap中,这里以register_intent_filter()为例,register_intent_filter中传入的是f.actionsIterator()对象,即获取是actions集合的迭代器

private final int register_intent_filter(F filter, Iterator<String> i, ArrayMap<String, F[]> dest, String prefix) {
    int num = 0;
    while (i.hasNext()) {   // 遍历Iterator
        String name = i.next();   // 取出数据集合DataSchemes下一个数据
        num++;
        addFilter(dest, name, filter);   // 添加到对应的Filter集合中,此处为mSchemeToFilter集合数据
    }
    return num;
}

在register_intent_filter中使用迭代器遍历每个action,然后取出每个action标签下设置的name属性,调用addFilter()方法执行保存,在addFilter()中传入要保存的相应的ArrayMap对象,如action对应的就是mActionToFilter

private final void addFilter(ArrayMap<String, F[]> map, String name, F filter) {
    F[] array = map.get(name);    // 根据name的名称去除保存数据的数组
    if (array == null) {
        array = newArray(2);    // 创建数组
        map.put(name,  array);    // 保存数据
        array[0] = filter;    // 保存filter
    } else {
        final int N = array.length;
        int i = N;
        while (i > 0 && array[i-1] == null) { // 遍历寻找为null的位置
            i--;
        }
        if (i < N) {
            array[i] = filter;
        } else {
            F[] newa = newArray((N*3)/2); // 原数组长度不够,扩展原数组长度
            System.arraycopy(array, 0, newa, 0, N);
            newa[N] = filter;
            map.put(name, newa);
        }
    }
}

addFilter()的执行逻辑很简单:

  1. 首先根据传入的name从相应的集合中获取数组,如果不存在则创建新数组,此时直接保存IntentFilter对象;
  2. 如果已经存在数组遍历循转数组中空位置,如果存在将IntentFilter对象保存在数组中;
  3. 如果不存在则扩展数组长度,然后保存IntentFilter数据;
  4. 最后将保存IntentFilter数据的数组添加到对应的ArrayMap中;

到此程序中注册的四大组件和相应的信息都会保存在IntentResolver类中,在使用时只需要根据设置的条件去查找匹配的对象即可;

3、IntentFilter的查找匹配

查询匹配方式:IntentResolver查询时分别从请求的Intent中取出数据(如:action、mime、scheme),然后分别以每个数据变量为Key,取出每个相应的ArrayMao中保存的对应的IntentFilter数组,最后求去这些数组的交集并去重,达到精准匹配的目的,最后返回匹配的所有ResolveInfo集合;

一般在查找是否能匹配意图时,会调用packageManager.queryIntentActivities(intent,flag)查找匹配的IntentResolve,这里的packageManager对象实际调用ApplicationPackageManager对象,程序进入ApplicationPackageManager中,在ApplicationPackageManager.queryIntentActivities()中直接调用了queryIntentActivitiesAsUser()

  • ApplicationPackageManager
@Override
@SuppressWarnings("unchecked")
public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
        int flags, int userId) {
    try {
    ParceledListSlice<ResolveInfo> parceledList = 
    mPM.queryIntentActivities(intent,
                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                        flags, userId);2return parceledList.getList();
    } 
}

在queryIntentActivitiesAsUser()中调用PMS中方法查询匹配Intent,PMS.queryIntentActivities()中间接调用queryIntentActivitiesInternal()方法

  • queryIntentActivitiesInternal()
if (!sUserManager.exists(userId)) return Collections.emptyList(); // 判断userId
final String instantAppPkgName = getInstantAppPackageName(filterCallingUid); // 获取userId对应的进程包名
final String pkgName = intent.getPackage(); // 获取Intent中携带的包名
ComponentName comp = intent.getComponent(); // 获取Component对象
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId); // 首先从PMs中保存的mActivites集合中获取ActivityInfo信息
result = filterIfNotSystemUser(mActivities.queryIntent( // 从mActivities中查询匹配的List<ResolveInfo>
        intent, resolvedType, flags, userId), userId);

在queryIntentActivitiesInternal()方法中:

  1. 首先判断当前用于的userId,如果不存在则直接返回空集合;
  2. 从请求的Intent中获取包含的Component对象;
  3. 如果Component不为空说明此时是显示启动,直接调用首先从PMs中保存的mActivites集合中获取ActivityInfo信息;
  4. 对于Component为空的则调用mActivities.queryIntent()匹配能处理的ActivityInfo对象;
  • ActivityIntentResolve.queryIntent()中直接调用父类IntentResolve.queryIntent(),方法执行到IntentResolve.queryIntent()中
public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
        int userId) {
String scheme = intent.getScheme(); // 获取scheme
ArrayList<R> finalList = new ArrayList<R>();
F[] firstTypeCut = null;   //保存匹配的结果
F[] secondTypeCut = null;
F[] thirdTypeCut = null;
F[] schemeCut = null;
if (scheme != null) {
    schemeCut = mSchemeToFilter.get(scheme); // 1、先根据scheme匹配,获取匹配的数组
}
   final String baseType = resolvedType.substring(0, slashpos);
    if (!baseType.equals("*")) {
        if (resolvedType.length() != slashpos+2
                || resolvedType.charAt(slashpos+1) != '*') {
            firstTypeCut = mTypeToFilter.get(resolvedType); // 根据type匹配
            secondTypeCut = mWildTypeToFilter.get(baseType);
        } else {
            firstTypeCut = mBaseTypeToFilter.get(baseType);
            secondTypeCut = mWildTypeToFilter.get(baseType);
        }
        thirdTypeCut = mWildTypeToFilter.get("*");
    } else if (intent.getAction() != null) {
        firstTypeCut = mTypedActionToFilter.get(intent.getAction());
    }
}
if (resolvedType == null && scheme == null && intent.getAction() != null) {
    firstTypeCut = mActionToFilter.get(intent.getAction()); // 2、根据action匹配
}
if (firstTypeCut != null) {
    buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
            scheme, firstTypeCut, finalList, userId); // 不断进行匹配
}
if (secondTypeCut != null) {
    buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
            scheme, secondTypeCut, finalList, userId);
}
if (thirdTypeCut != null) {
    buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
            scheme, thirdTypeCut, finalList, userId);
}
if (schemeCut != null) {
    buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
            scheme, schemeCut, finalList, userId);
}
sortResults(finalList); // 将数组中元素按照优先级排序
return finalList; // 返回最终匹配的结果集合

在queryIntent()中首先从Intent中取出所有属性信息,如action、scheme等,然后创建四个数组对象,这四个数组主要保存根据Intent中设置的属性查找出对应的数组,之后从每个ArrayMap中匹配返回相应的数组,然后根据四个数数组是否存在数据从而多此执行buildResolveList()方法,buildResolveList主要是获取四个数组中保存的IntentFilter对象转换为输出的对象,然后执行sortResults()其中的重复对象此时即可返回最终匹配结果;

private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
        boolean debug, boolean defaultOnly, String resolvedType, String scheme,
        F[] src, List<R> dest, int userId) {
final int N = src != null ? src.length : 0;
F filter;
for (i=0; i<N && (filter=src[i]) != null; i++) {
match = filter.match(action, resolvedType, scheme, data, categories, TAG);
if (match >= 0) {
    if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
        final R oneResult = newResult(filter, match, userId); // 将filter转换为 ResolveInfo 
        if (oneResult != null) {
            dest.add(oneResult); // 保存到dest集合中
        }
    } 
}
}
}

在上述的匹配过程之后即可获取到所有的可处理请求的Activity对象,然后将其中的信息设置在Intent之后再执行请求,此时就是像动态启动Activity一样直接启动目标活动;

Intent intent = new Intent(intentToResolve);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(ris.get(0).activityInfo.packageName,
ris.get(0).activityInfo.name); 
return intent;

到此PMS中关于保存IntentFilter和静态启动过程中的匹配过程介绍完毕了,通过上面的学习相信对PMS如何处理apk文件和系统如何识别要启动的程序或活动有了更深的理解,本篇也是PMS系列的最后一篇,希望整个系列的分析对大家学习有所帮助;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章