Android ANR不會?這里有ANR全解析和各種案例!包教包會!

<meta charset="utf-8">

1、ANR介紹

1.1 ANR是什么

ANR,全稱為Application Not Responding,也就是應用程序無響應。如果 Android 應用的界面線程處于阻塞狀態(tài)的時間過長,就會觸發(fā)“應用無響應”(ANR) 的錯誤。

此時系統(tǒng)會向用戶顯示一個對話框,ANR 對話框會為用戶提供強行退出應用的選項。

image

1.2 ANR的四種類型

在Android系統(tǒng)中,應用程序的響應由Activity Manager及Window Manager兩個系統(tǒng)服務所監(jiān)控。通常情況下,應用出現(xiàn)如下四類情況時,系統(tǒng)將報ANR:

  • KeyDispatchTimeout(最常見類型)—— input事件5s內(nèi)未處理完成導致ANR發(fā)生,主要為按鍵和觸摸事件;

日志關(guān)鍵字:InputDispatching Timeout

  • BroadcastTimeout:—— BroadcastReceiver在特定時間內(nèi)未處理完成導致ANR發(fā)生(限制:前臺廣播10s;后臺廣播60s);

日志關(guān)鍵字:Timeout of broadcast BroadcastRecord

  • ServiceTimeout —— Service在特定的時間內(nèi)未處理完成導致ANR發(fā)生。(限制:前臺服務20s;后臺服務200s);

日志關(guān)鍵字:Timeout executing service

  • ContentProviderTimeout —— 內(nèi)容提供者,在10s內(nèi)未處理完成導致ANR發(fā)生;

日志關(guān)鍵字:Timeout publishing content providers

1.3 ANR的發(fā)生原因

經(jīng)過大量ANR案例的分析,總結(jié)出以下三個ANR問題產(chǎn)生的典型場景:

  • 主線程被其他線程鎖(占比57%):調(diào)用了thread的sleep()、wait()等方法,導致的主線程等待超時。

  • 系統(tǒng)資源被占用(占比14%):其他進程系統(tǒng)資源(CPU/RAM/IO)占用率高,導致該進程無法搶占到足夠的系統(tǒng)資源。

  • 主線程耗時工作導致線程卡死(占比9%):例如大量的數(shù)據(jù)庫讀寫,耗時的網(wǎng)絡情況,高強度的硬件計算等。

2、解決ANR問題方法論

2.1 總體思路

  1. 導出ANR日志信息,根據(jù)日志信息,判斷確認發(fā)生ANR的包名類名,進程號,發(fā)生時間,導致ANR原因類型等。

  2. 關(guān)注系統(tǒng)資源信息,包括ANR發(fā)生前后的CPU,內(nèi)存,IO等系統(tǒng)資源的使用情況。

  3. 查看主線程狀態(tài),關(guān)注主線程是否存在耗時、死鎖、等鎖等問題,判斷該ANR是App導致還是系統(tǒng)導致的。

  4. 結(jié)合應用日志,代碼或源碼等,分析ANR問題發(fā)生前,應用是否有異常,其中具體問題具體分析。

2.2 導出ANR日志

ANR問題發(fā)生時,系統(tǒng)會收集ANR相關(guān)的日志信息,CPU使用情況,trace日志也就是各線程執(zhí)行情況等信息,生成一個traces.txt的文件并且放在/data/anr/路徑下。

注意:每一次新的ANR問題的發(fā)生,會把之前的ANR信息覆蓋掉。

我們可以通過adb命令將traces文件導出到本地。

    adb root     
    adb shell ls /data/anr     
    adb pull /data/anr/<filename>
復制代碼

2.3 讀取關(guān)鍵日志信息

1)在log中找到ANR發(fā)生信息: Traces文件中的關(guān)鍵字,例如:

09-24 15:20:20.211 1001 1543 1570 XXXXXXX: ANR in xxxxxx 
09-24 15:20:20.211 1001 1543 1570 XXXXXXX: PID: xxxxx 
09-24 15:20:20.211 1001 1543 1570 XXXXXXX: Reason: xxxxxx
復制代碼

其中:

  • ANR in中,包括導致ANR的包名,類名

  • PID 中,為發(fā)生ANR的進程PID

  • Reason 中,為導致ANR的原因,例如keyDispatchingTimedOut

2)找到CPU Usage信息

09-24 15:20:20.211 1001 1543 1570 XXXXXX: CPUusage from xxx to xxx ago xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx 
09-24 15:20:20.211 1001 1543 1570 XXXXXX: CPUusage from xxx to xxx later xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx
復制代碼

