Skytoby

BroadcastCast广播机制原理

BroadcastCast广播机制原理

基于Android10.0,分析广播机制的原理

一、概述

广播(BroadcastCast)用于进程/线程间的通信,广播有发送广播和接收广播两部分组成,其中广播接收者BroadcastReceiver是四大组件之一。

BroadcastReceiver分为两类:

  • 静态广播:通过AndroidManifeset.xml的标签来注册BroadcastReceiver。

  • 动态广播:通过AMS.registeredReceiver方式注册BroadcastReceiver,动态注册相对静态注册更加的灵活,在不需要时通过unregisteredReceiver来取消注册。

从广播的发送方式分为四种:

  • 普通广播:完全异步的广播,在广播发出之后,所有的广播接收器几乎在同一时刻接收到这条广播消息,接收的先后顺序是随机的。通过Context.sendBroadcast发送。

  • 有序广播:同步执行的广播。在广播发出去之后,同一时刻只有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑处理完成后,广播才可以继续传递。这种广播的接收顺序通过优先级(priority)设置,高的优先级先会收到广播。有序广播可以被接收者截断,使得后面的广播无法收到它。通过Context.sendOrderedBroadcast发送。

  • 粘性广播:这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到这个广播。粘性广播如果被销毁,下一次重建时会重新接收到消息数据。这种方式一般用来确保重要状态改变后的信息被持久的保存,并且能随时广播给新的广播接收器,比如:耗电量的改变。通过Context.sendStickyBroadcast发送。Android系统已经 @Deprecated该广播方式。

  • 本地广播:发送处理的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收本应用程序发出的广播。通过LocalBroadcastManager.sendBroadcast发送。(基本原理是Handler,所以在AMS中没有本地广播的处理)

广播在系统中通过BroadcastRecord来记录。

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
/**
* An active intent broadcast.
*/
final class BroadcastRecord extends Binder {
final Intent intent; // the original intent that generated us
final ComponentName targetComp; // original component name set on the intent
final ProcessRecord callerApp; // process that sent this
final String callerPackage; // who sent this
final int callingPid; // the pid of who sent this
final int callingUid; // the uid of who sent this
final boolean callerInstantApp; // caller is an Instant App?
final boolean ordered; // serialize the send to receivers?
final boolean sticky; // originated from existing sticky data?
final boolean initialSticky; // initial broadcast from register to sticky?
final int userId; // user id this broadcast was for
final String resolvedType; // the resolved data type
final String[] requiredPermissions; // permissions the caller has required
final int appOp; // an app op that is associated with this broadcast
final BroadcastOptions options; // BroadcastOptions supplied by caller
//包括动态注册的BroadcastFilter和静态注册的ResolveInfo
final List receivers; // contains BroadcastFilter and ResolveInfo
//广播的分发状态
final int[] delivery; // delivery state of each receiver
IIntentReceiver resultTo; // who receives final result if non-null

//入队列时间
long enqueueClockTime; // the clock time the broadcast was enqueued
//分发时间
long dispatchTime; // when dispatch started on this set of receivers
//分发时间
long dispatchClockTime; // the clock time the dispatch started
//接收时间
long receiverTime; // when current receiver started for timeouts.
//广播完成时间
long finishTime; // when we finished the broadcast.

}

二、注册广播

注册广播一般可以在Activity/Service中调用registerReceiver方法,而这两者间接集成Context,其实现是ContextImpl。

2.1 CI.registerReceiver

[->ContextImpl.java]

1
2
3
4
5
6
7
8
9
10
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}

其中broadcastPermission表示广播的权限,scheduler表示接收广播时onReceive执行的线程,当scheduler==null时代表在主线程中执行,大部分情况是不会指令scheduler。getOuterContext可以获取最外层调用者。

2.2 CI.registerReceiverInternal

[->ContextImpl.java]

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
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) {
if (scheduler == null) {
//主线程Handler赋予scheduler
scheduler = mMainThread.getHandler();
}
//见2.3节,获取IIntentReceiver
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//context为空,新建ReceiverDispatcher对象(见2.3.1节),并获取IIntentReceiver
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
//通过Binder调用AMS.registerReceiver
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

2.3 LA.getReceiverDispatcher

[->LoadedApk.java]

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
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
//已经注册
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
//广播分发者为空,创建ReceiverDispatcher
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
//验证广播分发者的context和handler是否一致
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}

mReceivers定义为final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers;

mReceivers是以Context为key,以ArrayMap为value的ArrayMap。

2.3.1 创建ReceiverDispatcher

[->LoadedApk.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}

mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
}

mActivityThread为前面传过来的Handler。

2.3.2 创建InnerReceiver

[->LoadedApk.java]

1
2
3
4
5
6
7
8
9
10
11
  final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;

InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
//弱引用
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
...
}

InnerReceiver继承于IIntentReceiver.Stub,是一个服务器端,广播分发者通过getReceiverDispatcher可以获取该Binder服务端对象InnerReceiver,用于IPC通信。

2.4 AMS.registerReceiver

[->ActivityManagerService.java]

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
int callingUid;
int callingPid;
boolean instantApp;
synchronized(this) {
if (caller != null) {
//查询调用者的进程信息
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
if (callerApp.info.uid != SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage)) {
throw new SecurityException("Given caller package " + callerPackage
+ " is not running in process " + callerApp);
}
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
} else {
callerPackage = null;
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
}
//是否是即时应用
instantApp = isInstantApp(callerApp, callerPackage, callingUid);
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
//获取InterFilter中的Action
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}

// Collect stickies of users
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
//从mStickyBroadcasts中查看用户的sticky intent
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
//将sticky intent加入队列
stickyIntents.addAll(intents);
}
}
}
}
}

ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
//即时应用跳过
// Don't provided intents that aren't available to instant apps.
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
//查询匹配到的sticky广播,见2.4.2节
// If intent has scheme "content", it will need to acccess
// 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<Intent>();
}
//匹配成功,则将该intent添加到allSticky队列
allSticky.add(intent);
}
}
}
//返回第一个stick intent
// The first sticky in the list is returned directly back to the client.
Intent sticky = allSticky != null ? allSticky.get(0) : null;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
if (receiver == null) {
return sticky;
}

synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died
//调用者已经死亡
return null;
}
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
//对于没有注册的广播,则创建接收者队列
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
//每个应用最多只能注册1000个接收者
final int totalReceiversForApp = rl.app.receivers.size();
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
//新创建的接收者队列,添加到已注册队列
rl.app.receivers.add(rl);
} else {
try {
//服务停止后重连
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
throw new IllegalArgumentException(
"Receiver requested to register for uid " + callingUid
+ " was previously registered for uid " + rl.uid
+ " callerPackage is " + callerPackage);
} else if (rl.pid != callingPid) {
throw new IllegalArgumentException(
"Receiver requested to register for pid " + callingPid
+ " was previously registered for pid " + rl.pid
+ " callerPackage is " + callerPackage);
} else if (rl.userId != userId) {
throw new IllegalArgumentException(
"Receiver requested to register for user " + userId
+ " was previously registered for user " + rl.userId
+ " callerPackage is " + callerPackage);
}
//创建BroadcastFilter队列,并添加到接收者队列
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
//新创建的广播过滤对象,添加到mReceiverResolver队列
mReceiverResolver.addFilter(bf);
}
//所有匹配该filter的stick广播执行入队操作
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);

