Android 8.0 源碼分析 (六) BroadcastReceiver 啓動

前言

咱們熟知通常 Android 工程師都是在應用層上開發,不會涉及系統源碼,可是若是你想往底層發展,或者深刻插件化、Framework 系統層等開發工做,若是不瞭解 Android 源碼但是不行的,那麼接下來我基於本身的理解跟學習來記錄跟 Android 開發息息相關的源碼分析,大概從 Android 中的 SystemServer 啓動、四大組件啓動、AMS、PMS 等幾個維度來介紹,下面是個人計劃,固然在將來也有可能改變。java

尚未關注的小夥伴,能夠先關注一波,系列文章會持續更新。android

Android 8.0 源碼分析 (一) SystemServer 進程啓動服務器

Android 8.0 源碼分析 (二) Launcher 啓動app

Android 8.0 源碼分析 (三) 應用程序進程建立到應用程序啓動的過程ide

Android 8.0 源碼分析 (四) Activity 啓動函數

Android 8.0 源碼分析 (五) Service 啓動oop

Android 8.0 源碼分析 (六) BroadcastReceiver 啓動源碼分析

Android 8.0 源碼分析 (七) ContentProvider 啓動post

介紹

廣播做爲四大組件之一,使用頻率雖然沒有 Activity 高,可是使用場景也仍是比較普遍,好比監聽開機、息屏亮屏、組件或者進程間發送消息等等。接下來將爲你們介紹廣播的工做過程,分別從註冊、發送、接收這三點來介紹。學習

源碼分析

廣播的註冊過程

廣播的註冊分爲靜態跟動態註冊,靜態註冊須要經過 PMS 來解析 Android 清單文件等等複雜操做,這裏咱們以動態註冊廣播來說解。先來看一下注冊時序圖:

首先,想要使用廣播就得經過 registerReceiver 方法註冊一個廣播,最終也是在 Activity 的父類 ContextWrapper 中實現,代碼以下:

//ContextWrapper.java
		/** * 應用調用註冊廣播的函數 * @param receiver The BroadcastReceiver to handle the broadcast. * @param filter Selects the Intent broadcasts to be received. * * @return */
    @Override
    public Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) {
        //mBase 是 Context的引用
        return mBase.registerReceiver(receiver, filter);
    }
複製代碼

咱們在講解 Android 8.0 源碼分析 (五) Service 啓動 的時候,開篇介紹了 Activity,Context,ContextImpl 之間的關係,這裏就不在多說了,有不瞭解能夠先去看一下上一篇文章。這裏咱們直接看 Context 的實現類 ContextImpl 中的實現,代碼以下:

/** * Context 調用 * @param receiver The BroadcastReceiver to handle the broadcast. * @param filter Selects the Intent broadcasts to be received. * * @return */
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        //調用內部重載方法
        return registerReceiver(receiver, filter, null, null);
    }



    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
        //調用內部重載方法
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    }


    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context, int flags) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            /** * 1. */
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    //獲取 ActivityThread H
                    scheduler = mMainThread.getHandler();
                }
                //獲取 IIntentReceiver 對象,經過它與 AMS 交互,而且經過 Handler 傳遞消息
                rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        /** * 2. */
                        mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                /** * 3. */
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            //調用 AMS 的 registerReceiver
            /** * 4. */
            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();
        }
    }
複製代碼

前面 2 個函數都是簡單的調用內部重載方法,咱們直接看 registerReceiverInternal 方法實現,註釋 1 判斷 mPackageInfo 與 context 是否爲空,若是不爲空將執行註釋 2 代碼,經過 mPackageInfo 方法調用 getReceiverDispatch 方法獲取 rd 對象,不然就調用註釋 3 處的代碼來建立 rd 對象。這 2 步代碼主要就是來獲取 IIntentReceiver 對象,它是一個 Binder 接口,用於廣播的跨進程通訊,它在 LoadedApk.ReceiverDispatcher.InnerReceiver 中實現,代碼以下所示:

//LoadedApk.java
    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }
          
          ....
            
        }
複製代碼

回到 registerReceiverInternal 方法,在註釋 4 處調用 AMS 代理類 IActivityManagerregisterReceiver 方法,經過進程間通訊最後在 AMS 類的 registerReceiver 方法,並將 IIntentReceiver 類型的 rd 引用也一併傳遞進 AMS 中,這裏之因此不直接傳入客戶端的 BroadcastReceiver 而是傳入 IIntetnReceiver ,由於註冊廣播是一個跨進程的過程,須要具備跨進程通訊功能的 IIntentReceiver ,你也能夠把它理解爲一箇中間者,registerReceiver 方法內部比較多,這裏分爲 2 個部分來說解,先來看 part1,代碼以下:

