- PMS 在系统运行过程中,很重要的一项工作就是通过 Intent 来查询组件信息。系统中响应 Intent 的组件有多个,所以返回的是列表而不是单个(比如 intent 启动的时候会让你自己选择启动哪个app,多个地图软件,多个邮箱软件等),查到的组件都是用类 ResolveInfo 来表示的,为了统一所有的组件都通过它来表示;
PMS 中 Intent查询接口如下
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(
queryIntentActivitiesInternal(intent, resolvedType, flags, userId));
}
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(
queryIntentReceiversInternal(intent, resolvedType, flags, userId,
false /*allowDynamicSplits*/));
}
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
String resolvedType, int flags, int userId) {
final int callingUid = Binder.getCallingUid();
return new ParceledListSlice<>(queryIntentServicesInternal(
intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
}
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(
queryIntentContentProvidersInternal(intent, resolvedType, flags, userId));
}
- ResolveInfo 结构如下:
public class ResolveInfo implements Parcelable {
private static final String TAG = "ResolveInfo";
/**
* The activity or broadcast receiver that corresponds to this resolution
* match, if this resolution is for an activity or broadcast receiver.
* Exactly one of {@link #activityInfo}, {@link #serviceInfo}, or
* {@link #providerInfo} will be non-null.
*/
public ActivityInfo activityInfo;
/**
* The service that corresponds to this resolution match, if this resolution
* is for a service. Exactly one of {@link #activityInfo},
* {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
*/
public ServiceInfo serviceInfo;
/**
* The provider that corresponds to this resolution match, if this
* resolution is for a provider. Exactly one of {@link #activityInfo},
* {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
*/
public ProviderInfo providerInfo;
/**
* An auxiliary response that may modify the resolved information. This is
* only set under certain circumstances; such as when resolving instant apps
* or components defined in un-installed splits.
* @hide
*/
public AuxiliaryResolveInfo auxiliaryInfo;
// ....
// ....
}
- 下面以查找 queryIntentActivities 为例
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits) {
// 检查用户调用接口的权限
if (!sUserManager.exists(userId)) return Collections.emptyList();
final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
final String pkgName = intent.getPackage();
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/);
// 如果已经指定了 模块和组件名称,那么只会有一个结果
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
// ...
if (!blockResolution) {
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
}
// 调用 applyPostResolutionFilter 查找
return applyPostResolutionFilter(
list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent);
}
// reader
boolean sortResult = false;
boolean addInstant = false;
List<ResolveInfo> result;
synchronized (mPackages) {
// 如果 pkgName 未设置 则需要去系统的所有包中查找
if (pkgName == null) {
// 获取所有匹配的 intent filter
List<CrossProfileIntentFilter> matchingFilters =
getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
// Check for results that need to skip the current profile.
// 检查带有 SKIP_CURRENT_PROFILE 标志的 filter
ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
resolvedType, flags, userId);
if (xpResolveInfo != null) {
// 优先匹配 SKIP_CURRENT_PROFILE 的 filter
List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
xpResult.add(xpResolveInfo);
return applyPostResolutionFilter(
filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
}
// 继续查找
// Check for results in the current profile.
result = filterIfNotSystemUser(mActivities.queryIntent(
intent, resolvedType, flags, userId), userId);
addInstant = isInstantAppResolutionAllowed(intent, result, userId,
false /*skipPackageCheck*/);
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
xpResolveInfo = queryCrossProfileIntents(
matchingFilters, intent, resolvedType, flags, userId,
hasNonNegativePriorityResult);
if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
boolean isVisibleToUser = filterIfNotSystemUser(
Collections.singletonList(xpResolveInfo), userId).size() > 0;
if (isVisibleToUser) {
result.add(xpResolveInfo);
sortResult = true;
}
}
// 如果有webUri
if (intent.hasWebURI()) {
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 && !addInstant) {
// No result in current profile, but found candidate in parent user.
// And we are not going to add emphemeral app, so we can return the
// result straight away.
result.add(xpDomainInfo.resolveInfo);
return applyPostResolutionFilter(result, instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart, userId,
intent);
}
} else if (result.size() <= 1 && !addInstant) {
// No result in parent user and <= 1 result in current profile, and we
// are not going to add emphemeral app, so we can return the result without
// further processing.
return applyPostResolutionFilter(result, instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart, userId,
intent);
}
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
result = filterCandidatesWithDomainPreferredActivitiesLPr(
intent, flags, result, xpDomainInfo, userId);
sortResult = true;
}
} else {
// 如果有包名的话 在指定包中查找
final PackageParser.Package pkg = mPackages.get(pkgName);
result = null;
if (pkg != null) {
// 如果有 pkgName 查找到了 直接在通过指定包地址查找就行了
result = filterIfNotSystemUser(
mActivities.queryIntentForPackage(
intent, resolvedType, flags, pkg.activities, userId),
userId);
}
if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
// 否则 则一个包下一个包下查找 这是最慢的查询方式
addInstant = isInstantAppResolutionAllowed(
intent, null /*result*/, userId, true /*skipPackageCheck*/);
if (result == null) {
result = new ArrayList<>();
}
}
}
}
if (addInstant) {
result = maybeAddInstantAppInstaller(
result, intent, resolvedType, flags, userId, resolveForStart);
}
if (sortResult) {
Collections.sort(result, mResolvePrioritySorter);
}
return applyPostResolutionFilter(
result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent);
}
最后都是通过 applyPostResolutionFilter 返回,里面通过一些过滤掉一些不应该返回的 info