final int stickyCount = allSticky.size();
for (int i = 0; i < stickyCount; i++) {
Intent intent = allSticky.get(i);
//根据intent返回前台或者后台广播队列,见2.4.3节
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
//该广播加入到并行队列
queue.enqueueParallelBroadcastLocked(r);
//调度广播,发送BROADCAST_INTENT_MSG消息,触发处理广播
queue.scheduleBroadcastsLocked();
}
}

return sticky;
}
}

mReceiverResolver记录着所有已经注册的广播,是以receiver IBinder为key, ReceiverList为value的ArrayMap。

在BroadcastQueue中有两个广播队列mParallelBroadcasts、mOrderedBroadcasts,类型为ArrayList

  • mParallelBroadcasts:并行广播队列,可以立刻执行,而无需等待另一个广播运行完成,该队列只允许动态已注册的广播,从而避免发生同时拉起大量进程来执行广播,前台和后台的广播分别位于独立的队列。

  • mOrderedBroadcasts:有序广播,同一时间只允许执行一个广播,该队列头部的广播就是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台和后台的广播。

2.4.1 AMS.getRecordForAppLocked

[->ActivityManagerService.java]

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
ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
if (thread == null) {
return null;
}
//从mLruProcesses队列中获取
int appIndex = getLRURecordIndexForAppLocked(thread);
if (appIndex >= 0) {
return mLruProcesses.get(appIndex);
}
//mLruProcesses不存在,再检查一遍
// Validation: if it isn't in the LRU list, it shouldn't exist, but let's
// double-check that.
final IBinder threadBinder = thread.asBinder();
final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
for (int i = pmap.size()-1; i >= 0; i--) {
final SparseArray<ProcessRecord> procs = pmap.valueAt(i);
for (int j = procs.size()-1; j >= 0; j--) {
final ProcessRecord proc = procs.valueAt(j);
if (proc.thread != null && proc.thread.asBinder() == threadBinder) {
Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "
+ proc);
return proc;
}
}
}

return null;
}

mLruProcesses 定义为ArrayList mLruProcesses ,ProcessRecord对象中有一个IApplicationThread字段,根据该字段来查找对应的ProcessRecord。

2.4.3 IntentFilter.match

[->IntentFilter.java]

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
public final int match(ContentResolver resolver, Intent intent,
boolean resolve, String logTag) {
String type = resolve ? intent.resolveType(resolver) : intent.getType();
return match(intent.getAction(), type, intent.getScheme(),
intent.getData(), intent.getCategories(), logTag);
}
public final int match(String action, String type, String scheme,
Uri data, Set<String> categories, String logTag) {
//不存在匹配的action,存在即可以
if (action != null && !matchAction(action)) {
if (false) Log.v(
logTag, "No matching action " + action + " for " + this);
return NO_MATCH_ACTION;
}
//不存在匹配的type或data
int dataMatch = matchData(type, scheme, data);
if (dataMatch < 0) {
if (false) {
if (dataMatch == NO_MATCH_TYPE) {
Log.v(logTag, "No matching type " + type
+ " for " + this);
}
if (dataMatch == NO_MATCH_DATA) {
Log.v(logTag, "No matching scheme/path " + data
+ " for " + this);
}
}
return dataMatch;
}
//不存在匹配的category,需要全部匹配
String categoryMismatch = matchCategories(categories);
if (categoryMismatch != null) {
if (false) {
Log.v(logTag, "No matching category " + categoryMismatch + " for " + this);
}
return NO_MATCH_CATEGORY;
}

// It would be nice to treat container activities as more
// important than ones that can be embedded, but this is not the way...
if (false) {
if (categories != null) {
dataMatch -= mCategories.size() - categories.size();
}
}

return dataMatch;
}

该方法用于匹配Intent的数据是否成功,匹配的数据包括action,type,data,category四项,任何一项匹配不成功都会失败。

2.4.3 AMS.broadcastQueueForIntent

[->ActivityManagerService.java]

1
2
3
4
5
6
7
BroadcastQueue broadcastQueueForIntent(Intent intent) {
final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
"Broadcast intent " + intent + " on "
+ (isFg ? "foreground" : "background") + " queue");
return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}

broadcastQueueForIntent通过判断intent中是否包含FLAG_RECEIVER_FOREGROUND来决定是前台广播还是后台广播

2.5 小结

注册广播:

1.注册广播的参数为广播BroadcastReceiver和过滤添加IntentFilter;

2.创建对象LoadedApk.ReceiverDispatcher.InnerReceiver,该对象集成于IIntentReceiver.Stub;

3.通过AMS把当前进程的ApplicationThread和InnerReceiver对象的代理类,注册到systemserver进程;

4.当广播receiver没有注册时,则创建广播接收者队列ReceiverList,该对象集成于ArrayList,并添加到AMS.mRegisteredReceivers(已注册广播队列);

5.创建BroadcastFilter队列,并添加到AMS.mReceiverResolver

6.将BroadcastFilter添加到广播接收者的ReceiverList

当注册的广播为Sticky广播:

1.创建BroadcastRecord,并添加到BroadcastQueue中的mParallelBroadcasts,注册后,调用AMS处理该广播

2.根据注册的intent中是否包含FLAG_RECEIVER_FOREGROUND,包含则是mFgBroadcastQueue队列,否则为mBgBroadcastQueue队列。

三、发送广播

和注册广播一样,最后调用的是ContextImpl.sendBroadcast

3.1 CI.sendBroadcast

