Android源碼解析四大組件系列(七)---廣播的發(fā)送過程

本篇文章的目錄

1谆趾、廣播數(shù)據(jù)結構分析
2、線程的切換
3袍睡、processNextBroadcast分析
  • 3.1、處理并行廣播
  • 3.2肋僧、處理Pending廣播
  • 3.3斑胜、處理有序廣播
  • 3.4、獲取下一條廣播
  • 3.5嫌吠、檢查是否是動態(tài)廣播
  • 3.6止潘、檢查是否是靜態(tài)廣播
  • 3.7、啟動進程辫诅,處理未發(fā)送的靜態(tài)廣播
4凭戴、動態(tài)廣播receiver處理
5、靜態(tài)廣播receiver處理

先了解一下廣播的數(shù)據(jù)結構炕矮,然后在分析廣播的處理過程么夫。建議看本文,需要先看前面兩篇文章

Android源碼解析---廣播的注冊過程
Android源碼解析---廣播的處理過程

1肤视、廣播數(shù)據(jù)結構分析

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; // 廣播調(diào)用者進程
 
   final String[] requiredPermissions; // 調(diào)用者需要的權限
  
   final List receivers;   //存儲廣播接收者档痪, 包含 BroadcastFilter 和 ResolveInfo
  
   IIntentReceiver resultTo; // who receives final result if non-null
   long enqueueClockTime;  // 加入隊列的時間
   long dispatchTime;      // 分發(fā)時間
   long dispatchClockTime; //分發(fā)時間
   long receiverTime;      // 接收時間.
   long finishTime;        ////廣播完成時間
 
   int nextReceiver;       // 下一個廣播接收者
   IBinder receiver;       //當前廣播接收者
   int state;
   int anrCount;           //廣播ANR次數(shù)
 
   ProcessRecord curApp;       // hosting application of current receiver.
   ComponentName curComponent; // the receiver class that is currently running.
   ActivityInfo curReceiver;   // info about the receiver that is currently running.

}

比較重要的數(shù)據(jù)成員有receivers,存儲的都是廣播接收器邢滑,callerApp是廣播調(diào)用者進程腐螟,還要注意四個時間點,有入隊列殊鞭,分發(fā)遭垛,接收,完成操灿,另外動態(tài)廣播節(jié)點用BroadcastFilter描述锯仪,靜態(tài)的用ResolveInfo描述。

  • ReceiverDispatcher: 客戶端廣播分發(fā)者對象趾盐,第一篇講的很清楚了庶喜,ReceiverDispatcher的內(nèi)部類InnerReceiver為binder對象小腊,用于與AMS的傳遞與通信。

  • ReceiverList: 繼承自ArrayList久窟,存放了Receiver的binder對象以及其注冊的BroadcastFilter列表秩冈。AMS中定義了
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();key為InnerReceiver的binder對象,值為ReceiverList斥扛,ReceiverList內(nèi)部記錄的是動態(tài)注冊的廣播接收者入问,mRegisteredReceivers只有動態(tài)注冊的時候才會有內(nèi)容。

  • BroadcastFilter: 封裝了IntentFilter稀颁,描述動態(tài)廣播芬失,是動態(tài)廣播節(jié)點。

  • ResolveInfo:Parcelable子類匾灶,描述靜態(tài)廣播棱烂,是靜態(tài)廣播節(jié)點。

  • IntentResolver: 解析Intent阶女,在addFilter時即進行解析颊糜。其內(nèi)部有mSchemeToFilter,mActionToFilter秃踩,mTypedActionToFilter三個map對象衬鱼。key為對應的action(scheme或者type),value為Filter吞瞪。

  • BroadcastRecord:描述一個廣播馁启, 將intent等一堆信息驾孔,封裝成BroadcastRecord芍秆,交給BroadcastQueue進行處理。

  • BroadcastQueue: BroadcastQueue為Broadcast處理隊列翠勉,分為前臺隊列mFgBroadcastQueue和后臺隊列mBgBroadcastQueue妖啥,mFgBroadcastQueue會有更高的權限,被優(yōu)先處理对碌。mFgBroadcastQueue和mBgBroadcastQueue兩個隊列中都含有mOrderedBroadcasts和mParallelBroadcasts兩個列表用來表示有序廣播列表和無序廣播列表荆虱。

