Skip to content

ComponentResolver 组件解析器

分析四类组件 resolver、Provider authority 索引、注册注销与快照一致性。

AndroidPMSPackageManagerIntent

ComponentResolver 组件解析器 ​

ComponentResolver 是 PMS 中保存组件解析索引的可变 owner。它不负责决定最终启动哪个 Activity,而是把包扫描得到的 Activity、Service、Receiver、Provider 和 IntentFilter 注册到四套 resolver,并在查询时生成候选 ResolveInfo。ComputerEngine 读取它的快照,IntentResolver 执行过滤器匹配,ResolveIntentHelper 再做最终选择。

1. 四套索引 ​

组件resolver额外索引
ActivityActivityIntentResolverComponentName → ParsedActivity
ReceiverReceiverIntentResolverComponentName → ParsedActivity
ServiceServiceIntentResolverComponentName → ParsedService
ProviderProviderIntentResolverComponentName → ParsedProvider、authority → Provider

四套 resolver 共享 IntentResolver 的 action/type/scheme 索引,但 newResult、停止态判断和组件信息生成各自不同。Provider 的 authority 表用于 content://authority 的精确查询,不经过隐式 Intent filter。

2. 查询契约 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java

java
protected ActivityIntentResolver mActivities;
protected ProviderIntentResolver mProviders;
protected ReceiverIntentResolver mReceivers;
protected ServiceIntentResolver mServices;
protected ArrayMap<String, ParsedProvider> mProvidersByAuthority;

@Override
public List<ResolveInfo> queryActivities(
        Computer computer, Intent intent, String resolvedType,
        long flags, int userId) {
    return mActivities.queryIntent(
            computer, intent, resolvedType, flags, userId);
}

Base 类保存四种 resolver 和 Provider authority map,并把组件查询路由给对应实例。它只提供查询契约;添加、删除和快照由具体 ComponentResolver 实现。

3. 包扫描时注册组件 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolver.java

java
public void addAllComponents(AndroidPackage pkg, boolean chatty,
        String setupWizardPackage, Computer computer) {
    synchronized (mLock) {
        addAllComponentsLocked(pkg, chatty, setupWizardPackage, computer);
    }
}

注册在 mLock 内完成,保证包扫描不会与查询同时观察半套组件。InstallPackageHelper 在安装/扫描完成后调用它;卸载路径对应 removeAllComponents。

java
private void addAllComponentsLocked(AndroidPackage pkg, boolean chatty,
        String setupWizardPackage, Computer computer) {
    final List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents =
            new ArrayList<>();
    for (ParsedActivity a : pkg.getActivities()) {
        mActivities.addActivity(computer, a, "activity", newIntents);
    }
    for (ParsedActivity a : pkg.getReceivers()) {
        mReceivers.addActivity(computer, a, "receiver", null);
    }
    for (ParsedService s : pkg.getServices()) {
        mServices.addService(computer, s);
    }
    for (ParsedProvider p : pkg.getProviders()) {
        addProviderLocked(computer, p);
    }
    adjustPriority(newIntents, setupWizardPackage);
}

Activity 和 Receiver 都使用 ParsedActivity,但进入不同 resolver;Activity 注册时收集 filter 供后续 priority 调整。Provider 还要建立 authority 索引。

4. Activity 注册 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolver.java

java
protected void addActivity(@NonNull Computer computer, ParsedActivity a,
        String type, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {
    mActivities.put(a.getComponentName(), a);
    final int intentsSize = a.getIntents().size();
    for (int j = 0; j < intentsSize; j++) {
        ParsedIntentInfo intent = a.getIntents().get(j);
        IntentFilter intentFilter = intent.getIntentFilter();
        if (newIntents != null && "activity".equals(type)) {
            newIntents.add(Pair.create(a, intent));
        }
        if (!intentFilter.debugCheck()) {
            Log.w(TAG, "==> For Activity " + a.getName());
        }
        addFilter(computer, Pair.create(a, intent));
    }
}

组件名先写入精确 map,再把每个 ParsedIntentInfo 交给父类 addFilter。父类会按 action、MIME type、scheme 等建立桶;同一 Activity 的多个 filter 可以匹配同一个 Intent,后续 allowFilterResult 会按组件去重。

5. Provider 索引 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolver.java

java
for (String authority : p.getAuthorities()) {
    if (!mProvidersByAuthority.containsKey(authority)) {
        mProvidersByAuthority.put(authority, p);
    } else {
        ParsedProvider other = mProvidersByAuthority.get(authority);
        Slog.w(TAG, "Skipping provider " + p.getComponentName()
                + " with authority " + authority
                + ": already owned by " + other.getComponentName());
    }
}

authority map 采用先注册者占用策略;后注册 Provider 不会覆盖已有 authority。这个冲突与组件名冲突不同:两个 Provider 可以有不同 ComponentName,却不能安全地共享同一个 authority。

java
@Nullable
public ProviderInfo queryProvider(@NonNull Computer computer,
        @NonNull String authority, long flags, int userId) {
    final ParsedProvider p = mProvidersByAuthority.get(authority);
    if (p == null) return null;
    final PackageStateInternal packageState =
            computer.getPackageStateInternal(p.getPackageName());
    if (packageState == null || packageState.getPkg() == null) return null;
    final PackageUserStateInternal state =
            packageState.getUserStateOrDefault(userId);
    final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
            packageState.getPkg(), flags, state, userId, packageState);
    if (appInfo == null) return null;
    return PackageInfoUtils.generateProviderInfo(
            packageState.getPkg(), p, flags, state, appInfo,
            userId, packageState);
}

authority 命中后仍要读取包状态和用户状态;包卸载、用户不可见或 flags 过滤都会返回 null。索引命中不等于 Provider 对调用方可见。

6. Resolver 查询 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java

java
@Override
public List<ResolveInfo> queryServices(Computer computer, Intent intent,
        String resolvedType, long flags, int userId) {
    return mServices.queryIntent(
            computer, intent, resolvedType,
            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
            userId);
}

@Override
public List<ResolveInfo> queryReceivers(Computer computer, Intent intent,
        String resolvedType, long flags, int userId) {
    return mReceivers.queryIntent(
            computer, intent, resolvedType,
            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
            userId);
}

MATCH_DEFAULT_ONLY 被转换为 defaultOnly 参数,由 IntentResolver 在 match 成功后检查 CATEGORY_DEFAULT。ComponentResolver 不重复实现 action/data/category 算法,只负责把正确 flags 传给对应 resolver。

7. 组件移除 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolver.java

java
private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) {
    for (ParsedActivity a : pkg.getActivities()) {
        mActivities.removeActivity(a, "activity");
    }
    for (ParsedReceiver r : pkg.getReceivers()) {
        mReceivers.removeActivity(r, "receiver");
    }
    for (ParsedService s : pkg.getServices()) {
        mServices.removeService(s);
    }
    for (ParsedProvider p : pkg.getProviders()) {
        mProviders.removeProvider(p);
        for (String authority : p.getAuthorities()) {
            if (mProvidersByAuthority.get(authority) == p) {
                mProvidersByAuthority.remove(authority);
            }
        }
    }
}

移除同时清理 ComponentName map、IntentFilter 桶和 authority map。Provider 删除时使用对象身份比较,避免旧 Provider 清理时误删已经接管 authority 的新对象。漏掉任一索引都会造成“组件已卸载但仍可解析”或“authority 指向失效对象”。

8. 快照读取 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/resolution/ComponentResolver.java

java
private final SnapshotCache<ComponentResolverApi> mSnapshot;

public ComponentResolverApi snapshot() {
    return mSnapshot.snapshot();
}

PMS 在构造 ComputerEngine 时获取 mComponentResolver.snapshot()。写线程继续修改可变 resolver,读线程使用快照中的 resolver API,从而避免一次查询跨越安装事务看到“Activity 已注册但 filter 尚未注册”的中间状态。

快照只解决 resolver 数据的一致读取;包的用户状态、可见性、组件 enabled 和跨 profile 规则仍由 Computer 与后置过滤负责。

9. 调试与排查 ​

  1. ComponentName 显式查找失败:检查组件是否进入对应 map,以及包状态是否仍存在。
  2. 隐式 Activity 无结果:先看 resolver 是否注册 filter,再看 IntentResolver 的 type/scheme/action 候选桶。
  3. Provider authority 失败:区分 authority 未注册、冲突被先占用、用户状态不可见和包状态为空。
  4. 卸载后仍能解析:检查 remove 是否同时清理 resolver filter 和 authority map。
  5. 安装后偶发看不到组件:确认查询使用的 Computer snapshot 是否在注册完成前创建。
  6. 多个 filter 产生重复:检查 Activity resolver 的 allowFilterResult,它按目标组件去重而不是按 filter 去重。

10. 源码阅读路线 ​

  1. ComponentResolver.addAllComponents/removeAllComponents:看包生命周期如何批量注册和注销。
  2. ComponentResolverBase:看四套 resolver 和 Provider authority 查询契约。
  3. ActivityIntentResolver.addActivity:理解组件精确 map 与 IntentFilter 索引的双写。
  4. IntentResolver.queryIntent/buildResolveList:继续阅读候选桶和过滤器匹配。
  5. ComponentResolver.snapshot 与 PackageManagerService 创建 ComputerEngine 的代码:确认读写隔离。
  6. ResolveIntentHelper:理解 ComponentResolver 返回候选后如何排序和选择。

ComponentResolver 的核心职责是维护“组件实体索引”和“IntentFilter 候选索引”的一致性。它不直接决定最终目标,也不替代用户状态或可见性检查;理解这条边界,才能正确定位注册、查询、卸载和快照相关问题。