Android卡頓優(yōu)化 | ANR分析與實(shí)戰(zhàn)(附ANR-WatchDog源碼分析及實(shí)戰(zhàn)、與AndroidPerformanceMonitor的區(qū)別)

本文要點(diǎn)

  • ANR概述
  • 發(fā)生ANR后Android系統(tǒng)的執(zhí)行流程
  • ANR-WatchDog原理與實(shí)戰(zhàn)
  • ANR的傳統(tǒng)解決套路
  • ANR模擬實(shí)戰(zhàn)
  • 線上ANR監(jiān)控方案【ANR-WatchDog原理分析】
  • ANR-WatchDog實(shí)戰(zhàn)
  • ANR-WatchDog總結(jié)
  • ANR-WatchDog與AndroidPerformanceMonitor的區(qū)別

項(xiàng)目GitHub

ANR概述

  • KeyDispatchTimeout,5s
    即按鍵或者觸摸事件驱证,在特定的時(shí)間(一般5s)之內(nèi)沒有響應(yīng)撑毛;

  • BroadcastTimeout牙躺,前臺(tái)10s鸿吆,后臺(tái)60s
    BroadReceiver 在特定的時(shí)間(一般前臺(tái)10s,后臺(tái)60s)之內(nèi)沒有響應(yīng)完成述呐;

  • ServiceTimeout,前臺(tái)20s蕉毯,后臺(tái)200s
    Service 在特定的時(shí)間(一般前臺(tái)20s乓搬,后臺(tái)200s)之內(nèi)沒有處理完成;

發(fā)生ANR后Android系統(tǒng)的執(zhí)行流程

  • APP發(fā)生ANR
  • 進(jìn)程接收異常終止信號(hào)代虾,開始寫入進(jìn)程ANR信息(當(dāng)時(shí)場(chǎng)景进肯,包含當(dāng)前線程所有堆棧信息、CPU/IO的使用情況等)棉磨;
  • 彈出ANR提示框江掩,提示用戶關(guān)閉APP或者繼續(xù)等待;(不同ROM表現(xiàn)不同乘瓤,有的手機(jī)廠商會(huì)去掉這個(gè)提示框)

ANR的傳統(tǒng)解決套路

  • 【線下】在AS的Terminal中环形,使用
    adb pull data/anr/traces.txt 要存儲(chǔ)在本地的路徑
    導(dǎo)出上面提到的ANR現(xiàn)場(chǎng)信息文件
    導(dǎo)出來后衙傀,便可對(duì)文件內(nèi)容進(jìn)行詳細(xì)分析:從CPU抬吟、IO、鎖沖突等原因思考统抬;

ANR模擬實(shí)戰(zhàn)

  • 模擬ANR原因:鎖沖突火本;

    更改代碼:
    運(yùn)行程序,等到程序ANR或崩潰聪建,

    在Terminal使用剛剛提到的命令钙畔,導(dǎo)出ANR的信息文件:
    生成文件:
    打開文件,可以找到原因:
    上次的BlockCanary同樣捕捉到原因:

線下套路其實(shí)就是在APP發(fā)生ANR時(shí)金麸,
導(dǎo)出信息文件擎析,
查看文件,結(jié)合代碼進(jìn)行分析钱骂;