2、線程的切換

上篇說到不管是有序廣播朽们、無序廣播還是粘性廣播最終都是調(diào)用scheduleBroadcastsLocked處理的怀读。那么scheduleBroadcastsLocked做了什么?

   public void scheduleBroadcastsLocked() {
       if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
               + mQueueName + "]: current="
               + mBroadcastsScheduled);

       //mBroadcastsScheduled參數(shù)是用來標記是否已經(jīng)向消息隊列發(fā)送了一個類型為BROADCAST_INTENT_MSG消息
       if (mBroadcastsScheduled) {
           return;
       }
       //發(fā)送一個BROADCAST_INTENT_MSG消息
       mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
       mBroadcastsScheduled = true;
   }

mHandler是BroadcastQueue的成員變量骑脱,定義如下

final BroadcastHandler mHandler;

它在BroadcastQueue構造函數(shù)中初始化

  BroadcastQueue(ActivityManagerService service, Handler handler,
           String name, long timeoutPeriod, boolean allowDelayBehindServices) {
       mService = service;
       mHandler = new BroadcastHandler(handler.getLooper());
       mQueueName = name;
       mTimeoutPeriod = timeoutPeriod;
       mDelayBehindServices = allowDelayBehindServices;
   }

參數(shù)中的handler是AMS中的MainHandler菜枷,所以BroadcastHandler采用的是ActivityManager線程的Looper,所以通過上面發(fā)送一個BROADCAST_INTENT_MSG消息叁丧,現(xiàn)在由system_server的binder線程切換到system_server的ActivityManager線程中啤誊。

   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");
                   // 處理廣播
                   processNextBroadcast(true);
               } break;
               case BROADCAST_TIMEOUT_MSG: {
                   synchronized (mService) {
                     //超時的時候走這里
                       broadcastTimeoutLocked(true);
                   }
               } break;
               case SCHEDULE_TEMP_WHITELIST_MSG: {
                   DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
                   if (dic != null) {
                       dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
                               msg.arg2, true, (String)msg.obj);
                   }
               } break;
           }
       }
   }

所以現(xiàn)在重點分析processNextBroadcast方法岳瞭。

3、processNextBroadcast分析

processNextBroadcast方法的代碼跟broadcastIntentLocked方法一樣蚊锹,也是很長瞳筏,所以分段來分析。

3.1牡昆、處理并行廣播

  mService.updateCpuStats();

   //fromMsg字段標記是否是從handleMessage中調(diào)用的該方法  
   if (fromMsg) {
       //設置該參數(shù)為false姚炕,表示前面發(fā)送到消息隊列中的BROADCAST_INTENT_MSG消息已經(jīng)被處理了
       mBroadcastsScheduled = false;
   }

   //并行廣播在這里循環(huán)一次性處理掉
   while (mParallelBroadcasts.size() > 0) {
       r = mParallelBroadcasts.remove(0);
       r.dispatchTime = SystemClock.uptimeMillis();
       r.dispatchClockTime = System.currentTimeMillis();
       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);
           //并行廣播都是從deliverToRegisteredReceiverLocked發(fā)送出去的,此時r.receivers里面的都是BroadcastFilter
           deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
       }
       
       addBroadcastToHistoryLocked(r);
       if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
               + mQueueName + "] " + r);
   }

3.2丢烘、處理Pending廣播

