考察内容:
- 广播的注册原理
- 广播的发送原理
- 广播的接收原理
广播的注册
注册广播在应用端的实现
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, ...) {
return registerReceiverInternal(receiver, getUserId(), filter, ...);
}
Intent registerReceiverInternal(BroadcastReceiver receiver, ...) {
//IIntentReceiver是一个binder对象,是可以跨进程传递的
IIntentReceiver rd = null;
scheduler = mMainThread.getHandler();
rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler, ...);
//把IIntentReceiver对象传递到AMS中
return ActivityManagerNative.getDefault().registerReceiver(rd, filter, ...);
}
IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, ...) {
receiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, ReceiverDispatcher> map = null;
map = mReceivers.get(context);
//为BroadcastReceiver new了一个ReceiverDispatcher对象
rd = new ReceiverDispatcher(r, context, handler, ...);
//然后put到map中
map.put(r, rd);
return rd.getIIntentReceiver();
}
- 一个Context和一个BroadcastReceiver可以构成一个二元组,这个二元组会对应一个IIntentReceiver对象
- 同一个Context注册不同的BroadcastReceiver就会对应不同的IIntentReceiver
- 同一个BroadcastReceiver在不同的Activity中注册,也会对应不同的IIntentReceiver
ReceiverDispatcher的构造函数:
ReceiverDispatch(BroadcastReceiver receiver, Context context, ...) {
//生成IInerReceiver对象
mIIntentReceiver = new IInerReceiver(this, !registerd);
//保存了BroadcastReceiver的引用
mReceiver = receiver;
}
final static class InnerReceiver extends IIntentReceiver.Stub {
//IInerReceiver就是IIntentReceiver,是一个binder对象,
//这个对象持有ReceiverDispatcher的弱引用
final WeakReference<ReceiverDispatcher> mDispatcher;
IInerReceiver(ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<ReceiverDispatcher>(rd);
}
}
引用连:
- AMS持有IIntentReceiver的引用
- IIntentReceiver持有ReceiverDispatcher的弱引用
- ReceiverDispatcher持有BroadcastReceiver的引用
AMS调用IIntentReceiver对象的函数将通过引用连最终调用到BroadcastReceiver的onReceived()函数
注册广播在AMS是如何处理的
public Intent registerReceiver(IApplicationThread caller, ...) {
//mRegisteredReceivers是一个Map: Map<IBinder, ReceiverList>
//其中key为一个binder对象,也就是从应用端传过来的IIntentReceiver
//value是一个ReceiverList,这个名字似乎没取好,叫FilterList更合适
//因为它是一个List<BroadcastFilter>,BroadcastFilter继承了IntentFilter
//一个IIntentReceiver可能对应多个IntentFilter,例如:
//在一个Activity中先用一个IntentFilter注册了一个BroadcastReceiver
//然后用另一个IntentFilter对注册同一个BroadcastReceiver
//这样在AMS端一个IIntentReceiver就会对应两个IntentFilter
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(receiver, ...);
rl.app.receivers.add(rl);
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
BroadcastFiler bf = new BroadcastFilter(filter, rl, ...);
rl.add(bf);
//mReceiverResolver是一个IntentResolver,用来解析Intent————看它是否匹配
mReceiverResolver.addFilter(bf);
}
广播的发送
下面只讨论普通广播,不讨论order广播和sticky广播
应用端:
@Override
public void sendBroadcast(Intent intent) {
ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, ...);
}
int broadcastIntent(IApplicationThread caller, Intent intent, ...) {
...
//AMS端执行
broadcastIntentLocked(callerApp, ...);
}
int broadcastIntentLocked(ProcesRecord callerApp, ...) {
...
//首先根据Intent找到匹配的Receiver列表
registeredReceivers = mReceiverResolver.queryIntent(intent, ...);
int NR = registeredReceivers.size();
//ordered表示是否为有序广播,动态广播默认是无序的,因此ordered为false
if (!ordered && NR > 0) {
//AMS中有两个BroadcastQueue:一个是分发紧急任务的,另一个是普通任务的
//此处应该是得到分发普通任务的Queue
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建一个BroadcastRecord,它包含Receiver列表
BroadcastRecord r = new BroadcastRecord(queue, intent, registeredReceivers, ...);
//把BroadcastRecord加到BroadcastQueue中
//BroadcastQueue里其实是有两个列表的:一个是并行分发的,另一个是串行分发的
//动态广播默认是并行分发的,因此这里把BroadcastRecord加到并行分发列表中
queue.enqueueParallelBroadcastLocked(r);
//准备分发广播
queue.scheduleBroadcastLocked();
registeredReceivers = null;
NR = 0;
}
...
}
BroadcastQueue中处理广播分发的函数
final void processNextBroadcast(boolean fromMsg) {
BroadcastRecord r;
while (mParallelBroadcasts.size() > 0) {
//依次取出并行分发列表中的BroadcastRecord
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
for (int i = 0; i < N; i++) {
//依次取得Receiver列表中的receiver
BroadcastFilter target = r.receivers.get(i);
//然后把广播分发给它
//下面这个函数将调用performReceiveLocked(filter.receiverList.app, ...);
deliverToRegisteredReceiverLocked(r, target, false);
}
}
...
}
performReceiveLocked函数进入广播的接收原理
广播的接收原理
AMS端:
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, ...) {
if (app != null) {
//AMS通过applicationThread调用应用端的scheduleRegisteredReceiver
app.thread.scheduleRegisteredReceiver(receiver, intent, ...);
} else {
receiver.performReceive(intent, resultCode, data, ...);
}
}
应用端
void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, ...) {
//注意:并没有转到主线程处理,而是直接调用performReceive函数
receiver.performReceive(intent, resultCode, dataStr, ...);
}
应用端没有把调用转到主线程而是直接调用performReceive函数,那AMS为何不直接调用IntentReceiver的performReceive而要通过applicationThread来调用呢?答案是:为了把广播串行化!因为applicationThread的调用是一个oneway binder调用,所以AMS发起的对这个接口的所有的调用都会被自动 串行化。如果直接调用IntentReceiver的performReceive函数,虽然IntentReceiver也是oneway的,但它只是对这个接口串行化分发。但是AMS希望所有的广播在应用端都是串行化分发的,因此广播尽量从applicationThread走而不是从IntentReceiver走。
广播分发原理图:
- 假如AMS要把intent分发到应用的五个receiver
- 对AMS来说普通的动态广播是并行分发的,加上分发接口又是oneway的,因此对AMS来说调用是异步的——一口所把广播全分发出去了
- 广播被分发到应用进程时,它分发起来却是同步的——自动把它串行化
IIntentReceiver的performReceive实现
public void performReceive(Intent intent, int resultCode, String data, ...) {
//先找到ReceiverDispatcher
ReceiverDispatcher rd = mDispatcher.get();
rd.performReceive(intent, resultCode, data, extras, ...);
}
public void performReceive(Intent intent, int resultCode, ...) {
//new 一个Args,Args实现了Runnable
Args args = new Args(intent, resultCode, data, ...);
//Post到主线程的Handler中,onReceive最终会在主线程调用
mActivityThread.post(args);
}
class Args implements Runnable {
public void run() {
//Args是ReceiverDispatch的内部类,因此它可以拿到BroadcastReceiver的对象
final BroadcastReceiver receiver = mReceiver;
receiver.setPendingResult(this);
//然后调用onReceive函数
receiver.onReceive(mContext, intent);
if (receiver.getPendingResult() != null) {
finish();
}
}
}
//收发工作:
//对于普通的动态广播来说,AMS是一口气并行分发的,它不会管应用端处理完没有
//但是静态广播或者是带ORDER标记的动态广播,AMS是要串行化分发的:它要关注上一个广播执行完了没有,执行完了才会分发下一个广播
//finish()函数就是去通知AMS当前这个广播已经执行完了
//对于普通动态广播,其实finishe()什么都没做
public final void finish() {
if (mType == TYPE_COMPONENT) {
//静态广播
final IActivityManager mgr = ActivityManagerNative.getDefault();
if (QueuedWork.hasPendingWork()) {
QueueWork.singleThreadExecutor().execute(new Runnable() {
@Override public void run() {
//调用sendFinished告诉AMS:当前广播已经执行完了
sendFinished(mgr);
}
});
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
//带ORDER标记的动态广播,也要向AMS报告
IActivityManager mgr = ActivityManagerNative.getDefault();
sendFinished(mgr);
}
}
总结动态广播的注册和收发流程
- 首先应用A向AMS注册广播,将生成一个binder对象,把这个binder和filter注册到AMS
- 然后应用B发送广播,广播中带了一个intent
- AMS会在所有注册了的Receiver里根据intent找到匹配的Receiver,然后开始分发
- 对于普通的动态广播来说,AMS是并行分发的,但是 广播到达应用端之后变成了串行化分发
- 通过binder对象找到对应的BroadcastReceiver然后执行它的onReceived函数
回归: 说说动态广播的注册和收发原理
- 注册广播封装了一个binder对象到AMS
- 通过广播intent找到匹配的receiver,然后分发
- 普通动态广播在系统端 并行分发的,应用端串行分发