[->ContextImpl.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void sendBroadcast(Intent intent) {
//UID如果是SYSTEM_UID则提示警告信息
//"Calling a method in the system process without a qualified user:""
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
//通过binder方式调用AMS.broadcastIntent
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

3.2 AMS.broadcastIntent

[->ActivityManagerService.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
//验证广播intent是否有效
intent = verifyBroadcastLocked(intent);
//获取调用者进程记录对象
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
//见3.2节
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}

broadcastIntent有两个boolean值参数serialized、sticky共同决定是普通广播,有效广播,还是sticky广播。

类型 serialized sticky
sendBroadcast false false
sendOrderedBroadcast true false
sendStickyBroadcast false true

3.3 AMS.broadcastIntentLocked

[->ActivityManagerService.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {

//setp1:设置广播flags
//setp2:广播权限验证
//setp3:处理系统相关广播
//setp4:增加sticky广播
//setp5:查询receivers和registeredReceivers
//setp6:处理并行广播
//setp7:合并registeredReceivers到receivers
//setp8:处理串行广播

return ActivityManager.BROADCAST_SUCCESS;
}

该方法比较长,这里分为8部分进行分析。

3.3.1 设置广播flags

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
intent = new Intent(intent);
//判断是否是即时应用
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
//即时应用如果没有设置FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS则不会收到广播
// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
if (callerInstantApp) {
intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
//增加flag,广播不会发送给已经停止的package
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

//系统没有启动完成,不允许启动新进程
// If we have not finished booting, don't allow this to launch new processes.
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}

if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered + " userid=" + userId);
if ((resultTo != null) && !ordered) {
Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
}

userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_NON_FULL, "broadcast", callerPackage);
//检查发送广播时的用户状态
// Make sure that the user who is receiving this broadcast or its parent is running.
// If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.
if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
if ((callingUid != SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
+ ": user " + userId + " and its parent (if any) are stopped");
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}

这个过程主要的工作如下:

1.是否设置FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS标志,如果设置广播对即时应用可见;

2.添加flagFLAG_EXCLUDE_STOPPED_PACKAGES,保证已经停止的app不会收到广播;

3.当系统还没有启动完成,不允许启动新进程;

4.非USER_ALL广播且接收广播的用户没有处于Running的情况下,除非是系统升级广播和关键广播,否则直接返回。

BroadcastReceiver还有其他flag,位于Intent.java常量中:

1
2
3
4
5
6
7
8
9
FLAG_RECEIVER_REGISTERED_ONLY  //只允许已经注册的receiver接收广播
FLAG_RECEIVER_REPLACE_PENDING //新广播会替代相同广播
FLAG_RECEIVER_FOREGROUND //只允许前台receiver接收广播
FLAG_RECEIVER_NO_ABORT //对于有序广播,先接收到的receiver无权抛弃广播
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT //boot完成之前,只允许已注册的receiver接收广播
FLAG_RECEIVER_BOOT_UPGRADE //升级模式下,允许系统准备就绪前发送广播
FLAG_RECEIVER_INCLUDE_BACKGROUND //允许后台台receiver接收广播
FLAG_RECEIVER_EXCLUDE_BACKGROUND //不允许后台台receiver接收广播
FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS //广播对即时应用可见

3.3.2 广播权限验证

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
final String action = intent.getAction();
BroadcastOptions brOptions = null;
if (bOptions != null) {
brOptions = new BroadcastOptions(bOptions);
if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
//如果AppWhitelistDuration>0,检查是否有CHANGE_DEVICE_IDLE_TEMP_WHITELIST权限
// See if the caller is allowed to do this. Note we are checking against
// the actual real caller (not whoever provided the operation as say a
// PendingIntent), because that who is actually supplied the arguments.
if (checkComponentPermission(
android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
//检查是否有后台限制
if (brOptions.isDontSendToRestrictedApps()
&& !isUidActiveLocked(callingUid)
&& isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage
+ " has background restrictions");
return ActivityManager.START_CANCELED;
}
}
//检查受保护的广播只允许系统使用
// Verify that protected broadcasts are only being sent by system code,
// and that system code is only sending protected broadcasts.
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}

final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID:
case SYSTEM_UID:
case PHONE_UID:
case BLUETOOTH_UID:
case NFC_UID:
case SE_UID:
case NETWORK_STACK_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.persistent;
break;
}
//非系统发送的广播
// First line security check before anything else: stop non-system apps from
// sending protected broadcasts.
if (!isCallerSystem) {
//是保护广播,则抛出异常
if (isProtectedBroadcast) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);

} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
//限制广播只发送自己
// Special case for compatibility: we don't want apps to send this,
// but historically it has not been protected and apps may be using it
// to poke their own app widget. So, instead of making it protected,
// just limit it to the caller.
if (callerPackage == null) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from unknown caller.";
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (intent.getComponent() != null) {
// They are good enough to send to an explicit component... verify
// it is being sent to the calling app.
if (!intent.getComponent().getPackageName().equals(
callerPackage)) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " to "
+ intent.getComponent().getPackageName() + " from "
+ callerPackage;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} else {
// Limit broadcast to their own package.
intent.setPackage(callerPackage);
}
}
}
if (action != null) {
//如果允许后台应用接收广播,则添加FLAG_RECEIVER_INCLUDE_BACKGROUND
if (getBackgroundLaunchBroadcasts().contains(action)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
}
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}

主要工作如下:

1.如果TemporaryAppWhitelistDuration>0,检查是否有CHANGE_DEVICE_IDLE_TEMP_WHITELIST权限,没有抛出异常

2.检查是否后台限制发送广播,如果限制,则后台应用将不能发送广播

3.callingUid为 ROOT_UID, SYSTEM_UID,PHONE_UID,BLUETOOTH_UID,NFC_UID,SE_UID,NETWORK_STACK_UID和persistent进程时,可以发送受保护广播

4.为非系统应用发送广播时:当发送的是受保护的广播,则抛出异常;当action为ACTION_APPWIDGET_CONFIGURE或ACTION_APPWIDGET_UPDATE时,限制该广播只发送给自己,否则抛出异常。

5.如果允许后台应用接收广播,则添加FLAG_RECEIVER_INCLUDE_BACKGROUND

3.3.3 处理系统相关广播

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
switch (action) {
case Intent.ACTION_UID_REMOVED://uid移除
case Intent.ACTION_PACKAGE_REMOVED://package移除
case Intent.ACTION_PACKAGE_CHANGED://改变package
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE://外部设备不可用
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
case Intent.ACTION_PACKAGES_SUSPENDED:
case Intent.ACTION_PACKAGES_UNSUSPENDED:
// Handle special intents: if this broadcast is from the package
// manager about a package being removed, we need to remove all of
// its activities from the history stack.
if (checkComponentPermission(
android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
callingPid, callingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
switch (action) {
case Intent.ACTION_UID_REMOVED:
final int uid = getUidFromIntent(intent);
if (uid >= 0) {
mBatteryStatsService.removeUid(uid);
mAppOpsService.uidRemoved(uid);
}
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
// If resources are unavailable just force stop all those packages
// and flush the attribute cache as well.
String list[] =
intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (list != null && list.length > 0) {
for (int i = 0; i < list.length; i++) {
forceStopPackageLocked(list[i], -1, false, true, true,
false, false, userId, "storage unmount");
}
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
sendPackageBroadcastLocked(
ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,
list, userId);
}
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
break;
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
Uri data = intent.getData();
String ssp;
if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
final boolean replacing =
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
final boolean killProcess =
!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
final boolean fullUninstall = removed && !replacing;
if (removed) {
if (killProcess) {
forceStopPackageLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)),
false, true, true, false, fullUninstall, userId,
removed ? "pkg removed" : "pkg changed");
}
final int cmd = killProcess
? ApplicationThreadConstants.PACKAGE_REMOVED
: ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;
sendPackageBroadcastLocked(cmd,
new String[] {ssp}, userId);
if (fullUninstall) {
mAppOpsService.packageRemoved(
intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

// Remove all permissions granted from/to this package
removeUriPermissionsForPackageLocked(ssp, userId, true,
false);

mRecentTasks.removeTasksByPackageName(ssp, userId);

mServices.forceStopPackageLocked(ssp, userId);
mAppWarnings.onPackageUninstalled(ssp);
mCompatModePackages.handlePackageUninstalledLocked(ssp);
mBatteryStatsService.notePackageUninstalled(ssp);
}
} else {
if (killProcess) {
killPackageProcessesLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)),
userId, ProcessList.INVALID_ADJ,
false, true, true, false, "change " + ssp);
}
cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess,
intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
}
}
break;
case Intent.ACTION_PACKAGES_SUSPENDED:
case Intent.ACTION_PACKAGES_UNSUSPENDED:
final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.equals(
intent.getAction());
final String[] packageNames = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_PACKAGE_LIST);
final int userHandle = intent.getIntExtra(
Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);

