重点分析流程,而不陷于代码,可以照着流程再细看。
一、广播注册
//客户端注册广播的例子
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.broadcast.test");
registerReceiver(mBroadcastReceiver, intentFilter);
registerReceiver其实是ContexImpl来调用的,走过几个类似重载的registerReceiver方法,最终来到registerReceiverInternal方法。在registerReceiverInternal里构建出ReceiverDispatcher,ReceiverDispatcher具有跨进程的binder内部类IIntentReceiver,然后交给ActivityManagerService的registerReceiver方法去完成注册。ActivityManagerService用 mRegisteredReceivers存储注册的动态广播,
/**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
final HashMap mRegisteredReceivers = new HashMap<>();
key为注册的receiver,value为ReceiverList,ReceiverList为ArrayList
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId);
rl.add(bf);
mReceiverResolver.addFilter(bf);
上面注意最后一句,mReceiverResolver的作用是什么呢?见源码,下一节分析。
/**
* Resolver for broadcast intents to registered receivers.
* Holds BroadcastFilter (subclass of IntentFilter).
*/
final IntentResolver mReceiverResolver
= new IntentResolver() {
二、发送广播
//发送广播的例子
Intent intent = new Intent();
intent.setAction("android.broadcast.test");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//sendBroadcast(intent);
sendOrderedBroadcast(intent, null);
客户端的sendBroadcast最终会走到ActivityManagerService的broadcastIntentLocked,前面很多代码是权限之类的检查,忽略掉,重点分析怎么发送。因为存在动态广播和静态广播,所以检查sendBroadcast的Intent是不是只有动态广播receiver可以接收,通过下面这句,如果不只是动态广播receiver能接收,那就要也发送那些静态注册的receiver。registeredReceivers是动态广播接收器列表 ,receivers是静态广播接收器列表。
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY ==0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
还记得在广播注册最后的mReceiverResolver吗?在这里派上用场,registeredReceivers通过下面这句得到。
registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false, userId);
这样就得到了符合能接收Intent的所有Receiver。
下面要构建一个BroadcastRecord对象,并入队发送出去。首先的问题是入哪个队列,有ActivityManagerService前台和后台两个队列,如果发送的Intent有Intent.FLAG_RECEIVER_FOREGROUND就选前台队列,否则选后台队列。
前台和后台队列又分别含有两个列表mParallelBroadcasts和mOrderedBroadcasts对应无序广播和有序广播。
最后发送时,调用
//无序广播
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
//有序广播
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
三、广播的处理
scheduleBroadcastsLocked只是通过Handler发送一个消息BROADCAST_INTENT_MSG,Handler收到消息后调用processNextBroadcast,这里如果是无序广播,一次处理,走到deliverToRegisteredReceiverLocked,然后调用LoadedApk中ReceiverDispatcher的performReceive,在里面构造一个叫Args的Runnable,然后ActivityThread中的H这个Handler去post执行。
这样Runnable的run()方法执行,走到了我们熟悉的onReceive回调。
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
四、其他东西
以上简单分析了广播的整个流程,中间很多细节的东西还需要精读源码分析,比如有序广播怎么处理的,静态广播怎么处理的。
下面列一些结论性的东西:
// 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;
1.默认动态注册的广播ANR时间为60S,说明默认动态注册的广播为后台广播。
2.无序广播不会ANR,有序广播会ANR。但是广播回调onReceive如果在主线程耗时,会出现ANR,此ANR非广播ANR,而是Activity的ANR。
3.ActivityManagerService中有两个BroadcastQueue,分别是mFgBroadcastQueue和mBgBroadcastQueue,对应前台广播和后台广播,而每个BroadcastQueue中又含有两个ArrayList
4.ANR简单流程如下,重点在函数processNextBroadcast:取得下一个有序广播,Handler发送延迟ANR msg,如果没有TIMEOUT,Handler remove ANR msg,如果TIMEOUT,Handler执行AppNotResponding这个Runnable。
//前台广播mTimeoutPeriod为10s,后台广播为60s,通过Handler发送BROADCAST_TIMEOUT_MSG
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
}
//如果没有timeout,将之前的BROADCAST_TIMEOUT_MSG取消掉
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}
}
/*如果到了timeout时间,还没有取消BROADCAST_TIMEOUT_MSG,就会执行这个,
调用到broadcastTimeoutLocked,最终通过Handler来post AppNotResponding这个Runnable*/
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
当然还有个地方也会发生ANR,和Receiver的个数有关系,而且不是通过Handler来发生的,当发生Timeout时,直接调用broadcastTimeoutLocked
//在processNextBroadcast方法里
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&(now > r.dispatchTime +
(2*mTimeoutPeriod*numReceivers))) {
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
5.设置 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);这个flag后,广播不会发送给已经停止的应用,系统默认是不让我们的广播发送给已经停止的应用的。