ANR監測機制包含三種:java
Service ANR,前臺進程中Service生命週期不能超過20秒,後臺進程中Service的生命週期不能超過200秒。 在啓動Service時,拋出定時消息SERVICE_TIMEOUT_MSG或SERVICE_BACKGOURND_TIMEOUT_MSG,若是定時消息響應了,則說明發生了ANRandroid
Broadcast ANR,前臺的「串行廣播消息」必須在10秒內處理完畢,後臺的「串行廣播消息」必須在60秒處理完畢, 每派發串行廣播消息到一個接收器時,都會拋出一個定時消息BROADCAST_TIMEOUT_MSG,若是定時消息響應,則判斷是否廣播消息處理超時,超時就說明發生了ANRgit
Input ANR,輸入事件必須在5秒內處理完畢。在派發一個輸入事件時,會判斷當前輸入事件是否須要等待,若是須要等待,則判斷是否等待已經超時,超時就說明發生了ANRgithub
ANR監測機制其實是對應用程序主線程的要求,要求主線成必須在限定的時間內,完成對幾種操做的響應;不然,就能夠認爲應用程序主線程失去響應能力。數組
從ANR的三種監測機制中,咱們看到不一樣超時機制的設計:緩存
Service和Broadcast都是由AMS調度,利用Handler和Looper,設計了一個TIMEOUT消息交由AMS線程來處理,整個超時機制的實現都是在Java層; InputEvent由InputDispatcher調度,待處理的輸入事件都會進入隊列中等待,設計了一個等待超時的判斷,超時機制的實如今Native層。app
不管哪一種類型的ANR發生之後,最終都會調用 AMS.appNotResponding() 方法,所謂「異曲同工」。這個方法的職能就是向用戶或開發者報告ANR發生了。 最終的表現形式是:彈出一個對話框,告訴用戶當前某個程序無響應;輸入一大堆與ANR相關的日誌,便於開發者解決問題。async
最終形式咱們見過不少,但輸出日誌的原理是什麼,未必全部人都瞭解,下面咱們就來認識一下是如何輸出ANR日誌的。ide
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 HashMap<