Android廣播事件流程與廣播ANR原理深入刨析_第1頁
Android廣播事件流程與廣播ANR原理深入刨析_第2頁
Android廣播事件流程與廣播ANR原理深入刨析_第3頁
Android廣播事件流程與廣播ANR原理深入刨析_第4頁
Android廣播事件流程與廣播ANR原理深入刨析_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論