線上ANR監(jiān)控方案

  • 通過FileOberver監(jiān)控上述的ANR信息文件的變化叔锐,
    如果這個(gè)文件發(fā)生了變化,那就說明發(fā)生了ANR见秽,
    那便可以把它上報(bào)到服務(wù)器愉烙,進(jìn)行詳細(xì)的分析;
    【高版本需注意權(quán)限問題】

  • ANR-WatchDog

    • 依賴compile 'com.github.anrwatchdog:anrwatchdog:1.4.0'
    • 官網(wǎng) https://github.com/SalomonBrys/ANR-WatchDog
    • 原理(源碼分析):ANRWatchDog本身就是Thread的子類:
      ANRWatchDog中解取,用一個(gè)綁定了主線程Looper的Handler步责,
      去處理_ticker【一個(gè)Runnable任務(wù)單元】;
      任務(wù)單元對(duì)一些值進(jìn)行了處理,如_tick蔓肯、_reported
      _tick在初始為ANRWatchDog的全局變量時(shí)遂鹊,被賦值為0;^^^^^^^^^^^^^^^^^
      ANRWatchDogrun()中蔗包,
      首先被利用去判定_ticker被post沒有(因?yàn)橐婚_始就_tick為0的話說明_tick還沒被post)秉扑,
      沒有便將_tick=加上卡頓周期,之后post了_ticker调限;
      此時(shí)_tick不為0V勐健!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      _ticker中的run()耻矮,再一次將_tick置零秦躯;^^^^^^^^^^^^^^^^^^^^^^^^^^
      所以只要_ticker不被處理,其run()便不會(huì)執(zhí)行裆装,
      _tick就不會(huì)被置零踱承,
      由此根據(jù)_tick的值可以判斷_ticker是否被處理了;
      _tick重新歸零則主線程處理了_ticker哨免,
      _tick不為零則判定主線程卡頓茎活,它沒處理_tick!W镣佟C钌!;鬯!I肀妗!芍碧!


      ANRWatchDogrun()中煌珊,
      用剛說的主線程Handler,post了_ticker這個(gè)任務(wù)泌豆,
      然后自己sleep一段時(shí)間【即一個(gè)卡頓周期定庵,稍后細(xì)說】,
      如果sleep結(jié)束之后踪危,如果_tick != 0 && !_reported蔬浙,
      則說明主線程還沒有處理_tickerrun()
      沒有處理_ticker這個(gè)任務(wù)單元,
      那便認(rèn)為主線程發(fā)生了卡頓【如源碼注釋所示】:U暝丁3氩!@吨佟>悴 官疲!
      確定發(fā)生了卡頓,就開始封裝一個(gè)ANRError亮隙,進(jìn)行后續(xù)處理了:
      另外補(bǔ)充一下途凫,
      ANRWatchDog提供了兩個(gè)重載的構(gòu)造器,
      提供給開發(fā)者對(duì)卡頓判定周期進(jìn)行設(shè)置溢吻,開發(fā)者不設(shè)置則使用默認(rèn)配置
      【跟BlockCanary同一個(gè)德行】
      接著仔細(xì)看ANRError的構(gòu)造流程
      這里是有兩種構(gòu)造方式New()维费、NewMainOnly(),其最終處理都差不多促王,
      就是通過mainLooper拿到主線程掩完,
      再通過主線程拿到現(xiàn)場(chǎng)的堆棧信息
      最后返回構(gòu)造好的ANRError實(shí)例:
      拿到ANRError實(shí)例之后硼砰,
      通過_anrListener.onAppNotResponding(error);回調(diào)機(jī)制處理ANRError實(shí)例;

      回調(diào)機(jī)制就妙靶琅稹题翰!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      剛剛的_anrListener.onAppNotResponding(error);只是一個(gè)應(yīng)用層上的調(diào)用;
      onAppNotResponding()的實(shí)現(xiàn)方式暴露給開發(fā)者了诈胜,
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      在外部可以通過setANRListener()自己定制包含不同處理方式的ANRListener
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      開發(fā)者不定制豹障,則使用框架自帶的默認(rèn)處理方式唄:
      處理方式簡(jiǎn)單粗暴哈,直接把ANRError丟出去焦匈,
      這樣APP就直接崩潰了:
      ANRError乃是Error的子類:

ANR-WatchDog實(shí)戰(zhàn)

  • 引入依賴
  • 初始化ANR-WatchDog:
  • 還是上面那個(gè)項(xiàng)目血公,手動(dòng)阻塞60s,
    運(yùn)行程序缓熟,
    程序會(huì)5s后崩潰【5s是默認(rèn)周期時(shí)間累魔,崩潰操作見上面源碼分析】
    logcat定位關(guān)鍵字fatal,可以看到ANRError打印的信息够滑,
    信息中包括了崩潰現(xiàn)場(chǎng)所有線程堆棧信息垦写;
    以及顯示bug代碼的位置

