本文要點
- ANR概述
- 發生ANR後Android系統的執行流程
- ANR-WatchDog原理與實戰
- ANR的傳統解決套路
- ANR模拟實戰
- 線上ANR監控方案【ANR-WatchDog原理分析】
- ANR-WatchDog實戰
- ANR-WatchDog總結
- ANR-WatchDog與AndroidPerformanceMonitor的差別
項目GitHub
ANR概述
-
KeyDispatchTimeout,5s
即按鍵或者觸摸事件,在特定的時間(一般5s)之内沒有響應;
-
BroadcastTimeout,前台10s,背景60s
BroadReceiver 在特定的時間(一般前台10s,背景60s)之内沒有響應完成;
-
ServiceTimeout,前台20s,背景200s
Service 在特定的時間(一般前台20s,背景200s)之内沒有處理完成;
發生ANR後Android系統的執行流程
- APP發生ANR
- 程序接收異常終止信号,開始寫入程序ANR資訊(當時場景,包含目前線程所有堆棧資訊、CPU/IO的使用情況等);
- 彈出ANR提示框,提示使用者關閉APP或者繼續等待;(不同ROM表現不同,有的手機廠商會去掉這個提示框)
ANR的傳統解決套路
- 【線下】在AS的Terminal中,使用
導出上面提到的adb pull data/anr/traces.txt 要存儲在本地的路徑
ANR現場資訊檔案
;
導出來後,便可對檔案内容進行詳細分析:從
等原因思考;CPU、IO、鎖沖突
ANR模拟實戰
-
模拟ANR原因:鎖沖突;
更改代碼:

運作程式,等到程式ANR或崩潰,
在Terminal使用剛剛提到的指令,導出ANR的資訊檔案:
生成檔案:
打開檔案,可以找到原因:
上次的BlockCanary同樣捕捉到原因:
線下套路其實就是在APP發生ANR時,
導出資訊檔案,
檢視檔案,結合代碼進行分析;
線上ANR監控方案
- 通過
FileOberver
監控上述的ANR資訊檔案的變化,
如果這個檔案發生了變化,那就說明發生了ANR,
那便可以把它上報到伺服器,進行詳細的分析;
【高版本需注意權限問題】
- ANR-WatchDog
- 依賴
compile 'com.github.anrwatchdog:anrwatchdog:1.4.0'
- 官網 https://github.com/SalomonBrys/ANR-WatchDog
- 原理(源碼分析):
本身就是ANRWatchDog
的子類:Thread
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別 ANRWatchDog
中,用一個綁定了主線程Looper的Handler,
去處理
_ticker
【一個Runnable任務單元】;
任務單元對一些值進行了處理,如
、_tick
:_reported
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
在初始為_tick
ANRWatchDog
的全局變量時,被指派為0;^^^^^^^^^^^^^^^^^
在
的ANRWatchDog
run()
中,
首先被利用去判定
被post沒有(因為一開始就_ticker
為0的話說明_tick
_tick
還沒被post),
沒有便将
=加上_tick
,之後post了卡頓周期
_ticker
;
此時
不為0!!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_tick
中的_ticker
,再一次将run()
_tick
置零;^^^^^^^^^^^^^^^^^^^^^^^^^^
是以隻要
不被處理,其_ticker
便不會執行,run()
就不會被置零,_tick
由此根據Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
的值可以判斷_tick
是否被處理了;_ticker
重新歸零則主線程處理了_tick
,_ticker
不為零則判定_tick
,它沒處理主線程卡頓
!!!!!!!!_tick
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
的ANRWatchDog
run()
中,
用剛說的主線程Handler,post了
_ticker
這個任務,
然後自己sleep一段時間【即一個卡頓周期,稍後細說】,
如果sleep結束之後,如果
_tick != 0 && !_reported
,
則說明主線程還沒有處理
的_ticker
run()
,
沒有處理
_ticker
這個任務單元,
那便認為
發生了主線程
卡頓
【如源碼注釋所示】:!!!!!!
确定發生了卡頓,就開始封裝一個
,進行後續處理了:ANRError
另外補充一下,Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別 ANRWatchDog
提供了兩個重載的構造器,
提供給開發者對
進行設定,開發者不設定則使用卡頓判定周期
預設配置
:
【跟
同一個德行】BlockCanary
接着仔細看Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
的構造流程ANRError
這裡是有兩種構造方式Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
、New()
NewMainOnly()
,其最終處理都差不多,
就是通過
mainLooper
拿到主線程,
再通過主線程拿到
現場的堆棧資訊
,
最後傳回構造好的
執行個體:ANRError
拿到Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別 ANRError
執行個體之後,
通過
回調機制處理_anrListener.onAppNotResponding(error);
執行個體;ANRError
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別 回調機制就妙啊!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
剛剛的
隻是一個應用層上的調用;_anrListener.onAppNotResponding(error);
onAppNotResponding()
的實作方式暴露給開發者了,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
在外部可以通過
自己定制包含不同處理方式的setANRListener()
ANRListener
:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別 開發者不定制,則使用架構自帶的預設處理方式呗:
處理方式簡單粗暴哈,直接把
ANRError
丢出去,
這樣APP就直接
了:崩潰
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
乃是ANRError
的子類:Error
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別 - 依賴
ANR-WatchDog實戰
- 引入依賴
- 初始化ANR-WatchDog:
-
還是上面那個項目,手動阻塞60s,
運作程式,
程式會5s後崩潰【5s是預設周期時間,崩潰操作見上面源碼分析】
在
定位關鍵字logcat
,可以看到fatal
ANRError
列印的資訊,
資訊中包括了
的崩潰現場所有線程
堆棧資訊
;
以及顯示
;bug代碼的位置
優化:
當然預設的APP崩潰處理法并不妥當,
影響使用者體驗,
實際開發中,
我們可以自己定義
ANRListener
,自定義處理方式【上面說過了】,
把堆棧資訊上報給伺服器就是了!!!!
總結
- 非浸入式
- 彌補高版本無權限問題
與AndroidPerformanceMonitor的差別
-
AndroidPerformanceMonitor:
原理是基于Handler-Message機制,
監控主線程每一個Message的執行,
在每一個Message的分發執行前後,進行資訊處理;
(不足:
一般沒有阻塞的情況下,
每一個Message的執行時間是非常短暫的,
達不到ANR的級别;
而且InputEvent在queue.next中block,不會繼續執行dispatchMessage,
而是從native回調給InputEventReceiver.dispatchInputEvent處理分發,
是以BlockCanary也就無法監控到這類ANR)
-
ANR-WatchDog:
不管主線程是怎麼執行的,
隻管最後的結果,
我sleep一個周期之後,就要看我
_tick
值有沒有被修改,
沒被修改就是ANR!
-
适合全程監控卡頓,AndroidPerformanceMonitor
ANR-WatchDog
适合補充ANR監控;
兩者可以相輔相成,結合使用!