广播的注册过程

基于Android U

广播的注册通俗来讲就是广播接收者注册自己感兴趣的广播。想要动态注册广播,需要调用registerReceiver方法,它在ContextWrapper中实现。

1
2
3
4
frameworks/base/core/java/android/content/ContextWrapper.java
public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}

mBase具体指向就是ContextImpl,ContextImpl的registerReceiver()方法有很多重载的方法,最终会调用registerReceiverInternal()方法。

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
frameworks/base/core/java/android/app/ContextImpl.java
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) { // 1
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true); // 2
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
receiver, context, scheduler, null, true).getIIntentReceiver(); // 3
}
}
try {
final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
flags); // 4
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
getAttributionSource());
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

注释1处判断如果LoadedApk类型的mPackageInfo不等于null,并且context不等于null就调用注释2处的代码,通过mPackageInfo的getReceiverDispatcher()方法获取rd对象,否则就调用注释3处的代码来创建rd对象。注释2和注释3处的代码的目的都是要获取IIntentReceiver类型的rd对象,IIntentReceiver是一个Binder接口,用于广播的跨进程的通信,它在LoadedApk.ReceiverDispatcher.InnerReceiver中实现。

注释4处调用了IActivityManager的registerReceiverWithFeature()方法,最终会调用AMS的registerReceiverWithFeature()方法,并将IIntentReceiver类型的rd传进去,这里之所以不直接传入BroadcastReceiver而是传入IIntentReceiver,是因为注册广播是一个跨进程通信过程,需要具有跨进程通信能力的IIntentReceiver。

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
109
110
111
112
113
114
115
116
117
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
return registerReceiverWithFeature(caller, callerPackage, null, null,
receiver, filter, permission, userId, flags);
}

public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
...
ArrayList<StickyBroadcast> stickyBroadcasts = null;
ProcessRecord callerApp = null;
...

int callingUid;
int callingPid;
boolean instantApp;
synchronized(this) {
callerApp = getRecordForAppLOSP(caller); // 1
...
Iterator<String> actions = filter.actionsIterator(); // 2
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
boolean onlyProtectedBroadcasts = true;

// Collect stickies of users and check if broadcast is only registered for protected
// broadcasts
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap<String, ArrayList<StickyBroadcast>> stickies =
mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList<StickyBroadcast> broadcasts = stickies.get(action);
if (broadcasts != null) {
if (stickyBroadcasts == null) {
stickyBroadcasts = new ArrayList<>();
}
stickyBroadcasts.addAll(broadcasts); // 3
}
}
}
...
}
...
}

// Dynamic receivers are exported by default for versions prior to T
final boolean exported = (flags & Context.RECEIVER_EXPORTED) != 0;

ArrayList<StickyBroadcast> allSticky = null;
if (stickyBroadcasts != null) {
final ContentResolver resolver = mContext.getContentResolver();
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyBroadcasts.size(); i < N; i++) {
final StickyBroadcast broadcast = stickyBroadcasts.get(i);
Intent intent = broadcast.intent;
// Don't provided intents that aren't available to instant apps.
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
// If intent has scheme "content", it will need to access
// provider that needs to lock mProviderMap in ActivityThread
// and also it may need to wait application response, so we
// cannot lock ActivityManagerService here.
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<>();
}
allSticky.add(broadcast); // 4
}
}
}

...

synchronized (this) {
...
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); // 5
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver); // 6
if (rl.app != null) {
...
rl.app.mReceivers.addReceiver(rl);
} else {
...
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
...
} else if (rl.pid != callingPid) {
...
} else if (rl.userId != userId) {
...
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
exported); // 7
if (rl.containsFilter(filter)) {
...
} else {
rl.add(bf); // 8
...
mReceiverResolver.addFilter(getPackageManagerInternal().snapshot(), bf); // 9
}
...
return sticky;
}
}

注释1处通过getRecordForAppLOSP()方法得到ProcessRecord类型的callerApp对象,它用于描述请求AMS注册广播接收者的Activity所在的应用程序进程。

在注释2处根据传入的IntentFilter类型filter得到actions列表,根据actions列表和userIds(userIds可以理解为应用程序的uid)得到所有的粘性广播的StickyBroadcast(StickyBroadcast里存了粘性广播的状态,包括Intent),并在注释3处传入到stickyBroadcasts中。接下来从stickyBroadcasts中找到匹配传入的参数filter的粘性广播的intent,在注释4处将这些intent存入到allSticky列表中,从这里可以看出粘性广播是存储在AMS中的。

注释5处获取ReceiverList列表,如果为空则在注释6处创建,ReceiverList继承自ArrayList,用来存储广播接收者。

在注释7处创建BroadcastFilter并传入此前创建的ReceiverList,BroadcastFilter用来描述注册的广播接收者,并在注释8处通过add()方法将自身添加到ReceiverList中。在注释9处将BroadcastFilter添加到IntentResolver类型的mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了,从而达到了注册广播的目的。


广播的注册过程
https://citrus-maxima.github.io/2024/03/10/广播的注册过程/
作者
柚子树
发布于
2024年3月10日
许可协议