ComponentResolver 组件解析器
ComponentResolver 是 PMS 中保存组件解析索引的可变 owner。它不负责决定最终启动哪个 Activity,而是把包扫描得到的 Activity、Service、Receiver、Provider 和 IntentFilter 注册到四套 resolver,并在查询时生成候选 ResolveInfo。ComputerEngine 读取它的快照,IntentResolver 执行过滤器匹配,ResolveIntentHelper 再做最终选择。
1. 四套索引
| 组件 | resolver | 额外索引 |
|---|---|---|
| Activity | ActivityIntentResolver | ComponentName → ParsedActivity |
| Receiver | ReceiverIntentResolver | ComponentName → ParsedActivity |
| Service | ServiceIntentResolver | ComponentName → ParsedService |
| Provider | ProviderIntentResolver | ComponentName → 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
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
public void addAllComponents(AndroidPackage pkg, boolean chatty,
String setupWizardPackage, Computer computer) {
synchronized (mLock) {
addAllComponentsLocked(pkg, chatty, setupWizardPackage, computer);
}
}注册在 mLock 内完成,保证包扫描不会与查询同时观察半套组件。InstallPackageHelper 在安装/扫描完成后调用它;卸载路径对应 removeAllComponents。
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
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
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。
@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
@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
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
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. 调试与排查
- ComponentName 显式查找失败:检查组件是否进入对应 map,以及包状态是否仍存在。
- 隐式 Activity 无结果:先看 resolver 是否注册 filter,再看 IntentResolver 的 type/scheme/action 候选桶。
- Provider authority 失败:区分 authority 未注册、冲突被先占用、用户状态不可见和包状态为空。
- 卸载后仍能解析:检查 remove 是否同时清理 resolver filter 和 authority map。
- 安装后偶发看不到组件:确认查询使用的
Computersnapshot 是否在注册完成前创建。 - 多个 filter 产生重复:检查 Activity resolver 的
allowFilterResult,它按目标组件去重而不是按 filter 去重。
10. 源码阅读路线
ComponentResolver.addAllComponents/removeAllComponents:看包生命周期如何批量注册和注销。ComponentResolverBase:看四套 resolver 和 Provider authority 查询契约。ActivityIntentResolver.addActivity:理解组件精确 map 与 IntentFilter 索引的双写。IntentResolver.queryIntent/buildResolveList:继续阅读候选桶和过滤器匹配。ComponentResolver.snapshot与PackageManagerService创建ComputerEngine的代码:确认读写隔离。ResolveIntentHelper:理解 ComponentResolver 返回候选后如何排序和选择。
ComponentResolver 的核心职责是维护“组件实体索引”和“IntentFilter 候选索引”的一致性。它不直接决定最终目标,也不替代用户状态或可见性检查;理解这条边界,才能正确定位注册、查询、卸载和快照相关问题。