如果一個廣播在發(fā)送的時候钻心,進程還沒有啟動起來,那么會將它存在mPendingBroadcast中铅协。由于動態(tài)廣播是不會保證一定能夠收到的捷沸,所以mPendingBroadcast是用來描述一個正在等待靜態(tài)注冊的目標廣播接收者啟動的廣播。

 // 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;
       // 檢查這個靜態(tài)注冊的目標廣播接收者所運行在的應用程序進程是否已經(jīng)啟動起來  
       synchronized (mService.mPidsSelfLocked) {
           ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
           isDead = proc == null || proc.crashing;
       }
       如果這個應用程序進程還活著狐史,就會繼續(xù)等待痒给,否則就不等了
       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;

3.3、處理有序廣播

有序廣播是一個接著一個處理的骏全,并且還可以攔截苍柏,

do {
        //有序廣播隊列為0,不用處理姜贡,返回
        if (mOrderedBroadcasts.size() == 0) {
            // No more broadcasts pending, so all done!
            mService.scheduleAppGcsLocked();
            if (looped) {
                // If we had finished the last ordered broadcast, then
                // make sure all processes have correct oom and sched
                // adjustments.
                //更改一下OOM
                mService.updateOomAdjLocked();
            }
            return;
        }
        //獲取一個有序廣播(最頂部的BroadcastRecord)
        r = mOrderedBroadcasts.get(0);
        boolean forceReceive = false;

         //廣播超時處理试吁,這個會在下一節(jié)具體分析
        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;
                //恢復初始狀態(tài)楼咳。
                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;
        }
         // 進入下面的條件有以下集中可能熄捍,一:廣播沒有接收者了,二:默認第一次r.nextReceiver = 0,但是它每次都會++母怜,等待最后一個處理完了余耽,再++就會得到一個不存在的nextReceiver,此時r.nextReceiver >= numReceivers苹熏,條件成立碟贾,三:
廣播是否已經(jīng)被攔截了,四:廣播是否已經(jīng)被強制結束了  
        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);
                   //處理廣播消息消息轨域,調(diào)用到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");
                //r所描述的廣播轉發(fā)任務已經(jīng)在規(guī)定時間內(nèi)處理完了袱耽,需要remove掉前面給mHandler發(fā)送的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);
            }
            // 將r所描述的廣播轉發(fā)任務從有序廣播隊列中刪除  
            mOrderedBroadcasts.remove(0);
            //賦值為null干发,進入下一次循環(huán)
            r = null;
            looped = true;
            continue;
        }
 } while (r == null);

3.4朱巨、獲取下一條廣播

  //通過上面的循環(huán),r就有值了铐然,獲取下一條廣播
  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 (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);
  }ComponentName component

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

3.5蔬崩、檢查是否是動態(tài)廣播

   //檢查是否是動態(tài)廣播
 if (nextReceiver instanceof BroadcastFilter) {
      BroadcastFilter filter = (BroadcastFilter)nextReceiver;
      if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
              "Delivering ordered ["
              + mQueueName + "] to registered "
              + filter + ": " + r);
     //動態(tài)注冊的廣播給deliverToRegisteredReceiverLocked處理
      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設置為IDLE恶座,表示不需要等待它的前一個目標廣播接收者處理完成一個廣播,  
         // 就可以將該廣播繼續(xù)發(fā)送給它的下一個目標廣播接收者處理  
          r.state = BroadcastRecord.IDLE;
      //執(zhí)行下一個廣播沥阳,內(nèi)部也是發(fā)送消息
          scheduleBroadcastsLocked();
      } else {
          ....
      }
     //有序廣播一次只處理一個跨琳,直接返回就行
      return;
  }