synchronized(ActivityManagerService.this) {
mRecentTasks.onPackagesSuspendedChanged(
packageNames, suspended, userHandle);
}
break;
}
break;
case Intent.ACTION_PACKAGE_REPLACED:
{
final Uri data = intent.getData();
final String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
ApplicationInfo aInfo = null;
try {
aInfo = AppGlobals.getPackageManager()
.getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
} catch (RemoteException ignore) {}
if (aInfo == null) {
Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
+ " ssp=" + ssp + " data=" + data);
return ActivityManager.BROADCAST_SUCCESS;
}
mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
mServices.updateServiceApplicationInfoLocked(aInfo);
sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
new String[] {ssp}, userId);
}
break;
}
case Intent.ACTION_PACKAGE_ADDED:
{
// Special case for adding a package: by default turn on compatibility mode.
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
final boolean replacing =
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
mCompatModePackages.handlePackageAddedLocked(ssp, replacing);

try {
ApplicationInfo ai = AppGlobals.getPackageManager().
getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
mBatteryStatsService.notePackageInstalled(ssp,
ai != null ? ai.versionCode : 0);
} catch (RemoteException e) {
}
}
break;
}
case Intent.ACTION_PACKAGE_DATA_CLEARED:
{
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
mCompatModePackages.handlePackageDataClearedLocked(ssp);
mAppWarnings.onPackageDataCleared(ssp);
}
break;
}
case Intent.ACTION_TIMEZONE_CHANGED:
// If this is the time zone changed action, queue up a message that will reset
// the timezone of all currently running processes. This message will get
// queued up before the broadcast happens.
mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
break;
case Intent.ACTION_TIME_CHANGED:
// EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between
// the tri-state value it may contain and "unknown".
// For convenience we re-use the Intent extra values.
final int NO_EXTRA_VALUE_FOUND = -1;
final int timeFormatPreferenceMsgValue = intent.getIntExtra(
Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,
NO_EXTRA_VALUE_FOUND /* defaultValue */);
// Only send a message if the time preference is available.
if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {
Message updateTimePreferenceMsg =
mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,
timeFormatPreferenceMsgValue, 0);
mHandler.sendMessage(updateTimePreferenceMsg);
}
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteCurrentTimeChangedLocked();
}
break;
case Intent.ACTION_CLEAR_DNS_CACHE: //清除DNS cache
mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
break;
case Proxy.PROXY_CHANGE_ACTION: //网络代理改变
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));
break;
case android.hardware.Camera.ACTION_NEW_PICTURE:
case android.hardware.Camera.ACTION_NEW_VIDEO:
// In N we just turned these off; in O we are turing them back on partly,
// only for registered receivers. This will still address the main problem
// (a spam of apps waking up when a picture is taken putting significant
// memory pressure on the system at a bad point), while still allowing apps
// that are already actively running to know about this happening.
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
break;
case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);
break;
case "com.android.launcher.action.INSTALL_SHORTCUT":
// As of O, we no longer support this broadcasts, even for pre-O apps.
// Apps should now be using ShortcutManager.pinRequestShortcut().
Log.w(TAG, "Broadcast " + action
+ " no longer supported. It will not be delivered.");
return ActivityManager.BROADCAST_SUCCESS;
}

if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
final int uid = getUidFromIntent(intent);
if (uid != -1) {
final UidRecord uidRec = mActiveUids.get(uid);
if (uidRec != null) {
uidRec.updateHasInternetPermission();
}
}
}
}

该过程主要系统广播,主要是package、时间、网络相关的广播,并对这些广播进行相应的处理。

3.3.4 增加sticky广播

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
// Add to the sticky list if requested.
if (sticky) {
//检查是否有BROADCAST_STICKY权限
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
+ callingPid + ", uid=" + callingUid
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (requiredPermissions != null && requiredPermissions.length > 0) {
Slog.w(TAG, "Can't broadcast sticky intent " + intent
+ " and enforce permissions " + Arrays.toString(requiredPermissions));
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
//发送指定组件,抛出异常
if (intent.getComponent() != null) {
throw new SecurityException(
"Sticky broadcasts can't target a specific component");
}
//当非USER_ALL广播和USER_ALL冲突
// We use userId directly here, since the "all" target is maintained
// as a separate set of sticky broadcasts.
if (userId != UserHandle.USER_ALL) {
// But first, if this is not a broadcast to all users, then
// make sure it doesn't conflict with an existing broadcast to
// all users.
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
UserHandle.USER_ALL);
if (stickies != null) {
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i<N; i++) {
if (intent.filterEquals(list.get(i))) {
throw new IllegalArgumentException(
"Sticky broadcast " + intent + " for user "
+ userId + " conflicts with existing global broadcast");
}
}
}
}
}
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<>();
mStickyBroadcasts.put(userId, stickies);
}
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null) {
list = new ArrayList<>();
stickies.put(intent.getAction(), list);
}
final int stickiesCount = list.size();
int i;
for (i = 0; i < stickiesCount; i++) {
if (intent.filterEquals(list.get(i))) {
// This sticky already exists, replace it.
list.set(i, new Intent(intent));
break;
}
}
if (i >= stickiesCount) {
list.add(new Intent(intent));
}
}

这个过程主要是检查sticky广播,将sticky广播放入到mStickyBroadcasts,并增加到list

3.3.5 查询receivers和registeredReceivers

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
//发送广播的user
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
users = mUserController.getStartedUserArray();
} else {
// Caller wants broadcast to go to one specific user.
users = new int[] {userId};
}
//查询哪些广播将会接受广播
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
//当允许静态接收者处理广播时,则通过PKMS根据intent查询静态receivers
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
for (int i = 0; i < users.length; i++) {
if (mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
//查询动态注册广播
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}

主要工作如下:

1.根据userId判断发送的是全部的接收者还是指定的userId

2.查询广播,并将其放入到两个列表:

registeredReceivers:来匹配当前intent的所有动态注册的广播接收者(mReceiverResolver见2.4节)

receivers:记录当前intent的所有静态注册的广播接收者

1
2
3
4
5
6
7
8
9
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
int callingUid, int[] users) {
...
//调用PKMS的queryIntentReceivers,可以获取AndroidManifeset中注册的接收信息
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
.queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
...
return receivers;
}

3.3.6 处理并行广播

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
//用于标识是否需要用新的intent替换旧的intent
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
//处理并行广播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
//发送的不是有序广播
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
//检查系统发送的广播
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
//根据intent的flag来判断前台队列还是后台队列,见2.4.3节
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建BroadcastRecord
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
//将BroadcastRecord加入到并行广播队列
queue.enqueueParallelBroadcastLocked(r);
//处理广播,见4.1节
queue.scheduleBroadcastsLocked();
}
//动态注册的广播接收者处理完成,则将该变量设置为空
registeredReceivers = null;
NR = 0;
}

广播队列中有一个mParallelBroadcasts变量,类型为ArrayList,记录所有的并行广播

1
2
3
4
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
enqueueBroadcastHelper(r);
}

