广播的发送和接收过程
基于Android U,以无序广播为例
ContextImpl到AMS的调用过程
发送无序广播需要调用sendBroadcast()方法,它在ContextWrapper中实现。
1 |
|
mBase具体指向就是ContextImpl。
1 |
|
最终会调用AMS的broadcastIntentWithFeature()方法。
1 |
|
注释1处验证广播是否合法;
注释2处调用broadcastIntentLocked()。
verifyBroadcastLocked()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final Intent verifyBroadcastLocked(Intent intent) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) { // 1
throw new IllegalArgumentException("File descriptors passed in Intent");
}
int flags = intent.getFlags(); // 2
if (!mProcessesReady) {
// if the caller really truly claims to know what they're doing, go
// ahead and allow the broadcast without launching any receivers
if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { // 3
// This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.
} else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // 4
Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+ " before boot completion");
throw new IllegalStateException("Cannot broadcast before boot completed");
}
}
...
return intent;
}verifyBroadcastLocked()方法主要验证广播是否合法,注释1处验证intent是否有文件描述符。注释2处获得intent中的flag。注释3处如果系统正在启动过程中,判断如果flag设置为FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT(启动检查时只接受动态注册的广播接收者)则不做处理,如果不是则在注释4处判断如果flag没有设置为FLAG_RECEIVER_REGISTERED_ONLY(只接受动态注册的广播接收者)则会抛出异常。
broadcastIntentLocked()
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
68frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, excludedPackages, appOp,
BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
callingPid, callingUid, realCallingUid, realCallingPid, userId,
backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
BroadcastQueue.traceEnd(cookie);
return res;
}
final int broadcastIntentLockedTraced(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, String[] excludedPackages, int appOp,
BroadcastOptions brOptions, boolean ordered, boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
...
if (!ordered && NR > 0 && !mEnableModernQueue) {
...
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
registeredReceivers, resultToApp, resultTo, resultCode, resultData,
resultExtras, ordered, sticky, false, userId,
backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
callerAppProcessState); // 1
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
queue.enqueueBroadcastLocked(r); // 2
registeredReceivers = null;
NR = 0;
}
...
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
...
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId,
backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
callerAppProcessState); // 3
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
queue.enqueueBroadcastLocked(r); // 4
} else {
...
}
return ActivityManager.BROADCAST_SUCCESS;
}broadcastIntentLockedTraced代码较多,主要做了以下几件事情:
- 设置intent,处理不同的action;
- 粘性广播的处理;
- 发送动态注册的无序广播列表(注释1、2);
- 合并动态注册的有序广播列表和静态注册的广播列表,并发送(注释3、4)。
AMS到BroadcastReceiver的调用过程
1 |
|
注释1处判断是否是有序发送;
注释2处如果是无序广播,但是是静态注册的广播接收者,serialDispatch会被设置为true,按照有序广播发送流程来发送;
注释3处有序发送,注释4处将BroadcastRecord添加到有序广播队列中,注释5处发送广播;
注释6处将BroadcastRecord添加到无序广播队列中,注释7处发送广播。
1 |
|
注释1处如果已经处理过了,则返回;
注释2处向BroadcastHandler类型的mHandler对象发送了BROADCAST_INTENT_MSG类型的消息。
1 |
|
注释1处在handleMessage()方法中调用了processNextBroadcast()方法,方法对无序广播和有序广播分别进行处理,旨在将广播发送给广播接收者。
1 |
|
注释1处,从前面BroadcastHandler#handleMessage()中我们得知传入的参数fromMsg的值为true,因此在注释2处将
mBroadcastsScheduled设置为false,表示对于此前发来的BROADCAST_INTENT_MSG类型的消息已经处理了。
注释3处的mParallelBroadcasts列表用来存储无序广播,通过while循环将mParallelBroadcasts列表中的无序广播发送给对应的广播接收者。在注释4处获取每一个mParallelBroadcasts列表中存储的BroadcastRecord类型的r对象。在注释5处将这些r对象描述的广播发送给对应的广播接收者。
1 |
|
注释1处接着调用performReceiveLocked()。
1 |
|
注释1和注释2处的代码表示如果广播接收者所在的应用程序进程存在并且正在运行,则执行注释3处的代码,表示用广播接收者所在的应用程序进程来接收广播,这里thread指的是ApplicationThread。
1 |
|
调用了IIntentReceiver类型的对象receiver的performReceive()方法。IIntentReceiver用于广播的跨进程通信。调用LoadedApk.ReceiverDispatcher.InnerReceiver的performReceive()继续发送广播。
1 |
|
IIntentReceiver和IActivityManager一样,都使用了AIDL来实现进程间通信。InnerReceiver继承自IIntentReceiver.Stub,是Binder通信的服务器端,IIntentReceiver则是Binder通信的客户端、InnerReceiver在本地的代理,它的具体实现就是InnerReceiver。
注释1处调用了ReceiverDispatcher类型的rd对象的performReceive()方法。
1 |
|
注释1处将广播的intent等信息封装为Args对象,注释2处调用mActivityThread的post()方法并传入了Args对象。这个mActivityThread是一个Handler对象,具体指向的就是H,注释2处的代码就是将Args对象的getRunnable()方法通过H发送到线程的消息队列中。
1 |
|
注释1处执行了BroadcastReceiver类型的receiver对象的onReceive()方法,这样注册的广播接收者就收到了广播并得到了intent。