PackageManagerService Intent匹配查询

来源:互联网 发布:js音乐的获取方式 编辑:程序博客网 时间:2024/06/05 16:10

      PKMS除了负责应用的安装、更新、卸载之外,同时也对外提供信息的查询。例如查询系统中匹配某Intent的Activities、Services等。本文就以Activity为例,分析PKMS如何通过Intent查询Activity。

本文分为三个部分:

1.   Activity信息的保存

2.   Intent查询Activity的规则

3.   PKMS通过Intent查询Activity的过程


一、Activity信息的保存

     Activity信息的保存是在安装应用时完成的,在scanPackageDirtyLI()方法最后会把Activity信息保存在PKMS的变量mActivities中。mActivities为ActivityIntenResolver类型,为PKMS的内部类。主要处理Intent的查询操作,其父类为IntentResolver<F extends IntentFilter, R extends Object>,为泛型编程,因为还有ServiceIntentResolver等。


    final class ActivityIntentResolver            extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,                boolean defaultOnly, int userId) {            if (!sUserManager.exists(userId)) return null;            mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;            return super.queryIntent(intent, resolvedType, defaultOnly, userId);        }        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,                int userId) {            if (!sUserManager.exists(userId)) return null;            mFlags = flags;            return super.queryIntent(intent, resolvedType,                    (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);        }        public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,                int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {            if (!sUserManager.exists(userId)) return null;            if (packageActivities == null) {                return null;            }            mFlags = flags;            final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;            final int N = packageActivities.size();            ArrayList<PackageParser.ActivityIntentInfo[]> listCut =                new ArrayList<PackageParser.ActivityIntentInfo[]>(N);            ArrayList<PackageParser.ActivityIntentInfo> intentFilters;            for (int i = 0; i < N; ++i) {                intentFilters = packageActivities.get(i).intents;                if (intentFilters != null && intentFilters.size() > 0) {                    PackageParser.ActivityIntentInfo[] array =                            new PackageParser.ActivityIntentInfo[intentFilters.size()];                    intentFilters.toArray(array);                    listCut.add(array);                }            }            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);        }        public final void addActivity(PackageParser.Activity a, String type) {            final boolean systemApp = a.info.applicationInfo.isSystemApp();            mActivities.put(a.getComponentName(), a);            if (DEBUG_SHOW_INFO)                Log.v(                TAG, "  " + type + " " +                (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");            if (DEBUG_SHOW_INFO)                Log.v(TAG, "    Class=" + a.info.name);            final int NI = a.intents.size();            for (int j=0; j<NI; j++) {                PackageParser.ActivityIntentInfo intent = a.intents.get(j);                if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {                    intent.setPriority(0);                    Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "                            + a.className + " with priority > 0, forcing to 0");                }                if (DEBUG_SHOW_INFO) {                    Log.v(TAG, "    IntentFilter:");                    intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");                }                if (!intent.debugCheck()) {                    Log.w(TAG, "==> For Activity " + a.info.name);                }                addFilter(intent);            }        }        public final void removeActivity(PackageParser.Activity a, String type) {            mActivities.remove(a.getComponentName());            if (DEBUG_SHOW_INFO) {                Log.v(TAG, "  " + type + " "                        + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel                                : a.info.name) + ":");                Log.v(TAG, "    Class=" + a.info.name);            }            final int NI = a.intents.size();            for (int j=0; j<NI; j++) {                PackageParser.ActivityIntentInfo intent = a.intents.get(j);                if (DEBUG_SHOW_INFO) {                    Log.v(TAG, "    IntentFilter:");                    intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");                }                removeFilter(intent);            }        }        @Override        protected boolean allowFilterResult(                PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {            ActivityInfo filterAi = filter.activity.info;            for (int i=dest.size()-1; i>=0; i--) {                ActivityInfo destAi = dest.get(i).activityInfo;                if (destAi.name == filterAi.name                        && destAi.packageName == filterAi.packageName) {                    return false;                }            }            return true;        }        @Override        protected ActivityIntentInfo[] newArray(int size) {            return new ActivityIntentInfo[size];        }        @Override        protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {            if (!sUserManager.exists(userId)) return true;            PackageParser.Package p = filter.activity.owner;            if (p != null) {                PackageSetting ps = (PackageSetting)p.mExtras;                if (ps != null) {                    // System apps are never considered stopped for purposes of                    // filtering, because there may be no way for the user to                    // actually re-launch them.                    return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0                            && ps.getStopped(userId);                }            }            return false;        }        @Override        protected boolean isPackageForFilter(String packageName,                PackageParser.ActivityIntentInfo info) {            return packageName.equals(info.activity.owner.packageName);        }        @Override        protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,                int match, int userId) {            if (!sUserManager.exists(userId)) return null;            if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) {                return null;            }            final PackageParser.Activity activity = info.activity;            if (mSafeMode && (activity.info.applicationInfo.flags                    &ApplicationInfo.FLAG_SYSTEM) == 0) {                return null;            }            PackageSetting ps = (PackageSetting) activity.owner.mExtras;            if (ps == null) {                return null;            }            ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags,                    ps.readUserState(userId), userId);            if (ai == null) {                return null;            }            final ResolveInfo res = new ResolveInfo();            res.activityInfo = ai;            if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {                res.filter = info;            }            if (info != null) {                res.handleAllWebDataURI = info.handleAllWebDataURI();            }            res.priority = info.getPriority();            res.preferredOrder = activity.owner.mPreferredOrder;            //System.out.println("Result: " + res.activityInfo.className +            //                   " = " + res.priority);            res.match = match;            res.isDefault = info.hasDefault;            res.labelRes = info.labelRes;            res.nonLocalizedLabel = info.nonLocalizedLabel;            if (userNeedsBadging(userId)) {                res.noResourceId = true;            } else {                res.icon = info.icon;            }            res.iconResourceId = info.icon;            res.system = res.activityInfo.applicationInfo.isSystemApp();            return res;        }        @Override        protected void sortResults(List<ResolveInfo> results) {            Collections.sort(results, mResolvePrioritySorter);        }        @Override        protected void dumpFilter(PrintWriter out, String prefix,                PackageParser.ActivityIntentInfo filter) {            out.print(prefix); out.print(                    Integer.toHexString(System.identityHashCode(filter.activity)));                    out.print(' ');                    filter.activity.printComponentShortName(out);                    out.print(" filter ");                    out.println(Integer.toHexString(System.identityHashCode(filter)));        }        @Override        protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) {            return filter.activity;        }        protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {            PackageParser.Activity activity = (PackageParser.Activity)label;            out.print(prefix); out.print(                    Integer.toHexString(System.identityHashCode(activity)));                    out.print(' ');                    activity.printComponentShortName(out);            if (count > 1) {                out.print(" ("); out.print(count); out.print(" filters)");            }            out.println();        }//        List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {//            final Iterator<ResolveInfo> i = resolveInfoList.iterator();//            final List<ResolveInfo> retList = Lists.newArrayList();//            while (i.hasNext()) {//                final ResolveInfo resolveInfo = i.next();//                if (isEnabledLP(resolveInfo.activityInfo)) {//                    retList.add(resolveInfo);//                }//            }//            return retList;//        }        // Keys are String (activity class name), values are Activity.        private final ArrayMap<ComponentName, PackageParser.Activity> mActivities                = new ArrayMap<ComponentName, PackageParser.Activity>();        private int mFlags;    }


1.1在scanPackageDirtyLI()最后,待用mActivities.addActiviy()方法保存Activity。

    private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {......            N = pkg.activities.size();            r = null;            for (i=0; i<N; i++) {                PackageParser.Activity a = pkg.activities.get(i);                a.info.processName = fixProcessName(pkg.applicationInfo.processName,                        a.info.processName, pkg.applicationInfo.uid);                mActivities.addActivity(a, "activity");                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {                    if (r == null) {                        r = new StringBuilder(256);                    } else {                        r.append(' ');                    }                    r.append(a.info.name);                }            }......}

1.2 .addActivity()首先以Component为键,Packageparser.Activity对象为值保存Activity信息在mActivities的内部变量mActivities。然后调用其父类的addFilter保存Activity的intent信息(用PackageParser.ActivityIntentInfo表示)


        public final void addActivity(PackageParser.Activity a, String type) {            final boolean systemApp = a.info.applicationInfo.isSystemApp();            mActivities.put(a.getComponentName(), a);            if (DEBUG_SHOW_INFO)                Log.v(                TAG, "  " + type + " " +                (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");            if (DEBUG_SHOW_INFO)                Log.v(TAG, "    Class=" + a.info.name);            final int NI = a.intents.size();            for (int j=0; j<NI; j++) {                PackageParser.ActivityIntentInfo intent = a.intents.get(j);                if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {                    intent.setPriority(0);                    Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "                            + a.className + " with priority > 0, forcing to 0");                }                if (DEBUG_SHOW_INFO) {                    Log.v(TAG, "    IntentFilter:");                    intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");                }                if (!intent.debugCheck()) {                    Log.w(TAG, "==> For Activity " + a.info.name);                }                addFilter(intent);            }        }
1.3   在为了加快匹配速度,创建了较多种类的成员变量:

ArraySet<F>mFilters : 保存了所有的IntentFilter

ArrayMap<String,F[]> mTypeToFilter : 保存所有MIME types类型

ArrayMap<String,F[]> mBaseTypeToFilter : 包含MIME中Base类型的IntentFilter信息,但不包括Sub type为“*”的IntentFilter

ArrayMap<String,F[]> mWildTypeToFilter : 用于保存设置了Data类型类似“image/*”的IntentFilter

ArrayMap<String,F[]> mSchemeToFilter : 保存与scheme相关的IntentFilter信息

ArrayMap<String,F[]> mActionToFilter : 保存仅设置Action条件的IntentFilter信息

ArrayMap<String,F[]> mTypedActionToFilter : 保存了既设置了Action又设置了Data的MIME类型的IntentFilter信息

    public void addFilter(F f) {        if (localLOGV) {            Slog.v(TAG, "Adding filter: " + f);            f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "      ");            Slog.v(TAG, "    Building Lookup Maps:");        }        mFilters.add(f);        int numS = register_intent_filter(f, f.schemesIterator(),                mSchemeToFilter, "      Scheme: ");        int numT = register_mime_types(f, "      Type: ");        if (numS == 0 && numT == 0) {            register_intent_filter(f, f.actionsIterator(),                    mActionToFilter, "      Action: ");        }        if (numT != 0) {            register_intent_filter(f, f.actionsIterator(),                    mTypedActionToFilter, "      TypedAction: ");        }    }


至此,Package中Activity的信息已保存完毕。


二、Intent查询Activity的规则

这部分对于开发APP也是需要掌握的知识,这里简单介绍下匹配规则。

2.1指定ComponentName

不需要使用<intent-filter.../>元素进行配置。直接根据Component启动相应的组件。

2.2 通过Action、category匹配

Intent的Action、Category属性的值都是一个普通的字符串,其中Action代表该Intent所要完成的一个抽象“动作”,而Category则用于为Action增加额外的附加类别信息,通常Action属性会与Category属性结合使用。

Action:Intent中的Action必须能够和Activity过滤规则中的Action匹配.(这里的匹配是完全相等).一个过滤规则中有多个action,那么只要Intent中的action能够和Activity过滤规则中的任何一个action相同即可匹配成功。

Category: 如果Intent中的存在category那么所有的category都必须和Activity过滤规则中的category相同。才能和这个Activity匹配。Intent中的category数量可能少于Activity中配置的category数量,但是Intent中的这category必须和Activity中配置的category相同才能匹配。

2.3 通过Type、Data匹配

 Data属性通常用于向Action属性提供操作的数据。Data属性接受一个Uri对象,一个Uri对象通常通过如下形式的字符串来表示:

content://com.android.contacts:8080/contacts/1

例如上面给出的content://com.android.contacts/contacts/1,其中content是scheme部分,com.android.contacts是host部分,port为8080,/contacts/1是path部分。

Type属性用于指定该Data属性所指定Uri对应的MIME类型,这种MIME类型可以是任何自定义的MIME类型,只要符合abc/xyz格式的字符串即可。

Type:Intent的Type属性也用于指定该Intent的要求,对应组件中<intent-filter.../>元素的<data.../>子元素的mimeType属性必须与此相同,才能启动该组件。

Data:

·        如果目标组件的<data.../>子元素只指定了android:scheme属性,那么只要Intent的Data属性的scheme部分与android:scheme属性值相同,即可启动该组件。

·        如果目标组件的<data../>子元素只指定了android:scheme、android:host属性,那么只要Intent的Data属性的scheme、host部分与android:scheme、android:host属性值相同,即可启动该组件。

·        如果目标组件的<data../>子元素只指定了android:scheme、android:host、android:port属性,那么只要Intent的Data属性的scheme、host、port部分与android:scheme、android:host、android:port属性值相同,即可启动该组件。(注意:如果<data.../>子元素只有android:port属性,没有指定android:host属性,那么android:port属性将不会起作用)。

·        如果目标组件的<data../>子元素只指定了android:scheme、android:host、android:path属性,那么只要Intent的Data属性的scheme、host、path部分与android:scheme、android:host、android:path属性值相同,即可启动该组件。(注意:如果<data.../>子元素只有android:path属性,没有指定android:host属性,那么android:path属性将不会起作用)。

·        如果目标组件的<data../>子元素只指定了android:scheme、android:host、android:port、android:path属性,那么只要Intent的Data属性的scheme、host、port、path部分与android:scheme、android:host、android:port、android:path属性值相同,即可启动该组件。


三 、PKMS通过Intent查询Activity的过程

当要打开一个Activity时,客户端通过ApplicationPackageManager输出的queryIntentActivities方法向PKMS发起送查询请求,这会调用到PKMS的queryIntentActivities方法。

查询Activity分为三种情况

1.   指定了ComponentName

2.   指定了Package

3.   既没指定Component也没指定package


    @Override    public List<ResolveInfo> queryIntentActivities(Intent intent,            String resolvedType, int flags, int userId) {        if (!sUserManager.exists(userId)) return Collections.emptyList();        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");        ComponentName comp = intent.getComponent();        if (comp == null) {            if (intent.getSelector() != null) {                intent = intent.getSelector();                comp = intent.getComponent();            }        }        //指定了Component        if (comp != null) {            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);            final ActivityInfo ai = getActivityInfo(comp, flags, userId);            if (ai != null) {                final ResolveInfo ri = new ResolveInfo();                ri.activityInfo = ai;                list.add(ri);            }            return list;        }        // reader        synchronized (mPackages) {            final String pkgName = intent.getPackage();//既没有指定packgae也没有指定Component。            if (pkgName == null) {                List<CrossProfileIntentFilter> matchingFilters =                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);                // Check for results that need to skip the current profile.                ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,                        resolvedType, flags, userId);                if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {                    List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);                    result.add(xpResolveInfo);                    return filterIfNotPrimaryUser(result, userId);                }                // Check for results in the current profile.                List<ResolveInfo> result = mActivities.queryIntent(                        intent, resolvedType, flags, userId);                // Check for cross profile results.                xpResolveInfo = queryCrossProfileIntents(                        matchingFilters, intent, resolvedType, flags, userId);                if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {                    result.add(xpResolveInfo);                    Collections.sort(result, mResolvePrioritySorter);                }                result = filterIfNotPrimaryUser(result, userId);                if (hasWebURI(intent)) {                    CrossProfileDomainInfo xpDomainInfo = null;                    final UserInfo parent = getProfileParent(userId);                    if (parent != null) {                        xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,                                flags, userId, parent.id);                    }                    if (xpDomainInfo != null) {                        if (xpResolveInfo != null) {                            // If we didn't remove it, the cross-profile ResolveInfo would be twice                            // in the result.                            result.remove(xpResolveInfo);                        }                        if (result.size() == 0) {                            result.add(xpDomainInfo.resolveInfo);                            return result;                        }                    } else if (result.size() <= 1) {                        return result;                    }                    result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,                            xpDomainInfo, userId);                    Collections.sort(result, mResolvePrioritySorter);                }                return result;            }            final PackageParser.Package pkg = mPackages.get(pkgName);//指定了Package            if (pkg != null) {                return filterIfNotPrimaryUser(                        mActivities.queryIntentForPackage(                                intent, resolvedType, flags, pkg.activities, userId),                        userId);            }            return new ArrayList<ResolveInfo>();        }    }

3.1 指定Component

指定ComponentName获取ActivityInfo是最简单的,根据前面第一部分保存Activity信息可知,Activity信息被保存在PKMS的变量mActivities的内部变量mActivities中,其结构为HashMap<ComponentName ,PackageParser.Activity>,通过Component即可获取Activity信息。

    @Override    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {        if (!sUserManager.exists(userId)) return null;        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");        synchronized (mPackages) {            PackageParser.Activity a = mActivities.mActivities.get(component);            if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);            if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());                if (ps == null) return null;                return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),                        userId);            }            if (mResolveComponentName.equals(component)) {                return PackageParser.generateActivityInfo(mResolveActivity, flags,                        new PackageUserState(), userId);            }        }        return null;    }

3.2  指定Package

 指定Package的情况下,PKMS调用queryIntentForPackage进行查询。流程如下:


1.    获取Package下所有Activity的intent信息,保存在ArrayList<PackageParser.ActivityIntentInfo[]> listCut中,PackageParser.ActivityIntentInfo[]数组保存了一个Activity包含的IntentFilter信息。然后调用父类的queryIntentFromList方法。

        public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,                int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {            if (!sUserManager.exists(userId)) return null;            if (packageActivities == null) {                return null;            }            mFlags = flags;            final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;            final int N = packageActivities.size();            ArrayList<PackageParser.ActivityIntentInfo[]> listCut =                new ArrayList<PackageParser.ActivityIntentInfo[]>(N);            ArrayList<PackageParser.ActivityIntentInfo> intentFilters;            for (int i = 0; i < N; ++i) {                intentFilters = packageActivities.get(i).intents;                if (intentFilters != null && intentFilters.size() > 0) {                    PackageParser.ActivityIntentInfo[] array =                            new PackageParser.ActivityIntentInfo[intentFilters.size()];                    intentFilters.toArray(array);                    listCut.add(array);                }            }            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);        }

2.    queryIntentFromList方法中遍历listCut列表,即逐一取出每个Activiy的intentFilter信息,然后调用buildResolveList方法来和intent进行匹配

    public List<R> queryIntentFromList(Intent intent, String resolvedType,             boolean defaultOnly, ArrayList<F[]> listCut, int userId) {        ArrayList<R> resultList = new ArrayList<R>();        final boolean debug = localLOGV ||                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);        final String scheme = intent.getScheme();        int N = listCut.size();        for (int i = 0; i < N; ++i) {            buildResolveList(intent, categories, debug, defaultOnly,                    resolvedType, scheme, listCut.get(i), resultList, userId);        }        sortResults(resultList);        return resultList;    }

3.    buildResolveList中,首先获取intent的action、category、type、data信息,然后遍历IntentFilter,调用其match方法进行匹配。匹配规则如第二部分所描述的,具体代码可以参考IntentFilter类的match方法。

   private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,            boolean debug, boolean defaultOnly,            String resolvedType, String scheme, F[] src, List<R> dest, int userId) {        final String action = intent.getAction();        final Uri data = intent.getData();        final String packageName = intent.getPackage();        final boolean excludingStopped = intent.isExcludingStopped();        final Printer logPrinter;        final PrintWriter logPrintWriter;        if (debug) {            logPrinter = new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM);            logPrintWriter = new FastPrintWriter(logPrinter);        } else {            logPrinter = null;            logPrintWriter = null;        }        final int N = src != null ? src.length : 0;        boolean hasNonDefaults = false;        int i;        F filter;        for (i=0; i<N && (filter=src[i]) != null; i++) {            int match;            if (debug) Slog.v(TAG, "Matching against filter " + filter);            if (excludingStopped && isFilterStopped(filter, userId)) {                if (debug) {                    Slog.v(TAG, "  Filter's target is stopped; skipping");                }                continue;            }            // Is delivery being limited to filters owned by a particular package?            if (packageName != null && !isPackageForFilter(packageName, filter)) {                if (debug) {                    Slog.v(TAG, "  Filter is not from package " + packageName + "; skipping");                }                continue;            }            // Are we verified ?            if (filter.getAutoVerify()) {                if (localVerificationLOGV || debug) {                    Slog.v(TAG, "  Filter verified: " + isFilterVerified(filter));                    int authorities = filter.countDataAuthorities();                    for (int z = 0; z < authorities; z++) {                        Slog.v(TAG, "   " + filter.getDataAuthority(z).getHost());                    }                }            }            // Do we already have this one?            if (!allowFilterResult(filter, dest)) {                if (debug) {                    Slog.v(TAG, "  Filter's target already added");                }                continue;            }            match = filter.match(action, resolvedType, scheme, data, categories, TAG);            if (match >= 0) {                if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +                        Integer.toHexString(match) + " hasDefault="                        + filter.hasCategory(Intent.CATEGORY_DEFAULT));                if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {                    final R oneResult = newResult(filter, match, userId);                    if (oneResult != null) {                        dest.add(oneResult);                        if (debug) {                            dumpFilter(logPrintWriter, "    ", filter);                            logPrintWriter.flush();                            filter.dump(logPrinter, "    ");                        }                    }                } else {                    hasNonDefaults = true;                }            } else {                if (debug) {                    String reason;                    switch (match) {                        case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;                        case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;                        case IntentFilter.NO_MATCH_DATA: reason = "data"; break;                        case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;                        default: reason = "unknown reason"; break;                    }                    Slog.v(TAG, "  Filter did not match: " + reason);                }            }        }        if (hasNonDefaults) {            if (dest.size() == 0) {                Slog.w(TAG, "resolveIntent failed: found match, but none with CATEGORY_DEFAULT");            } else if (dest.size() > 1) {                Slog.w(TAG, "resolveIntent: multiple matches, only some with CATEGORY_DEFAULT");            }        }    }

4.    若匹配成功则把IntentFilter转化为ResolveInfo对象,添加到结果List<ResolveInfo>中。


三、     全局搜索Intent

        调用了IntentResolver的queryIntent。为了加快Intent全局搜索,保存IntentFilter时就保存了多个成员变量,如mTypeToFilter、mSchemeToFilter等,见第一部分分析,queryIntent的主要逻辑就是根据请求的Intent信息,去相应的成员变量中获取IntentFilter,并保存在F[]变量中,然后调用buildResolveList进行匹配,buildResolveList上面已经介绍过了。

       例如,Intent中信息为type为abc/xyz scheme为content。那么,首先会查看mTypeToFilter中键为“abc/xyz”的IntentFilter值,并保存在firstTypeCut中,因为mTypeToFilter是保存了所有Type值,然后继续查找mWildTypeToFilter中包含“abc”的IntentFilter,并保存在secondTypeCut中,然后在调用buildResolveList进行逐个匹配。


public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,            int userId) {        String scheme = intent.getScheme();        ArrayList<R> finalList = new ArrayList<R>();        final boolean debug = localLOGV ||                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);        if (debug) Slog.v(            TAG, "Resolving type=" + resolvedType + " scheme=" + scheme            + " defaultOnly=" + defaultOnly + " userId=" + userId + " of " + intent);        F[] firstTypeCut = null;        F[] secondTypeCut = null;        F[] thirdTypeCut = null;        F[] schemeCut = null;        // If the intent includes a MIME type, then we want to collect all of        // the filters that match that MIME type.        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) != '*') {                        // Not a wild card, so we can just look for all filters that                        // completely match or wildcards whose base type matches.                        firstTypeCut = mTypeToFilter.get(resolvedType);                        if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));                        secondTypeCut = mWildTypeToFilter.get(baseType);                        if (debug) Slog.v(TAG, "Second type cut: "                                + Arrays.toString(secondTypeCut));                    } else {                        // We can match anything with our base type.                        firstTypeCut = mBaseTypeToFilter.get(baseType);                        if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));                        secondTypeCut = mWildTypeToFilter.get(baseType);                        if (debug) Slog.v(TAG, "Second type cut: "                                + Arrays.toString(secondTypeCut));                    }                    // Any */* types always apply, but we only need to do this                    // if the intent type was not already */*.                    thirdTypeCut = mWildTypeToFilter.get("*");                    if (debug) Slog.v(TAG, "Third type cut: " + Arrays.toString(thirdTypeCut));                } else if (intent.getAction() != null) {                    // The intent specified any type ({@literal *}/*).  This                    // can be a whole heck of a lot of things, so as a first                    // cut let's use the action instead.                    firstTypeCut = mTypedActionToFilter.get(intent.getAction());                    if (debug) Slog.v(TAG, "Typed Action list: " + Arrays.toString(firstTypeCut));                }            }        }        // If the intent includes a data URI, then we want to collect all of        // the filters that match its scheme (we will further refine matches        // on the authority and path by directly matching each resulting filter).        if (scheme != null) {            schemeCut = mSchemeToFilter.get(scheme);            if (debug) Slog.v(TAG, "Scheme list: " + Arrays.toString(schemeCut));        }        // If the intent does not specify any data -- either a MIME type or        // a URI -- then we will only be looking for matches against empty        // data.        if (resolvedType == null && scheme == null && intent.getAction() != null) {            firstTypeCut = mActionToFilter.get(intent.getAction());            if (debug) Slog.v(TAG, "Action list: " + Arrays.toString(firstTypeCut));        }        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);        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);        if (debug) {            Slog.v(TAG, "Final result list:");            for (int i=0; i<finalList.size(); i++) {                Slog.v(TAG, "  " + finalList.get(i));            }        }        return finalList;    }

至此,PKMS查询Intent已介绍完成。