3.3.7 合并registeredReceivers到receivers

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
// Merge into one list.
int ir = 0;
if (receivers != null) {
//防止应用监听广播,在安装时直接运行
// A special case for PACKAGE_ADDED: do not allow the package
// being added to see this broadcast. This prevents them from
// using this as a back door to get run as soon as they are
// installed. Maybe in the future we want to have a special install
// broadcast or such for apps, but we'd like to deliberately make
// this decision.
String skipPackages[] = null;
if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data != null) {
String pkgName = data.getSchemeSpecificPart();
if (pkgName != null) {
skipPackages = new String[] { pkgName };
}
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
//将skipPackages相关的广播接收者从receivers列表中移除。
if (skipPackages != null && (skipPackages.length > 0)) {
for (String skipPackage : skipPackages) {
if (skipPackage != null) {
int NT = receivers.size();
for (int it=0; it<NT; it++) {
ResolveInfo curt = (ResolveInfo)receivers.get(it);
if (curt.activityInfo.packageName.equals(skipPackage)) {
receivers.remove(it);
it--;
NT--;
}
}
}
}
}
//3.4.6节有处理动态广播的过程,处理完成后再执行将动态注册的registeredReceivers合并到receivers中
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
while (it < NT && ir < NR) {
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
//优先级大的,则插到前面
if (curr.getPriority() >= curt.priority) {
// Insert this broadcast record into the final list.
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
} else {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir));
ir++;
}
//检查系统发送的广播
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, receivers);
}

这里主要是将动态注册的registeredReceivers(如果发送的广播不是有序广播则registeredReceivers = null)全部合并到receivers,再统一按照串行方式处理。

3.3.8 处理串行广播

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
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
//根据intent的flag判断是前台队列还是后台队列,见2.4.3节
BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建BroadcastRecord
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Enqueueing broadcast " + r.intent.getAction());

final BroadcastRecord oldRecord =
replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
if (oldRecord != null) {
// Replaced, fire the result-to receiver.
if (oldRecord.resultTo != null) {
final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
try {
oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
false, false, oldRecord.userId);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["
+ queue.mQueueName + "] sending broadcast result of "
+ intent, e);

}
}
} else {
//将BroadcastRecord加入到有序广播队列
queue.enqueueOrderedBroadcastLocked(r);
//处理广播,见4.1节
queue.scheduleBroadcastsLocked();
}
} else {
// There was nobody interested in the broadcast, but we still want to record
// that it happened.
if (intent.getComponent() == null && intent.getPackage() == null
&& (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
}
}

广播队列中有一个mOrderedBroadcasts变量,类型为ArrayList,记录所有的有序广播

1
2
3
4
5
//串行广播加入到mOrderedBroadcasts队列
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
mOrderedBroadcasts.add(r);
enqueueBroadcastHelper(r);
}

3.4 小结

发送广播的过程:

1.默认不发送给已停止的(FLAG_EXCLUDE_STOPPED_PACKAGES)应用和即时应用(需要添加该FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS标记才可以)

2.对广播进行权限验证,是否是受保护的广播,是否允许后台接收广播,是否允许后台发送广播

3.处理系统广播,主要是package、时间、网络相关的广播

4.当为粘性广播时,将sticky广播增加到list,并放入mStickyBroadcasts队列

5.当广播的intent没有设置FLAG_RECEIVER_REGISTERED_ONLY,则允许静态广播接收者来处理该广播;创建BroadcastRecord对象,并将该对象加入到相应的广播队列,然后调用BroadcastQueue的scheduleBroadcastsLocked方法来完成不同广播的处理。

不同广播的处理方式:

1.sticky广播:广播注册过程中处理AMS.registerReceiver,开始处理粘性广播,见2.4节

  • 创建BroadcastRecord对象
  • 添加到mParallelBroadcasts队列
  • 然后执行 queue.scheduleBroadcastsLocked()

2.并行广播:广播发送处理过程见3.3.6节

  • 只有动态注册的registeredReceivers才会进行并行处理
  • 创建BroadcastRecord对象
  • 添加到mParallelBroadcasts队列
  • 然后执行 queue.scheduleBroadcastsLocked()

3.串行广播:广播发送处理过程见3.3.8节

  • 所有静态注册的receivers以及动态注册的registeredReceivers(发送的广播是有序广播)合并到一张表处理
  • 创建BroadcastRecord对象
  • 添加到mOrderedBroadcasts队列
  • 然后执行 queue.scheduleBroadcastsLocked()

从上面可以看出,不管哪种广播方式,都是通过broadcastQueueForIntent来根据intent的flag判段是前台队列还是后台队列广播,然后再调用对应广播队列的scheduleBroadcastsLocked方法来处理广播。

四、接收广播

在发送广播的过程会执行scheduleBroadcastsLocked方法来处理广播

4.1 BQ.scheduleBroadcastsLocked

[->BroadcastQueue.java]

1
2
3
4
5
6
7
8
9
10
11
12
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
//正在处理BROADCAST_INTENT_MSG消息
if (mBroadcastsScheduled) {
return;
}
//发送BROADCAST_INTENT_MSG消息
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}

4.1.1 BroadcastHandler

[->BroadcastQueue.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}

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

发送BROADCAST_INTENT_MSG消息后,BroadcastHandler进行处理,其初始化在构造函数中创建,而BroadcastQueue是在AMS初始化,从源码中可以看出handler采用的是”ActivityManagerService”线程的loop。

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
BroadcastQueue(ActivityManagerService service, Handler handler,
String name, long timeoutPeriod, boolean allowDelayBehindServices) {
mService = service;
//创建BroadcastHandler
mHandler = new BroadcastHandler(handler.getLooper());
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
mDelayBehindServices = allowDelayBehindServices;
}

public ActivityManagerService(Context systemContext) {
...
//名为ActivityManagerService的线程
mHandlerThread = new ServiceThread(TAG,
THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
//创建BroadcastQueue对象
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);

//android10.0新增加的一个分流队列,目前仅处理BOOT_COMPLETED广播
// Convenient for easy iteration over the queues. Foreground is first
// so that dispatch of foreground broadcasts gets precedence.
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
...
}

//广播超时时间定义
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;

4.2 BQ.processNextBroadcast

[->BroadcastQueue.java]

1
2
3
4
5
6
final void processNextBroadcast(boolean fromMsg) {
//同步mService
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}

此次mService为AMS,整个流程比较长,全程持有AMS锁,所以广播效率低下的情况下,直接会严重影响手机的性能和流畅度,这里是否应考虑细化同步锁的粒度。

1
2
3
4
5
6
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
//setp1:处理并行广播
//setp2:处理串行广播
//setp3:获取下条有序广播
//setp4:处理下条有序广播
}

整个处理的过程比较长,将分为四个部分进行分析。

4.2.1 处理并行广播

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
BroadcastRecord r;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
+ mParallelBroadcasts.size() + " parallel broadcasts, "
+ mOrderedBroadcasts.size() + " ordered broadcasts");
//更新cpu统计信息
mService.updateCpuStats();
//方法传进来的是true,将mBroadcastsScheduled重置为false
if (fromMsg) {
mBroadcastsScheduled = false;
}

// 处理并行队列
// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();

if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
}

final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
//分发广播给已经注册的receiver,见4.3节
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
//将广播添加到历史记录
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}

通过while循环,每次取出一个,一次性分发完所有的并发广播后,将分发完成的添加到历史广播队列。

4.2.2 处理串行广播

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Now take care of the next serialized one...
// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point. Just in case, we
// check that the process we're waiting for still exists.
if (mPendingBroadcast != null) {
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"processNextBroadcast [" + mQueueName + "]: waiting for "
+ mPendingBroadcast.curApp);

