一文帶你了解ANR(測試人員)


一、首先,了解一下什么是ANR

ANR,是“Application Not Responding”的縮寫,即“應用程序無響應”。系統會向用戶顯示一個對話框,用戶可以選擇“等待”而讓程序繼續運行,也可以選擇“強制關閉”。

在Android中,應用程序的響應是由Activity Manager和WindowManager系統服務監視的 。當它監測到A、B、C情況中的一個時,Android就會針對特定的應用程序顯示ANR:

  • A.在5秒內沒有響應輸入的事件(例如,按鍵按下,屏幕觸摸)--主要類型

  • B.BroadcastReceiver在10秒內沒有執行完畢

  • C.Service在特定時間內(20秒內)無法處理完成--小概率類型

造成ABC的原因有很多,比如在主線程中做了非常耗時的操作,如下載,io異常等。還需要注意的是產生這種ANR的前提是要有輸入事件,如果用戶沒有觸發任何輸入事件,即便是主線程阻塞了,也不會產生ANR,因為InputDispatcher沒有分發事件給應用程序,當然也不會檢測處理超時和報告ANR了。

各個應用進程和系統進程的函數堆棧信息都輸出到了/data/anr/traces.txt的文件中

二、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問題,應該怎么做

  1. 首先,應該截圖,保留“證據”;

  2. 描述清楚出現步驟,並嘗試復現,確認是否必現或出現概率

  3. 導出traces文件

獲取traces文件命令:
adb pull /data/anr
  1. 導出logcat日志信息。

擴展一:traces文件信息解析

開頭顯示進程號、ANR發生的時間點和進程名稱

    ----- pid 9183 at 2012-09-28 22:20:42 ----
 Cmd line: com.example.anrdemo

DALVIK THREADS: //以下是各個線程的函數堆棧信息
//依次是:線程名、線程優先級、線程號、線程當前狀態(TIMED_WAIT或SUSPENDED在anr時很常見)
//線程名稱后面標識有daemon,說明這是個守護線程

"main" prio=5 tid=1 TIMED_WAIT
//依次是:線程組名稱、suspendCount個數、debugSuspendCount個數、線程的Java對象地址、線程的Native對象地址
| group="main" sCount=1 dsCount=0 obj=0x4025b1b8 self=0xce68

//sysTid是線程號,主線程的線程號和進程號相同
| sysTid=9183 nice=0 sched=0/0 cgrp=default     
handle=-1345002368| schedstat=( 140838632 210998525 213 )
at java.lang.VMThread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1213)
.......


//Binder線程是進程的線程池中用來處理binder請求的線程

"Binder Thread #2" prio=5 tid=8 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x40750b90 self=0x1440b8
| sysTid=9190 nice=0 sched=0/0 cgrp=default handle=1476256
| schedstat=( 915528 18463135 4 )
at dalvik.system.NativeStart.run(Native Method)



//JDWP線程是支持虛擬機調試的線程,不需要關心

"JDWP" daemon prio=5 tid=5 VMWAIT
| group="system" sCount=1 dsCount=0 obj=0x4074b878 self=0x16c958
| sysTid=9187 nice=0 sched=0/0 cgrp=default handle=1510224
| schedstat=( 366211 2807617 7 )
t dalvik.system.NativeStart.run(Native Method)
//“Signal Catcher”負責接收和處理kernel發送的各種信號,例如SIGNAL_QUIT、SIGNAL_USR1等就是被該線程
//接收到,這個文件的內容就是由該線程負責輸出的,可以看到它的狀態是RUNNABLE,不過此線程也不需要關心

"Signal Catcher" daemon prio=5 tid=4 RUNNABLE
| group="system" sCount=0 dsCount=0 obj=0x4074b7b8 self=0x150008
| sysTid=9186 nice=0 sched=0/0 cgrp=default handle=1501664
| schedstat=( 1708985 6286621 9 )

擴展二:如何避免ANR

  1. 絕對不要在主線程上進行復雜耗時的操作,比如說發送接收網絡數據、進行大量計算、操作數據庫、讀寫文件等,統統采用異步操作

  2. broadCastReceiver 要進行復雜操作的的時候,可以在onReceive()方法中啟動一個IntentService或者JobIntentService去做。

  3. Service中的耗時操作最好也是采用異步任務

  4. 在設計及代碼編寫階段避免出現出現同步/死鎖、死循環等不恰當情況


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM