首頁 > 軟體

Android ANR分析trace檔案的產生流程詳情

2022-07-04 18:01:53

前言

首先收集需要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檔案的產生流程詳情的文章就介紹到這了,更多相關Android ANR分析 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com