boolean isDead;
if (mPendingBroadcast.curApp.pid > 0) {
synchronized (mService.mPidsSelfLocked) {
//从mPidsSelfLocked获取正在处理的广播进程,判断进程是否死亡
ProcessRecord proc = mService.mPidsSelfLocked.get(
mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
} else {
//从mProcessNames获取正在处理的广播进程,判断进程是否死亡
final ProcessRecord proc = mService.mProcessNames.get(
mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
isDead = proc == null || !proc.pendingStart;
}
if (!isDead) {
// 如果正在处理广播的进程保持活跃状态,则继续等待其执行完成
// It's still alive, so keep waiting
return;
} else {
Slog.w(TAG, "pending app ["
+ mQueueName + "]" + mPendingBroadcast.curApp
+ " died before responding to broadcast");
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}

boolean looped = false;

do {
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
//所有的串行广播处理完成,则调度执行gc
mService.scheduleAppGcsLocked();
if (looped) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
mService.updateOomAdjLocked();
}
return;
}
r = mOrderedBroadcasts.get(0);
boolean forceReceive = false;

// Ensure that even if something goes awry with the timeout
// detection, we catch "hung" broadcasts here, discard them,
// and continue to make progress.
//
// This is only done if the system is ready so that PRE_BOOT_COMPLETED
// receivers don't get executed with timeouts. They're intended for
// one time heavy lifting after system upgrades and can take
// significant amounts of time.
//所有有序广播的接收者
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
//系统进程已经准备好
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
Slog.w(TAG, "Hung broadcast ["
+ mQueueName + "] discarded after timeout failure:"
+ " now=" + now
+ " dispatchTime=" + r.dispatchTime
+ " startTime=" + r.receiverTime
+ " intent=" + r.intent
+ " numReceivers=" + numReceivers
+ " nextReceiver=" + r.nextReceiver
+ " state=" + r.state);
//广播超时,强制结束这条广播
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
if (r.state != BroadcastRecord.IDLE) {
if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
"processNextBroadcast("
+ mQueueName + ") called when not idle (state="
+ r.state + ")");
return;
}

if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// No more receivers for this broadcast! Send the final
// result if requested...
if (r.resultTo != null) {
try {
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Finishing broadcast [" + mQueueName + "] "
+ r.intent.getAction() + " app=" + r.callerApp);
//处理广播消息,调用到onReceive()
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
} catch (RemoteException e) {
r.resultTo = null;
Slog.w(TAG, "Failure ["
+ mQueueName + "] sending broadcast result of "
+ r.intent, e);

}
}

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
//取消BROADCAST_TIMEOUT_MSG消息
cancelBroadcastTimeoutLocked();

if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Finished with ordered broadcast " + r);

// 添加到队列消息记录
// ... and on to the next...
addBroadcastToHistoryLocked(r);
if (r.intent.getComponent() == null && r.intent.getPackage() == null
&& (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
}
mOrderedBroadcasts.remove(0);
r = null;
looped = true;
continue;
}
} while (r == null);

mTimeoutPeriod,对于前台广播为10s,后台广播为60s。广播超时为2 mTimeoutPeriod numReceivers,接收者个数numReceivers越多,则广播超时总时间越大。

4.2.3 获取下条有序广播

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
//获取下条广播的index
// Get the next receiver...
int recIdx = r.nextReceiver++;

// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
//记录开始时间
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
}
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
+ mQueueName + "] " + r);
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Submitting BROADCAST_TIMEOUT_MSG ["
+ mQueueName + "] for " + r + " at " + timeoutTime);
//发送广播超时
setBroadcastTimeoutLocked(timeoutTime);
}

final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);

if (nextReceiver instanceof BroadcastFilter) {
// Simple case: this is a registered receiver who gets
// a direct call.
//对于动态注册的广播接收者
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
//处理广播,见4.3节
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
+ mQueueName + "]: ordered="
+ r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
//处理下一个广播
scheduleBroadcastsLocked();
} else {
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
}
return;
}

// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.
//对于静态注册的广播接收者
ResolveInfo info =
(ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);

//下面都是各种检查权限,权限不满足时则跳过
boolean skip = false;
if (brOptions != null &&
(info.activityInfo.applicationInfo.targetSdkVersion
< brOptions.getMinManifestReceiverApiLevel() ||
info.activityInfo.applicationInfo.targetSdkVersion
> brOptions.getMaxManifestReceiverApiLevel())) {
skip = true; //sdk版本,Androidmanifest中设置
}
int perm = mService.checkComponentPermission(info.activityInfo.permission,
r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
info.activityInfo.exported);
//Component权限
if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
if (!info.activityInfo.exported) {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
+ " is not exported from uid " + info.activityInfo.applicationInfo.uid
+ " due to receiver " + component.flattenToShortString());
} else {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
+ " requires " + info.activityInfo.permission
+ " due to receiver " + component.flattenToShortString());
}
skip = true;
} else if (!skip && info.activityInfo.permission != null) {
final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
if (opCode != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,
r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires appop " + AppOpsManager.permissionToOp(
info.activityInfo.permission)
+ " due to registered receiver "
+ component.flattenToShortString());
skip = true;
}
}

if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
try {
perm = AppGlobals.getPackageManager().
checkPermission(requiredPermission,
info.activityInfo.applicationInfo.packageName,
UserHandle
.getUserId(info.activityInfo.applicationInfo.uid));
} catch (RemoteException e) {
perm = PackageManager.PERMISSION_DENIED;
}
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires appop " + AppOpsManager.permissionToOp(
requiredPermission)
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
break;
}
}
}
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(r.appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires appop " + AppOpsManager.opToName(r.appOp)
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}
if (!skip) {
skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
}
boolean isSingleton = false;
try {
isSingleton = mService.isSingleton(info.activityInfo.processName,
info.activityInfo.applicationInfo,
info.activityInfo.name, info.activityInfo.flags);
} catch (SecurityException e) {
Slog.w(TAG, e.getMessage());
skip = true;
}
if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
if (ActivityManager.checkUidPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS,
info.activityInfo.applicationInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
+ " requests FLAG_SINGLE_USER, but app does not hold "
+ android.Manifest.permission.INTERACT_ACROSS_USERS);
skip = true;
}
}
if (!skip && info.activityInfo.applicationInfo.isInstantApp()
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
+ " Instant Apps do not support manifest receivers");
skip = true;
}
if (!skip && r.callerInstantApp
&& (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " requires receiver have visibleToInstantApps set"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}
if (r.curApp != null && r.curApp.crashing) {
// If the target process is crashing, just skip it.
Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
+ " to " + r.curApp + ": process crashing");
skip = true;
}
if (!skip) {
boolean isAvailable = false;
try {
isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
info.activityInfo.packageName,
UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
} catch (Exception e) {
// all such failures mean we skip this receiver
Slog.w(TAG, "Exception getting recipient info for "
+ info.activityInfo.packageName, e);
}
if (!isAvailable) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid
+ " : package no longer available");
skip = true;
}
}

// If permissions need a review before any of the app components can run, we drop
// the broadcast and if the calling app is in the foreground and the broadcast is
// explicit we launch the review UI passing it a pending intent to send the skipped
// broadcast.
if (mService.mPermissionReviewRequired && !skip) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
info.activityInfo.packageName, UserHandle.getUserId(
info.activityInfo.applicationInfo.uid))) {
skip = true;
}
}
// This is safe to do even if we are skipping the broadcast, and we need
// this information now to evaluate whether it is going to be allowed to run.
final int receiverUid = info.activityInfo.applicationInfo.uid;
// If it's a singleton, it needs to be the same app or a special app
if (r.callingUid != Process.SYSTEM_UID && isSingleton
&& mService.isValidSingletonCall(r.callingUid, receiverUid)) {
info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
}
String targetProcess = info.activityInfo.processName;
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);

