Android系統(tǒng)源碼分析-Broadcast注冊和注銷

距離上一篇博客進(jìn)程的加載過了很久的時(shí)間,這中間換了一份工作,加入了新的團(tuán)隊(duì),也開始了新的項(xiàng)目,比較忙,所以最近才有時(shí)間將四大組件之一的廣播原理看完,最近一段時(shí)間會(huì)相繼把四大組件分析寫完,讓我們對四大組件有更深的了解。本來想一篇把廣播的內(nèi)容寫完,但是發(fā)現(xiàn)要解釋的代碼比較多,所以還是分開來講,那么這篇先分析廣播的注冊和注銷,下一篇再分析廣播的發(fā)送。

Broadcast的注冊

注冊廣播時(shí)序圖

Step-1:注冊廣播入口ContextImpl.registerReceiver:

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }

然后調(diào)用registerReceiver復(fù)寫方法:

@Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                                   String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }

Step-2:調(diào)用registerReceiverInternal方法:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                                            IntentFilter filter, String broadcastPermission,
                                            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        // 需要注冊的廣播接收器不為null
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    // 獲取主線程的Handler,mMainThread是描述當(dāng)前應(yīng)用程序進(jìn)程的
                    scheduler = mMainThread.getHandler();
                }
                // 將廣播接收者receiver封裝成一個(gè)實(shí)現(xiàn)了IIntentReceiver接口的Binder對象rd(ReceiverDispatcher)
                rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    // 獲取主線程的Handler
                    scheduler = mMainThread.getHandler();
                }
                // 將廣播接收者receiver封裝成一個(gè)實(shí)現(xiàn)了IIntentReceiver接口的Binder對象rd(ReceiverDispatcher)
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            // 調(diào)用ActivityManagerProxy的registerReceiver,最終通過mRemote.transact方法傳遞到
            // ActivityManagerService中的registerReceiver方法
            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
            ...
            return intent;
        } catch (RemoteException e) {
            ...
        }
    }

mPackageInfo是LoadedApk類型對象,這個(gè)對象是在一個(gè)應(yīng)用啟動(dòng)的時(shí)候創(chuàng)建的。

Step-3:LoadedApk.getReceiverDispatcher方法:

    // 每一個(gè)注冊過廣播接收者的Activity組件在LaodApk類中都有一個(gè)對應(yīng)的ReceiverDispatcher對象,它負(fù)責(zé)
    // 將這個(gè)被注冊的廣播接收者與注冊它的Activity組件關(guān)聯(lián)在一起。這些ReceiverDispatcher對象保存在一個(gè)
    // HashMap中,并且以它們所關(guān)聯(lián)的廣播接收者為關(guān)鍵字。最后用來保存這些ReceiverDispatcher對象的HashMap
    // 又以它們所關(guān)聯(lián)的Activity組件的Context接口為關(guān)鍵字保存在LoadApk類的成員變量mReceivers中
    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
                                                 Context context, Handler handler,
                                                 Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            // 是不是注冊廣播
            if (registered) {
                // 查找有沒有對應(yīng)的廣播接收者對象列表
                map = mReceivers.get(context);
                if (map != null) {
                    // 查找是否存在該廣播接收者對應(yīng)的ReceiverDispatcher對象
                    rd = map.get(r);
                }
            }
            if (rd == null) {// 不存在
                // 初始化廣播接收器調(diào)度員
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    // 緩存ReceiverDispatcher
                    map.put(r, rd);
                }
            } else {
                // 驗(yàn)證廣播分發(fā)者的Context和Handler是否一致。
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }

這里主要是將廣播接收者receiver封裝成一個(gè)實(shí)現(xiàn)了IIntentReceiver接口的Binder對象rd,然后將其放置到LoadedApk對象中的mReceivers中保存起來。

再回到上面代碼中,將生成的實(shí)現(xiàn)了IIntentReceiver接口的Binder對象rd通過mRemote.transact方法傳遞到ActivityManagerService中的registerReceiver方法,因?yàn)樗拇蠼M件的消息傳遞都是通過這種方式實(shí)現(xiàn)的。