1. registerReceiver 方法的 part1

//AMS.java
    /** * 這裏是經過 Binder 通知調用 * @return Intent */
    public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) {
        enforceNotIsolatedCaller("registerReceiver");
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        final boolean visibleToInstantApps
                = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
        int callingUid;
        int callingPid;
        boolean instantApp;
        synchronized(this) {
            if (caller != null) {
                /** * 1. 經過 getRecordForAppLocked 方法獲得 ProcessRecord類型的 callerApp 對象,用描述 AMS 註冊廣播接收者的 Activity 所在的進程 */
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid()
                            + ") when registering receiver " + receiver);
                }
                if (callerApp.info.uid != SYSTEM_UID &&
                        !callerApp.pkgList.containsKey(callerPackage) &&
                        !"android".equals(callerPackage)) {
                    throw new SecurityException("Given caller package " + callerPackage
                            + " is not running in process " + callerApp);
                }
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }

            instantApp = isInstantApp(callerApp, callerPackage, callingUid);
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            /** * 2. 根據傳入的 IntentFilter 類型的 filter 獲得一個 action 列表 */
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Collect stickies of users
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                
                String action = actions.next();
                for (int id : userIds) {
                    //根據actions 列表和 userIds 獲得全部的粘性廣播的 intent,並在註釋 3 處傳入到 stickyIntents 中
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            /** * 3. 將匹配到的粘性廣播 action 存入容器中 */
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            // Look for any matching sticky broadcasts...
            /** * 遍歷尋找匹配的粘性廣播 */
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                // Don't provided intents that aren't available to instant apps.
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                //開始匹配
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    /** * 4. 將intent 存入 allSticky 列表中 */
                    allSticky.add(intent);
                }
            }
        }

        ....//後面代碼 part2 講解

            return sticky;
        }
    }

複製代碼

在註釋 1 經過 getRecordForAppLocked 方法獲得 ProcessRecord 類型的 callerApp 對象,它用於描述請求 AMS 註冊廣播接收者的 Activity 所在的應用程序進程。在註釋 2 處根據傳入的 IntentFilter 類型的 filter 獲得一個 actions 列表,根據 actions 列表和 userIds 獲得全部的粘性廣播的 intent ,並在註釋 3 處傳入到 stickyIntents 中。接下來從 stickyIntent 中匹配傳入的參數 filter 的粘性廣播的 intent ,在註釋 4 處將這些 intent 存入到 allSticky 列表中,從這裏能夠看出粘性廣播是存儲在 AMS 中的。

2. registerReceiver 方法的 part2

接下來看 AMS 的 registerReceiver 方法剩餘內容,代碼以下所示:

//AMS.java

    /** * 這裏是經過 Binder 通知調用 * @return Intent */
    public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) {
     ...
       
       
          synchronized (this) {
					...
            /** * 1. 獲取 ReceiverList */
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {//若是爲空調用註釋 2
                /** * 2. 建立一個 ReceiverList 對象,它繼承自 ArrayList,用於存放廣播接收者 */
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                ...
            }

            /** * 3. 構建 BroadcastFilter 對象,而且將 廣播接收者列表 ReceiverList 添加到進去 * 用於描述註冊的廣播接收者 */
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            /** * 4. 經過 add 函數將自身添加到廣播接收者列表中 */
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            /** * 5. 將 BroadcastFilter 添加到 IntentResolver 類型的 mReceiverResolver 中。 */
            mReceiverResolver.addFilter(bf);

    
      ...
    }
複製代碼

在註釋 1 處獲取到了 ReceiverList 列表,若是爲空則在註釋 2 處建立一個新的接收列表 ReceiverList 對象,它繼承自 ArrayList,用來存儲廣播接收者。在註釋 3 處建立 BroadcastFilter 並傳入此前建立的 ReceiverList ,BroadcastFilter 用來描述註冊的廣播接收者,並在註釋 4 處經過 add 方法將自身添加到 ReceiverList 中。在註釋 5 處將 BroadcastFilter 添加到 IntentResolver 類型的 mReceiverResolver 中,這樣當 AMS 接收到廣播時就能夠從 mReceiverResolver 中找到對應的廣播接收者了。從而達到註冊廣播的目的。

廣播的發送和接收過程

廣播的發送和接收分爲 2 個階段來分析,經過應用進程到 AMS SystemServer 進程的調用,而後 AMS 所在的進程通知應用進程的調用,下面咱們先來分析應用程序進程到 AMS 的過程。

ContextImpl 到 AMS 的調用過程

廣播發送多種類型的廣播,好比 無序、有序、粘性廣播,這裏以最簡單的廣播無序廣播來說解,也就是發送一個普通廣播,它的實現也是在 ContextWrapper 中,下面先來看一個總體調用時序圖.

直接來看 ContextWrapper 的 sendBroadcast 方法,代碼以下:

//ContextWrapper.java
    @Override
    public void sendBroadcast(Intent intent) {
      	//調用 Context 的實現類 ContextImpl
        mBase.sendBroadcast(intent);
    }
複製代碼

這裏的 mBase 是 Context , 在以前文章中將到了 ContextImpl 是 Context 的實現類,咱們直接看它的實現,代碼以下:

//ContextImpl.java
    @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();
        }
    }
複製代碼

看到上面的代碼是否是倍感的親切,熟悉,沒錯它又調用 AMS 的代理類 IActivityManager 的 broadcastIntent 函數,咱們發現跟咱麼以前講解的 Activity,Service 調用方式同樣都會通過 AMS 的代理類 IActivityManager ,那麼 AMS 究竟是何方神聖,這個咱們講解完 四大組件 以後會單獨來介紹,下面咱們直接看 AMS 的實現:

//AMS.java

    /** * 應用程序進程調用 * @param caller * @param intent * @param resolvedType * @param resultTo * @param resultCode * @param resultData * @param resultExtras * @param requiredPermissions * @param appOp * @param bOptions * @param serialized * @param sticky * @param userId * @return */
    public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            /** * 1. 驗證廣播是否合法 */
            intent = verifyBroadcastLocked(intent);
            /** * 拿到所在的進程 */
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            /** * 2. */
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
複製代碼

咱們先看註釋 1 內部驗證廣播代碼實現:

//AMS.java

    final Intent verifyBroadcastLocked(Intent intent) {
        // Refuse possible leaked file descriptors
        /** * 1. 驗證 intent 是否不爲null 而且有文件描述符 */
        if (intent != null && intent.hasFileDescriptors() == true) {
          ...
          }

        /** * 2. 得到 intent 的 flags */
        int flags = intent.getFlags();

        if (!mProcessesReady) {
            /** * 3. 系統正在啓動過程當中。若是是動態廣播者不作處理 */
            if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
                
                /** * 4. 若是 flag 沒有設置爲 FLAG_RECEIVER_REGISTERED_ONLY 只接受動態註冊的廣播接收者則會拋出異常 */
            } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            ...    
            }
        }

				...

        return intent;
    }
複製代碼

根據上面的註釋咱們知道就是對 Intent 判斷是否合法性,下面咱們繼續回到 broadcastIntent 註釋 2 ,代碼以下:

//AMS.java
    final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
      ...
        
            /** * 1. 建立 BroadcastRecord 對象將 receivers 傳進去。 */
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);
      
                  final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
           
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                /** * 2. */
                //處理廣播分發
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
        
      ...
      
    }     
複製代碼

註釋 1 上面省略了不少代碼,省略的代碼如要是把註冊 動態/靜態的廣播接收者按照優先級高低不一樣儲存在不一樣的列表中,在將這 2 個列表合併到 receivers 列表中,這樣 receivers 列表包含了全部的廣播接收者。在註釋 1 處建立 BroadcastReceiver 對象並將 receivers 傳遞進去,在註釋 2 處調用 BroadcastQuque 的 scheduleBroadcastsLocked 方法。

AMS 到 BroadcastReceiver 的調用過程

AMS 到 BroadcastReceiver 的調用過程請先看下面時序圖:

下面直接看 BroadcastQueue 的 scheduleBroadcastsLocked 函數實現,代碼以下:

//BroadcastQueue.java

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

        if (mBroadcastsScheduled) {
            return;
        }
        //經過 Handler 分發
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
複製代碼

上面的代碼向 BroadcastHandler 類型的 mHandler 對象發送了 BROADCAST_INTENT_MSG 類型的消息,這個消息在 BroadcastHandler 的 handleMessage 方法中進行處理,以下所示:

//BroadcastQueue.java
 		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;
            }
        }
    }
複製代碼

在 handleMessage 方法中調用了 processnextBroadcast 方法,方法對無序廣播和有序廣播分別進行處理,在將廣播發送給廣播接收者,處理代碼以下:

//BroadcastQueue.java

    final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) {
            BroadcastRecord r;

  				...
            mService.updateCpuStats();

            if (fromMsg) {
                /** * 1. 已經處理了 BROADCAST_INTENT_MSG 這條消息 */
            
                mBroadcastsScheduled = false;
            }

            /** * 2. 遍歷存儲無序廣播的 mParallelBroadcasts 列表 */
            while (mParallelBroadcasts.size() > 0) {
                /*** 3.獲取無序廣播 */
                r = mParallelBroadcasts.remove(0);
                ...
                
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                 /** * 4. 將 r 對象描述的廣播發送給對應的廣播者 */
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }

                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            }

            ...
        }
    }