其中

  • ago 表示ANR發(fā)生前的CPU的使用情況

  • later表示ANR發(fā)生后的CPU的使用情況

  • 重點關(guān)注xxx%TOTAL: xxx% user + xxx% kernel + xxx% iowait,可通過這幾項了解到CPU的占用情況。

2.4 具體分析

分析CPU usage以后,如若還是無法找出問題原因,則需要進一步分析trace文件。traces文件中詳細記錄了發(fā)生ANR前后該進程的各個線程的Stack,一般從主線程的stack入手分析,查看分析ANR問題發(fā)生前,應用是否有異常。

其中不同場景下的ANR問題情況不大相同,需要具體情況具體分析,此處就不展開詳細描述。

3、ANR問題難點及破題思路

3.1 ANR難點

用戶在應用內(nèi)的絕大部分操作,比如按鈕點擊,加載資源,頁面跳轉(zhuǎn)等操作,都需要有App的主動反饋,但ANR發(fā)生時,在用戶等待數(shù)秒后,僅會彈出一個“應用無響應”的彈窗給用戶,這會給用戶帶來“應用難用”的感覺,極其影響用戶體驗。

但是,現(xiàn)網(wǎng)中的ANR問題又很難處理,問題包括但不限于:

  1. 平時的測試難以覆蓋,畢竟ANR經(jīng)常出現(xiàn)在老設備、弱網(wǎng)絡環(huán)境的場景下,測試難以做到全場景覆蓋。

  2. 對于現(xiàn)網(wǎng)應用的ANR問題,如果問題非必現(xiàn),則定位難度較高,需要有可以復現(xiàn)問題的實際設備在身邊,才能獲取到具體日志trace等信息。

  3. ANR問題定位復雜,影響因素多,一些新負責定位ANR問題的同學,上手困難,問題解決比較依賴經(jīng)驗。

3.2 ANR處理新方案

除了依賴現(xiàn)有傳統(tǒng)的ANR問題定位經(jīng)驗,配合第三方應用監(jiān)控平臺、進行ANR問題的處理,也是方便快捷的ANR處理手段。

提升用戶體驗迫在眉睫,但ANR問題對用戶體驗影響大, 定位解決ANR問題老大難,針對這個需求痛點,越來愈多的第三方開始研究并對外提供應用性能監(jiān)控工具。

性能管理(App Performance Management,簡稱APM)是華為AppGallery Connect質(zhì)量系列服務中的其中一項,提供分鐘級應用性能監(jiān)控能力,其ANR分析功能,更是解決ANR問題定位與處理的最佳搭檔。使用AGC性能管理服務監(jiān)控應用ANR,能夠為您帶來以下好處:

1.實時監(jiān)控現(xiàn)網(wǎng)應用ANR,現(xiàn)網(wǎng)應用ANR趨勢全掌握。

2.ANR現(xiàn)場信息自動采集和展示,大部分情況無需復現(xiàn),在線定位問題。

3.通過APM頁面,定位思路系統(tǒng)化,快速上手ANR問題定位,及時解決問題。

4、ANR問題解決案例整理

接下來以華為AGC性能管理服務為例,介紹配合AGC性能管理服務,如何快速定位典型的ANR問題。

4.1 案例(一):死鎖導致的ANR問題定位

4.1.1 發(fā)現(xiàn)問題 在華為AGC控制臺的我的項目-質(zhì)量-性能管理頁面,在“ANR分析”頁簽下,發(fā)現(xiàn)排在第一位的“用戶ANR率”高達16.67%,決定優(yōu)先解決該類ANR問題。

image

4.1.2 定位問題 點開TOP排行榜中該類問題卡片,進入了該類“ANR問題詳情”頁面,進一步查看分析該ANR 問題的數(shù)據(jù)報告。

image

在這個“ANR問題詳情”頁面中,分析用戶數(shù)分布餅圖,發(fā)現(xiàn)該類ANR問題在“應用版本2.0”、“手機型號HUAWEI VOG-AL10”、“系統(tǒng)版本10”這三個條件下,ANR影響的用戶數(shù)最多。

image

在報告下方的“發(fā)生記錄”中,找到滿足這三個條件的發(fā)生記錄,點擊“查看詳情”準備針對具體的問題進行分析。

image

(1) 分析系統(tǒng)資源狀態(tài) 首先,通過報告,發(fā)現(xiàn)該問題發(fā)生時,CPU占用是20%、IO占用是0%、未發(fā)生過低內(nèi)存、應用被分配堆是26.50MB、應用已用堆是8.69MB,線程數(shù)是61,從系統(tǒng)資源來看,未出現(xiàn)明顯的異常,如下圖所示:

