各大廠與卡頓和ANR的戰(zhàn)斗記錄篇

作者:Drummor

1.1 認(rèn)識ANR

1.1.1 系統(tǒng)如何處理ANR

設(shè)計原理和影響因素篇,主要對以下關(guān)鍵問題展開

  • ANR觸發(fā)的條件以及根本原因
  • 發(fā)生ANR之后,系統(tǒng)處理ANR的流程。
  • 應(yīng)用層如何判定ANR:對ANR的感知,通過監(jiān)聽SIGQUIT信號。
  • 應(yīng)用層面如何獲取有用的信息幫助解決ANR問題。

1.1.2 ANR問題分類

把ANR 產(chǎn)生的影響因素清晰的分為了四個大的類別,基本覆蓋了ANR問題產(chǎn)生的原因。

  • 應(yīng)用內(nèi)主線程存在耗時任務(wù);
  • 應(yīng)用主線程處理大量任務(wù);
  • 系統(tǒng)內(nèi)部其他進(jìn)程或者資源負(fù)載過高;
  • 應(yīng)用自身其他線程或者負(fù)載過高。

系列文章其實就是圍繞著這些問題的監(jiān)控、分析、解決展開的。

2 工具建設(shè)-消息調(diào)度監(jiān)控

通過博文得知,今日頭條團(tuán)隊,ANR 監(jiān)控的工具叫 Raster,其最主要的功能就是采集主線程調(diào)度。

ANR 產(chǎn)生的原因很多情況下可能是歷史耗時問題的累計。因而單純采集發(fā)生ANR 時那一刻的堆棧就會有【堆棧漂移的問題】,也就是采集到的堆棧不是誘發(fā)ANR 產(chǎn)生的真正原因?,F(xiàn)在ANR 監(jiān)控的很多框架也是圍繞這一問題展開的。

應(yīng)對方式 對主線程消息調(diào)度進(jìn)行監(jiān)控記錄,包括歷史消息,正在執(zhí)行的消息和將要執(zhí)行的消息。同時對四大組件執(zhí)行的消息進(jìn)行單獨的監(jiān)控,這對我們分析哪個組件產(chǎn)生的ANR 是很重要的參考依據(jù)。

這一方案是在網(wǎng)上公開的我能接觸到的最早提出的,后面我們會看到很多團(tuán)隊對ANR 問題的監(jiān)控都是這一方案的變種,或者大同小異。

這一方案的細(xì)化,主要包括以下幾個方面

2.1 消息聚合

消息統(tǒng)計聚合策略:主線程消息會很多,記錄過去5-10秒的消息本身是一個比較重的動作,采用一定的聚合策略是很有必要的。

  • 合并耗時段的多個消息:耗時較小的消息,對ANR 問題的產(chǎn)生影響不大,只記錄總耗時和和消息的個數(shù)。
  • 獨立組件消息:ActivtyThread 組件調(diào)度通過Handler我們可以采集到這些調(diào)度,單獨記錄。
  • 獨立耗時消息:對超過閾值(比如300ms)的消息單獨記錄,耗時消息是我們重點關(guān)注的對象。
  • 記錄IDEL 狀態(tài),主線程無消息的時候,會進(jìn)入IDEL 狀態(tài),堵塞在nativePoll 處。這一狀態(tài)單獨統(tǒng)計。
  • 發(fā)生ANR 時,采集當(dāng)前正在進(jìn)行的任務(wù)。
  • ANR 發(fā)生時,采集pending消息,根據(jù)pending消息中的組件調(diào)度消息能讓們知道哪個組件觸發(fā) ANR,同時根據(jù)等待的時常側(cè)面反映系統(tǒng)負(fù)載的能力。

2.2 每條消息記錄的關(guān)鍵信息

  • 消息調(diào)度的時長:cputime 和 walltime,記錄兩個時間能更好的判斷一次消息耗時是執(zhí)行耗時還是等待或者搶占較多。
  • 消息調(diào)度的類型:組件調(diào)度,耗時調(diào)度,多消息聚合調(diào)度
  • 消息堆棧:對消息內(nèi)具體執(zhí)行信息,采集其堆棧。

2.3 主線程線程堆棧的采樣

