[toc]
本文基于 Android 7.1.1 源码,分析 BroadcastReceiver 的静态注册过程,转载请说明出处,谢谢!
0 综述
广播接收者除了动态注册之外,还有静态注册,就是在 AndroidManifest.xml 文件中进行配置!
1 | <receiver |
我们来简单地看看这些属性的意思:
- android:enabled:此 broadcastReceiver 是否可用,默认值为 true。
- android:exported:此 broadcastReceiver 能否接收其它 App 的发出的广播,如果标签中定义了 intent-filter 字段,则此值默认值为 true,否则为 false。
- android:name:此 BroadcastReceiver 的组件名。
- android:permission:广播发送方应该具有的权限;
- android:process:表示 broadcastReceiver 运行的进程,BroadcastReceiver 默认运行在当前 app 的进程中,也可以通过此字段指定其运行于其它独立的进程。
- intent-filter:用于指定该broadcastReceiver接收广播的类型。
静态注册的 BroadcastReceiver 不能作为内部类,必须要单独作为一个 BroadcastReceiver.java 文件!
其实,如果大家对于 PMS 熟悉的话,应该很清楚了,对于静态注册的方式,是会通过 PMS 的解析来获得 BroadcastReceiver 的信息的!!下面我们就到 PMS 中去看看:
1 PackageParser.parseBaseApplication - 解析 application
解析的关键的代码段如下,我们简单的回顾下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
... ... ... ...
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, flags, outError, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a);
//【2.1】解析 "receiver",获得静态注册的广播接收者的信息!
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
//【1】将解析到的 receiver 加入到 Package owner 中!
owner.receivers.add(a);
}
... ... ...
}
... ... ... ...
}
可以看到,这里会解析静态注册的广播接收者,并将其信息封装成 Activity 对象保存到了 Package.receivers 对象中去!
我们进入到 PackageParser 的 parseActivity 中去看看!
2.1 PackageParser.parseActivity
1 | private Activity parseActivity(Package owner, Resources res, |
2.2 PackageParser.parseIntent
我们来看看 parseIntent 方法中做过了些什么!
1 | private boolean parseIntent(Resources res, XmlResourceParser parser, |
其实看到这里,我们已经能够看出静态注册的 broadcastReceiver 是如何被 PMS 解析了,解析的数据都会被保存到 PackageParser.Package 中!
2 PMS.scanPackageDirtyLI
接下来,PMS 会进一步处理解析的数据!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
... ... ...
//【1】将解析到的 BroadcastRecord 数据保存到 PMS 的内部变量 mReceivers 中!
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
//【2】获得该 package 中静态注册的广播接收者的信息对象 Activity;
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
//【3】添加到 PMS.mReceivers 中;
mReceivers.addActivity(a, "receiver");
if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
... ...
}
将之前是扫描解析到的信息对象 Activity,保存到 PMS.mReceivers 对象中,mReceivers 是一个 ActivityIntentResolver 类的对象,用于保存系统中定义的所有的静态接收者:
1 | // All available receivers, for your resolving pleasure. |
我们继续分析!
2.1 PMS.ActivityIntentResolver
我们来看下 ActivityIntentResolver 是如何处理静态接收者的注册的!
1 | final class ActivityIntentResolver |
ActivityIntentResolver 继承了 IntentResolver,IntentResolver 是一个模板类:
2.2 IntentResolver.addFilter
这里 F 是 PackageParser.ActivityIntentInfo, R 是 ResolveInfo:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
//【1】调用了 addFilter 方法!
public void addFilter(F f) {
if (localLOGV) {
Slog.v(TAG, "Adding filter: " + f);
f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
Slog.v(TAG, " Building Lookup Maps:");
}
//【2】添加到内部总集合 mFilters 中!
mFilters.add(f);
//【3】根据 filter 属性配置,添加到不同的子集合中!
//【3.1】处理 Scheme;
int numS = register_intent_filter(f, f.schemesIterator(),
mSchemeToFilter, " Scheme: ");
//【3.2】处理 Type;
int numT = register_mime_types(f, " Type: ");
//【3.3】处理 Action;
if (numS == 0 && numT == 0) {
register_intent_filter(f, f.actionsIterator(),
mActionToFilter, " Action: ");
}
//【3.4】处理 TypedAction;
if (numT != 0) {
register_intent_filter(f, f.actionsIterator(),
mTypedActionToFilter, " TypedAction: ");
}
}
private final ArraySet<F> mFilters = new ArraySet<F>(); // 所有注册的 filter
}
这里我们就是实现了对静态注册的广播接收者的处理!!
2.2.1 IntentResolver.register_intent_filter
register_intent_filter 用于注册 filter ,并返回注册的数量,对于参数,我们以 mSchemeToFilter 为例:
F filter:这里是我们解析的 intentFilter 的 ActivityIntentInfo 对象!
Iterator
ArrayMap<String, F[]> dest:是我们要加入集合,这里是 mSchemeToFilter;
String prefix:用于 log,不过多关注!
1 | private final int register_intent_filter(F filter, Iterator<String> i, |
2.2.2 IntentResolver.addFilter
1 | private final void addFilter(ArrayMap<String, F[]> map, String name, F filter) { |
当我们要发送广播时,是要查找当前系统中所有已经静态注册的广播接收者的,那么我们去看看查询相关的方法:
3 PMS.queryIntentReceivers - 查询静态接收者
查询静态注册的广播接收者方法如下:1
2
3
4
5
6
7
public ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(
queryIntentReceiversInternal(intent, resolvedType, flags, userId));
}
最终会调用:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49private List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
String resolvedType, int flags, int userId) {
//【1】如果不存在这个设备用户 id,就返回一个数据为 null 的 list;
if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
//【2】如果 Intent 设置了组件名,就通过组件名直接获取!
if (comp != null) {
List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
//【3.1】创建 ResolveInfo 的 list 列表,用于保存匹配结果!
ActivityInfo ai = getReceiverInfo(comp, flags, userId);
if (ai != null) {
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
return list;
}
synchronized (mPackages) {
//【2】如果 Intent 没有设置组件名和包名,就调用 queryIntent 进行查询!
String pkgName = intent.getPackage();
if (pkgName == null) {
//【3.2】使用 queryIntent 方法!
return mReceivers.queryIntent(intent, resolvedType, flags, userId);
}
//【3】如果 Intent 没有设置组件名,但是设置了包名,就通过之前的扫描解析信息,查询!
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
//【3.3】使用 queryIntentForPackage 根据包名查询,mReceivers 中保存了解析到的所有的;
return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
userId);
}
return Collections.emptyList();
}
}
下面我们一个一个去看看:
3.1 PackageManagerS.getReceiverInfo - 组件名查询
1 |
|
继续看:
3.1.1 PackageParser.generateActivityInfo
1 | public static final ActivityInfo generateActivityInfo(Activity a, int flags, |
这里很简单,返回了之前解析获得的广播接收者的 ActivityInfo 对象 ai!
然后,创建 ResolveInfo ri = new ResolveInfo() 对象,然后初始化 ri.activityInfo = ai,将 ResolveInfo 对象 ri 添加到 List
3.2 ActivityIntentResolver.queryIntent - 意图匹配查询
这里先会调用子类 ActivityIntentResolver 的 queryIntent 方法!
1 | public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, |
进入父类 IntentResolver:
3.2.1 IntentResolver.queryIntent
这里的模板参数 R 为 ResolveInfo 类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
int userId) {
String scheme = intent.getScheme();
//【1】最终要返回的 ArrayList<R> list 集合!
ArrayList<R> finalList = new ArrayList<R>();
final boolean debug = localLOGV ||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
if (debug) Slog.v(
TAG, "Resolving type=" + resolvedType + " scheme=" + scheme
+ " defaultOnly=" + defaultOnly + " userId=" + userId + " of " + intent);
F[] firstTypeCut = null;
F[] secondTypeCut = null;
F[] thirdTypeCut = null;
F[] schemeCut = null;
//【2】如果 intent 包含一个 MIME type,我们会手机所有能匹配该 MIME 的 filters!
// MIME 是描述消息内容类型的因特网标准,格式如下:application/pdf
if (resolvedType != null) {
int slashpos = resolvedType.indexOf('/');
//【2.1】校验指定的 MIME 的格式是否正确,必须要有 / 隔开!
if (slashpos > 0) {
//【2.1.1】获得 MIME 的前半部分:application,针对其取值做不同的处理!
final String baseType = resolvedType.substring(0, slashpos);
if (!baseType.equals("*")) {
//【2.1.1.1】如果 baseType 不为 *,说明 intent 可能指定了一个 MIME,接下来,我们继续处理!
if (resolvedType.length() != slashpos+2
|| resolvedType.charAt(slashpos+1) != '*') {
// Not a wild card, so we can just look for all filters that
// completely match or wildcards whose base type matches.
//【2.1.1.1.1】如果 resolvedType
firstTypeCut = mTypeToFilter.get(resolvedType);
if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));
secondTypeCut = mWildTypeToFilter.get(baseType);
if (debug) Slog.v(TAG, "Second type cut: "
+ Arrays.toString(secondTypeCut));
} else {
//【2.1.1.1.2】如果 resolvedType 的长度等于 slashpos + 2,且 slashpos + 1 为 "*"
// 那么其能够匹配所有的 "baseType/*"
firstTypeCut = mBaseTypeToFilter.get(baseType);
if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTypeCut));
secondTypeCut = mWildTypeToFilter.get(baseType);
if (debug) Slog.v(TAG, "Second type cut: "
+ Arrays.toString(secondTypeCut));
}
// Any */* types always apply, but we only need to do this
// if the intent type was not already */*.
thirdTypeCut = mWildTypeToFilter.get("*");
if (debug) Slog.v(TAG, "Third type cut: " + Arrays.toString(thirdTypeCut));
} else if (intent.getAction() != null) {
//【2.1.1.2】如果 baseType 为 *,说明是通过正则表达式匹配任何类型的 filters
// 这种情况会有风险,那就使用 action 来匹配!
firstTypeCut = mTypedActionToFilter.get(intent.getAction());
if (debug) Slog.v(TAG, "Typed Action list: " + Arrays.toString(firstTypeCut));
}
}
}
//【3】如果 intent 设置了 scheme(data URI),收集所有能匹配该 scheme 的 filter!
if (scheme != null) {
schemeCut = mSchemeToFilter.get(scheme);
if (debug) Slog.v(TAG, "Scheme list: " + Arrays.toString(schemeCut));
}
//【4】intent 没有设置 Scheme 和 MIME,那就匹配 action!
if (resolvedType == null && scheme == null && intent.getAction() != null) {
firstTypeCut = mActionToFilter.get(intent.getAction());
if (debug) Slog.v(TAG, "Action list: " + Arrays.toString(firstTypeCut));
}
//【3.4】开始进一步的匹配,将结果保存到 finalList 中!
FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
if (firstTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, firstTypeCut, finalList, userId);
}
if (secondTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, secondTypeCut, finalList, userId);
}
if (thirdTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, thirdTypeCut, finalList, userId);
}
if (schemeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, schemeCut, finalList, userId);
}
//【3.5】对结果进行过滤;
filterResults(finalList);
//【3.6】对结果进行排序;
sortResults(finalList);
if (debug) {
Slog.v(TAG, "Final result list:");
for (int i=0; i<finalList.size(); i++) {
Slog.v(TAG, " " + finalList.get(i));
}
}
return finalList;
}
最后返回匹配的 intent filter!
3.3 ActivityIntentResolver.queryIntentForPackage - 包名查询
参数:
- ArrayList<PackageParser.Activity> packageActivities:传入 PackageParser.Package.receivers list 集合!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {
//【1】userId 不存在,返回 null;
if (!sUserManager.exists(userId)) return null;
//【2】如果 packageActivities 为 null,返回 null;
if (packageActivities == null) {
return null;
}
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int N = packageActivities.size();
ArrayList<PackageParser.ActivityIntentInfo[]> listCut =
new ArrayList<PackageParser.ActivityIntentInfo[]>(N);
//【3】这里是找到 packageActivities 列表中所有 Activity 对象的 ActivityIntentInfo 数组!
// 将其收集起来,保存到 listCut 列表中!
ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
for (int i = 0; i < N; ++i) {
intentFilters = packageActivities.get(i).intents;
if (intentFilters != null && intentFilters.size() > 0) {
PackageParser.ActivityIntentInfo[] array =
new PackageParser.ActivityIntentInfo[intentFilters.size()];
intentFilters.toArray(array);
listCut.add(array);
}
}
//【3.3.1】调用父类的 queryIntentFromList 方法继续查询!
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
进入父类 IntentResolver 中:
3.3.1 ActivityIntentResolver.queryIntentFromList
这里的模板参数 R 为 ResolveInfo 类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public List<R> queryIntentFromList(Intent intent, String resolvedType,
boolean defaultOnly, ArrayList<F[]> listCut, int userId) {
//【1】用于保存查询的结果!
ArrayList<R> resultList = new ArrayList<R>();
final boolean debug = localLOGV ||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
final String scheme = intent.getScheme();
int N = listCut.size();
for (int i = 0; i < N; ++i) {
//【3.4】遍历 ArrayList<PackageParser.ActivityIntentInfo[]> 列表 listCut
// 处理每一个 ActivityIntentInfo 数组,也就是 IntentFliter 数组!
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, listCut.get(i), resultList, userId);
}
filterResults(resultList);
//【3】对结果进行排序!
sortResults(resultList);
return resultList;
}
3.4 IntentResolver.buildResolveList
下面我们来看一下,查询静态注册的广播接收者信息的最重要的一个方法,如何通过 ActivityIntentInfo[]
数组 src,生成 List<ResolveList>
列表 dest:
1 | private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories, |
这个方法流程很简单,我们来看一些细节!
3.4.1 ActivityIntentResolver ActivityIntentResolver.isFilterStopped
1 |
|
isFilterStopped 方法用来判断 filter 所属的应用是否被强行停止了,返回 true 的情况如下:
- 设备用户 id 不存在;
- filter 所属的应用是非系统应用,且应用的 stoped 属性被置为 true;
该方法返回 true,表示该应用在该设备用户下,被强制停止了!
3.4.2 ActivityIntentResolver.isPackageForFilter
1 |
|
这个方法很简单,不用多说了,就是判断 Intent 设置的包名和 filter 所属的应用的包名是不是一样的!一样的话,说明该应用是广播的目标应用!
3.4.3 ActivityIntentResolver.allowFilterResult
1 |
|
该方法的作用是是否重复添加过同一个 filter,判断依据是:要被添加的 filter 的组件名和包名是否和 dest 集合中的某个 filter 一样!!
ActivityInfo 是对应组件的信息对象,ActivityInfo.name 这个值来自于 android:name 属性!!
3.4.4 ActivityIntentResolver.newResult
最后,就是将 ActivityIntentInfo 对象封装为 ResolveInfo 对象了!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
int match, int userId) {
//【1】如果设备用户不存在,返回 null;
if (!sUserManager.exists(userId)) return null;
if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
return null;
}
final PackageParser.Activity activity = info.activity;
PackageSetting ps = (PackageSetting) activity.owner.mExtras;
if (ps == null) {
return null;
}
//【2】获得组件新的 ActivityInfo 拷贝对象 ai!
ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags,
ps.readUserState(userId), userId);
if (ai == null) {
return null;
}
//【3】创建一个 ResolveInfo 对象 res,并设置 res.activityInfo 为 ai;
final ResolveInfo res = new ResolveInfo();
res.activityInfo = ai;
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = info;
}
if (info != null) {
res.handleAllWebDataURI = info.handleAllWebDataURI();
}
res.priority = info.getPriority();
res.preferredOrder = activity.owner.mPreferredOrder;
//System.out.println("Result: " + res.activityInfo.className +
// " = " + res.priority);
res.match = match;
res.isDefault = info.hasDefault;
res.labelRes = info.labelRes;
res.nonLocalizedLabel = info.nonLocalizedLabel;
if (userNeedsBadging(userId)) {
res.noResourceId = true;
} else {
res.icon = info.icon;
}
res.iconResourceId = info.icon;
//【4】是否是系统应用!
res.system = res.activityInfo.applicationInfo.isSystemApp();
//【5】返回我们创建的新的 ResolveInfo 对象!
return res;
}
到这里,我们就知道了如何查询系统中所有注册过的广播接收者了!
4 总结!
我们来看看广播的静态注册的类关系图:
4.1 静态注册类关系图
PMS 解析了静态注册的广播接收者后,数据结婚间的关系图如下: