广播的发送和接收过程

基于Android U,以无序广播为例

ContextImpl到AMS的调用过程

发送无序广播需要调用sendBroadcast()方法,它在ContextWrapper中实现。

1
2
3
4
frameworks/base/core/java/android/content/ContextWrapper.java
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}

mBase具体指向就是ContextImpl。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
frameworks/base/core/java/android/app/ContextImpl.java
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
null, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

最终会调用AMS的broadcastIntentWithFeature()方法。

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
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, String[] excludedPermissions,
String[] excludedPackages, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent); // 1
final ProcessRecord callerApp = getRecordForAppLOSP(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();

// We're delivering the result to the caller
final ProcessRecord resultToApp = callerApp;

// Permission regimes around sender-supplied broadcast options.
enforceBroadcastOptionPermissionsInternal(bOptions, callingUid);

final long origId = Binder.clearCallingIdentity();
try {
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
appOp, bOptions, serialized, sticky, callingPid, callingUid, callingUid,
callingPid, userId, BackgroundStartPrivileges.NONE, null, null); // 2
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}

注释1处验证广播是否合法;

注释2处调用broadcastIntentLocked()。

  1. verifyBroadcastLocked()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    frameworks/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(只接受动态注册的广播接收者)则会抛出异常。

  2. 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
    68
    frameworks/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代码较多,主要做了以下几件事情:

    1. 设置intent,处理不同的action;
    2. 粘性广播的处理;
    3. 发送动态注册的无序广播列表(注释1、2);
    4. 合并动态注册的有序广播列表和静态注册的广播列表,并发送(注释3、4)。

AMS到BroadcastReceiver的调用过程

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
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl.java
public void enqueueBroadcastLocked(BroadcastRecord r) {
...
// Ordered broadcasts obviously need to be dispatched in serial order,
// but this implementation expects all manifest receivers to also be
// dispatched in a serial fashion
boolean serialDispatch = r.ordered; // 1
if (!serialDispatch) {
final int N = (r.receivers != null) ? r.receivers.size() : 0;
for (int i = 0; i < N; i++) {
if (r.receivers.get(i) instanceof ResolveInfo) {
serialDispatch = true; // 2
break;
}
}
}

if (serialDispatch) { // 3
final BroadcastRecord oldRecord =
replacePending ? replaceOrderedBroadcastLocked(r) : null;
if (oldRecord != null) {
// Replaced, fire the result-to receiver.
if (oldRecord.resultTo != null) {
...
}
} else {
enqueueOrderedBroadcastLocked(r); // 4
scheduleBroadcastsLocked(); // 5
}
} else {
final boolean replaced = replacePending
&& (replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
enqueueParallelBroadcastLocked(r); // 6
scheduleBroadcastsLocked(); // 7
}
}
}

注释1处判断是否是有序发送;

注释2处如果是无序广播,但是是静态注册的广播接收者,serialDispatch会被设置为true,按照有序广播发送流程来发送;

注释3处有序发送,注释4处将BroadcastRecord添加到有序广播队列中,注释5处发送广播;

注释6处将BroadcastRecord添加到无序广播队列中,注释7处发送广播。

1
2
3
4
5
6
7
8
9
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl.java
public void scheduleBroadcastsLocked() {
...
if (mBroadcastsScheduled) { // 1
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); // 2
mBroadcastsScheduled = true;
}

注释1处如果已经处理过了,则返回;

注释2处向BroadcastHandler类型的mHandler对象发送了BROADCAST_INTENT_MSG类型的消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl$BroadcastHandler

private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+ mQueueName + "]");
processNextBroadcast(true); // 1
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}

注释1处在handleMessage()方法中调用了processNextBroadcast()方法,方法对无序广播和有序广播分别进行处理,旨在将广播发送给广播接收者。

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
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl.java
private void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}

public void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
...
if (fromMsg) { // 1
mBroadcastsScheduled = false; // 2
}

// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) { // 3
r = mParallelBroadcasts.remove(0); // 4
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
r.mIsReceiverAppRunning = true;
...
final int N = r.receivers.size();
...
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
....
deliverToRegisteredReceiverLocked(r,
(BroadcastFilter) target, false, i); // 5
}
...
}
...
}

注释1处,从前面BroadcastHandler#handleMessage()中我们得知传入的参数fromMsg的值为true,因此在注释2处将

mBroadcastsScheduled设置为false,表示对于此前发来的BROADCAST_INTENT_MSG类型的消息已经处理了。

注释3处的mParallelBroadcasts列表用来存储无序广播,通过while循环将mParallelBroadcasts列表中的无序广播发送给对应的广播接收者。在注释4处获取每一个mParallelBroadcasts列表中存储的BroadcastRecord类型的r对象。在注释5处将这些r对象描述的广播发送给对应的广播接收者。

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
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
...