if (!skip) {
final int allowed = mService.getAppStartModeLocked(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
// to it and the app is in a state that should not receive it
// (depending on how getAppStartModeLocked has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
} else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
|| (r.intent.getComponent() == null
&& r.intent.getPackage() == null
&& ((r.intent.getFlags()
& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
&& !isSignaturePerm(r.requiredPermissions))) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
Slog.w(TAG, "Background execution not allowed: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
}
}
}

if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())
&& !mService.mUserController
.isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
0 /* flags */)) {
skip = true;
Slog.w(TAG,
"Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid + " : user is not running");
}

//跳过该广播
if (skip) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery of ordered [" + mQueueName + "] "
+ r + " for whatever reason");
r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
r.manifestSkipCount++;
scheduleBroadcastsLocked();
return;
}
r.manifestCount++;

r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
+ info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+ receiverUid);
}

if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(receiverUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
// Broadcast正在执行,stopped状态设置成false
// Broadcast is being executed, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.curComponent.getPackageName() + ": " + e);
}

发送广播超时,如果是动态注册的广播则执行deliverToRegisteredReceiverLocked方法,如果是静态注册的广播,则进行一系列的权限检查,不满足则跳过该广播。

4.2.4 处理下条有序广播

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
 // Is this receiver's application already running?
if (app != null && app.thread != null && !app.killed) {
// 接收广播的进程还在运行
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
processCurBroadcastLocked(r, app, skipOomAdj);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Failed sending broadcast to "
+ r.curComponent + " with " + r.intent, e);
// If some unexpected exception happened, just skip
// this broadcast. At this point we are not in the call
// from a client, so throwing an exception out from here
// will crash the entire system instead of just whoever
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
//如果启动receiver失败,则重置状态
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}

// If a dead object exception was thrown -- fall through to
// restart the application.
}

// Not running -- get it started, to be executed when the app comes up.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Need to start app ["
+ mQueueName + "] " + targetProcess + " for broadcast " + r);
//receiver所对应的进程尚未启动,则创建该进程
if ((r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ receiverUid + " for broadcast "
+ r.intent + ": process is bad");
//创建失败,直接结束该receiver
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//开启下一个广播
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}

mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
  • 如果是动态广播接收者,则调用deliverToRegisteredReceiverLocked处理

  • 如果是静态广播接收者,且对应进程已经创建,则调用processCurBroadcastLocked处理

  • 如果是静态广播接收者,且对应进程未创建,则调用startProcessLocked创建进程

4.3 BQ.deliverToRegisteredReceiverLocked

[->BroadcastQueue.java]

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
//检查发送者是否有BroadcastFilter所需要的权限
if (filter.requiredPermission != null) {
int perm = mService.checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires " + filter.requiredPermission
+ " due to registered receiver " + filter);
skip = true;
} else {
final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
if (opCode != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,
r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires appop " + AppOpsManager.permissionToOp(
filter.requiredPermission)
+ " due to registered receiver " + filter);
skip = true;
}
}
}
if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
int perm = mService.checkComponentPermission(requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
filter.receiverList.uid, filter.packageName)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires appop " + AppOpsManager.permissionToOp(
requiredPermission)
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
break;
}
}
}
if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {
int perm = mService.checkComponentPermission(null,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: security check failed when receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}
}
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(r.appOp,
filter.receiverList.uid, filter.packageName)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires appop " + AppOpsManager.opToName(r.appOp)
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}

if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, filter.receiverList.uid)) {
skip = true;
}

if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed
|| filter.receiverList.app.crashing)) {
Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
+ " to " + filter.receiverList + ": process gone or crashing");
skip = true;
}
//即时应用检查
// Ensure that broadcasts are only sent to other Instant Apps if they are marked as
// visible to Instant Apps.
final boolean visibleToInstantApps =
(r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;

if (!skip && !visibleToInstantApps && filter.instantApp
&& filter.receiverList.uid != r.callingUid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
+ " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
skip = true;
}

if (!skip && !filter.visibleToInstantApp && r.callerInstantApp
&& filter.receiverList.uid != r.callingUid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires receiver be visible to instant apps"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}

if (skip) {
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
}

// If permissions need a review before any of the app components can run, we drop
// the broadcast and if the calling app is in the foreground and the broadcast is
// explicit we launch the review UI passing it a pending intent to send the skipped
// broadcast.
if (mService.mPermissionReviewRequired) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
filter.owningUserId)) {
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
}
}

r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;
//如果是有序广播
// If this is not being sent as an ordered broadcast, then we
// don't want to touch the fields that keep track of the current
// state of ordered broadcasts.
if (ordered) {
r.receiver = filter.receiverList.receiver.asBinder();
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
if (filter.receiverList.app != null) {
// Bump hosting application to no longer be in background
// scheduling class. Note that we can't do that if there
// isn't an app... but we can only be in that case for
// things that directly call the IActivityManager API, which
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceivers.add(r);
mService.updateOomAdjLocked(r.curApp, true);
}
}
try {
if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
"Delivering to " + filter + " : " + r);
if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
// Skip delivery if full backup in progress
// If it's an ordered broadcast, we need to continue to the next receiver.
if (ordered) {
//跳过有序广播
skipReceiverLocked(r);
}
} else {
//处理广播,见4.4节
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
if (ordered) {
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
if (filter.receiverList.app != null) {
filter.receiverList.app.curReceivers.remove(r);
}
}
}
}

这里是检查动态注册的广播的相关权限,如果是有序广播则跳过。最后执行performReceiveLocked处理并行广播。

4.4 BQ.performReceiveLocked

[->BroadcastQueue.java]

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
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
//通过binder机制,发送到广播接收者
if (app != null) {
if (app.thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
//见4.5节
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
// DeadObjectException when the process isn't actually dead.
//} catch (DeadObjectException ex) {
// Failed to call into the process. It's dying so just let it die and move on.
// throw ex;
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
synchronized (mService) {
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.pid + "). Crashing it.");
app.scheduleCrash("can't deliver broadcast");
}
throw ex;
}
} else {
//应有进程死亡,则应有不存在
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
//调用者进程为空
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}

通过app.thread获取到IApplicationThread代理类,通过这个代理类,访问到ApplicationThread中的方法。

4.5 AT.scheduleRegisteredReceiver

[->ActivityThread.java::ApplicationThread]

1
2
3
4
5
6
7
8
9
10
11
12
// This function exists to make sure all receiver dispatching is
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
//更新进程状态
updateProcessState(processState, false);
//见4.6节,其中receiver为2.3.2节所创建
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}

receiver是注册广播时创建的,见2.3.3节 receiver=LoadedApk.ReceiverDispatcher.InnerReceiver

4.6 IR.performReceive

[->LoadedApk.java::InnerReceiver]

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
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
}
if (rd != null) {
//见4.7节
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}

4.7 RD.performReceive

[->LoadedApk.java::ReceiverDispatcher]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
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);
}
}
//见4.8节
if (intent == null || !mActivityThread.post(args.getRunnable())) {
//消息post到主线程,则不会走这里
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}

