欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?ANR分析trace文件的產(chǎn)生流程詳情

 更新時間:2022年07月04日 15:15:02   作者:wx5e435a4343578  
這篇文章主要介紹了Android?ANR分析trace文件的產(chǎn)生流程詳情,文章圍繞主題展開相詳細的內(nèi)容介紹,需要的朋友可以參考一下

前言

首先收集需要dump trace的進程并給對應(yīng)進程發(fā)送dump trace的信號

1.當(dāng)一些帶有超時機制的系統(tǒng)消息(如:Service的創(chuàng)建)判定超時后,會調(diào)用系統(tǒng)服務(wù)AMS接口,收集ANR相關(guān)信息并存檔(data/anr/trace, data/system/dropbox)

2.進入到AMS中,AppError會先進行篩選(1.當(dāng)前進程正在進行dump流程 2.已經(jīng)發(fā)生crash 3. 已經(jīng)被系統(tǒng)kill 4.系統(tǒng)是否正在關(guān)機等情況),如果都不符合,則認為當(dāng)前進程發(fā)生了anr。

3.接下來系統(tǒng)在判斷當(dāng)前ANR進程對用戶是否可感知,然后開始統(tǒng)計與該進程由關(guān)聯(lián)的進程,或者一些系統(tǒng)核心服務(wù)進程的信息(例如與應(yīng)用交互的SurfaceFligner,System Server等系統(tǒng)進程),如果這些系統(tǒng)服務(wù)進程在響應(yīng)時被阻塞,那么將導(dǎo)致應(yīng)用進程IPC通信過程被卡死。接著獲取其他系統(tǒng)核心進程,因為這些服務(wù)進程是init進程直接創(chuàng)建的,并不在SystemServer或Zygote進程管理范圍。 >firstPids隊列:第一個是ANR進程,第二個是system_server,剩余是所有persistent進程; Native隊列:是指/system/bin/目錄的mediaserver,sdcard 以及surfaceflinger進程; lastPids隊列: 是指mLruProcesses中的不屬于firstPids的所有進程。

4.在收集完第一步信息后,接下來便開始統(tǒng)計各進程本地的更多信息,如虛擬機信息,java線程狀態(tài)及堆棧。首先會彈出一個ANR的對話框,然后向UI線程發(fā)送SHOW_NOT_RESPONDING_MSG消息

5.當(dāng)UI線程收到該消息后,會調(diào)用dumpStackTraces函數(shù):

最重要的一點:向目標(biāo)進程發(fā)送SINAL_QUIT(進程中的Signal Catcher會進行阻塞檢測收集信息后面講),firstPids列表中的進程, 兩個進程之間會休眠200ms, 可見persistent進程越多,則時間越長. top 5進程的traces過程中, 同樣是間隔200ms, 另外進程使用情況的收集也是比較耗時.

總結(jié);

>將am_anr信息輸出到EventLog(分析anr問題時先看該log) 獲取重要進程的信息,java進程的,和native的進程 將ANR的Reason和CPU使用的情況輸出到main_log 在將CPU使用情況和進程的trace文件信息,在保存到drpobox文件下 向收集到的進程發(fā)送SINAL_QUIT信號。

接著分析最后一步向收集到的進程發(fā)送信號

(Android5.0之前是dump用的SuspendAll線程,收集信息之后用ResumeAll恢復(fù)。在5.0之后采用的是checkPoint進行dump信息)

發(fā)生ANR時,systemServer進程會執(zhí)行dumpStackTraces函數(shù),在該函數(shù)中發(fā)SIGQUIT信號給對應(yīng)的進程(上面有分析到) 處于安全考慮,進程之間是相互隔離的,即使系統(tǒng)進程也無法獲取其他進程的信息,所以要借助于IPC通信,將指令發(fā)送到目標(biāo)進程,目標(biāo)進程接收到消息后,協(xié)助完成自身進程Dump信息并發(fā)送給系統(tǒng)進程。Android P 流程:

1.一個進程接收到了SIGQIUT信號的時候,SingaCatcher線程的WaitForSignal函數(shù)會返回接著會調(diào)用到HandlerSigQuit()函數(shù)。

2.hindleSigQuit()函數(shù)為:

3.DumpForSigQuit()函數(shù):

這是讀取的信息,但是什么時候去讀取呢(什么時候才能保證獲取到的卻是是需要的東西,例如GC信息,當(dāng)前分配了多少對象,這些打印一般都需要在suspend當(dāng)前進程里面的所有的線程),接下來先分析這個suspend過程:

這個掛起SupendAll實在Thread_list.cc中實現(xiàn)的,他的作用就是用來suspend當(dāng)前進程里面所有其他的線程(一般發(fā)生在GC,DumpForSigQuit等過程中)。SuspendAll過程實現(xiàn)最重要的就是ModifySupendCount(self,+1,false)這段語句他會修改對應(yīng)Thread對象的suspend引用計數(shù):