3.6、檢查是否是靜態(tài)廣播

 //如果上面沒有return,那么肯定是靜態(tài)注冊的廣播桐罕,靜態(tài)注冊注冊的廣播節(jié)點是ResolveInfo
  ResolveInfo info = (ResolveInfo)nextReceiver;
  //這個ComponentName會一直傳遞到ActivityThread脉让,用來反射new廣播接收者對象的
  ComponentName component = new ComponentName(
          info.activityInfo.applicationInfo.packageName,
          info.activityInfo.name);
  //很多的條件判斷,skip不滿足就為true
   boolean skip = false;
   .......
 
   String targetProcess = info.activityInfo.processName;
   ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
          info.activityInfo.applicationInfo.uid, false);

   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;
  //變成初始狀態(tài)
      r.state = BroadcastRecord.IDLE;
  //執(zhí)行下個廣播
      scheduleBroadcastsLocked();
      return;
   }

.......
//如果當前進程存在功炮,調(diào)用processCurBroadcastLocked處理溅潜,靜態(tài)廣播都是走processCurBroadcastLocked處理的
if (app != null && app.thread != null) {
      try {
          app.addPackage(info.activityInfo.packageName,
                  info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
          processCurBroadcastLocked(r, app);
      //處理完直接返回,一次處理一個
          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();
          // 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.
  }

 //程序走到這里薪伏,說明進程不存在滚澜,那么調(diào)用startProcessLocked啟動進程,
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 + "/"
              + info.activityInfo.applicationInfo.uid + " for broadcast "
              + r.intent + ": process is bad");
      logBroadcastReceiverDiscardLocked(r);
      finishReceiverLocked(r, r.resultCode, r.resultData,
              r.resultExtras, r.resultAbort, false);
  //啟動失敗就執(zhí)行下一個
      scheduleBroadcastsLocked();
      r.state = BroadcastRecord.IDLE;
      return;
  }
  //把當前的r存下來嫁怀,方便下一次處理
   mPendingBroadcast = r;
  //設置當前的receiver的索引,用來表示將要啟動的设捐。
  mPendingBroadcastRecvIndex = recIdx;

3.7、啟動進程塘淑,處理未發(fā)送的靜態(tài)廣播

當進程啟動完成之后萝招,會回調(diào)AMS的attachApplication,然后走到attachApplicationLocked存捺。

   // Check if a next-broadcast receiver is in this process...
      if (!badApp && isPendingBroadcastProcessLocked(pid)) {
          try {
              didSomething |= sendPendingBroadcastsLocked(app);
          } catch (Exception e) {
              // If the app died trying to launch the receiver we declare it 'bad'
              Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
              badApp = true;
          }
     }

  // The app just attached; send any pending broadcasts that it should receive
  boolean sendPendingBroadcastsLocked(ProcessRecord app) {
      boolean didSomething = false;
      for (BroadcastQueue queue : mBroadcastQueues) {
          didSomething |= queue.sendPendingBroadcastsLocked(app);
      }
      return didSomething;
  }


 public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
      boolean didSomething = false;
      final BroadcastRecord br = mPendingBroadcast;
      if (br != null && br.curApp.pid == app.pid) {
          if (br.curApp != app) {
              Slog.e(TAG, "App mismatch when sending pending broadcast to "
                      + app.processName + ", intended target is " + br.curApp.processName);
              return false;
          }
          try {
              //目標進程已經(jīng)成功啟動了槐沼,那么mPendingBroadcast就可以賦值為null了
              mPendingBroadcast = null;
          //調(diào)用processCurBroadcastLocked處理廣播
              processCurBroadcastLocked(br, app);
              didSomething = true;
          } catch (Exception e) {
              Slog.w(TAG, "Exception in new application when starting receiver "
                      + br.curComponent.flattenToShortString(), e);
              logBroadcastReceiverDiscardLocked(br);
              finishReceiverLocked(br, br.resultCode, br.resultData,
                      br.resultExtras, br.resultAbort, false);
              scheduleBroadcastsLocked();
              // We need to reset the state if we failed to start the receiver.
              br.state = BroadcastRecord.IDLE;
              throw new RuntimeException(e.getMessage());
          }
      }
      return didSomething;
  }

