Android?ANR分析trace文件的產(chǎn)生流程詳情
前言
首先收集需要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)文章
android中GridView實現(xiàn)點擊查看更多功能示例
本篇文章主要介紹了android中GridView實現(xiàn)點擊查看更多功能示例,非常具有實用價值,需要的朋友可以參考下。2017-02-02Flutter?LinearProgressIndicator使用指南分析
這篇文章主要為大家介紹了Flutter?LinearProgressIndicator使用指南分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03android實現(xiàn)倒計時功能(開始、暫停、0秒結(jié)束)
這篇文章主要為大家詳細介紹了android實現(xiàn)倒計時功能,開始、暫停、0秒結(jié)束,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09Android自定義view實現(xiàn)帶header和footer的Layout
這篇文章主要介紹了Android自定義view實現(xiàn)帶header和footer的Layout,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-02-02詳解Android使用CoordinatorLayout+AppBarLayout+CollapsingToolbarL
這篇文章主要為大家詳細介紹了Android使用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayou實現(xiàn)手指滑動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05Android使用Jetpack WindowManager開發(fā)可折疊設(shè)備(過程分享)
這篇文章主要介紹了Android使用Jetpack WindowManager開發(fā)可折疊設(shè)備,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11Android實現(xiàn)類似360,QQ管家那樣的懸浮窗
用到的就是WindowManager以及WindowManager.LayoutParams,對這個LayoutParams做文章,當(dāng)設(shè)置為屬性后,然后,創(chuàng)建一個View,將這個View添加到WindowManager中就行2013-06-06android AsynTask處理返回數(shù)據(jù)和AsynTask使用get,post請求
本文主要介紹了android AsynTask處理返回數(shù)據(jù)和AsynTask使用get,post請求方法。具有一定的參考價值,下面跟著小編一起來看下吧2017-01-01Android自定義View實現(xiàn)多邊形統(tǒng)計圖示例代碼
這篇文章主要給大家介紹了關(guān)于Android自定義View如何實現(xiàn)多邊形統(tǒng)計圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01