您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么使用Android ANR分析trace文件的產生流程”,在日常操作中,相信很多人在怎么使用Android ANR分析trace文件的產生流程問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用Android ANR分析trace文件的產生流程”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
首先收集需要dump trace的進程并給對應進程發送dump trace的信號
1.當一些帶有超時機制的系統消息(如:Service的創建)判定超時后,會調用系統服務AMS接口,收集ANR相關信息并存檔(data/anr/trace, data/system/dropbox)
2.進入到AMS中,AppError會先進行篩選(1.當前進程正在進行dump流程 2.已經發生crash 3. 已經被系統kill 4.系統是否正在關機等情況),如果都不符合,則認為當前進程發生了anr。
3.接下來系統在判斷當前ANR進程對用戶是否可感知,然后開始統計與該進程由關聯的進程,或者一些系統核心服務進程的信息(例如與應用交互的SurfaceFligner,System Server等系統進程),如果這些系統服務進程在響應時被阻塞,那么將導致應用進程IPC通信過程被卡死。接著獲取其他系統核心進程,因為這些服務進程是init進程直接創建的,并不在SystemServer或Zygote進程管理范圍。 >firstPids隊列:第一個是ANR進程,第二個是system_server,剩余是所有persistent進程; Native隊列:是指/system/bin/目錄的mediaserver,sdcard 以及surfaceflinger進程; lastPids隊列: 是指mLruProcesses中的不屬于firstPids的所有進程。
4.在收集完第一步信息后,接下來便開始統計各進程本地的更多信息,如虛擬機信息,java線程狀態及堆棧。首先會彈出一個ANR的對話框,然后向UI線程發送SHOW_NOT_RESPONDING_MSG消息
5.當UI線程收到該消息后,會調用dumpStackTraces函數:
最重要的一點:向目標進程發送SINAL_QUIT(進程中的Signal Catcher會進行阻塞檢測收集信息后面講),firstPids列表中的進程, 兩個進程之間會休眠200ms, 可見persistent進程越多,則時間越長. top 5進程的traces過程中, 同樣是間隔200ms, 另外進程使用情況的收集也是比較耗時.
總結;
>將am_anr信息輸出到EventLog(分析anr問題時先看該log) 獲取重要進程的信息,java進程的,和native的進程 將ANR的Reason和CPU使用的情況輸出到main_log 在將CPU使用情況和進程的trace文件信息,在保存到drpobox文件下 向收集到的進程發送SINAL_QUIT信號。
(Android5.0之前是dump用的SuspendAll線程,收集信息之后用ResumeAll恢復。在5.0之后采用的是checkPoint進行dump信息)
發生ANR時,systemServer進程會執行dumpStackTraces函數,在該函數中發SIGQUIT信號給對應的進程(上面有分析到) 處于安全考慮,進程之間是相互隔離的,即使系統進程也無法獲取其他進程的信息,所以要借助于IPC通信,將指令發送到目標進程,目標進程接收到消息后,協助完成自身進程Dump信息并發送給系統進程。Android P 流程:
1.一個進程接收到了SIGQIUT信號的時候,SingaCatcher線程的WaitForSignal函數會返回接著會調用到HandlerSigQuit()函數。
2.hindleSigQuit()函數為:
3.DumpForSigQuit()函數:
這是讀取的信息,但是什么時候去讀取呢(什么時候才能保證獲取到的卻是是需要的東西,例如GC信息,當前分配了多少對象,這些打印一般都需要在suspend當前進程里面的所有的線程),接下來先分析這個suspend過程:
這個掛起SupendAll實在Thread_list.cc中實現的,他的作用就是用來suspend當前進程里面所有其他的線程(一般發生在GC,DumpForSigQuit等過程中)。SuspendAll過程實現最重要的就是ModifySupendCount(self,+1,false)這段語句他會修改對應Thread對象的suspend引用計數:
因為傳入的delta值是+1所以會先執行AtmoicSetFlag()利用原子操作設置了KSuspendRequest標志位,代表當前這個線程有掛起請求。什么時候會進行檢測這個標志位呢?這里涉及到了checkPoint的知識點最后講解(在線程運行中進行上下文切換(例如java線程轉換為Native線程)時就會運行CheckSuspend函數,這個函數才是真正的把當前線程suspend:
可以看到檢測到了KSuspendRequest標記就會執行FullSuspend函數,KSuspendRequest標志位是用來dump線程的堆棧的,分析完了SuspendAll之后,再繼續分析FullSuspendCheck函數:
調用TransitionFromRunnableToSuspend()這個函數后,線程就進入了KSuspended狀態,然后在調用TransitionFromSuspendedToRunnablecpm函數從Suspend狀態切換到Runnable狀態的時候會阻塞在一個條件變量上,除非調用SuspendAll的線程接著又調用了ResumeAll()函數,要不然這些線程就會一直被阻塞住。 4.現在就把SuspendAll的流程分析完了,但是dump線程堆棧的時候并不是在設置了掛起標志位(KSuspendRequest)后執行的,與他相關的是另外一個標志位KCheckpointRequest,接下來看一下Thread_list的Dump函數,這個函數會在Thread_list的DumpForSigQuit中會被調用到,也就是在Signal Cathcer線程處理SIGQUIT信號的過程中。
這個函數先創建了一個叫DumpCheckPoint對象checkpoint,然后調用了RunCheckpoint將這個對象傳入,這個函數會返回現在處于Runnable狀態的線程個數,接著 調用了WaitForThreadsToRunThroughCheckpoint()等待這些處于Runnable的線程都執行完DumpCheckpoint的Run函數,如果等待超時就會報錯。
接著分析RunCheckPoint函數,先看前一部分:
對于處于Runnable狀態的線程執行它的RequestCheckpoint函數會返回true,其他狀態的線程則會返回false。對于這些非Runnable狀態的線程就會像SuspendAll一樣會設置KSuspendRequest標志位,后面狀態切換的時候就會檢查這個標志位掛起。同事RunCheckPoint函數會把這些線程統計到suspend_count_modified_threads這個Vector變量中,在這個變量中的線程,Singal Catcher線程會主動觸發他們的dump堆棧過程。接下來再看看這個RequestCheckpoint函數
最后一行設置kCheckpointRequest標志位,在剛才線程切換運行狀態時會執行CheckSuspend函數在檢測kCheckpointRequest標志位的時候會執行RunCheckpointFunction函數,接著會執行這個checkpoints里面元素的run函數:
(這個存儲的其實就是Thread中的RequestCheckpoint在這里不僅設置了標志位還把參數設置為元素的值,這個參數就是Dump里面調用RunCheckpoint傳過來的,其實就是DumpCheckpoint)。 ,所以也就是執行DumpCheckpoint的run函數:
其實就是調用了Thread的Dump函數,線程的java堆棧,Native堆棧和Kernel堆棧就是在這里打印的,剛才說對于處于Runnable狀態的線程是通過調用他們的RequestCkeckPoint函數,然后它們自己去dump當前堆棧的,而那些不處于Runnable狀態的線程則是添加到了一個Vector的變量中,接著就分析RunCheckPoint函數的第二部分:
對于這些不是Runnable狀態的線程,他們可能不會主動去調用Run函數,所以只能有Signal Catcher線程去幫他們Dump,至于DumpCheckpoint的Run函數的功能和Runnable狀態的線程是一樣的,都是打印線程堆棧,并且最后修改引用計數讓這些線程在切換狀態時繼續運行。
總結:
>1.SingalCatcher線程接收到信號后,首先Dump當前虛擬機有關信息(內存狀態。對象,加載class,GC等相關信息) 2.接下來會設置每個線程的標記為(check_point),和請求線程狀態(suspend)。當線程運行過程中進行上下文切換時,會檢查該標記。如果發現有掛起請求,會將自己主動掛起。等到所有線程都掛起之后,SingalCatcher線程開始遍歷Dump各個線程的堆棧和線程數據后再喚醒線程。如果某個線程一直無法掛起導致超時,那么本次Dump流程失敗拋出異常.
大致流程(Android5.0之前):
checkPoint:
先講解safePoint,對于ART編譯的代碼,可以定期輪詢當前Runtime來確認是否需要執行某些特定代碼;可以認為這些輪詢時的點,就是safepoint;safepoint可以用來實現暫定一個java線程,也可以用來實現Checkpoint機制; 例: 當正在執行java代碼的線程A執行到safepoint時,會執行CheckSuspend函數,在發現當前線程有 checkpoint request時, 會在這個點執行線程的CheckPoint函數;如果發現當前線程有suspend request時,會進行SuspendCheck,使得線程進入Suspend狀態(暫停); 所以說,ART CheckPoint應該是safepoint的一個功能實現;
到此,關于“怎么使用Android ANR分析trace文件的產生流程”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。