Step-7:ActivityManagerProxy.registerReceiver

 public Intent registerReceiver(IApplicationThread caller, String packageName,
                                   IIntentReceiver receiver,
                                   IntentFilter filter, String perm, int userId) throws RemoteException {
        ...
        // 通過內(nèi)部的一個(gè)Binder代理對象mRemote向AMS發(fā)送一個(gè)類型為REGISTER_RECEIVER_TRANSACTION的進(jìn)程
        // 間通信請求
        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        ...
        return intent;
    }

Step-8:ActivityManagerService.registerReceiver

通過上面的mRemote.transact方法傳遞到ActivityManagerService中對應(yīng)的方法:

/**
 * 粘性廣播(Sticky):一個(gè)粘性廣播被發(fā)送到AMS后,就會(huì)一直保存在AMS中,直到AMS下次再接收到另外一個(gè)
 * 同類型的粘性廣播為止。一個(gè)Activity組件在向AMS注冊接收某一種烈性的廣播時(shí),如果AMS內(nèi)部切好保存這個(gè)
 * 這種類型的粘性廣播,那么AMS就會(huì)將這個(gè)粘性廣播返回給Activity組件,以便它可以知道系統(tǒng)上一次發(fā)出的它
 * 所感興趣的廣播內(nèi)容。我們可以通過sendStrickyBroadcast向AMS發(fā)送粘性廣播
 */
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                                   IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
        ...
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        int callingUid;
        int callingPid;
        synchronized (this) {
            if (caller != null) {
                // 根據(jù)caller從ProcessRecord緩存列表中查詢ProcessRecord對象caller,用來描述正在請求
                // AMS注冊廣播接收者的一個(gè)Activity組件所運(yùn)行在的應(yīng)用程序進(jìn)程
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {// 沒有對應(yīng)進(jìn)程,不能注冊廣播
                    ...//拋出異常
                }
                ...
            } else {
                ...
            }

            // 獲取注冊廣播的用戶的userId(UserController是多用戶功能的用戶管理,一些系統(tǒng)包含訪客模式,或者多用戶,每個(gè)用戶就會(huì)有一個(gè)id)
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            // 獲取需要注冊廣播的IntentFilter中所有的action
            Iterator<String> actions = filter.actionsIterator();
            // 如果注冊廣播沒有Action則添加一個(gè)null
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Activity組件在注冊一個(gè)廣播接收者時(shí),并不是直接將這個(gè)廣播接收者注冊到了AMS中,而是將與它關(guān)聯(lián)
            // 的一個(gè)InnerReceiver對象注冊到了AMS中。當(dāng)AMS接收到一個(gè)廣播時(shí),它就會(huì)根據(jù)這個(gè)廣播的類型在內(nèi)
            // 部知道對應(yīng)的InnerReceiver對象,然后再通過這個(gè)對象將這個(gè)廣播發(fā)送給對應(yīng)的廣播接收者。AMS中每
            // 一個(gè)廣播接收者都是使用一個(gè)BroadcastFilter對象來描述的,而每一個(gè)BroadcastFilter對象又是根
            // 據(jù)它所描述的廣播接收者所關(guān)聯(lián)的一個(gè)BroadcastFilter對象,以及所要接受的廣播類型來創(chuàng)建。由于在
            // 一個(gè)應(yīng)用程序中,不同的Activity組件可能會(huì)使用同一個(gè)BroadcastFilter對象來注冊不同的廣播接收
            // 者,因此AMS會(huì)使用一個(gè)ReceiverList列表來保存這些使用了相同InnerReceiver對象來注冊的廣播接
            // 收者,并且以它們所使用的InnerReceiver對象為關(guān)鍵字。

            // Collect stickies of users
            // 收集與注冊用戶userId相關(guān)的所有已經(jīng)被廣播過的Intent,存儲(chǔ)在stickyIntents中
            // 包含所有用戶以及注冊廣播進(jìn)程對應(yīng)的用戶
            // 第一個(gè)UserHandle.USER_ALL表示設(shè)備上所有的用戶,
            // 第二個(gè)是callingUid對應(yīng)用戶的userId(當(dāng)前用戶的userId)
            int[] userIds = {UserHandle.USER_ALL, UserHandle.getUserId(callingUid)};
            // 這里只通過action進(jìn)行過濾
            while (actions.hasNext()) {
                String action = actions.next();
                // 遍歷與調(diào)度進(jìn)程相關(guān)的用戶id
                for (int id : userIds) {
                    // 根據(jù)userId查詢已經(jīng)發(fā)送過的對應(yīng)的Intent列表
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    // 如果已經(jīng)發(fā)送的Intent里包含上面要注冊的廣播的action的Intent,將其保存到stickyIntents中
                    if (stickies != null) {
                        // 根據(jù)action查詢Intent列表
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        // 下面對通過action過濾出來粘性廣播的Intent列表,包括:action,type,scheme,data,categories
        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);
                // 查找與IntentFilter匹配的Intent
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }

        ...
        if (receiver == null) {// 如果廣播接收器為null,則直接返回第一個(gè)Intent結(jié)束注冊
            return sticky;
        }

        synchronized (this) {
            // 首先判斷當(dāng)前進(jìn)程是否還活著
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died(注冊失敗)
                return null;
            }
            // 首先從緩存中查找注冊的receiver對應(yīng)的ReceiverList(ArrayList<BroadcastFilter>),
            // 第一次注冊為null,receiver對應(yīng)的是一個(gè)BroadcastFilter列表,也就是說可以通過調(diào)用
            // registerReceiver來為receiver注冊不同的廣播條件。
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            // 緩存中沒有,說明還沒有注冊過,如果有說明已經(jīng)注冊過了,不需要再添加
            if (rl == null) {
                // 如果沒有就創(chuàng)建新的廣播接收者(里面包含廣播過濾器列表)列表
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    rl.app.receivers.add(rl);
                } else {
                    ...
                }
                // 這里面最關(guān)鍵的就是下面將receiver以及對應(yīng)的ReceiverList列表放到mRegisteredReceivers中
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } 
            ...
            // 創(chuàng)建BroadcastFilter對象bf,用來描述正在注冊的廣播接收者,并添加到ReceiverList隊(duì)列rl中
            // 以及mReceiverResolver中
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            rl.add(bf);
            ...
            // 添加到已注冊接收器的廣播解析器中,注冊完成
            mReceiverResolver.addFilter(bf);

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            // 上面注冊結(jié)束以后,如果篩選出了與當(dāng)前注冊的IntentFilter匹配的sticky廣播的Intent列表,
            // 就將所有匹配的Intent逐條發(fā)送廣播給當(dāng)前的注冊者receiver,可以看到這里的接受者receivers
            // 里面就只有當(dāng)前創(chuàng)建的一個(gè)BroadcastFilter,也就是當(dāng)前的注冊者。
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                final int stickyCount = allSticky.size();
                for (int i = 0; i < stickyCount; i++) {
                    Intent intent = allSticky.get(i);
                    // 根據(jù)Intent返回時(shí)前臺廣播隊(duì)列還是后臺廣播隊(duì)列
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    // 需要發(fā)送的一條廣播記錄,receivers包含了所有能接收該條廣播的接收器
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                    // 將該廣播記錄加入廣播隊(duì)列中
                    queue.enqueueParallelBroadcastLocked(r);
                    // 調(diào)度廣播,發(fā)送BROADCAST_INTENT_MSG消息,觸發(fā)處理下一個(gè)廣播。但是如果目前有廣播還在
                    // 發(fā)送的處理過程中,這次推動(dòng)不會(huì)起作用
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }

上面時(shí)注冊廣播的核心代碼,主要是先判斷注冊的廣播的Action是不是已經(jīng)存在AMS(ActivityManagerService)中的粘性廣播中,如果存在就將這些Intent單獨(dú)保存到一個(gè)列表中,然后處理廣播接收器,上面代碼和注釋寫的很清楚了,廣播注冊不是直接將receiver保存在AMS中,而是先將其封裝到實(shí)現(xiàn)IIntentReceiver接口的Binder對象rd中,然后將這個(gè)對象放到ReceiverList對象中,這個(gè)ReceiverList對象是一個(gè)對應(yīng)receiver的IntentFilter列表,但是這個(gè)列表對象也包含了該receiver對象,也就是將receiver以及其對應(yīng)的IntentFilter列表封裝到了ReceiverList對象中,這樣每個(gè)廣播接收者以及其Action都封裝好了,然后將其放到該應(yīng)用所在進(jìn)程的ReceiverList對象列表中,這樣整個(gè)廣播注冊就完成了。

其實(shí)縷清了這個(gè)結(jié)構(gòu)就看懂廣播注冊了:首先是一個(gè)進(jìn)程對象ProcessRecord,里面有一個(gè)廣播的列表ArraySet<ReceiverList>,這個(gè)列表表示改進(jìn)程注冊的所有廣播接收者,每個(gè)ReceiverList對象包含了一個(gè)廣播接收者(實(shí)現(xiàn)了IIntentReceiver接口的Binder對象)封裝和與該廣播接收者對應(yīng)的多個(gè)Action對應(yīng)的IntentFilter對象的封裝BroadcastFilter列表,這個(gè)ReceiverList對象是將注冊的廣播接收者以及對應(yīng)的多個(gè)Action對應(yīng)起來,這樣就能查找對應(yīng)的廣播接收者,怎么調(diào)用我們下一篇發(fā)送廣播會(huì)詳細(xì)講解。

Step-9:getRecordForAppLocked

final ProcessRecord getRecordForAppLocked(
            IApplicationThread thread) {
        if (thread == null) {
            return null;
        }

        int appIndex = getLRURecordIndexForAppLocked(thread);
        return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
    }

這里是根據(jù)IApplicationThread獲取是否存在了該進(jìn)程,這里調(diào)用getLRURecordIndexForAppLocked獲取該進(jìn)程對應(yīng)的index

Step-10:getLRURecordIndexForAppLocked

    private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
        IBinder threadBinder = thread.asBinder();
        // Find the application record.
        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
            ProcessRecord rec = mLruProcesses.get(i);
            if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
                return i;
            }
        }
        return -1;
    }