Args继承于BroadcastReceiver.PendingResult,实现了Runnable,其中mActivityThread是当前的主线程,在2.3.1节完成赋值,post消息机制,将消息放入MessageQueue,该消息是Runnable,而后执行该Runnable。

4.8 ReceiverDispatcher.Args.getRunnable

[->LoadedApk.java]

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
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;

if (ActivityThread.DEBUG_BROADCAST) {
int seq = mCurIntent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
+ " seq=" + seq + " to " + mReceiver);
Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
+ " mOrderedHint=" + ordered);
}

final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
if (intent == null) {
Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
+ ": run() previously called at "
+ Log.getStackTraceString(mPreviousRunStacktrace));
}

mCurIntent = null;
mDispatched = true;
mPreviousRunStacktrace = new Throwable("Previous stacktrace");
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
}
return;
}

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
//获取mReceiver的类加载器
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//调用receiver的onReceive回调
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}

if (receiver.getPendingResult() != null) {
//见4.9节
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
};
}

4.9 PendingResult.finish

[->BroadcastReceiver.java::PendingResult]

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
/* Finish the broadcast.  The current result will be sent and the
* next broadcast will proceed.
*/
public final void finish() {
if (mType == TYPE_COMPONENT) {//代表静态注册的广播
final IActivityManager mgr = ActivityManager.getService();
if (QueuedWork.hasPendingWork()) {
// If this is a broadcast component, we need to make sure any
// queued work is complete before telling AM we are done, so
// we don't have our process killed before that. We now know
// there is pending work; put another piece of work at the end
// of the list to finish the broadcast, so we don't block this
// thread (which may be the main thread) to have it finished.
//
// Note that we don't need to use QueuedWork.addFinisher() with the
// runnable, since we know the AM is waiting for us until the
// executor gets to it.
QueuedWork.queue(new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);//见4.9.1节
}
}, false);
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);//见4.9.1节
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) { //动态注册的串行广播
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManager.getService();
sendFinished(mgr);//见4.9.1节
}
}

主要工作:

1.静态注册的广播接收者:

  • 当QueuedWork工作未完成时,则等待完成再执行sendFinished

  • 当QueuedWork工作已经完成,直接调用sendFinished方法

2.动态注册的广播接收者:当发送的是串行广播,则直接调用sendFinished

参数说明:

TYPE_COMPONENT:静态注册

TYPE_REGISTERED:动态注册

TYPE_UNREGISTERED:取消注册

4.9.1 PendingResult.sendFinished

[->BroadcastReceiver.java::PendingResult]

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
/** @hide */
public void sendFinished(IActivityManager am) {
synchronized (this) {
if (mFinished) {
throw new IllegalStateException("Broadcast already finished");
}
mFinished = true;

try {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
//串行广播,见4.9.2
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
// 并行广播,当属于静态注册的广播,需要告知AMS
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
}
}

4.9.2 AMS.finishReceiver

[->ActivityManagerService.java]

通过binder机制最后调用到AMS的finishReceiver方法。

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

public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);

// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}

final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
BroadcastRecord r;

synchronized(this) {
//属于哪个队列
BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
//见4.9.3节
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
if (doNext) {
//处理下一条广播
r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
}
// updateOomAdjLocked() will be done here
trimApplicationsLocked();
}

} finally {
Binder.restoreCallingIdentity(origId);
}
}

4.9.3 BQ.finishReceiverLocked

[->BroadcastQueue.java]

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
public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
final int state = r.state;
final ActivityInfo receiver = r.curReceiver;
r.state = BroadcastRecord.IDLE;
if (state == BroadcastRecord.IDLE) {
Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
r.receiver = null;
r.intent.setComponent(null);
if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
r.curApp.curReceivers.remove(r);
}
if (r.curFilter != null) {
r.curFilter.receiverList.curBroadcast = null;
}
r.curFilter = null;
r.curReceiver = null;
r.curApp = null;
mPendingBroadcast = null;

r.resultCode = resultCode;
r.resultData = resultData;
r.resultExtras = resultExtras;
if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
r.resultAbort = resultAbort;
} else {
r.resultAbort = false;
}

if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
&& r.queue.mOrderedBroadcasts.size() > 0
&& r.queue.mOrderedBroadcasts.get(0) == r) {
ActivityInfo nextReceiver;
if (r.nextReceiver < r.receivers.size()) {
Object obj = r.receivers.get(r.nextReceiver);
nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
} else {
nextReceiver = null;
}
// Don't do this if the next receive is in the same process as the current one.
if (receiver == null || nextReceiver == null
|| receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
|| !receiver.processName.equals(nextReceiver.processName)) {
// In this case, we are ready to process the next receiver for the current broadcast,
// but are on a queue that would like to wait for services to finish before moving
// on. If there are background services currently starting, then we will go into a
// special state where we hold off on continuing this broadcast until they are done.
if (mService.mServices.hasBackgroundServicesLocked(r.userId)) {
Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
r.state = BroadcastRecord.WAITING_SERVICES;
return false;
}
}
}

r.curComponent = null;

// We will process the next receiver right now if this is finishing
// an app receiver (which is always asynchronous) or after we have
// come back from calling a receiver.
return state == BroadcastRecord.APP_RECEIVE
|| state == BroadcastRecord.CALL_DONE_RECEIVE;
}

这个过程主要是设置BroadcastRecord各个参数为null,并判断是否还有广播需要处理。

4.10 小结

接收广播的过程,主要是对并行广播队列和串行广播队列的处理,先处理并行广播队列后处理串行广播队列:

1.处理广播队列,对广播队列进行相应的权限检查处理。无论是并行还是串行,最后调用的都是performReceiveLocked方法。其中串行广播还有时间限制,会调用broadcastTimeoutLocked方法,超时会强制结束广播;

2.通过Binder机制,将消息传递给接收广播的进程进行处理,如果接收广播的进程没起来,还需要启动其进程;

3.最后回调receiver.onReceive的方法,对于串行广播还需要通知AMS已经处理完该条广播,并进行下个广播的处理。

五、总结

发送广播过程的流程如下:

broadcast

广播机制

1.当发送串行广播(order= true)时

  • 静态注册的广播接收者(receivers),采用串行处理

  • 动态注册的广播接收者(registeredReceivers),采用串行处理

2.当发送并行广播(order= false)时

  • 静态注册的广播接收者(receivers),采用串行处理

  • 动态注册的广播接收者(registeredReceivers),采用并行处理

静态注册的receiver都是采用串行处理;动态注册的registeredReceivers处理方式无论是串行还是并行,取决于广播的发送方式(processNextBroadcast);静态注册的广播由于其所在的进程没有创建,而进程的创建需要耗费系统的资源比较多,所以让静态注册的广播串行化,防止瞬间启动大量的进程。

广播ANR只有在串行广播时才需要考虑,因为接收者是串行处理的,前一个receiver处理慢,会影响后一个receiver;并行广播通过一个循环一次性将所有的receiver分发完,不存在彼此影响的问题,没有广播超时。

串行超时情况:某个广播处理时间>2receiver总个数mTimeoutPeriod,其中mTimeoutPeriod,前后队列为10s,后台队列为60s;某个receiver的执行时间超过mTimeoutPeriod。

附录

源码路径

1
2
3
4
5
6
7
frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/LoadedApk.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/core/java/android/content/IntentFilter.java
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
frameworks/base/core/java/android/content/BroadcastReceiver.java