




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第Android廣播事件流程與廣播ANR原理深入刨析目錄序言一.基本流程和概念二.無序廣播流程注冊廣播接收者流程廣播通知流程三.有序廣播流程四.廣播ANR流程五.總結(jié)六.擴(kuò)展問題
序言
本想寫廣播流程中ANR是如何觸發(fā)的,但是如果想講清楚ANR的流程,就不得不提整個(gè)廣播事件的流程,所以就把兩塊內(nèi)容合并在一起講了。
本文會(huì)講內(nèi)容如下:
1.動(dòng)態(tài)注冊廣播的整個(gè)分發(fā)流程,從廣播發(fā)出,一直到廣播注冊者接收。
2.廣播類型ANR的判斷流程和原理。
PS:本文基于android13的源碼進(jìn)行講解。
一.基本流程和概念
動(dòng)態(tài)廣播的流程其實(shí)是很簡單的,整套流程都在java層執(zhí)行,不涉及到native流程。
我們先來看一下最基本的流程圖:
首先是廣播注冊者,向AMS注冊廣播接收器,AMS交給BroadcastQueue來處理。也就是說BroadcastQueue中裝載所有的廣播接收器。然后廣播發(fā)出者向AMS發(fā)出廣播,這時(shí)候AMS仍然會(huì)交給BroadcastQueue來處理,在其中找到符合條件的接受者,然后向接受者發(fā)出廣播的通知。
然后我們再來了解一些最基本類的功能
ContextImp:Context的最終實(shí)現(xiàn)類,activity,application中的各種功能最終都是委托給其來處理的,廣播功能自然也不例外。
ActivityManagerService:負(fù)責(zé)所有應(yīng)用的Activity的流程,包括廣播六層呢。至于為什么廣播也由其來進(jìn)行處理,而不是搞一個(gè)BroadcastManagerService,估計(jì)是覺得廣播功能簡單不需要單獨(dú)設(shè)計(jì)Service吧。
BroadCastQueue:裝載所有的動(dòng)態(tài)廣播接收器,靜態(tài)廣播也是由其來負(fù)責(zé)加載的,負(fù)責(zé)具體廣播的分發(fā)工作。一種有三種類型,前臺(tái),后臺(tái),離線。
BroadcastReceiver:廣播注冊者
二.無序廣播流程
首先我們了解下什么是無需廣播和有序廣播。簡單來說,有序廣播就是需要嚴(yán)格按照優(yōu)先級(jí),依次的執(zhí)行接收動(dòng)作,高優(yōu)先級(jí)的廣播接受者如果沒有處理完,低優(yōu)先級(jí)的廣播接受者是無法收到廣播的。無需廣播就是沒有順序,各個(gè)廣播接受者之間沒有相互依賴關(guān)系。
無需廣播,發(fā)送是sendBroadcast方法發(fā)送廣播通知。
有序廣播,需要使用sendOrderedBroadcast方法發(fā)送廣播通知。
無序廣播大體流程圖如下:
注冊廣播接收者流程
1.APP側(cè),無論activity還是application,還是service,最終都是交給Context的實(shí)現(xiàn)類ContentImpl進(jìn)行最終的處理的。所以注冊廣播的時(shí)候,最終調(diào)用的是ContentImpl的registerReceiver方法。
2.registerReceiver方法中通過binder,通知到AMS的registerReceiverWithFeature方法。
3.registerReceiverWithFeature方法中,首先做一些安全校驗(yàn)。
4.除了action類型,還會(huì)有scheme的類型,這里就不具體介紹了。
5.最終都會(huì)注冊到IntentResolver類型對(duì)象mReceiverResolver上。
廣播通知流程
1.仍然交由ContextImpl中的broadcastIntentWithFeature方法來處理。
2.broadcastIntentWithFeature通知到AMS的broadcastIntentLocked方法中。
3.首先從mReceiverResolver中查詢,看是否存在接受者,如果存在,加入到registeredReceivers集合中。
registeredReceivers=mReceiverResolver.queryIntent(intent,
resolvedType,false/*defaultOnly*/,userId);
4.如果mReceiverResolver不為空,并且是無序廣播,則根據(jù)intent找到所對(duì)應(yīng)的BroadcastQueue(根據(jù)前臺(tái),后臺(tái),離線的類型)。
if(!orderedNR0){
finalBroadcastQueuequeue=broadcastQueueForIntent(intent);
BroadcastRecordr=newBroadcastRecord(queue,intent,...);
if(!replaced){
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
egisteredReceivers=null;
NR=0;
}
5.生成BroadcastRecord對(duì)象用來記錄這次的action所對(duì)應(yīng)的廣播事件,然后加入到BroadcastQueue的mParallelBroadcasts集合中。然后通過scheduleBroadcastsLocked方法切換到主線程執(zhí)行。這里要強(qiáng)調(diào)的是,無論是有序廣播還是無序廣播,都是通過這個(gè)方法來分發(fā)的。最終主線程會(huì)調(diào)用到processNextBroadcast方法。代碼在上面5,6行。
6.processNextBroadcast方法中邏輯很多,我們這里先只講無序廣播的流程。上一步中,我們把BroadcastRecord加入到了mParallelBroadcasts中,所以這里發(fā)送廣播的時(shí)候,直接遍歷mParallelBroadcasts集合,然后通知接受者接收。具體的流程可以看流程圖,這里就不細(xì)講了。
具體代碼如下:
while(mParallelBroadcasts.size()0){
r=mParallelBroadcasts.remove(0);
r.dispatchTime=SystemClock.uptimeMillis();
r.dispatchClockTime=System.currentTimeMillis();
finalintN=r.receivers.size();
for(inti=0;ii++){
Objecttarget=r.receivers.get(i);
deliverToRegisteredReceiverLocked(r,
(BroadcastFilter)target,false,i);//分發(fā)給接受者
addBroadcastToHistoryLocked(r);
}
三.有序廣播流程
有序廣播流程和上面無序廣播是類似的,最終請(qǐng)求AMS的方法其實(shí)也是broadcastIntentWithFeature方法,兩者只是參數(shù)有區(qū)別而已。
我們?nèi)匀话凑兆詮V播接受者和發(fā)送廣播兩個(gè)流程來講,首先是注冊廣播。
注冊廣播接收者流程
注冊的流程和無序廣播是一樣的。
廣播通知流程
1.前面的流程和無序廣播是一樣的,唯一的區(qū)別是進(jìn)入到AMS的broadcastIntentLocked方法后,執(zhí)行邏略微有區(qū)別。有序廣播,調(diào)用的是BroadcastQueue中的
enqueueOrderedBroadcastLocked方法,把BroadcastRecord對(duì)象最終注冊到BroadcastDispatcher中的mOrderedBroadcasts集合中,然后在調(diào)用scheduleBroadcastsLocked方法切換到主線程,執(zhí)行processNextBroadcastLocked的主流程。
下面介紹的都是processNextBroadcastLocked方法,也是廣播事件分發(fā)的的核心流程代碼:
2.processNextBroadcastLocked中,首先仍然去無序隊(duì)列mParallelBroadcasts中查,這時(shí)候肯定是沒有值的,所以跳過這個(gè)步驟。
3.然后通過mDispatcher.getNextBroadcastLocked(now);方法去BroadcastDispatcher中查找,方法實(shí)現(xiàn)如下,因?yàn)閯偛艖?yīng)添加到了mOrderedBroadcasts集合中,所以這時(shí)候可以找到并返回BroadcastRecord對(duì)象。
4.BroadcastRecord.nextReceiver用來記錄一系列有序廣播執(zhí)行到了第幾個(gè),0代表開始,如果為0,則記錄一些必要信息。另外,會(huì)更新掉record的時(shí)間receiverTime,這一點(diǎn)很重要,下面ANR流程中會(huì)有涉及到。
代碼如下:
intrecIdx=r.nextReceiver++;
r.receiverTime=SystemClock.uptimeMillis();
if(recIdx==0){
r.dispatchTime=r.receiverTime;
r.dispatchClockTime=System.currentTimeMillis();
if(mLogLatencyMetrics){
FrameworkStatsLog.write(
FrameworkStatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,
r.dispatchClockTime-r.enqueueClockTime);
if(Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)){
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r,BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r,BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
if(DEBUG_BROADCAST_LIGHT)Slog.v(TAG_BROADCAST,"Processingorderedbroadcast["
+mQueueName+"]"+r);
}
5.發(fā)送一個(gè)延時(shí)廣播,延時(shí)時(shí)間具體看是前臺(tái)廣播還是后臺(tái)廣播定義的。如果已經(jīng)發(fā)送過并且未結(jié)束,則跳過。setBroadcastTimeoutLocked中的具體邏輯,第四章ANR流程中會(huì)講到。
if(!mPendingBroadcastTimeoutMessage){
longtimeoutTime=r.receiverTime+mConstants.TIMEOUT;
if(DEBUG_BROADCAST)Slog.v(TAG_BROADCAST,
"SubmittingBROADCAST_TIMEOUT_MSG["
+mQueueName+"]for"+r+"at"+timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
}
6.如果接受者是BroadcastFilter類型,則把廣播事件發(fā)送給接受者。
if(nextReceiverinstanceofBroadcastFilter){
BroadcastFilterfilter=(BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r,filter,r.ordered,recIdx);
}
至此,processNextBroadcastLocked的方法暫時(shí)介紹完成,即然用暫時(shí),那就說明后面還會(huì)涉及到。
7.接收者是LoadedApk中ReceiverDispatcher的內(nèi)部類InnerReceiver,它是binder的服務(wù)端接收者,其performReceive方法收到通知后,會(huì)交給ReceiverDispatcher中的performReceive方法處理。
if(rd!=null){
rd.performReceive(intent,resultCode,data,extras,
ordered,sticky,sendingUser);
}
所以,最終來處理廣播信息的方法是ReceiverDispatcher中的performReceive方法。其中部分代碼如下,getRunnable就是最終通知到我們注冊的廣播接受者的流程。如果getRunnable中的任務(wù)注冊不成功的話,會(huì)直接發(fā)送信號(hào)通知回AMS。什么情況下會(huì)注冊不成功呢?主線程Looper異常執(zhí)行完并退出時(shí)就會(huì)發(fā)生。
if(intent==null||!mActivityThread.post(args.getRunnable())){
if(mRegisteredordered){
IActivityManagermgr=ActivityManager.getService();
if(ActivityThread.DEBUG_BROADCAST)Slog.i(ActivityThread.TAG,
"Finishingsyncbroadcastto"+mReceiver);
args.sendFinished(mgr);
}
我們在來看一下getRunnable中返回的任務(wù),我們?nèi)匀恢毁N核心代碼:
if(receiver==null||intent==null||mForgotten){
if(mRegisteredordered){
if(ActivityThread.DEBUG_BROADCAST)Slog.i(ActivityThread.TAG,
"Finishingnullbroadcastto"+mReceiver);
sendFinished(mgr);
return;
try{
receiver.onReceive(mContext,intent);
}catch(Exceptione){
if(receiver.getPendingResult()!=null){
finish();
}
我們可以看到,先執(zhí)行onReceive的回調(diào),這里就會(huì)最終通知到我們的BroadcastReceiver中的onReceive方法。
然后我們在看一下finish方法:這個(gè)其實(shí)核心就是發(fā)送廣播完成的信號(hào)給AMS:
publicfinalvoidfinish(){
if(mType==TYPE_COMPONENT){
finalIActivityManagermgr=ActivityManager.getService();
if(QueuedWork.hasPendingWork()){
QueuedWork.queue(newRunnable(){
@Overridepublicvoidrun(){
if(ActivityThread.DEBUG_BROADCAST)Slog.i(ActivityThread.TAG,
"Finishingbroadcastafterworktocomponent"+mToken);
sendFinished(mgr);
},false);
}else{
if(ActivityThread.DEBUG_BROADCAST)Slog.i(ActivityThread.TAG,
"Finishingbroadcasttocomponent"+mToken);
sendFinished(mgr);
}elseif(mOrderedHintmType!=TYPE_UNREGISTERED){
if(ActivityThread.DEBUG_BROADCAST)Slog.i(ActivityThread.TAG,
"Finishingbroadcastto"+mToken);
finalIActivityManagermgr=ActivityManager.getService();
sendFinished(mgr);
}
最終,在BroadcastReceiver.PendingResult的sendFinished方法中,通過binder通知回AMS。
am.finishReceiver(mToken,mResultCode,mResultData,mResultExtras,
mAbortBroadcast,mFlags);
8.AMS的finishReceiver中,主要功能是先通過binder,找到所對(duì)應(yīng)的BroadcastRecord,然后結(jié)束掉當(dāng)前的這個(gè)事件流程,如果后面還有事件,則繼續(xù)調(diào)用processNextBroadcastLocked方法,進(jìn)行下一輪的廣播事件分發(fā)。
r=queue.getMatchingOrderedReceiver(who);
if(r!=null){
doNext=r.queue.finishReceiverLocked(r,resultCode,
resultData,resultExtras,resultAbort,true);
if(doNext){
cessNextBroadcastLocked(/*fromMsg=*/false,/*skipOomAdj=*/true);
}
四.廣播ANR流程
那么什么時(shí)候會(huì)導(dǎo)致廣播ANR呢?這一套題,我估計(jì)能考倒90%的安卓開發(fā)者,單純的無序廣播,廣播接受者中sleep幾分鐘,是不會(huì)產(chǎn)生廣播類型ANR的,ANR只存在于有序廣播并且廣播接受者未及時(shí)響應(yīng)。
其實(shí)了解完整個(gè)廣播流程,我們ANR流程就好講的多。我們只需關(guān)注整個(gè)流程中的幾個(gè)點(diǎn)就好了。
觸發(fā)廣播監(jiān)聽者流程
1.首先第三章的第五小節(jié)中,我們講到,通過setBroadcastTimeoutLocked方法設(shè)置一個(gè)延時(shí)的消息,消息的執(zhí)行時(shí)間=當(dāng)前時(shí)間+超時(shí)時(shí)間,此時(shí)伴隨著廣播通知到客戶端的流程。
longtimeoutTime=r.receiverTime+mConstants.TIMEOUT;
finalvoidsetBroadcastTimeoutLocked(longtimeoutTime){
if(!mPendingBroadcastTimeoutMessage){
Messagemsg=mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG,this);
mHandler.sendMessageAtTime(msg,timeoutTime);
mPendingBroadcastTimeoutMessage=true;
}
也就是說,一旦達(dá)到超時(shí)時(shí)間,那么就會(huì)發(fā)送BROADCAST_TIMEOUT_MSG類型的事件,就一定會(huì)執(zhí)行broadcastTimeoutLocked方法。
2.broadcastTimeoutLocked方法中,會(huì)再一次進(jìn)行判斷,如果沒有到執(zhí)行時(shí)間,會(huì)重新觸發(fā)一次setBroadcastTimeoutLocked的流程。
上面3.8中講到,如果是有序廣播,廣播接收者收到消息后,會(huì)通過binder回調(diào)AMS通知事件處理完成,并重新進(jìn)入processNextBroadcastLocked流程進(jìn)行下一輪的分發(fā),這時(shí)候,會(huì)更新掉上面用到的receiverTime時(shí)間。
3.processNextBroadcastLocked分發(fā)廣播的時(shí)候,如果判斷進(jìn)入到了結(jié)束的環(huán)節(jié),會(huì)主動(dòng)取消注冊BROADCAST_TIMEOUT_MSG類型的事件。
if(r.receivers==null||r.nex
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- T/CAZG 006-2019貘類飼養(yǎng)管理技術(shù)規(guī)范
- T/CATSI 05001-2018移動(dòng)式真空絕熱深冷壓力容器內(nèi)容器應(yīng)變強(qiáng)化技術(shù)要求
- T/CAQI 195-2021電熱水器健康功能技術(shù)要求和試驗(yàn)方法
- T/CAPE 12005-2023擴(kuò)散焊熱交換器
- 電網(wǎng)金融考試題及答案
- 鄭州云和數(shù)據(jù)java面試題及答案
- 急診科招聘面試題及答案
- 規(guī)劃選址面試題及答案
- 港口國企面試題及答案
- 骨干班考試題及答案
- 燃?xì)庑袠I(yè)數(shù)字化轉(zhuǎn)型與智能化
- VDA6.3檢查要求與證據(jù)清單(VDA6.3檢查表)
- 牙周檢查記錄表
- 外墻涂料吊籃施工方案
- 《新時(shí)代勞動(dòng)教育》新時(shí)代勞動(dòng)價(jià)值觀
- 第四章 地陪導(dǎo)游服務(wù)程序與服務(wù)質(zhì)量
- 山東紫薇種質(zhì)資源調(diào)查報(bào)告
- 2023年醫(yī)療招聘技術(shù)類-影像醫(yī)學(xué)與核醫(yī)學(xué)考試歷年真題集錦附答案
- “循環(huán)經(jīng)濟(jì)關(guān)鍵技術(shù)與裝備”重點(diǎn)專項(xiàng)2023年度項(xiàng)目申報(bào)指南
- 旅行社應(yīng)急處置方案
- 中移L2認(rèn)證(集團(tuán))備考題庫(濃縮版)
評(píng)論
0/150
提交評(píng)論