對耗時的消息,進(jìn)行采樣,采取的策略是超時采樣。具體來說,介于大部分的耗時小消息不需要進(jìn)行堆棧采樣,為了避免頻繁設(shè)置和取消超時任務(wù)(也就是采樣任務(wù)),頭條在此處做了一個優(yōu)化,每次消息開始是并不是重新設(shè)置采集超時任務(wù),而是修改目標(biāo)時間。

3 問題分析&解決

  • 結(jié)合結(jié)合采集的物料,這些物料包括ANR Info信息,采集的主線程調(diào)度信息等給出了分析ANR問題的一般思路。通過trace信息讀取是否有明顯的耗時調(diào)用,通過ANR Info分析系統(tǒng)負(fù)載,應(yīng)用內(nèi)負(fù)載,再結(jié)合Raster采集的線程調(diào)用,把ANR問題最終歸因上上述四大因素上。然后具體分析解決。這里不做展開了,今日頭條團(tuán)隊案例分析還是相當(dāng)精彩的不容錯過。
  • 對Barrier泄漏的監(jiān)控和由SP引發(fā)的案例進(jìn)行詳細(xì)的分析。

2 微信團(tuán)隊

2021年7月份,微信團(tuán)隊發(fā)布在公眾號上的兩篇文章關(guān)于卡頓監(jiān)控和ANR監(jiān)控的文章

  • 《微信Android客戶端的卡頓監(jiān)控方案》
  • 《微信Android客戶端的ANR監(jiān)控方案》

2.1 首先第一篇《微信Android客戶端的卡頓監(jiān)控方案》

  • 該篇是我接觸到的最早也可能是唯一一篇指出使用WatchDog方案漏報卡頓和ANR的問題的文章。文章里甚至還指出了漏報概率公式,以及如何不漏報的方案,如下圖

思考這樣一個問題,如果我們選擇間隔4.5秒去check發(fā)送到主線程Looper到Message是否被消費。現(xiàn)在有一個5秒到卡頓,從2秒開始,結(jié)束在第7秒耗時5秒,我們間隔5秒能監(jiān)控到的概率是多少?

答案是只有11%,驚訝不。原因就是在在0-4.5和4.5到9這兩個周期內(nèi)那些空閑的時間,消息都有可能被消費掉!這種情況我們就監(jiān)控不到了。想想,你再想想,真的是佩服騰訊工程師嚴(yán)謹(jǐn)?shù)墓こ套黠L(fēng)。

  • 另外,該篇全面的的提供了監(jiān)控主線程卡頓的方案,包括
  • 主線程Message處理的耗時,使用的是設(shè)置Looper Printer的方案,Android10以后我們可以通過設(shè)置Observer監(jiān)控
  • IdleHandler耗時的監(jiān)控,通過hook MessageQueue mIdleHandlers實現(xiàn)。
  • TouchEvent的耗時監(jiān)控,通過PLT Hook。這一塊要注意,TouchEvent的事件分發(fā)是不通過Handler機制,而是直接native層調(diào)到j(luò)ava層分發(fā)給View的,如果這個知識點不清楚的小伙伴注意了,又有新知識學(xué)習(xí)了。

2.2 第二篇文章

很是精彩,ANR如何產(chǎn)生,系統(tǒng)源碼實現(xiàn),找監(jiān)控方案直接一套組合拳,可見功底深厚大佬就是大佬。

其中,通過監(jiān)聽SIGQUIT信號并過濾誤報最終監(jiān)控ANR的方案,也是當(dāng)前主流的正規(guī)方案,為什么是加一個正規(guī)的修飾詞呢,想想ANRWatchDog那種多不正經(jīng)就知道這個有多正規(guī)。

這里面,幾個重要的點我列下

  • 監(jiān)聽SIGQUIT信號,需要注意重新發(fā)送出去
  • 梳理系統(tǒng)ANR的過程中,發(fā)現(xiàn)的ANR Trace 通過hook手段可以拿到

這就是微信團(tuán)隊出的關(guān)于Android卡頓和ANR的兩篇經(jīng)典文章,建議大家自信研讀,卷起來!

3 釘釘技術(shù)團(tuán)隊

2022年12月份,釘釘團(tuán)隊發(fā)表的ANR 問題的解決方案系列文章。

  • 《釘釘 ANR 治理最佳實踐 | 定位 ANR 不再霧里看花》
  • 《讓 nativePollOnce 不再排名第一 | 釘釘 ANR 治理最佳實踐》
  • 《釘釘 ANR 實戰(zhàn)踩坑與經(jīng)驗總結(jié) | 釘釘 ANR 治理最佳實踐》