try {
...
final boolean isInFullBackup = (filter.receiverList.app != null)
&& filter.receiverList.app.isInFullBackup();
final boolean isKilled = (filter.receiverList.app != null)
&& filter.receiverList.app.isKilled();
if (isInFullBackup || isKilled) {
...
} else {
...
performReceiveLocked(r, filter.receiverList.app, filter.receiverList.receiver,
prepareReceiverIntent(r.intent, filteredExtras), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.shareIdentity, r.userId,
filter.receiverList.uid, r.callingUid, r.callerPackage,
r.dispatchTime - r.enqueueTime,
r.receiverTime - r.dispatchTime, filter.getPriority(),
filter.receiverList.app != null
? filter.receiverList.app.mState.getCurProcState()
: ActivityManager.PROCESS_STATE_UNKNOWN); // 1
...
}
...
} catch (RemoteException e) {
...
}
}

注释1处接着调用performReceiveLocked()。

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
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl.java
public void performReceiveLocked(BroadcastRecord r, ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, boolean shareIdentity, int sendingUser,
int receiverUid, int callingUid, String callingPackage,
long dispatchDelay, long receiveDelay, int priority,
int receiverProcessState) throws RemoteException {
...
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) { // 1
final IApplicationThread thread = app.getThread();
if (thread != null) { // 2
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
final boolean assumeDelivered = !ordered;
thread.scheduleRegisteredReceiver(
receiver, intent, resultCode,
data, extras, ordered, sticky, assumeDelivered, sendingUser,
app.mState.getReportedProcState(),
shareIdentity ? callingUid : Process.INVALID_UID,
shareIdentity ? callingPackage : null); // 3
} catch (RemoteException ex) {
...
}
} else {
...
}
} else {
...
}
...
}

注释1和注释2处的代码表示如果广播接收者所在的应用程序进程存在并且正在运行,则执行注释3处的代码,表示用广播接收者所在的应用程序进程来接收广播,这里thread指的是ApplicationThread。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
frameworks/base/core/java/android/app/ActivityThread$ApplicationThread
private class ApplicationThread extends IApplicationThread.Stub {
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, boolean assumeDelivered, int sendingUser, int processState,
int sendingUid, String sendingPackage)
throws RemoteException {
...
if (receiver instanceof LoadedApk.ReceiverDispatcher.InnerReceiver) {
((LoadedApk.ReceiverDispatcher.InnerReceiver) receiver).performReceive(intent,
resultCode, dataStr, extras, ordered, sticky, assumeDelivered, sendingUser,
sendingUid, sendingPackage);
} else {
...
receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky,
sendingUser);
}
}
}

调用了IIntentReceiver类型的对象receiver的performReceive()方法。IIntentReceiver用于广播的跨进程通信。调用LoadedApk.ReceiverDispatcher.InnerReceiver的performReceive()继续发送广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
frameworks/base/core/java/android/app/LoadedApk$ReceiverDispatcher.InnerReceiver
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,
int sendingUser, int sendingUid, String sendingPackage) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
...
} else {
rd = mDispatcher.get();
}
...
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, assumeDelivered, sendingUser,
sendingUid, sendingPackage); // 1
} else if (!assumeDelivered) {
...
}
}
}
}

IIntentReceiver和IActivityManager一样,都使用了AIDL来实现进程间通信。InnerReceiver继承自IIntentReceiver.Stub,是Binder通信的服务器端,IIntentReceiver则是Binder通信的客户端、InnerReceiver在本地的代理,它的具体实现就是InnerReceiver。

注释1处调用了ReceiverDispatcher类型的rd对象的performReceive()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
frameworks/base/core/java/android/app/LoadedApk$ReceiverDispatcher
static final class ReceiverDispatcher {
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,
int sendingUser, int sendingUid, String sendingPackage) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, assumeDelivered, sendingUser, sendingUid, sendingPackage); // 1
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ " seq=" + seq + " to " + mReceiver);
}
}
if (intent == null || !mActivityThread.post(args.getRunnable())) { // 2
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}

注释1处将广播的intent等信息封装为Args对象,注释2处调用mActivityThread的post()方法并传入了Args对象。这个mActivityThread是一个Handler对象,具体指向的就是H,注释2处的代码就是将Args对象的getRunnable()方法通过H发送到线程的消息队列中。

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
frameworks/base/core/java/android/app/LoadedApk$ReceiverDispatcher.Args
static final class ReceiverDispatcher {
final class Args extends BroadcastReceiver.PendingResult {
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
...
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
mContext.getAttributionSource());
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent); // 1
} catch (Exception e) {
...
}
...
};
}
}
}

注释1处执行了BroadcastReceiver类型的receiver对象的onReceive()方法,这样注册的广播接收者就收到了广播并得到了intent。


广播的发送和接收过程
https://citrus-maxima.github.io/2024/03/09/广播的发送和接收过程/
作者
柚子树
发布于
2024年3月9日
许可协议