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

本文探讨了在Android中,当应用程序被安装或卸载时,SearchManagerService如何更新Searchable信息。通过分析内部类MyPackageMonitor对PackageMonitor的继承实现,揭示了系统服务管理第三方Search数据源的机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如上一篇文章介绍( http://blog.youkuaiyun.com/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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值