3.1 ANR 判定

作為ANR問題不可避免的兩個問題

  • 文章也是分析了系統(tǒng)ANR 的流程
  • 判定ANR的方案也是通過監(jiān)聽SIGQUIT 并過濾誤報的方式。

3.2 工具建設(shè)

監(jiān)控ANR 的方案思路與今日頭條基本一致,采集主線程的調(diào)度信息做記錄。其中也有一些不同,把主線程調(diào)度的分類,以下五類

  • 主線程的消息調(diào)度
  • IdelHandler 調(diào)度
  • IDLE 狀態(tài)
  • 觸摸事件
  • 傳感器事件

可見,其在主線程任務(wù)調(diào)度的方面監(jiān)控的更加具體,今日頭條的Raster工具從博文看只是對主線程的消息調(diào)度進(jìn)行了監(jiān)控,我們在結(jié)合微信團(tuán)隊的卡頓監(jiān)控方案,其實可以更全面的對主線程任務(wù)進(jìn)行調(diào)度,這一點很知道借鑒學(xué)習(xí)。

此外,博文里還提出有些手機廠商在應(yīng)用進(jìn)程會進(jìn)入凍結(jié)狀態(tài),APP 回到前臺后才繼續(xù)執(zhí)行,凍結(jié)的過程里會導(dǎo)致任務(wù)耗時過長,需要單獨記錄,不過這一點今日頭條的方案,里能夠通過CPUTime 和WallTime 識別出來。

其他方面,ANRCanery 采集也會采集過去當(dāng)下和等待的任務(wù)調(diào)度,也對會采集的消息進(jìn)行聚合處理。堆棧采集上,也是采用了時間對齊方案對堆棧進(jìn)行采樣。

3.3 實踐分享

  • 結(jié)合具體場景分享了一些死鎖場景,Barrier消息泄露場景等。
  • 還分享了工具建設(shè)的心得,很有啟發(fā)性。

4 其他團(tuán)隊

4.1 阿里其他技術(shù)團(tuán)隊

4.1.2 閑魚團(tuán)隊

2021年6月份, 《關(guān)于閑魚的ANR治理,我有幾條心得》

文章短小精悍

  • 【監(jiān)控】監(jiān)聽SIGQUIT信號
  • 【排查】搭建了ANR Info收集和主線程Message監(jiān)控。
  • 【優(yōu)化】給出了三個在借助排查工具的優(yōu)化案例。

3.3 手淘技術(shù)團(tuán)隊

《手淘 Android 幀率采集與監(jiān)控詳解》
手淘團(tuán)隊2022年1月份,提出了Android [滑動幀率]思路并給出了比較詳細(xì)的監(jiān)控方案。

4.2 shopee 團(tuán)隊

2022年8月份 LooperMonitor

《Android 卡頓與 ANR 的分析實踐》

  • ANR的判定: 也是通過SIGQUIT +過濾的方式。
  • ANR的監(jiān)控 :主線程的監(jiān)控思路與今日頭條和字節(jié)跳動一致,記錄主線程的調(diào)度信息,也是有聚合的策略。

值得注意的點:

  • 文章里重點提出了對消息的記錄使用了池化技術(shù),減少內(nèi)存重復(fù)分配問題。
  • 采集堆棧的方案上,這里提到了利用Kotlin協(xié)程非堵塞式掛起特性實現(xiàn)了高效的采集。該方案并沒有具體展開如何實現(xiàn)的。同時采集閾值線性增加。
  • 對Looper Message的監(jiān)控,在 Android api ≥ 28 時,Looper 中新增了一個 Observer 的接口,采用元反射的方式,減少了通過Looper Printer 拼接Message帶來的性能損耗。

4.3 毒物團(tuán)隊

2021年9月份得物團(tuán)隊發(fā)表了ANR監(jiān)控文章

《得物技術(shù) | 得物App ANR監(jiān)控平臺設(shè)計》

  • ANR判定使用了愛奇藝的XCarash因而能采集到tomsbtone信息
  • 主線程消息回溯采集思路與其他家類似。
  • 毒物搭建了ANR分析平臺,數(shù)據(jù)可視化,有一定的參考意義。

