目录
一.注册广播
时序图:
注册过程主要是创建2个存储Receiver的对象:
- ReceiverList 记录接收器的所有信息
- BroadcastFilter Receiver的选择条件,主要就是权限和Action
并将这2个对象进行存储
主要源码如下:
/framework/base/services/core/java/com/android/server/am/ActivityManagerService.java
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
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 bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
二.注销流程:
注销流程就是注册的逆过程,将创建的ReceiverList和BroadcastFilter移除并销毁。
主要源码如下:
/framework/base/services/core/java/com/android/server/am/ActivityManagerService.java
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl != null) {
final BroadcastRecord r = rl.curBroadcast;
if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
final boolean doNext = r.queue.finishReceiverLocked(
r, r.resultCode, r.resultData, r.resultExtras,
r.resultAbort, false);
if (doNext) {
doTrim = true;
r.queue.processNextBroadcast(false);
}
}
if (rl.app != null) {
rl.app.receivers.remove(rl);
}
removeReceiverLocked(rl);
if (rl.linkedToDeath) {
rl.linkedToDeath = false;
rl.receiver.asBinder().unlinkToDeath(rl, 0);
}
}
三.广播的处理流程:
在ActivityManagerService主要做了以下工作:
- 根据Action获取对应的static Receiver和Dynamic Receiver
- 根据Action获取对应处理Static Receiver和Dynamic Receiver的BroadcastQueue
- 针对static Receiver和Dynamic Receiver集合分别创建BroadcastRecord并交给对应的BroadcastQueue处理
对应的源码:
/framework/base/services/core/java/com/android/server/am/ActivityManagerService.java
的broadcastIntentLocked方法
//获取Static Receiver集合
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
//获取Dynamic Receiver集合
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
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的获取BroadcastQueue用来给Dynamic Receiver分发
final BroadcastQueue queue;
queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
Static Receiver的分发机制与Dynamic Receiver基本相同
接下来就到BroadQueue中执行了,在学习BroadQueue执行流程之前需要了解2个集合的作用:
- mParallelBroadcasts 并行集合,调用enqueueParallelBroadcastLocked方法将Receiver放到并行队列中执行,通常是Dynamic Receiver在并行队列中执行。
- mOrderedBroadcasts 串行集合,调用enqueueOrderedBroadcastLocked方法将Receiver放到串行队列中执行,通常是Static Receiver在串行队列中执行,因此Static Receiver必须等待上一个Receiver执行完毕,下一个Receiver才会开始执行。存在排队现象导致程序执行较慢,因此建议Receiver都使用Dynamic Receiver。
在BroadcastQueue中主要做了一下工作:
- 从并行集合中取出所有BroadcastRecord,并取出BroadcastRecord中所有的Receiver,循环遍历更新状态并调用BroadcastReceiver中的onReceiver方法。
- 处理完并行集合后在处理串行集合,流程同上。
- 处理完成后此次scheduleBroadcastsLocked执行完毕,等待下次调用scheduleBroadcastsLocked方法。
重要的源码如下:
/framewrk/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
BroadcastRecord r;
while (mParallelBroadcasts.size() > 0) {
synchronized (mParallelBroadcasts) {
r = mParallelBroadcasts.remove(0);
}
final int N = r.receivers.size();
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
}
}
四.总结:
-
在广播处理过程中使用了大量的Binder通信,因此需要具有Binder通信的基础之后才能读懂整个流程;
-
在日常编码过程中尽量使用动态注册广播,不要在onReceiver中处理耗时操作,否则会发生Broadcast的ANR错误;
-
广播的处理工作也是在ActivityManagerService这个服务中;
-
本文中贴的源码省略了大量的代码,阅读此文章最好和源代码一起参照学习;
-
有关Android广播的学习会持续进行,这篇只是最基层的处理;