image

因為ANR問題原因可以分為兩大類,一是系統(tǒng)資源不足導致,二是自身代碼邏輯導致,綜合以上系統(tǒng)資源信息,該ANR問題不是由于系統(tǒng)資源不足導致,那么分析該ANR問題思路轉(zhuǎn)變?yōu)椋涸揂NR問題由自身代碼邏輯導致,接下來,我們順著該思路分析這次的ANR問題。 (2) 查看主線程狀態(tài):發(fā)現(xiàn)ANR代碼片段 自身代碼邏輯導致ANR問題,其主要分析思路是查看主線程堆棧及線程狀態(tài),我們在性能管理頁面上“主線程堆?!表摵炛心軌蛘业絾栴}堆棧,發(fā)現(xiàn)該問題發(fā)生時,主線程處于獲取鎖狀態(tài),到此我們能夠得出結(jié)論:該ANR問題是因為主線程一直在等待鎖資源,而被阻塞,導致了后續(xù)輸入事件未被響應,從而觸發(fā)了應用的“Input dispatching timed out”類型的ANR。

image

查看具體的堆棧信息,我們找到了ANR問題代碼片段,發(fā)現(xiàn)死鎖是發(fā)生在“com.aiops.hiperformance.MainActivity.dispatchActivityDestroyed”調(diào)用中。查看代碼發(fā)現(xiàn),死鎖發(fā)生在“mLock.readLock().lock()”函數(shù)中。

image

通過在代碼中搜索mLock加鎖代碼的調(diào)用,發(fā)現(xiàn)了僅在MainActivity文件中,才會存在“mLock.readLock.lock()”代碼, 由此判斷,異常代碼僅存在于MainActivity中,因此我們縮小了問題代碼范圍。 在正在的代碼編寫過程中,鎖的申請與釋放已經(jīng)成為一種編碼習慣,如果鎖未釋放,可能是在釋放鎖之前,出現(xiàn)了某種我們編碼未考慮的異常,導致鎖未釋放或釋放失敗。 由此分析,我們接下來嘗試使用“找到ANR問題發(fā)生之前,應用是否有異常發(fā)生”的思路,繼續(xù)分析。

我們先找到申請鎖動作開始時間點,由阻塞動作開始時間點往前分析,尋找異常信息。我們切換到“ANR信息”頁簽, 發(fā)現(xiàn)主執(zhí)行隊列首元素在5.5s前已經(jīng)存在,ANR發(fā)生時間是“2020-09-27 09:48:27”, 因此我們可計算出獲取鎖動作大概是在“2020-09-27 09:48:21”發(fā)生。

image

(3) 查看應用日志 接下來,我們把頁簽切到“系統(tǒng)日志”中,我們目前知道鎖獲取動作在“2020-09-27 09:48:21”左右發(fā)生。我們接下來僅需要在日志中,從該時間點往前分析,看是否由相關(guān)異常,是導致該鎖未被釋放的關(guān)鍵因素。

image

我們發(fā)現(xiàn)在“09:48:18.365”時系統(tǒng)拋出了“OutofBoundsException”異常,并且打印了異常堆棧,我們發(fā)現(xiàn),該異常就出現(xiàn)在MainActivity,也就是我們之前的問題代碼范圍中,我們通過該堆棧,找到了異常代碼。

image

發(fā)現(xiàn)在“getShareDataInterceptor”調(diào)用時,拋出了“越界異?!?,導致了“mLock.readLock”未被釋放,由此我們已經(jīng)知道導致該ANR問題的具體原因:異常場景導致鎖資源未被釋放,從而造成了主線程出現(xiàn)死鎖。

4.1.3 解決問題 為了修復了該問題,我們做了以下措施,解決該問題的同時,預防同類問題發(fā)生:

  1. 分析異常具體原因并修改代碼,防止越界異常再次出現(xiàn)。

  2. 捕獲該異常,保護代碼在資源釋放前被異常拋出。

  3. 排查其他代碼,在資源釋放前,加上保護,保證資源及時釋放。

4.2 案例(二):IO資源不足導致ANR問題定位

4.2.1 定位問題 直奔問題核心,直接進入“單次ANR問題” 頁面,去分析問題,強化我們借助性能管理服務定位ANR問題思路。

image

(1)分析系統(tǒng)資源狀態(tài). 首先,通過報告,發(fā)現(xiàn)該問題發(fā)生時,CPU占用是100%、IO占用是84%、未發(fā)生過低內(nèi)存、應用被分配堆是26.50MB、應用已用堆是8.69MB,從系統(tǒng)資源來看,CPU占用和IO占用出現(xiàn)明顯異常,如下圖所示:

