ANR簡介
ANR,是“Application Not Responding”的縮寫,即“應用程式無響應”。在Android中,ActivityManagerService(簡稱AMS)和WindowManagerService(簡稱WMS)會監測應用程式的響應時間,如果應用程式主執行緒(即UI執行緒)在超時時間內對輸入事件沒有處理完畢,或者對特定操作沒有執行完畢,就會出現ANR。對於輸入事件沒有處理完畢產生的ANR,Android會顯示一個對話方塊,提示使用者當前應用程式沒有響應,使用者可以選擇繼續等待或者關閉這個應用程式(也就是殺掉這個應用程式的程式)。
ANR的產生需要同時滿足三個條件
主執行緒:只有應用程式程式的主執行緒響應超時才會產生ANR;
超時時間:產生ANR的上下文不同,超時時間也會不同,但只要在這個時間上限內沒有響應就會ANR
輸入事件/特定操作:輸入事件是指按鍵、觸屏等裝置輸入事件,特定操作是指BroadcastReceiver和Service的生命週期中的各個函式,產生ANR的上下文不同,導致ANR的原因也會不同;
針對這三個條件,有以下三種情況會觸發ANR:
1、主執行緒對輸入事件在5秒內沒有處理完畢 Android的事件系統從2.3開始做了完全不同的實現,原先2.2中是在Java層實現的,但在2.3中整體轉移到了C++層,本書基於2.3以後的版本進行說明。我們先簡單瞭解一下產生這種ANR的整個流程。 當應用程式的Window處於Active狀態並且能夠接收輸入事件(例如按鍵事件、觸控事件等)時,系統底層上報的事件就會被InputDispatcher分發給這個應用程式,應用程式的主執行緒通過InputChannel讀取輸入事件並交給介面檢視處理,介面檢視是一個樹狀結構,DecorView是檢視樹的根,事件從樹根開始一層一層向端點(例如一個Button)傳遞。我們通常會註冊一個監聽器來接收並處理事件,或者建立自定義的檢視控制元件來處理事件。 InputDispatcher執行在系統程式(程式名為system_server)的一個單獨的執行緒中,應用程式的主執行緒在處理事件的過程中,InputDispatcher會不斷的檢測處理過程是否超時,一旦超時,會通過一系列的回撥通知WMS的notifyANR函式,最終會呼叫到AMS中mHandler物件裡的SHOW_NOT_RESPONDING_MSG這個case,此時介面上就顯示系統提示對話方塊了,同時使用logcat命令檢視log(日誌資訊)也可以看到關於ANR的資訊。一下子出現了好幾個重要的名詞,要深入瞭解這種情況的ANR,需要熟悉Android的事件機制,這裡只需要記住他們的功能:
Window:具體指的是PhoneWindow物件,表示一個能夠顯示的視窗,它能夠接收系統分發的各種輸入事件;
InputDispatcher:將系統上報的輸入事件分發給當前活動的視窗; InputChannel:InputDispatcher和應用程式分別執行在兩個不同的程式中,InputDispatcher就是通過InputChannel將事件物件傳遞給應用程式的。
注意:產生這種ANR的前提是要有輸入事件,如果使用者沒有觸發任何輸入事件,即便是主執行緒阻塞了,也不會產生ANR,因為InputDispatcher沒有分發事件給應用程式,當然也不會檢測處理超時和報告ANR了。
2、主執行緒在執行BroadcastReceiver的onReceive函式時10秒內沒有執行完畢 BroadcastReceiver(簡稱BR)的onReceive函式執行在主執行緒中,當這個函式超過10秒鐘沒有返回就會觸發ANR。不過對這種情況的ANR系統不會顯示對話方塊提示,僅是輸出log而已。
3、主執行緒在執行Service的各個生命週期函式時20秒內沒有執行完畢 Service的各個生命週期函式也執行在主執行緒中,當這些函式超過20秒鐘沒有返回就會觸發ANR。同樣對這種情況的ANR系統也不會顯示對話方塊提示,僅是輸出log。
三種ANR中只有第1種會顯示系統提示對話方塊,因為使用者正在做介面互動操作,如果長時間沒有任何響應,會讓使用者懷疑裝置當機了,大多數人此時會開始亂按,甚至拔出電池重啟,給使用者的體驗肯定是非常糟糕的。
三種ANR發生時都會在log中輸出錯誤資訊,你會發現各個應用程式和系統程式的函式堆疊資訊都輸出到了一個/data/anr/traces.txt的檔案中,這個檔案是分析ANR原因的關鍵檔案,同時在日誌中還會看到當時的CPU使用率,這也是重要資訊,可以利用它們分析ANR問題。
這三種ANR不是孤立的,有可能會相互影響。例如一個應用程式程式中同時有一個正在顯示的Activity和一個正在處理訊息的BroadcastReceiver,它們都執行在這個程式的主執行緒中。如果BR的onReceive函式沒有返回,此時使用者點選螢幕,而onReceive超過5秒仍然沒有返回,主執行緒無法處理使用者輸入事件,就會引起第1種ANR。如果繼續超過10秒沒有返回,又會引起第2種ANR。
侵刪·原文連結