一、引言
ANR問題是android中常見且令人頭疼的問題,相當多的時候不易直接分析出原因。
二、ANR的定義
下面先看下百度百科給ANR的定義:
ANR問題常因在main(主線程)線程執行了復雜耗時的操作,比如文件IO、網絡訪問、無限循環等,最終無奈地被系統拋出ANR。
三、ANR的一般分析思路
1) 從手機的/data/traces/目錄導出traces.txt文件;
2) 從traces.txt文件獲取ANR產生的時間點T1;
3) 從traces.txt文件獲取main線程的運行狀態、調用棧;
4) 查看logcat日志,搜索"ANR in",找出ANR產生的時間點T2,以及時間點T2 前后幾秒鍾,在系統中運行的各進程CPU耗時占比;
5) 在步驟4)找出目標進程的cpu耗時占比,確認是user占比高,還是kernel占比高,還是iowait占比高;
6) 根據時間點T1、時間點T2,校准ANR產生的時間范圍 [T1, T2] 或 [T2, T1];
7) 查看logcat日志,將日志定位到步驟2)中獲取的時間點 [T1, T2] 或 [T2, T1]附近;
8) 查看logcat日志在時間點 [T1, T2] 或 [T2, T1]附近前后2分鍾的日志,以還原ANR產生前后的場景;
9) 根據以上步驟得出的信息,定位代碼中可能的問題代碼塊;
10) 解決問題,或提出階段分析結論。
四、ANR的分析示例
產生ANR后,系統會在/data/traces/下生成traces.txt文件,我們首先將該traces.txt文件從手機對應的目錄導出。
打開traces.txt后,先確認產生ANR的進程及ANR產生時間,如下圖紅框所示,產生ANR的進程是cn.evergrande.it.phone,ANR產生的時間是2018-08-16 10:34:43,
注意,在ANR分析中,ANR產生的時間點非常重要,是串接traces.txt和logcat相關日志線索的連接線,是推理ANR產生原因的重要線索。
繼續分析traces.txt,找到cn.evergrande.it.phone進程的main線程調用棧快照,如下圖所示,main線程在2018-08-16 10:34:43處於Runnable狀態,並且正在
執行java層代碼以測量layout布局中的RecylerView。
查看logcat日志,搜索"ANR in",定位到如下圖所示的CPU usage from 35958ms to 0ms ago部分的日志,可知 2018-08-16 10:34:07.546 到 2018-08-16 10:34:43.504 時間段,cn.evergrande.it.phone進程並沒有較多的cpu占比。
繼續查看CPU usage from 372ms to 893ms later部分的日志,可知在 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398 時間段,ANR問題開始出現,
其中cn.evergrande.it.phone進程的grande.it.phone、HDLogicThread-2、ReqTimer三個線程的cpu占比都比較高,可推斷是cn.evergrande.it.phone進程引發了ANR。
綜合上述ago、later兩部分的ANR日志,基本可以斷定ANR產生的源頭是cn.evergrande.it.phone進程,
其中,線程grande.it.phone的線程id是20974、HDLogicThread-2的線程id是21000,ReqTimer的線程id是20974,而在traces.txt中,main的線程id是20974,所以可斷定是
cn.evergrande.it.phone進程阻塞引發了ANR。
接下來要確認ANR產生的原因,先校准ANR產生的時間點,
1) traces.txt給出的時間點是 2018-08-16 10:34:43
2) logcat給出的時間范圍是 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398
綜合1)、2)時間(點)的交集,校准后的ANR產生時間范圍是 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398。
接下來,查看logcat在 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398范圍的日志,還原ANR產生時的情景。
上圖日志顯示了logcat在 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398附近的日志,可還原出此時間段系統正在播放音樂、用戶正在操作進度條控制音樂的播放,
但並沒有與ANR產生原因相關的線索,由於traces.txt是在main線程Runnable時生成的,所以不能從main的調用棧分析出ANR產生的可能原因。
五、小結
第四節中舉的示例是沒有足夠數據,以分析出產生ANR的原因,但本文旨在告訴讀者一種分析ANR的思路,以供大家借鑒和不斷完善。