前言
本文代碼基于 Android R。
注冊廣播接收者
Android 可以動態和靜態注冊廣播接收者。動態廣播接收者注冊后被 AMS 存儲在其 IntentResolver 數據結構中。而靜態廣播接收者開機后被 PMS 讀取解析并存儲在其 IntentResolver 中。
動態注冊廣播接收者
應用組件向 AMS 注冊 IIntentReceiver 和 IntentFilter ,當 AMS 派發其它組件請求派發的 Intent 時,通過其注冊的 IntentFilter 來判斷是否與派發的 Intent 匹配,如果匹配,AMS 調用 IIntentReceiver 通知組件處理收到 Intent 后的操作。
每個 BroadcastReceiver 都會有其對應的 IIntentReceiver ,它由其 Context 構建。IIntentReceiver 被發送給 AMS 后與其進程信息 ProcessRecord 被封裝在 ReceiverList 中,在發現匹配到的 Intent 時用來尋找 IIntentReceiver 對應進程。而 ReceiverList 被放在由 IntentFilter 構建的 BroadcastFilter 中,最后 BroadcastFilter 被緩存在 AMS 的 IntentResolver 中。代碼流程為:
靜態注冊廣播接收者
靜態注冊廣播接收者,那在 AndroidManifest.xml 中聲明 <receiver> ,并使用匹配器 IntentFilter 配置它要匹配的數據。
開機后,PMS 會去讀取每個 pkg 的信息,并把每個 pkg 里的每個組件信息存儲到 ComponentResolver 中,receiver 組件的信息存儲在 ComponentResolver#mReceivers 中。mReceivers 是一個 IntentResolver<F, ResolveInfo>,其方法 newResult() 負責將 F 轉換成 ResolveInfo。其中 F 為從 pkg 中讀取的 receiver 和 IntentFilter 的 Pair。AMS 在分發一個 Intent 時,會根據 Intent 封裝的數據格式去 PMS ComponentResolver 的 mReceivers 中取出對應的 Map 來查找,取出對應 Map 中的 [ParsedActivity, IntentFilter] 對,判斷 IntentFilter 是否和 Intent 匹配,如果匹配,通過 IntentFilter#newResult 方法將 [ParsedActivity, IntentFilter] 轉換成 ResolveInfo 返回給 AMS。AMS 根據 ResolveInfo 中的 ActivityInfo 找到接收者進程,把 Intent 發送給接收者進程后,再實例化一個和 ActivityInfo 對應的 BroadcastReceiver 實例。
分發廣播
根據 AMS 分發廣播的方式,可以分為串行分發和并行分發。
當 Intent 設置為有序分發(ordered)時,它會被串行分發。
當接收者為靜態注冊時,發送給它們的 Intent 會被串行分發。
僅 Intent 沒有設置為有序分發,且接收者為動態注冊,才會被并行分發。
并行分發不關注分發結果,一次性全部分發給所有接收者,并在串行分發前分發。
串行分發需要等上一個接收者處理完成后才會分發給下一個接收者。
并行分發廣播
AMS 為 Intent 和所有并行接收者創建廣播 BroadcastRecord,再根據 Intent 設置的屬性判斷它是由前臺還是后臺或是耗時 BroadcastQueue 分發。BroadcastRecord 會被插到對應 BroadcastQueue 并行廣播列表的末尾,等待派發。
串行分發廣播
如果 Intent 被要求有序派發,AMS 將它的所有接收者和 Intent 封裝成 BroadcastRecord ,找到要派發它的 BroadcastQueue ,然后把 BroadcastRecord 插入到對應 BroadcastQueue 的 BroadcastDispatcher 的有序廣播隊列中等待派發。如果是非有序派發的 Intent,AMS 將其所有靜態注冊的接收者和 Intent 封裝成 BroadcastRecord。
BroadcastDispatcher 負責為 BroadcastQueue 串行派發廣播。它加入了一個延遲策略,來特別關注耗時的接收者,以減少這些耗時者對性能效率的影響。延遲策略下一小節將單獨描述。
延遲策略
延遲策略主要是為了減小耗時接收者對整個廣播發送性能產生的影響。當一個接收者接收并處理 Intent 耗時超過系統設置的域值(默認 5s)時,這個接收者所在的進程被認為是低效進程,所有之后發送給它的 Intent 將被延遲發送,直到系統判定它恢復了正常。
當一個進程被判定為低效進程時,BroadcastDispatcher 為它創建一個 Deferrals ,負責管理延遲發送給他的 Intent:它包含了延遲開始時間、延遲時長、延遲結束時間、延遲的廣播列表(BroadcastQueue 會為某個 Intent 在這個進程中的所有接收者和 Intent 單獨創建一個廣播 BroadcastQueue,因此這個廣播列表中包含了一隊由不同的 Intent 和其在該進程中的接收者構成的廣播)。
當一個進程的 Deferrals 被創建后會被插入到 BroadcastDispatcher 的延遲進程廣播列表中,當其延遲到期后,會優先在下一次派發時派發。派發時會更新下一次的延遲時長(即 Deferrals 的廣播列表中下一個廣播被延遲派發的時長),默認為 上一次延遲時長*縮短因子(0.75f)。
當被延遲的進程正在接收 alarm 廣播時,它的 Deferrals 會被移到 Alarm 延遲進程廣播列表,直到它處理完 alarm 廣播處理。Alarm 延遲進程廣播列表中的廣播具有最高優先級的派發順序。
當 Deferrals 進程中的某個接收者在處理一個 Intent 時仍耗時超過 5s ,它下一次的延遲時長會被重新設置為 5s。
當系統中所有的串行廣播都被發送完成時,會立即派發延遲進程廣播隊列中的廣播而不管它是否到期。
接收者在接收處理某個 Intent 結束時,AMS 計算其耗時并判斷這個接收者所在進程是否為低效進程,是否需要對它使用延遲策略:總結
Intent 會根據其發送者要求的發送規則(是否有序)和接收者的注冊方式被 AMS 以并行或串行方式分發。
Intent 和其接收者列表構成廣播,插入到 AMS 為它分配的 BroadcastQueue 的并行或串行廣播隊列中,等待派發。
并行派發不關注接收者的處理結果。串行派發關注處理結果,如果處理耗時會對接收者進程采用延遲策略,且僅當上一個接收者接收完后才會發送給下一個接收者。ordered 廣播發送給動態注冊的接收者時,通過 BroadcastRecord.state 來判斷上一個接收者是否接收完成,發送給 receiver 之前為 CALL_IN_SERVICE,發送之后為 CALL_DONE_RECEIVE,接收者處理完后為 IDLE。
原創文章,歡迎轉載,但請注明出處。