複製代碼

從前面 BroadcastHandler 方法中咱們得知傳入的參數 fromMsg 的值爲 true,所以在註釋1 處將 mBroadcastsScheduled 設置爲 flase, 表示對於此前發來的 BROADCAST_INTENT_MSG 類型的消息已經處理了。在註釋 2 處的 mParallelBroadcasts 列表用來存儲無序廣播,經過 while 循環將 mParallelBroadcasts 列表中的無序廣播發送給對應的廣播接收者。在註釋 3 處獲取每個 mParallelBroadcasts 列表中存儲的 BroadcastRecord 類型的 r 對象。在註釋 4 處將這些 r 對象描述的廣播發送給對應的廣播接收者,deliverToRegisteredReceiverLocked 方法,以下所示:

//BroadcastQueue.java


    private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) {
     ...
       
                 if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                 if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                /*** * 1. */
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
            }  
       
     ...
       
      
    }
複製代碼

deliverToRegisteredReceiverLocked 內部代碼如要是用來檢查廣播發送者和廣播接收者的權限,若是經過了權限的檢查,則會調用註釋 1 處的 performReceiveLocked 方法。

//BroadcastQueue.java

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        /** * 1. */
        if (app != null) {
            /** * 2. */
            if (app.thread != null) {
                
                try {
                    /** * 3. */
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                ...
    }
複製代碼

在註釋 1 處和註釋 2 處的代碼表示若是廣播的接收者所在的應用程序進程存在而且正在運行,則執行註釋 3 處的代碼,表示用廣播接收者所在的應用程序進程來接收廣播,這裏 app.thread 指的是 ApplicationThread,它其實在 ActivityThread 內部類中,繼承於 IApplicationThread.Stub 下面咱們看它的實現,代碼以下:

//ActivityThread.java

    private class ApplicationThread extends IApplicationThread.Stub {
    ...
      
            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);
      			/***1. 調用 IIntentReceiver 中的 performReceive 函數*/
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }
    ...
      
    }
複製代碼

在註釋 1 中調用了 IIntentReceiver 的 performReceive 函數,IItentReceiver 在前面提到過,用於廣播的跨進程的通訊,它的具體實如今 LoadedApk.ReceiverDispatcher.InnerReceiver,代碼以下:

//LoadedApk.java
    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }

            @Override
            public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
              ...
                if (rd != null) {
                  //1. 
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                   ...
                }
            }
        }
      ....
        
    }
複製代碼

其實 IIntentReceiver 和 IActivityManager 同樣,都使用了 aidl 來實現進程間通訊。InnerReceiver 繼承自 IIntentReceiver.Stub,是 Binder 通訊的服務器端, IIntentReceiver 則是 Binder 通訊的客服端、InnerReceiver 在本地的代理,它的具體的實現就是 InnerReceiver. 在 InnerReceiver 的 performReceiver 方法的註釋 1 調用了 ReceiverDispatch 類型的 rd 對象的 performReceive 方法,代碼以下:

//LoadedApk.java
        public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            /** * 1. */
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
           ...
            /** * 2. */
            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);
                }
            }
        }

    }
複製代碼

在註釋 1 處將廣播的 intent 等信息封裝到了爲 Args 對象中,在註釋 2 處調用 mActivityThread 的 post 方法並傳入了 Args 對象。在這個 mActivityThread 是一個 Handler 對象,具體指向的就是 H 類,在註釋 2 處的代碼就是將 Args 對象的 getRunnable 方法經過 H 發送到線程的消息隊列中, Args 中的實現,代碼以下:

//LoadedApk.java

        final class Args extends BroadcastReceiver.PendingResult {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;
            private Throwable mPreviousRunStacktrace; // To investigate b/37809561. STOPSHIP remove.

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }

            public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    ...
                    try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //1. 回調到接收廣播的 onReceiver
                        receiver.onReceive(mContext, intent);
                    } catch (Exception e) {
                        ...
                  
                };
            }
        }
複製代碼

在註釋 1 處執行了 BroadcastReceiver 回調 **onReceive(mContext, intent);**方法,這樣註冊廣播接收者就收到了廣播並獲得了 intent。

整個流程到這裏就講解完了,下一篇將爲你們帶來四大組件中的最後一個組件 ContentProvider 啓動過程,敬請期待!

參考

  • 《Android 進階解密》
相關文章
相關標籤/搜索