四大組件-BroadcastReciver的工作原理基於android9.0

Android中的廣播分爲動態廣播和靜態廣播,靜態廣播需要在清單文件中註冊,動態廣播使用代碼在需要的地方註冊,這裏只分析動態廣播的註冊過程,

  1. 註冊過程

    動態的廣播註冊調用ContextWrapper的registerReceiver方法。mBase是Context類,具體的實現是在ContextImpl中。

     @Override
        public Intent registerReceiver(
            BroadcastReceiver receiver, IntentFilter filter) {
            return mBase.registerReceiver(receiver, filter);
        }
    
    • ContextImpl的registerReceiver方法

      該方法最終調用registerReceiverInternal方法。

      @Override
          public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
              return registerReceiver(receiver, filter, null, null);
          }
      
    • ContextImpl的registerReceiverInternal方法

      該方法內最終調用ActivityManagerService的registerReceiver方法。並將ThreadActivity內部的ApplicationThread傳入。這個過程涉及到跨進程,因此使用了IIntentReceiver這個Binder接口,它的具體實現時LoadedApk.ReceiverDispatcher.InnerReceiver,創建了ReceiverDispatcher對象,並將BroadCastReciver及InnerReceiver保存在ReceiverDispatcher對象中。

      private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                  IntentFilter filter, String broadcastPermission,
                  Handler scheduler, Context context, int flags) {
              IIntentReceiver rd = null;
              if (receiver != null) {
                  if (mPackageInfo != null && context != null) {
                      if (scheduler == null) {
                          scheduler = mMainThread.getHandler();
                      }
                      rd = mPackageInfo.getReceiverDispatcher(
                          receiver, context, scheduler,
                          mMainThread.getInstrumentation(), true);
                  } else {
                      if (scheduler == null) {
                          scheduler = mMainThread.getHandler();
                      }
                      rd = new LoadedApk.ReceiverDispatcher(
                              receiver, context, scheduler, null, true).getIIntentReceiver();
                  }
              }
              try {
                  final Intent intent = ActivityManager.getService().registerReceiver(
                          mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                          broadcastPermission, userId, flags);
                  if (intent != null) {
                      intent.setExtrasClassLoader(getClassLoader());
                      intent.prepareToEnterProcess();
                  }
                  return intent;
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              }
          }
      
    • ActivityManagerService的registerReceiver方法

      在該方法中將會將遠程的InnerReceiver以及BroadcastFilter保存起來。

       ...
        mRegisteredReceivers.put(receiver.asBinder(), rl);
       ....
       BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                          permission, callingUid, userId, instantApp, visibleToInstantApps);
                  if (rl.containsFilter(filter)) {
                      Slog.w(TAG, "Receiver with filter " + filter
                              + " already registered for pid " + rl.pid
                              + ", callerPackage is " + callerPackage);
                  } else {
                      rl.add(bf);
                      if (!bf.debugCheck()) {
                          Slog.w(TAG, "==> For Dynamic broadcast");
                      }
                      mReceiverResolver.addFilter(bf);
                  }
        ...
      
  2. 發佈過程
    • ContexImpl的sendBroadcast

    ​ 廣播的發送會調用Context的sendBroadcast方法,具體實現依然在ContextImpl中,

    ​ 在該方法中調用了AMS的broadcastIntent方法 。

    @Override
        public void sendBroadcast(Intent intent) {
            warnIfCallingFromSystemProcess();
            String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
            try {
                intent.prepareToLeaveProcess(this);
                ActivityManager.getService().broadcastIntent(
                        mMainThread.getApplicationThread(), intent, resolvedType, null,
                        Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                        getUserId());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    
  • ActivityManagerService的broadcastIntent

    在該方法中通過intent獲取BroadcastQueue一個隊列,最後調用scheduleBroadcastsLocked方法。

    ...
      final BroadcastQueue 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);
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
                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();
                }
    ...
    
  • BroadcastQueue的scheduleBroadcastsLocked方法

    在該方法內發送一個BROADCAST_INTENT_MSG狀態的消息。

        public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
    
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }
    

    BROADCAST_INTENT_MSG的消息處理如下,調用processNextBroadcast方法,並接着調用deliverToRegisteredReceiverLocked方法

     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;
                }
            }
        }
    
  • deliverToRegisteredReceiverLocked方法

    在該方法內調用performReceiveLocked方法。

    ...
    performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                            new Intent(r.intent), r.resultCode, r.resultData,
                            r.resultExtras, r.ordered, r.initialSticky, r.userId);
    ...
    
  • performReceiveLocked方法

    在該方法內調用app.thread.scheduleRegisteredReceiver方法,也就是ActiivtyThread內的ApplicationThread的scheduleRegisteredReceiver方法。

    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) {
                    // If we have an app thread, do the call through that so it is
                    // correctly ordered with other one-way calls.
                    try {
                        app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                                data, extras, ordered, sticky, sendingUser, app.repProcState);
                    // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                    // DeadObjectException when the process isn't actually dead.
                    //} catch (DeadObjectException ex) {
                    // Failed to call into the process.  It's dying so just let it die and move on.
                    //    throw ex;
                    } catch (RemoteException ex) {
                        // Failed to call into the process. It's either dying or wedged. Kill it gently.
                        synchronized (mService) {
                            Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                    + " (pid " + app.pid + "). Crashing it.");
                            app.scheduleCrash("can't deliver broadcast");
                        }
                        throw ex;
                    }
                } else {
                    // Application has died. Receiver doesn't exist.
                    throw new RemoteException("app.thread must not be null");
                }
            } else {
                receiver.performReceive(intent, resultCode, data, extras, ordered,
                        sticky, sendingUser);
            }
        }
    
  • ApplicationThread的scheduleRegisteredReceiver方法

    在該方法內調用IIntentReceiver這個Binder接口的performReceive,也就調用上文說到的LoadedAPK.ReceiverDispatcher.InnerReceiver的performReceive方法

    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);
                receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                        sticky, sendingUser);
            }
    
  • InnerReceiver的performReceive方法

    在該方法內調用LoadedApk.ReceiverDispatcher的performReceive方法

     @Override
                public void performReceive(Intent intent, int resultCode, String data,
                        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                    final LoadedApk.ReceiverDispatcher rd;
                  ....
                        rd.performReceive(intent, resultCode, data, extras,
                                ordered, sticky, sendingUser);
                   ...
                }
    
  • ReceiverDispatcher的performReceive方法

    在該方法中調用了mActivityThread.post(args.getRunnable()),mActivityThread是一個Handler,args是Args對象,通過getRunnable獲取一個Runnable對象,並執行run方法。

     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);
                    }
                }
                if (intent == null || !mActivityThread.post(args.getRunnable())) {
                    if (mRegistered && ordered) {
                        IActivityManager mgr = ActivityManager.getService();
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing sync broadcast to " + mReceiver);
                        args.sendFinished(mgr);
                    }
                }
            }
    

    Runnable的run方法。

    在該方法內最終調用BroadcastReciver的onReciver方法。

    ...
    try {
                            ClassLoader cl = mReceiver.getClass().getClassLoader();
                            intent.setExtrasClassLoader(cl);
                            intent.prepareToEnterProcess();
                            setExtrasClassLoader(cl);
                            receiver.setPendingResult(this);
                            receiver.onReceive(mContext, intent);
                        } catch (Exception e) {
    ...				                    
    

總結:當調用廣播的註冊方法時,會將BroadcastReciver保存在LoadedApk.BroadcastDispatcher中,並返回一個IIntentReceiver的Binder的接口,具體的實現是LoadedApk.BroadcastDispatcher.InnerReceiver,然後調用AMS的registerReceiver方法將IIntentReceiver和BroadcastFilter存儲起來。當調用廣播的發送方法時,會通過AMS調用broadcastIntent方法,最終調用ActivityThread內部類的ApplicationThread中的scheduleRegisteredReceiver,然後調用IIntentReceiver這個Binder類型的實現類IntentReceiver的performReceive,最終調用BroadcastReciver的onReciver方法。在這個過程中AMS持有IApplicationThread和IIntentReceiver這兩個Binder類型的接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章