Android广播机制简单分析

重点分析流程,而不陷于代码,可以照着流程再细看。

一、广播注册

//客户端注册广播的例子
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列表,而BroadcastFilter extends IntentFilter ,当发送广播后找匹配的receiver时,通过IntentFilter匹配,找动态注册的BroadcastFilter。 下面几句表示的BroadcastReceiver存储的方式:

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,分别为mParallelBroadcasts和mOrderedBroadcasts,对应并行广播和有序广播。
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后,广播不会发送给已经停止的应用,系统默认是不让我们的广播发送给已经停止的应用的。

你可能感兴趣的:(Android广播机制简单分析)