ANR監測機制包含三種:
-
Service ANR,前台進程中Service生命周期不能超過20秒,后台進程中Service的生命周期不能超過200秒。 在啟動Service時,拋出定時消息SERVICE_TIMEOUT_MSG或SERVICE_BACKGOURND_TIMEOUT_MSG,如果定時消息響應了,則說明發生了ANR
-
Broadcast ANR,前台的“串行廣播消息”必須在10秒內處理完畢,后台的“串行廣播消息”必須在60秒處理完畢, 每派發串行廣播消息到一個接收器時,都會拋出一個定時消息BROADCAST_TIMEOUT_MSG,如果定時消息響應,則判斷是否廣播消息處理超時,超時就說明發生了ANR
-
Input ANR,輸入事件必須在5秒內處理完畢。在派發一個輸入事件時,會判斷當前輸入事件是否需要等待,如果需要等待,則判斷是否等待已經超時,超時就說明發生了ANR
ANR監測機制實際上是對應用程序主線程的要求,要求主線成必須在限定的時間內,完成對幾種操作的響應;否則,就可以認為應用程序主線程失去響應能力。
從ANR的三種監測機制中,我們看到不同超時機制的設計:
Service和Broadcast都是由AMS調度,利用Handler和Looper,設計了一個TIMEOUT消息交由AMS線程來處理,整個超時機制的實現都是在Java層; InputEvent由InputDispatcher調度,待處理的輸入事件都會進入隊列中等待,設計了一個等待超時的判斷,超時機制的實現在Native層。
2.2 ANR的報告機制
無論哪種類型的ANR發生以后,最終都會調用 AMS.appNotResponding() 方法,所謂“殊途同歸”。這個方法的職能就是向用戶或開發者報告ANR發生了。 最終的表現形式是:彈出一個對話框,告訴用戶當前某個程序無響應;輸入一大堆與ANR相關的日志,便於開發者解決問題。
最終形式我們見過很多,但輸出日志的原理是什么,未必所有人都了解,下面我們就來認識一下是如何輸出ANR日志的。
final void appNotResponding(ProcessRecord app, ActivityRecord activity, ActivityRecord parent, boolean aboveSystem, final String annotation) { // app: 當前發生ANR的進程 // activity: 發生ANR的界面 // parent: 發生ANR的界面的上一級界面 // aboveSystem: // annotation: 發生ANR的原因 ... // 1. 更新CPU使用信息。ANR的第一次CPU信息采樣 updateCpuStatsNow(); ... // 2. 填充firstPids和lastPids數組。從最近運行進程(Last Recently Used)中挑選: // firstPids用於保存ANR進程及其父進程,system_server進程和persistent的進程(譬如Phone進程) // lastPids用於保存除firstPids外的其他進程 firstPids.add(app.pid); int parentPid = app.pid; if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid; if (parentPid != app.pid) firstPids.add(parentPid); if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID); for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); if (r != null && r.thread != null) { int pid = r.pid; if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) { if (r.persistent) { firstPids.add(pid); } else { lastPids.put(pid, Boolean.TRUE); } } } } ... // 3. 打印調用棧 File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, NATIVE_STACKS_OF_INTEREST); ... // 4. 更新CPU使用信息。ANR的第二次CPU使用信息采樣 updateCpuStatsNow(); ... // 5. 顯示ANR對話框 Message msg = Message.obtain(); HashMap<String, Object> map = new