由定位大部分ANR問題經(jīng)驗可知,該ANR問題是由于系統(tǒng)資源不足導致,那么分析該ANR問題思路為:找到自身應用程序ANR代碼片段,分析否能夠優(yōu)化代碼,在高IO情況下,不觸發(fā)ANR。

(2)查看主線程狀態(tài):發(fā)現(xiàn)問題原因 我們切換到“主線程堆?!表摵灒^察主線程代碼。

image

通過觀察主線程堆棧,我們發(fā)現(xiàn)了一個存在問題的地方,主線程里面直接在做數(shù)據(jù)庫操作,在系統(tǒng)IO高的情況,此操作必定會導致主線程被阻塞。我們通過堆棧找到對應的代碼。

image

由此我們確認,在代碼中存在訪問SQLite的操作。這時候有經(jīng)驗的開發(fā)者已經(jīng)知道,問題能夠通過優(yōu)化解決,僅需要將該IO操作放在線程中執(zhí)行即可。

(3) 查看應用日志 已經(jīng)在上一環(huán)節(jié)分析出ANR原因,無需此步驟。

4.2.2 解決問題 我們做了以下措施,優(yōu)化了該問題代碼,預防ANR問題發(fā)生。

image

4.3 案例(三):主線程死循環(huán)導致ANR問題定位 4.3.1 定位問題 話不多說,直接到“單次ANR問題”,固化問題定位思路。

image

(1)首先,通過報告,發(fā)現(xiàn)該問題發(fā)生時,CPU占用是25%、IO占用是0%、未發(fā)生過低內(nèi)存、應用被分配堆是18.01MB、應用已用堆是8.08MB,線程數(shù)是43,從系統(tǒng)資源來看,均未出現(xiàn)明顯異常,如下圖所示:

image

由定位大部分ANR問題經(jīng)驗可知,該ANR問題大概率不是由于系統(tǒng)資源不足導致,那么分析該ANR問題思路轉(zhuǎn)變?yōu)椋涸揂NR問題由自身代碼邏輯導致,接下來,我們順著該思路分析這次的ANR問題。

(2)查看主線程狀態(tài):發(fā)現(xiàn)問題原因 自身代碼邏輯導致ANR問題,其主要分析思路是查看主線程堆棧及線程狀態(tài),我們在性能管理頁面上“主線程堆?!表摵炛心軌蛘业絾栴}堆棧。

image

發(fā)現(xiàn)該問題發(fā)生時,發(fā)現(xiàn)主線程堆棧在getActivity中被阻塞,主線程處于“SUSPENDED”狀態(tài)。這時我們通過堆棧,找到問題代碼。

image

通過代碼分析,懷疑主線程在該處出現(xiàn)死循環(huán)。我們知道如果應用程序出現(xiàn)死循環(huán)會導致應用程序的CPU用戶態(tài)時間占用異常升高,我們知道“ANR信息”頁簽中記錄了ANR發(fā)生時的各進程的CPU占用信息,于是我們在頁面上切換到“ANR信息”頁簽。

image

我們在“ANR信息”頁簽中發(fā)現(xiàn),自身應用程序CPU用戶態(tài)的資源占用達到了94%,因此驗證了我們之前的猜想:主線程出現(xiàn)了死循環(huán),導致了ANR問題。

(3)查看應用日志 已經(jīng)在上一環(huán)節(jié)分析出ANR原因,無需此步驟。

4.3.2 解決問題 我們做了以下措施,優(yōu)化了該問題代碼,預防ANR問題發(fā)生。

image

5、案例總結(jié)

以上ANR問題的解決與處理,都是配合華為AppGallery Connect性能管理管理服務完成的,其中的ANR問題分析報告,ANR問題發(fā)生時的問題記錄,都由AGC性能管理服務界面所提供。

通過AGC性能服務里的 ANR分析詳情 可以查看發(fā)生某類ANR問題時的趨勢及分布信息,其中包括按應用版本版本分布,按手機型號分布,按系統(tǒng)版本分布和問題發(fā)生的實時走勢。幫助分析這一類ANR問題對用戶的影響趨勢,以及問題復現(xiàn)條件。

另外開發(fā)者可以通過詳細的問題發(fā)生記錄,獲取到該問題發(fā)生時更加詳細的設備信息,系統(tǒng)信息,應用信息和堆棧日志,幫助開發(fā)者快速定位該問題。

6、相關(guān)鏈接

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

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

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