看完上面的三個小節(jié),到這里總結一下 processNextBroadcast()的代碼邏輯:

  • 如果是動態(tài)廣播接收者(無序)捌治,會調(diào)用deliverToRegisteredReceiverLocked一次性處理岗钩,即遍歷并行列表(mParallelBroadcasts)的每一個BroadcastRecord以及其中的receivers列表,是一個雙重循環(huán)具滴。
  • 如果是靜態(tài)廣播接收者(有序)凹嘲,且對應進程已經(jīng)創(chuàng)建,會調(diào)用processCurBroadcastLocked繼續(xù)處理构韵;
  • 如果是靜態(tài)廣播接收者(有序),且對應進程尚未創(chuàng)建趋艘,會調(diào)用startProcessLocked創(chuàng)建進程疲恢,之后仍然會調(diào)用processCurBroadcastLocked繼續(xù)處理。

4瓷胧、動態(tài)廣播receiver處理

上面主要分析了動態(tài)廣播接收者和靜態(tài)廣播接收者該如何處理显拳,現(xiàn)在先看動態(tài)廣播是如何處理的。就是分析deliverToRegisteredReceiverLocked方法實現(xiàn)搓萧。

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
          BroadcastFilter filter, boolean ordered, int index) {
      boolean skip = false;
      //權限判斷杂数,  檢查發(fā)送者是否有權限宛畦,檢查接收者是否有發(fā)送者所需的權限等等,
  //此處省略揍移,不符合的skip==true,下面就return次和。
      ....

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

        ....
      //只有有序廣播才會進入這個分支
      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.curReceiver = r;
              mService.updateOomAdjLocked(r.curApp);
          }
      }
      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 {
          //處理廣播,filter.receiverList.receiver對應的是客戶端ReceiverDispatcher的Binder實體——InnerReceiver
              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) {
         ....
      }
  }
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.
       if (app != null) {
           if (app.thread != null) {
               try {
                   //終于走到ActivityThread里面了
                   app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                           data, extras, ordered, sticky, sendingUser, app.repProcState);
               } catch (RemoteException ex) {
                   .....
               }
           } else {
               // Application has died. Receiver doesn't exist.
               throw new RemoteException("app.thread must not be null");
           }
       } else {
           //調(diào)用者進程不存在那伐,則執(zhí)行該分支
           receiver.performReceive(intent, resultCode, data, extras, ordered,
                   sticky, sendingUser);
       }
   }

      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);
          //走到ReceiverDispatcher中的performReceive實際是InnerReceiver內(nèi)部類當中的方法
           receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                   sticky, sendingUser);
       }

終于走到客戶端的ReceiverDispatcher(廣播分發(fā)者)了踏施,ReceiverDispatcher知道我們這個廣播要分發(fā)給誰。此時正式由SystemServer進程回到客戶端進程了罕邀。

   @Override
    public void performReceive(Intent intent, int resultCode, String data,
           Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
       final LoadedApk.ReceiverDispatcher rd;
        ......
       if (rd != null) {
           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 = ActivityManagerNative.getDefault();
           try {
               if (extras != null) {
                   extras.setAllowFds(false);
               }
               mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
           } catch (RemoteException e) {
               throw e.rethrowFromSystemServer();
           }
       }
   }

可以看到我們調(diào)用ReceiverDispatcher中InnerReceiver的performReceive之后畅形,緊接著在內(nèi)部調(diào)用了ReceiverDispatcher的performReceive方法,再看ReceiverDispatcher的performReceive方法诉探。

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);
               }
           }
           //post了一個消息給主線程
           if (intent == null || !mActivityThread.post(args)) {
               if (mRegistered && ordered) {
                   IActivityManager mgr = ActivityManagerNative.getDefault();
                   if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                           "Finishing sync broadcast to " + mReceiver);
                   ///發(fā)送完成本次廣播處理日熬,用來進行下次的廣播處理。
                   args.sendFinished(mgr);
               }
           }
       }