這里主要通過for循環(huán)來從mLruProcesses列表中遍歷是否存在該IApplicationThread,如果存在返回對應(yīng)的Index,否則返回-1.

Step-11:UserController.handleIncomingUser

    int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
            int allowMode, String name, String callerPackage) {
        final int callingUserId = UserHandle.getUserId(callingUid);
        if (callingUserId == userId) {
            return userId;
        }

        ...
        int targetUserId = unsafeConvertIncomingUserLocked(userId);

        if (callingUid != 0 && callingUid != SYSTEM_UID) {
            final boolean allow;
            if (mService.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
                // If the caller has this permission, they always pass go.  And collect $200.
                allow = true;
            }
            ...
            if (!allow) {
                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
                    // In this case, they would like to just execute as their
                    // owner user instead of failing.
                    targetUserId = callingUserId;
                } else {
                    ...
                }
            }
        }
        
        ...
        return targetUserId;
    }

這里主要獲取callingPid等參數(shù)對應(yīng)的用戶id。

Step-24:BroadcastQueue.scheduleBroadcastsLocked

    // 驅(qū)動(dòng)廣播,所有廣播都應(yīng)該從這里走,然后會(huì)到processNextBroadcast
    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        // mBroadcastsScheduled用來描述AMS是否已經(jīng)向它所運(yùn)行在的線程的消息隊(duì)列發(fā)送了一個(gè)類型為
        // BROADCAST_INTENT_MSG的消息。AMS就是通過這個(gè)BROADCAST_INTENT_MSG消息類調(diào)度保存在無
        // 序廣播調(diào)度隊(duì)列mParallelBroadcasts和有序廣播調(diào)度隊(duì)列mOrderedBroadcasts中的廣播轉(zhuǎn)發(fā)任務(wù)的
        if (mBroadcastsScheduled) {// 如果true說明消息隊(duì)列已經(jīng)存在一個(gè)類型為BROADCAST_INTENT_MSG的消息了
            return;
        }
        // 雖然這里只發(fā)送了發(fā)送廣播的消息,但是這一步執(zhí)行完之后就已經(jīng)標(biāo)記廣播發(fā)送了,因此可以看出廣播發(fā)送和接
        // 受是異步的,即廣播發(fā)送者將一個(gè)廣播發(fā)送給AMS后,不會(huì)等待AMS將這個(gè)廣播轉(zhuǎn)發(fā)給廣播接收者處理
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