優(yōu)化:
當(dāng)然默認(rèn)的APP崩潰處理法并不妥當(dāng)彰触,
影響用戶體驗(yàn)梯投,
實(shí)際開發(fā)中,
我們可以自己定義ANRListener况毅,自定義處理方式【上面說過了】分蓖,
把堆棧信息上報(bào)給服務(wù)器就是了!6怼C春住!

總結(jié)

  • 非浸入式
  • 彌補(bǔ)高版本無權(quán)限問題

與AndroidPerformanceMonitor的區(qū)別

  • AndroidPerformanceMonitor:
    原理是基于Handler-Message機(jī)制味廊,
    監(jiān)控主線程每一個(gè)Message的執(zhí)行午磁,
    在每一個(gè)Message的分發(fā)執(zhí)行前后尝抖,進(jìn)行信息處理;
    (不足:
    一般沒有阻塞的情況下迅皇,
    每一個(gè)Message的執(zhí)行時(shí)間是非常短暫的昧辽,
    達(dá)不到ANR的級(jí)別;
    而且InputEvent在queue.next中block登颓,不會(huì)繼續(xù)執(zhí)行dispatchMessage搅荞,
    而是從native回調(diào)給InputEventReceiver.dispatchInputEvent處理分發(fā),
    所以BlockCanary也就無法監(jiān)控到這類ANR)
  • ANR-WatchDog:
    不管主線程是怎么執(zhí)行的框咙,
    只管最后的結(jié)果咕痛,
    我sleep一個(gè)周期之后,就要看我_tick值有沒有被修改喇嘱,
    沒被修改就是ANR茉贡!
  • AndroidPerformanceMonitor適合全程監(jiān)控卡頓,
    ANR-WatchDog適合補(bǔ)充ANR監(jiān)控者铜;
    兩者可以相輔相成腔丧,結(jié)合使用!





參考:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末作烟,一起剝皮案震驚了整個(gè)濱河市愉粤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拿撩,老刑警劉巖衣厘,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異压恒,居然都是意外死亡影暴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門探赫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坤检,“玉大人,你說我怎么就攤上這事期吓≡缧” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵讨勤,是天一觀的道長(zhǎng)箭跳。 經(jīng)常有香客問我,道長(zhǎng)潭千,這世上最難降的妖魔是什么谱姓? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮刨晴,結(jié)果婚禮上屉来,老公的妹妹穿的比我還像新娘路翻。我一直安慰自己,他們只是感情好茄靠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布茂契。 她就那樣靜靜地躺著,像睡著了一般慨绳。 火紅的嫁衣襯著肌膚如雪掉冶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天脐雪,我揣著相機(jī)與錄音厌小,去河邊找鬼。 笑死战秋,一個(gè)胖子當(dāng)著我的面吹牛璧亚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脂信,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼癣蟋,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了吉嚣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蹬铺,失蹤者是張志新(化名)和其女友劉穎尝哆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甜攀,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秋泄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了规阀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恒序。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谁撼,靈堂內(nèi)的尸體忽然破棺而出歧胁,到底是詐尸還是另有隱情,我是刑警寧澤厉碟,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布喊巍,位于F島的核電站,受9級(jí)特大地震影響箍鼓,放射性物質(zhì)發(fā)生泄漏崭参。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一款咖、第九天 我趴在偏房一處隱蔽的房頂上張望何暮。 院中可真熱鬧奄喂,春花似錦、人聲如沸海洼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贰军。三九已至玻蝌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間词疼,已是汗流浹背俯树。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贰盗,地道東北人许饿。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像舵盈,于是被迫代替她去往敵國(guó)和親陋率。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容