上面的mActivityThread在第一篇文章說過肾胯,代表主線程碍遍,所以現(xiàn)在會執(zhí)行args的run方法。

  public void run() {
       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 = ActivityManagerNative.getDefault();
       final Intent intent = mCurIntent;
       if (intent == null) {
           Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
       }

       ......
       try {
           ClassLoader cl =  mReceiver.getClass().getClassLoader();
           intent.setExtrasClassLoader(cl);
           intent.prepareToEnterProcess();
           setExtrasClassLoader(cl);
           receiver.setPendingResult(this);
       //onReceive方法回調(diào)
           receiver.onReceive(mContext, intent);
       } catch (Exception e) {
           .....
   }

到此阳液,deliverToRegisteredReceiverLocked是怎么處理動態(tài)廣播就分析完畢了怕敬。總結一下主要流程

------|-BroadcastQueue.performReceiveLocked()
------|-------|-ActivityThread.ApplicationThread.scheduleRegisteredReceiver()
------|-------|-------|- ReceiverDispatcher.InnerReceiver.performReceive()
------|-------|-------|-------|-Handler.post(args)
------|-------|-------|-------|-------|-Args.run()
------|-------|-------|-------|-------|-------|-BroadcastReceiver.onReceive()

5帘皿、靜態(tài)廣播receiver處理

剛剛說了靜態(tài)廣播是processCurBroadcastLocked處理的

   private final void processCurBroadcastLocked(BroadcastRecord r,
           ProcessRecord app) throws RemoteException {
       .....

       r.receiver = app.thread.asBinder();
       r.curApp = app;
       app.curReceiver = r;
      //更新進程狀態(tài)
       app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
       //更新內(nèi)存
       mService.updateLruProcessLocked(app, false, null);
       //更新adj
       mService.updateOomAdjLocked();

       // Tell the application to launch this receiver.告訴客戶端啟動這個receiver
       r.intent.setComponent(r.curComponent);

       boolean started = false;
       try {
             .....
           //走到了ActivityThread中的ApplicationThread中對應的方法东跪。
           app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                   mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                   r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                   app.repProcState);
           if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                   "Process cur broadcast " + r + " DELIVERED for app " + app);
           started = true;
       } finally {
           .....
           }
        }
    }

此時正式由SystemServer進程進入了客戶端進程了

public final void scheduleReceiver(Intent intent, ActivityInfo info,
               CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
               boolean sync, int sendingUser, int processState) {
           updateProcessState(processState, false);
           ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                   sync, false, mAppThread.asBinder(), sendingUser);
           r.info = info;
           r.compatInfo = compatInfo;
           sendMessage(H.RECEIVER, r);
       }

