資安

一文教你輕鬆搞定ANR異常捕獲與分析方法

1. ANR 產生原理

關於 ANR 的觸發原因,Android 官方開發者文檔中 “What Triggers ANR?” 有介紹,如下:

Generally, the system displays an ANR if an application cannot respond to user input. For example, if an application blocks on some I/O operation (frequently a network access) on the UI thread so the system can't process incoming user input events. Or perhaps the app spends too much time building an elaborate in-memory structure or computing the next move in a game on the UI thread. It's always important to make sure these computations are efficient, but even the most efficient code still takes time to run......

即,常見的有如下兩種情況會產生 ANR:

輸入事件(例如按鍵或屏幕輕觸事件等)在 5 秒內沒有響應;

BroadcastReceiver 在 10 秒內沒有執行完成。

結合 Android 相關源碼分析可知,輸入事件的 ANR 檢測是基於輸入事件本身驅動的,系統要求在 App進程中處理完成每個輸入事件後,通知系統進程事件處理完畢,以此判斷 App是否無響應。

要產生 ANR,至少得有兩個輸入事件,場景如下:

第一個輸入事件產生,系統將其發送給用戶當前操作的 App;

系統收到第二個事件,發現當前距第一個輸入事件發送時間超過 0.5s 仍未處理完畢,則設置一個定時器,5s 後觸發;

5s 之後,若系統發現第一個輸入事件仍然沒有迴應時,則觸發 ANR,激活 App 中的 Signal Cather 線程生成 traces.txt,然後彈出 ANR 對話框,告知用戶 App 無響應。

也就是說,要產生 ANR,第一個輸入事件必需在 5.5s 以上沒有被處理完成並反饋回系統;並且要有第二個輸入事件產生。如果沒有第二個輸入事件,即便第一個輸入事件執行了 60s 或更長時間,也是不會產生 ANR 的。

2. ANR 日誌生成原理

系統的 system_server 進程在檢測到 App 出現 ANR 後,會向出現 ANR 的進程發送 SIGQUIT (signal 3) 信號。正常情況下,系統的 libart.so 會收到該信號,並調用 Java 虛擬機的 dump 方法生成 traces。

以友盟+的 U-APM 應用性能監控平臺為例,集成SDK 後,SDK 會攔截 SIGQUIT。在出現 ANR 時,libcrashsdk.so 會優先收到信號,並生成 traces 和 ANR 日誌。在 SDK 處理完信號後,會將信號繼續傳遞給系統的 libart.so,讓系統生成 ANR traces.txt。

如下圖,紅色線為 U-APM SDK 處理 ANR 信號和生成 ANR 日誌的流程,紫色線為系統生成 ANR traces.txt 的流程。

圖片1.png

U-APM SDK ANR 捕獲原理

其中,SDK 生成 traces 時,使用的是 libart.so 中的 dump 方法,生成的內容與系統原生的基本一致。並且,U-APM SDK 在調用 dump 方法時進行了優化,dump 速度較系統生成原生 traces 的速度顯著提升,有效地避免了可能因生成 traces 時間過長,而被 system_server 使用 SIGKILL (signal 9) 再次強殺。

在獲取所有線程的 traces 信息後,生成完整的 ANR 日誌,還會提供獲取觸發 ANR 的原因、手機中 TOP 進程 CPU 使用率、ANR 進程中 TOP 線程 CPU 使用率、CPU 各核心處理時間分佈情況、磁盤 IO 操作等待時長等重要信息。

目前,SDK 生成的 ANR 日誌信息,基本包含系統生成的 ANR 日誌的所有內容,甚至還包含一些系統日誌中沒有的內容,以及 App增加的自身的業務相關信息,對分析、定位和解決 ANR 問題,提供了更加強有力的支撐。

3、日誌分析

如開發者接入了SDK,ANR 日誌將自動啟用,出現 ANR 時,會先於系統生成 ANR 日誌。日誌的主要內容介紹如下:

1). ANR 日誌結構

使用日誌分析插件,我們可以清晰地看到 生成的 ANR 日誌包含的內容以及重點信息,如下:

圖片2.png

ANR 日誌結構

除了生成的日誌以 Section 分為多個部分,其中,包含重要信息的 Section 會使用紅色標出,特別重要的信息還會加粗。另外,每個 Section 有快捷鍵可直接跳轉到相應位置。

2). ANR 概要

概要信息如下:

圖片3.png

ANR 概要信息

這部分內容主要從系統獲取,其包含了 ANR 的進程名、ANR 產生的時間、ANR 的原因、ANR 前後幾秒內系統 TOP 進程的 CPU 使用率等。其中,通過 ANR 原因可以得知是輸入事件處理超時,還是 BroadcastReceiver 等其它消息處理時間過長;通過 CPU 使用率則可以得知是哪個進程佔用 CPU 資源過多。

3). 系統資源使用情況

可記錄在出現 ANR 前一段時間內,CPU 平均使用率、CPU 各核心使用率及其耗時分佈,ANR 進程中 TOP 線程的執行耗時及比例、出現頁錯誤的次數,磁盤 IO 操作等待時長及次數等內容。如下:

圖片4.png


系統資源使用情況

當 IO 繁忙導致 ANR 時,io wait time 和 CPU 時間分佈中的 iowait 比例會比較突出;通過 CPU 時間分佈中的 user 和 system 佔比,則可以知道是用戶態代碼執行耗時過長,還是 Linux 內核的系統調用耗時太久。

4). ANR traces

traces 信息是 ANR 日誌中最關鍵的內容。如U-APM生成的 traces 信息包含了出現 ANR 時主線程的 native 調用棧和所有線程的 java 調用棧。通常死鎖問題通過調用棧中的信息可以很容易發現。

圖片5.png

ANR traces

U-APM SDK 的 traces 由 fork 的子進程生成,不會因 Java 虛擬機出現 BUG 導致生成 traces 時又出現 native 崩潰,也不會因 dump 時卡死阻塞整個 ANR 日誌的生成。

5). Logcat

以U-APM為例,會在 ANR 時抓取 Android logcat。APM SDK 能繞開部分 ROM 增加的權限控制,拿到當前 App ANR 前相關的 log 信息。當前進程以及當前錯誤線程輸出的 log 會被重點標出,error 和 warning 也會以顯目的顏色標出。

圖片6.png

logcat

6). 內存等其它信息

通過ANR日誌可以分析出一系列的內存信息,如:

系統的 RAM 總內存、剩餘可用內存;

當前進程佔用的虛擬內存、物理內存;

Java 佔用的總內存和可用內存;

Native 佔用的內存和可用內存等。

另外,ANR 日誌同 Java 和 Native 崩潰日誌一樣,支持業務自定義日誌內容擴展,如:

崩潰前增加簡短的自定義頭信息;

崩潰前註冊外部文件,崩潰時其內容將被帶入日誌;

崩潰前緩存業務相關的最近若干條操作或信息;

崩潰時通過回調返回業務最新內容等。

4、ANR監控工具

選擇一款有超強捕獲能力的專業產品,對於開發者定位和修復穩定性問題至關重要。友盟+U-APM SDK集成了UC 內核團隊強大的技術及友盟+超強的錯誤捕獲能力,通過數萬次捕獲實踐中積累了豐富經驗,在產品、性能和研發能力上都極大保障了開發者定位和修復穩定性問題的超強效率。

Leave a Reply

Your email address will not be published. Required fields are marked *