乾貨-ANR問題處理套路

anr問題的處理技巧

hi, 大家好,我是愛喫香蕉的猴子,今天記錄一下ANR問題的處理套路吧,這也是自己分析ANR問題一般的思路;


  • 根據測試的描述,區分是Monkey測試偶現的 ,還是可以手動復現,一般情況前者多一些,我也是根據前者寫這個記錄;
  • 首先,要會區分ANR類型,是什麼類型的ANR ??
    • 用戶輸入事件處理超時: KeyDispatchTimeout-主要類型按鍵或觸摸事件,input事件在5S內沒有處理完成發生ANR
      • 關鍵字:Reason: Input dispatching timed out xxxx
    • Broadcast超時: BroadcastReceiver onReceiver處理事務時前臺廣播在10S內,後臺廣播在60s內沒有處理完成發生ANR
    • 關鍵字:Timeout of broadcast XXX/Receiver during timeout:XXX/Broadcast of XXX
    • Service超時:ServiceTimeout-bind,create,start,unbind等在主線程處理耗時,前臺Service在20s內,後臺Service在200s內沒有處理完成發生ANR
    • 關鍵字:Timeout executing service:/executing service XXX
    • ContentProvider超時: publish在10s內沒有處理完成發生ANR
      • 關鍵字:timeout publishing content providers
  • 補充一種類型 窗口獲取焦點超時(input 類型的一種子類型)
    • 關鍵字:Reason: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)需要注意區分同爲Input dispatching timed out大類的用戶輸入事件處理超時,這兩類超時括號內的提示語是不同的。
    • 這個問題,我可以簡單理解爲窗口切換時,A --> B, 開始焦點在A 窗口在A ,後面 焦點在A 這時窗口時null,如果這個時候超過了5s,那就會發生anr.

查看現場
- ag “am_anr” / ag ag “ANR in” # 這個時候,你會發現很多或者幾個anr的地方, 我先看時間最早的,我這裏就不貼log了
- 確定最早發生的anr的時間,進程,(如果還沒有確定anr類型) 這裏基本也會看到特定類型anr的信息
- 然後既然確定了一個anr的位置,那我們就要分析,這個是怎麼造成的?? 猜測思路如下
- 1. 主線程耗時操作,如複雜的layout,龐大的for循環,IO等
- 2. 主線程被子線程同步鎖block
- 3. 主線程被Binder 對端block
- 4. Binder被佔滿導致主線程無法和SystemServer通信
- 5. 得不到系統資源(CPU/RAM/IO)(有一個關鍵搜索:CPU usage)
- 如果,並沒有有效的收穫,那就檢索 上面的anr類型的關鍵字grep -v ‘mmm|nnn’ abc.txt









看anr的trace文件 我一般是大概有了瞭解,最後看trace文件

  • 匹配一下,上面看到的時間 進程 線程(如果不匹配,也可以反向去找)
  • 補充一下:
    • main tid=1 //主線程
    • group: 線程組名稱
    • sCount: suspendCount個數
    • dsCount: debugSuspendCount個數
    • obj: 0x4025b1b8 線程java對象地址
    • self: 線程native的對象地址
    • Binder Thread #2: Binder線程是進程的線程中用來處理binder請求的線程.
    • SUSPENDED:線程暫停,可能是由於輸出Trace、GC或debug被暫停
    • NATIVE: 正在執行JNI本地函數
    • MONITOR: 線程阻塞,等待獲取對象鎖
    • WAIT: 執行了無限等待的wait函數
    • TIMED_WAIT: 執行了帶有超時參數的wait、sleep或join函數
    • VMWAIT: 正在等待VM資源
    • RUNNING/RUNNABLE: 線程可運行或正在運行
    • INITALIZING: 新建,正在初始化,爲其分配資源
    • STARTING: 新建,正在啓動
    • ZOMBIE: 線程死亡,終止運行,等待父線程回收它
  • 一般我們要首先查看main線程,是否出現 block wait suspend ,有沒有線程間的死鎖,有沒有出現binder調用服務端沒有響應,有沒有阻塞在system server.
    • 死鎖:線程在獲得一個鎖L1的情況下再去申請另外一個鎖L2,也就是鎖L1想要包含了鎖L2,也就是說在獲得了鎖L1,並且沒有釋放鎖L1的情況下,又去申請獲得鎖L2,這個是產生死鎖的最根本原因。看一個android中的簡單Log
Cmd line: com.android.inputmethod.latin
"main" prio=5 tid=1 NATIVE
......
  at android.os.BinderProxy.transact(Native Method)
  at com.android.internal.view.IInputMethodManager$Stub$Proxy.getCurrentInputMethodSubtype(IInputMethodManager.java:908) ......
Cmd line: system_server
"main" prio=5 tid=1 MONITOR
  - waiting to lock <0x41c5a650> (a java.lang.Object) held by tid=12 (WindowManager)......
"WindowManager" prio=5 tid=12 MONITOR
  - waiting to lock <0x41c0c118> (a android.view.inputmethod.InputMethodManager$H) held by tid=61 (Binder_F)......
"Binder_F" prio=5 tid=61 MONITOR
  at com.android.server.InputMethodManagerService.getCurrentInputMethodSubtype(InputMethodManagerService.java:~3078)
  • 解析一下:main等待WindowManager ,WindowManager 又等待Binder_F。因此inputmethod主線程的遠程調用無法返回,導致ANR。
  • 還有一點,這裏查看這個cpu佔用信息
11 CPU usage from 9818ms to 0ms ago (2020-12-09 06:03:39.534 to 2020-12-09 06:03:49.352):
12   109% 10198/system_server: 85% user + 24% kernel / faults: 12620 minor 11 major
13   35% 2724/pulseaudio: 34% user + 1.7% kernel
14   13% 10545/com.android.car: 10% user + 3.1% kernel / faults: 3518 minor
............
110 74% TOTAL: 49% user + 24% kernel + 0.1% iowait + 0.1% softirq
  • binder調用服務端沒有響應: 基本通過clent和server共同的方法去grep,看服務端在做什麼?
  • system server出現block
  • 有時候,也可以根據:id threadid 進行grep看執行了什麼程序,例如:1089 1089
  • 其實,74%這個是負載,這個負載是算是高,在這個負載的情況出現anr也是有可能是系統性能問題,但不能明確,起碼我們還要找到什麼原因造成的負載高。cpu其他進程佔用信息,基本都相對容易判斷。

  • 其實還有一些分析策略,但最常用的還是這些套路吧,有了好的且可以分享的案例,我會補充上來。

                                                 Code的搬運工V1.0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章