Android框架/系统服务是怎样管理第三方Search数据源的?

来源:互联网 发布:php 上传工具 编辑:程序博客网 时间:2024/05/22 13:10
如上一篇文章介绍(http://blog.csdn.net/zhanglianyu00/article/details/61196900 ),安卓search框架支持通过实现接口,将第三方App作为外部数据源接入到系统搜索。这篇文章看一下系统侧如何管理这些searchable info。

安卓框架层有一个SearchManager作为Search管理者的对外的接口。官方文档:https://developer.android.com/reference/android/app/SearchManager.html 。对应的系统服务是SearchManagerService.java。代码路径:frameworks/base/services/core/java/com/android/server/search。可以看到,是frameworks/base/services/core/java/com/android/server的一个子路径,可见SearchManagerService是系统核心服务之一,与PackageManagerService、ActivityManagerService地位等同。

在frameworks/base/services/core/java/com/android/server/search下只有两个文件:
Searchables.java  SearchManagerService.java
SearchManagerService是系统服务类,实现了ISearchManager.stub接口。
Searchables定义了所有Searchable Activity的信息。

以某个App被安装/卸载的场景为例,看看SearchManagerService是怎么样维护Searchable info的。内部类MyPackageMonitor继承PackageMonitor:

/** * Refreshes the "searchables" list when packages are added/removed. */class MyPackageMonitor extends PackageMonitor {    @Override    public void onSomePackagesChanged() {        updateSearchables();    }    @Override    public void onPackageModified(String pkg) {        updateSearchables();    }    private void updateSearchables() {        final int changingUserId = getChangingUserId();        synchronized (mSearchables) {            // Update list of searchable activities            for (int i = 0; i < mSearchables.size(); i++) {                if (changingUserId == mSearchables.keyAt(i)) {                    getSearchables(mSearchables.keyAt(i)).buildSearchableList();                    break;                }            }        }        // Inform all listeners that the list of searchables has been updated.        Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING                | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);        mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));    }}

在SearchManagerService的构造方法中注册,这里看到会侦听所有User的Package Changed:
new MyPackageMonitor().register(context, null, UserHandle.ALL, true);

PackageMonitor.updateSearchables()里面做两件事:(1)更新一遍Searchable info;(2)向发生了packages changed的user发SEARCHABLES_CHANGED广播。(1)里面主要的逻辑是Searchables.buildSearchableList():
/** * Builds an entire list (suitable for display) of * activities that are searchable, by iterating the entire set of * ACTION_SEARCH & ACTION_WEB_SEARCH intents. * * Also clears the hash of all activities -> searches which will * refill as the user clicks "search". * * This should only be done at startup and again if we know that the * list has changed. * * TODO: every activity that provides a ACTION_SEARCH intent should * also provide searchability meta-data.  There are a bunch of checks here * that, if data is not found, silently skip to the next activity.  This * won't help a developer trying to figure out why their activity isn't * showing up in the list, but an exception here is too rough.  I would * like to find a better notification mechanism. * * TODO: sort the list somehow?  UI choice. */public void buildSearchableList() {    // These will become the new values at the end of the method    HashMap<ComponentName, SearchableInfo> newSearchablesMap                            = new HashMap<ComponentName, SearchableInfo>();    ArrayList<SearchableInfo> newSearchablesList                            = new ArrayList<SearchableInfo>();    ArrayList<SearchableInfo> newSearchablesInGlobalSearchList                            = new ArrayList<SearchableInfo>();    // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.    List<ResolveInfo> searchList;    final Intent intent = new Intent(Intent.ACTION_SEARCH);    long ident = Binder.clearCallingIdentity();    try {        searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);        List<ResolveInfo> webSearchInfoList;        final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);        webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);        // analyze each one, generate a Searchables record, and record        if (searchList != null || webSearchInfoList != null) {            int search_count = (searchList == null ? 0 : searchList.size());            int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());            int count = search_count + web_search_count;            for (int ii = 0; ii < count; ii++) {                // for each component, try to find metadata                ResolveInfo info = (ii < search_count)                        ? searchList.get(ii)                        : webSearchInfoList.get(ii - search_count);                ActivityInfo ai = info.activityInfo;                // Check first to avoid duplicate entries.                if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {                    SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai,                            mUserId);                    if (searchable != null) {                        newSearchablesList.add(searchable);                        newSearchablesMap.put(searchable.getSearchActivity(), searchable);                        if (searchable.shouldIncludeInGlobalSearch()) {                            newSearchablesInGlobalSearchList.add(searchable);                        }                    }                }            }        }        List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();        // Find the global search activity        ComponentName newGlobalSearchActivity = findGlobalSearchActivity(                newGlobalSearchActivities);        // Find the web search activity        ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);        // Store a consistent set of new values        synchronized (this) {            mSearchablesMap = newSearchablesMap;            mSearchablesList = newSearchablesList;            mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;            mGlobalSearchActivities = newGlobalSearchActivities;            mCurrentGlobalSearchActivity = newGlobalSearchActivity;            mWebSearchActivity = newWebSearchActivity;        }    } finally {        Binder.restoreCallingIdentity(ident);    }}

看到两点信息:(1)这部分逻辑不含对Search Setting的处理。(2)对于应用安装/卸载的处理是粗线条的。也就是说即使被安装/卸载的App并没有实现Search接口,也会全量刷新整个Searchable info。

0 0