因為傳入的delta值是+1所以會先執(zhí)行AtmoicSetFlag()利用原子操作設(shè)置了KSuspendRequest標(biāo)志位,代表當(dāng)前這個線程有掛起請求。什么時候會進行檢測這個標(biāo)志位呢?這里涉及到了checkPoint的知識點最后講解(在線程運行中進行上下文切換(例如java線程轉(zhuǎn)換為Native線程)時就會運行CheckSuspend函數(shù),這個函數(shù)才是真正的把當(dāng)前線程suspend:

可以看到檢測到了KSuspendRequest標(biāo)記就會執(zhí)行FullSuspend函數(shù),KSuspendRequest標(biāo)志位是用來dump線程的堆棧的,分析完了SuspendAll之后,再繼續(xù)分析FullSuspendCheck函數(shù):

調(diào)用TransitionFromRunnableToSuspend()這個函數(shù)后,線程就進入了KSuspended狀態(tài),然后在調(diào)用TransitionFromSuspendedToRunnablecpm函數(shù)從Suspend狀態(tài)切換到Runnable狀態(tài)的時候會阻塞在一個條件變量上,除非調(diào)用SuspendAll的線程接著又調(diào)用了ResumeAll()函數(shù),要不然這些線程就會一直被阻塞住。 4.現(xiàn)在就把SuspendAll的流程分析完了,但是dump線程堆棧的時候并不是在設(shè)置了掛起標(biāo)志位(KSuspendRequest)后執(zhí)行的,與他相關(guān)的是另外一個標(biāo)志位KCheckpointRequest,接下來看一下Thread_list的Dump函數(shù),這個函數(shù)會在Thread_list的DumpForSigQuit中會被調(diào)用到,也就是在Signal Cathcer線程處理SIGQUIT信號的過程中。

這個函數(shù)先創(chuàng)建了一個叫DumpCheckPoint對象checkpoint,然后調(diào)用了RunCheckpoint將這個對象傳入,這個函數(shù)會返回現(xiàn)在處于Runnable狀態(tài)的線程個數(shù),接著 調(diào)用了WaitForThreadsToRunThroughCheckpoint()等待這些處于Runnable的線程都執(zhí)行完DumpCheckpoint的Run函數(shù),如果等待超時就會報錯。

接著分析RunCheckPoint函數(shù),先看前一部分:

對于處于Runnable狀態(tài)的線程執(zhí)行它的RequestCheckpoint函數(shù)會返回true,其他狀態(tài)的線程則會返回false。對于這些非Runnable狀態(tài)的線程就會像SuspendAll一樣會設(shè)置KSuspendRequest標(biāo)志位,后面狀態(tài)切換的時候就會檢查這個標(biāo)志位掛起。同事RunCheckPoint函數(shù)會把這些線程統(tǒng)計到suspend_count_modified_threads這個Vector變量中,在這個變量中的線程,Singal Catcher線程會主動觸發(fā)他們的dump堆棧過程。接下來再看看這個RequestCheckpoint函數(shù)

最后一行設(shè)置kCheckpointRequest標(biāo)志位,在剛才線程切換運行狀態(tài)時會執(zhí)行CheckSuspend函數(shù)在檢測kCheckpointRequest標(biāo)志位的時候會執(zhí)行RunCheckpointFunction函數(shù),接著會執(zhí)行這個checkpoints里面元素的run函數(shù):

(這個存儲的其實就是Thread中的RequestCheckpoint在這里不僅設(shè)置了標(biāo)志位還把參數(shù)設(shè)置為元素的值,這個參數(shù)就是Dump里面調(diào)用RunCheckpoint傳過來的,其實就是DumpCheckpoint)。 ,所以也就是執(zhí)行DumpCheckpoint的run函數(shù):

其實就是調(diào)用了Thread的Dump函數(shù),線程的java堆棧,Native堆棧和Kernel堆棧就是在這里打印的,剛才說對于處于Runnable狀態(tài)的線程是通過調(diào)用他們的RequestCkeckPoint函數(shù),然后它們自己去dump當(dāng)前堆棧的,而那些不處于Runnable狀態(tài)的線程則是添加到了一個Vector的變量中,接著就分析RunCheckPoint函數(shù)的第二部分:

對于這些不是Runnable狀態(tài)的線程,他們可能不會主動去調(diào)用Run函數(shù),所以只能有Signal Catcher線程去幫他們Dump,至于DumpCheckpoint的Run函數(shù)的功能和Runnable狀態(tài)的線程是一樣的,都是打印線程堆棧,并且最后修改引用計數(shù)讓這些線程在切換狀態(tài)時繼續(xù)運行。

總結(jié):

>1.SingalCatcher線程接收到信號后,首先Dump當(dāng)前虛擬機有關(guān)信息(內(nèi)存狀態(tài)。對象,加載class,GC等相關(guān)信息) 2.接下來會設(shè)置每個線程的標(biāo)記為(check_point),和請求線程狀態(tài)(suspend)。當(dāng)線程運行過程中進行上下文切換時,會檢查該標(biāo)記。如果發(fā)現(xiàn)有掛起請求,會將自己主動掛起。等到所有線程都掛起之后,SingalCatcher線程開始遍歷Dump各個線程的堆棧和線程數(shù)據(jù)后再喚醒線程。如果某個線程一直無法掛起導(dǎo)致超時,那么本次Dump流程失敗拋出異常.

大致流程(Android5.0之前):

checkPoint:

先講解safePoint,對于ART編譯的代碼,可以定期輪詢當(dāng)前Runtime來確認是否需要執(zhí)行某些特定代碼;可以認為這些輪詢時的點,就是safepoint;safepoint可以用來實現(xiàn)暫定一個java線程,也可以用來實現(xiàn)Checkpoint機制; 例: 當(dāng)正在執(zhí)行java代碼的線程A執(zhí)行到safepoint時,會執(zhí)行CheckSuspend函數(shù),在發(fā)現(xiàn)當(dāng)前線程有 checkpoint request時, 會在這個點執(zhí)行線程的CheckPoint函數(shù);如果發(fā)現(xiàn)當(dāng)前線程有suspend request時,會進行SuspendCheck,使得線程進入Suspend狀態(tài)(暫停); 所以說,ART CheckPoint應(yīng)該是safepoint的一個功能實現(xiàn);

到此這篇關(guān)于Android ANR分析trace文件的產(chǎn)生流程詳情的文章就介紹到這了,更多相關(guān)Android ANR分析 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論