Broadcast的注銷

了解了廣播注冊,廣播注銷就很簡單了,就是從列表中刪除對應(yīng)的廣播對象封裝。

注銷廣播時(shí)序圖

Step-1:unregisterReceiver

    public void unregisterReceiver(BroadcastReceiver receiver) {
        if (mPackageInfo != null) {
            IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
                    getOuterContext(), receiver);
            try {
                ActivityManagerNative.getDefault().unregisterReceiver(rd);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } else {
            ...
        }
    }

首先通過LoadedApk.forgetReceiverDispatcher方法獲取與該注銷廣播接收者對應(yīng)的實(shí)現(xiàn)IIntentReceiver接口的Binder對象。

Step-2:LoadedApk.forgetReceiverDispatcher

    public IIntentReceiver forgetReceiverDispatcher(Context context,
                                                    BroadcastReceiver r) {
        synchronized (mReceivers) {
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
            LoadedApk.ReceiverDispatcher rd = null;
            if (map != null) {
                rd = map.get(r);
                if (rd != null) {
                    map.remove(r);
                    if (map.size() == 0) {
                        mReceivers.remove(context);
                    }
                    ...
                    return rd.getIIntentReceiver();
                }
            }
            ...
        }
    }

首先去mReceivers中獲取,我們從上面注冊知道,注冊時(shí)會(huì)將實(shí)現(xiàn)了IIntentReceiver接口的廣播接收者的封裝放到mReceivers保存,所以這里先去獲取有沒有,注冊了肯定是有的,因此將其移除。