5 多說一些抓棧問題。

java層面直接通過thread.getStackTrace()獲取堆棧信息,是有一定損耗的,對此我們看到大家常規(guī)的做法是控制采集的頻率,shoppe團(tuán)隊提到的由協(xié)程的非堵塞式掛起實現(xiàn)高效的線程堆棧采集,對此我是持懷疑態(tài)度

業(yè)內(nèi)確實對高效采集堆棧方向有探索,給出了高效的抓棧方案,妥妥的黑科技看到了比較優(yōu)秀的兩篇供大家參考。

  • 《西瓜視頻穩(wěn)定性治理體系建設(shè)三:Sliver 原理及實踐》
  • 網(wǎng)易云音樂《不一樣的Android堆棧抓取方案》

總結(jié)

縱觀各廠在卡頓和ANR 方面做的探索和方案,我們可以看出,思路上都有重合,在細(xì)節(jié)方面做了很多針對自身業(yè)務(wù)和實際情況做的針對性的優(yōu)化和個性化的開發(fā)??偟膩碚f逃不出以下幾個步驟

  • ANR的感知上:業(yè)界主流的方案就是監(jiān)聽SIGQUIT 信號+誤報過濾。騰訊技術(shù)團(tuán)隊,提到的OV 廠商對ANR的處理并不是常規(guī)的處理,而是做閃退處理,所以要以check主線程正在處理的 Message,延誤時間作為輔助防止漏報。
  • 信息采集上:由于發(fā)生ANR 時,主線程正在處理的任務(wù)可能并不是發(fā)生ANR的真正原因,因而需要對主線程任務(wù)過往調(diào)度進(jìn)行統(tǒng)計記錄,同時對消息進(jìn)行監(jiān)控,監(jiān)控的類型,其實微信團(tuán)隊卡頓方案監(jiān)控給出了全面的方案。需要對消息進(jìn)行聚合處理。任務(wù)的執(zhí)行棧抓取,控制頻次,也有團(tuán)隊給出了高效抓棧方案。另外,出了主線程調(diào)度消息外,系統(tǒng)負(fù)載情況信息對我們分析ANR 很重要,因為ANR 發(fā)生的原因可不僅僅是主線程執(zhí)行了耗時任務(wù)。
  • 問題解決:全面準(zhǔn)確的信息采集的基礎(chǔ)上,會讓找出問題解決問題工作變得更簡單,各團(tuán)隊也給出了思路和案例,參考性很高。

上述ANR 的監(jiān)控方案,截止到現(xiàn)在都沒有開源,卡頓監(jiān)控在Matrix上開源了。talk is cheap ,因而我在正在嘗試取各家之所長,編寫開源一個ANR監(jiān)控工具。目前正在草稿階段,把基本框架做完之后會盡快開源出來,希望大家參與進(jìn)來共同建設(shè)。關(guān)注作者 別錯過更新進(jìn)度。

ANR問題從監(jiān)控到采集都使用了各種hook手段黑科技,ANR作為Android一種保護(hù)機制, 只提出問題,不解決問題的行為都是xxx,目前還未看到官方對此有何動作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 如何定義發(fā)生了卡頓現(xiàn)象: 線下很難復(fù)現(xiàn),與發(fā)生場景強相關(guān)(所以需要我們?nèi)プ隹D監(jiān)控,收集現(xiàn)場信息) CPU相關(guān)知識...
    今陽說閱讀 1,030評論 0 2
  • 作者:Drummor 1 哪來的ANR ANR(Application Not responding):如果 An...
    艾瑞敗類閱讀 1,670評論 0 1
  • 對于卡頓分析,首先需要明確分析的因素,即影響卡頓有哪些點,是 CPU 繁忙,線程鎖資源導(dǎo)致的阻塞,IO 耗時操作,...
    Kip_Salens閱讀 622評論 0 0
  • 前言 成為一名優(yōu)秀的Android開發(fā),需要一份完備的知識體系[https://github.com/JsonCh...
    我卡蘇總我閱讀 1,682評論 0 1
  • 卡頓原因 人眼能感覺到的幀率是每秒24幀,而屏幕每16毫秒會刷新一次,也就是每秒會刷新60次。當(dāng)每秒刷新次數(shù)少于6...
    Archer_J閱讀 3,102評論 0 16

友情鏈接更多精彩內(nèi)容