深入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系列的最後一篇,希望整個系列的分析對大家學習有所幫助;

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