Step-4:ActivityManagerProxy.unregisterReceiver

    public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException {
        ...
        mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        ...
    }

上面注冊廣播我們分析過調(diào)用ActivityManagerProxy這里的方法,然后通過Binder傳遞到AMS中對應(yīng)的方法中

Step-5:ActivityManagerService.unregisterReceiver

    // 注銷廣播
    public void unregisterReceiver(IIntentReceiver receiver) {
        ...
        try {
            boolean doTrim = false;

            synchronized (this) {
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                // 如果不為null,說明還沒注銷廣播
                if (rl != null) {
                    final BroadcastRecord r = rl.curBroadcast;
                    if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
                        final boolean doNext = r.queue.finishReceiverLocked(
                                r, r.resultCode, r.resultData, r.resultExtras,
                                r.resultAbort, false);
                        if (doNext) {
                            doTrim = true;
                            r.queue.processNextBroadcast(false);
                        }
                    }

                    if (rl.app != null) {
                        // 從廣播接收器對應(yīng)的進(jìn)程中移除
                        rl.app.receivers.remove(rl);
                    }

                    // 移除對應(yīng)廣播過濾器
                    removeReceiverLocked(rl);
                    if (rl.linkedToDeath) {
                        rl.linkedToDeath = false;
                        rl.receiver.asBinder().unlinkToDeath(rl, 0);
                    }
                }
            }

            // If we actually concluded any broadcasts, we might now be able
            // to trim the recipients' apps from our working set
            if (doTrim) {
                trimApplications();
                return;
            }

        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

找到對應(yīng)的注冊廣播對象ReceiverList,然后將其移除。

Step-6:BroadcastQueue.getMatchingOrderedReceiver

    public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
        if (mOrderedBroadcasts.size() > 0) {
            final BroadcastRecord r = mOrderedBroadcasts.get(0);
            if (r != null && r.receiver == receiver) {
                return r;
            }
        }
        return null;
    }

