天天看點

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

本文要點
  • 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原因:鎖沖突;

    更改代碼:

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

運作程式,等到程式ANR或崩潰,

在Terminal使用剛剛提到的指令,導出ANR的資訊檔案:

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

生成檔案:

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

打開檔案,可以找到原因:

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

上次的BlockCanary同樣捕捉到原因:

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

線下套路其實就是在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()

    中,

    首先被利用去判定

    _ticker

    被post沒有(因為一開始就

    _tick

    為0的話說明

    _tick

    還沒被post),

    沒有便将

    _tick

    =加上

    卡頓周期

    ,之後post了

    _ticker

    此時

    _tick

    不為0!!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    _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:
Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別
  • 還是上面那個項目,手動阻塞60s,

    運作程式,

    程式會5s後崩潰【5s是預設周期時間,崩潰操作見上面源碼分析】

    logcat

    定位關鍵字

    fatal

    ,可以看到

    ANRError

    列印的資訊,

    資訊中包括了

    崩潰現場所有線程

    堆棧資訊

    以及顯示

    bug代碼的位置

Android卡頓優化 | ANR分析與實戰(附ANR-WatchDog源碼分析及實戰、與AndroidPerformanceMonitor的差別)ANR概述發生ANR後Android系統的執行流程ANR的傳統解決套路ANR模拟實戰線上ANR監控方案ANR-WatchDog實戰總結與AndroidPerformanceMonitor的差別

優化:

當然預設的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監控;

    兩者可以相輔相成,結合使用!