一樣的套路,發(fā)送一個消息給主線程鹰溜,進入對應的case,執(zhí)行 handleReceiver((ReceiverData)msg.obj)虽填;

   private void handleReceiver(ReceiverData data) {
     
      // 這個最初就是在processNextBroadcast處理靜態(tài)注冊的ResolveInfo時,new的ComponentName曹动。
       String component = data.intent.getComponent().getClassName();

       LoadedApk packageInfo = getPackageInfoNoCheck(
               data.info.applicationInfo, data.compatInfo);

       IActivityManager mgr = ActivityManagerNative.getDefault();

       BroadcastReceiver receiver;
       try {
       //反射出BroadcastReceiver
           java.lang.ClassLoader cl = packageInfo.getClassLoader();
           data.intent.setExtrasClassLoader(cl);
           data.intent.prepareToEnterProcess();
           data.setExtrasClassLoader(cl);
           receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
       } catch (Exception e) {
           if (DEBUG_BROADCAST) Slog.i(TAG,
                   "Finishing failed broadcast to " + data.intent.getComponent());
           data.sendFinished(mgr);
           throw new RuntimeException(
               "Unable to instantiate receiver " + component
               + ": " + e.toString(), e);
       }

       try {
           Application app = packageInfo.makeApplication(false, mInstrumentation);

           if (localLOGV) Slog.v(
               TAG, "Performing receive of " + data.intent
               + ": app=" + app
               + ", appName=" + app.getPackageName()
               + ", pkg=" + packageInfo.getPackageName()
               + ", comp=" + data.intent.getComponent().toShortString()
               + ", dir=" + packageInfo.getAppDir());

           ContextImpl context = (ContextImpl)app.getBaseContext();
           sCurrentBroadcastIntent.set(data.intent);
           receiver.setPendingResult(data);
       //這個和動態(tài)的不一樣斋日,靜態(tài)的廣播onReceive方法中的context是RestrictedContext
           receiver.onReceive(context.getReceiverRestrictedContext(),
                   data.intent);
       } catch (Exception e) {
           if (DEBUG_BROADCAST) Slog.i(TAG,
                   "Finishing failed broadcast to " + data.intent.getComponent());
           data.sendFinished(mgr);
           if (!mInstrumentation.onException(receiver, e)) {
               throw new RuntimeException(
                   "Unable to start receiver " + component
                   + ": " + e.toString(), e);
           }
       } finally {
           sCurrentBroadcastIntent.set(null);
       }

       if (receiver.getPendingResult() != null) {
           data.finish();
       }
   }

到這總結一下靜態(tài)廣播接收者的處理流程,如下:
如果應用程序已經(jīng)啟動(app.thread != null)
------|-ActivityThread.ApplicationThread.scheduleReceiver()
------|------|- ActivityThread.handleReceiver()
------|-------|-------|- BroadcastReceiver.onReceive()
否則
------|-LoadedApk.ReceiverDispatcher.IntentReceiver.performReceive()
------|-------|-LoadedApk.ReceiverDispatcher.performReceiver()
------|-------|-------|- LoadedApk.ReceiverDispatcher.Args.run()
------|-------|-------|-------|-BroadcastReceiver.onReceive()

至此廣播的處理過程就結束了墓陈,下篇寫一下廣播細節(jié)恶守,加深理解,比如廣播有序是怎么保證的贡必?怎么實現(xiàn)廣播攔截處理的?廣播超時是怎么處理的?onReceive方法中可以在發(fā)送廣播嗎?registerReceiver方法發(fā)返回值有什么用?粘性廣播等等

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兔港,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仔拟,更是在濱河造成了極大的恐慌衫樊,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異科侈,居然都是意外死亡载佳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門臀栈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔫慧,“玉大人,你說我怎么就攤上這事挂脑∨菏” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵崭闲,是天一觀的道長肋联。 經(jīng)常有香客問我,道長刁俭,這世上最難降的妖魔是什么橄仍? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮牍戚,結果婚禮上侮繁,老公的妹妹穿的比我還像新娘。我一直安慰自己如孝,他們只是感情好宪哩,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著第晰,像睡著了一般锁孟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茁瘦,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天品抽,我揣著相機與錄音,去河邊找鬼甜熔。 笑死圆恤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的腔稀。 我是一名探鬼主播盆昙,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烧颖!你這毒婦竟也來了弱左?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤炕淮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后跳夭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涂圆,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡们镜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了润歉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片模狭。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖踩衩,靈堂內(nèi)的尸體忽然破棺而出嚼鹉,到底是詐尸還是另有隱情,我是刑警寧澤驱富,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布锚赤,位于F島的核電站,受9級特大地震影響褐鸥,放射性物質(zhì)發(fā)生泄漏线脚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一叫榕、第九天 我趴在偏房一處隱蔽的房頂上張望浑侥。 院中可真熱鬧,春花似錦晰绎、人聲如沸寓落。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伶选。三九已至,卻和暖如春锄弱,著一層夾襖步出監(jiān)牢的瞬間考蕾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工会宪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肖卧,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓掸鹅,卻偏偏與公主長得像塞帐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子巍沙,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容