從隊(duì)列中找到對應(yīng)的BroadcastRecord對象然后返回。

Step-8:BroadcastQueue.finishReceiverLocked

    public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
                                        String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
        final int state = r.state;
        final ActivityInfo receiver = r.curReceiver;
        r.state = BroadcastRecord.IDLE;
        ...
        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
                && r.queue.mOrderedBroadcasts.size() > 0
                && r.queue.mOrderedBroadcasts.get(0) == r) {
            ActivityInfo nextReceiver;
            if (r.nextReceiver < r.receivers.size()) {
                Object obj = r.receivers.get(r.nextReceiver);
                nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo) obj : null;
            } else {
                nextReceiver = null;
            }
            // Don't do this if the next receive is in the same process as the current one.
            if (receiver == null || nextReceiver == null
                    || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                    || !receiver.processName.equals(nextReceiver.processName)) {
                if (mService.mServices.hasBackgroundServices(r.userId)) {
                    r.state = BroadcastRecord.WAITING_SERVICES;
                    return false;
                }
            }
        }

        r.curComponent = null;

        // We will process the next receiver right now if this is finishing
        // an app receiver (which is always asynchronous) or after we have
        // come back from calling a receiver.
        return state == BroadcastRecord.APP_RECEIVE
                || state == BroadcastRecord.CALL_DONE_RECEIVE;
    }

這里判斷是否結(jié)束廣播接收,如果結(jié)束則處理下一條廣播。

Step-10:BroadcastQueue.processNextBroadcast

這個(gè)是處理下一條廣播的,也是廣播的核心部分,這個(gè)我們在下一篇發(fā)送廣播時(shí)會(huì)詳細(xì)講解。

Step-11:removeReceiverLocked

    void removeReceiverLocked(ReceiverList rl) {
        mRegisteredReceivers.remove(rl.receiver.asBinder());
        for (int i = rl.size() - 1; i >= 0; i--) {
            mReceiverResolver.removeFilter(rl.get(i));
        }
    }

這個(gè)就是通過for循環(huán)刪除對應(yīng)的BroadcastFilter對象,這樣就注銷了廣播。

主要的基本都分析了,還有以下其他不重要的大家想要了解自己看看代碼。

廣播注冊結(jié)構(gòu)

注冊廣播結(jié)構(gòu)圖

最后這里我們再加一個(gè)廣播注冊結(jié)構(gòu)的總結(jié),上面是一個(gè)廣播注冊時(shí)的結(jié)構(gòu)圖,也就是廣播以及對應(yīng)的IntentFilter列表封裝,整個(gè)過程是由下向上注冊。首先是將BroadcastReceiver封裝成Binder對象IIntentReceiver,將IntentFilter封裝成BroadcastFilter對象,ReceiverList繼承的是ArrayList<BroadcastFilter>,因此它本身就是一個(gè)用來盛放BroadcastFilter對象列表的ArrayList對象,同時(shí)ReceiverList對象還放入了IntentFilter列表對應(yīng)的BroadcastReceiver的封裝對象IIntentReceiver,這樣就將BroadcastReceiver和IntentFilter綁定到一起了,然后將ReceiverList放到mRegisteredReceivers中,保存在ActivityManagerService(AMS)中,同時(shí)將ReceiverList放置到該廣播所在進(jìn)程的receivers中,而該進(jìn)程保存在AMS中的mLruProcesses中,同時(shí)將IntentFilter的封裝對象BroadcastReceiver放置到AMS中的mReceiverResolver中,這樣就注冊完成了。

這樣從整個(gè)機(jī)構(gòu)來說就非常清楚了,其實(shí)里面還有一些相互引用的情況,我沒有完全畫出來,只畫了主要的部分,相對清晰一些。

首發(fā)地址:http://www.codemx.cn

Android開發(fā)群:192508518

微信公眾賬號:Code-MX


注:本文原創(chuàng),轉(zhuǎn)載請注明出處,多謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

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