Android系統中,有硬件WatchDog用於定時檢測關鍵硬件是否正常工做,相似地,在framework層有一個軟件WatchDog用於按期檢測關鍵系統服務是否發生死鎖事件。android
watchdog的源碼很簡單,主要有兩個功能oop
1監控system_server中幾個關鍵的鎖,原理就是在android_fg線程中嘗試加鎖post
2監控幾個經常使用線程的執行時間,原理就是在這幾個線程中執行任務ui
在SystemServer.startOtherServices()方法進行初始化this
system_server進程啓動的過程當中初始化WatchDog,主要進行三個動做:lua
1.建立Watchdog對象spa
public class Watchdog extends Thread { //全部的HandlerChecker對象組成的列表,HandlerChecker對象類型 final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>(); ... private Watchdog() { super("watchdog"); //將前臺線程加入隊列 mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread", DEFAULT_TIMEOUT); mHandlerCheckers.add(mMonitorChecker); //將主線程加入隊列 mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()), "main thread", DEFAULT_TIMEOUT)); //將ui線程加入隊列 mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread", DEFAULT_TIMEOUT)); //將i/o線程加入隊列 mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", DEFAULT_TIMEOUT)); //將display線程加入隊列 mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(), "display thread", DEFAULT_TIMEOUT)); addMonitor(new BinderThreadMonitor()); } }
Watchdog繼承於Thread,建立的線程名爲」watchdog」。mHandlerCheckers隊列包括、 主線程,fg, ui, io, display線程的HandlerChecker對象。線程
2.HandlerChecker對象debug
public final class HandlerChecker implements Runnable { private final Handler mHandler; //Handler對象 private final String mName; //線程描述名 private final long mWaitMax; //最長等待時間 //記錄着監控的服務 private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>(); private boolean mCompleted; //開始檢查時先設置成false private Monitor mCurrentMonitor; private long mStartTime; //開始準備檢查的時間點 HandlerChecker(Handler handler, String name, long waitMaxMillis) { mHandler = handler; mName = name; mWaitMax = waitMaxMillis; mCompleted = true; } }
HandlerChecker繼承自Runnable對象,裏面維護着監控服務Monitor對象列表,使用Watchdog.addMonitor方法將服務監聽者加入列表調試
addMonitor(new BinderThreadMonitor());
這裏監控Binder線程, 將monitor添加到HandlerChecker的成員變量mMonitors
列表中。將BinderThreadMonitor對象加入該線程。
private static final class BinderThreadMonitor implements Watchdog.Monitor { public void monitor() { Binder.blockUntilThreadAvailable(); } }
blockUntilThreadAvailable最終調用的是IPCThreadState,監控是否有可用的binder進程。
3.Watchdog start
當調用Watchdog.getInstance().start()時,則進入線程「watchdog」的run()方法, 該方法分紅兩部分:
4.Watchdog run
public void run() { boolean waitedHalf = false; while (true) { final ArrayList<HandlerChecker> blockedCheckers; final String subject; final boolean allowRestart; int debuggerWasConnected = 0; synchronized (this) { long timeout = CHECK_INTERVAL; //CHECK_INTERVAL=30s for (int i=0; i<mHandlerCheckers.size(); i++) { HandlerChecker hc = mHandlerCheckers.get(i); //執行全部的Checker的監控方法, 每一個Checker記錄當前的mStartTime[見小節3.2] hc.scheduleCheckLocked(); } if (debuggerWasConnected > 0) { debuggerWasConnected--; } long start = SystemClock.uptimeMillis(); //經過循環,保證執行30s纔會繼續往下執行 while (timeout > 0) { if (Debug.isDebuggerConnected()) { debuggerWasConnected = 2; } try { wait(timeout); //觸發中斷,直接捕獲異常,繼續等待. } catch (InterruptedException e) { Log.wtf(TAG, e); } if (Debug.isDebuggerConnected()) { debuggerWasConnected = 2; } timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); } //評估Checker狀態【見小節3.3】 final int waitState = evaluateCheckerCompletionLocked(); if (waitState == COMPLETED) { waitedHalf = false; continue; } else if (waitState == WAITING) { continue; } else if (waitState == WAITED_HALF) { if (!waitedHalf) { //首次進入等待時間過半的狀態 ArrayList<Integer> pids = new ArrayList<Integer>(); pids.add(Process.myPid()); //輸出system_server和3個native進程的traces【見小節4.2】 ActivityManagerService.dumpStackTraces(true, pids, null, null, NATIVE_STACKS_OF_INTEREST); waitedHalf = true; } continue; } ... //進入這裏,意味着Watchdog已超時【見小節4.1】 } ... } } public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] { "/system/bin/mediaserver", "/system/bin/sdcard", "/system/bin/surfaceflinger" };
該方法主要功能:
由此,可見當觸發一次Watchdog, 則必然會調用兩次AMS.dumpStackTraces, 也就是說system_server和3個Native進程的traces 的traces信息會輸出兩遍,且時間間隔超過30s.
5.scheduleCheckLocked
public final class HandlerChecker implements Runnable { ... public void scheduleCheckLocked() { if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) { mCompleted = true; //當目標looper正在輪詢狀態則返回。 return; } if (!mCompleted) { return; //有一個check正在處理中,則無需重複發送 } mCompleted = false; mCurrentMonitor = null; // 記錄當下的時間 mStartTime = SystemClock.uptimeMillis(); //發送消息,插入消息隊列最開頭, 見下方的run()方法 mHandler.postAtFrontOfQueue(this); } public void run() { final int size = mMonitors.size(); for (int i = 0 ; i < size ; i++) { synchronized (Watchdog.this) { mCurrentMonitor = mMonitors.get(i); } //回調具體服務的monitor方法 mCurrentMonitor.monitor(); } synchronized (Watchdog.this) { mCompleted = true; mCurrentMonitor = null; } } }
該方法主要功能:
向Watchdog的監控線程的Looper池的最頭部執行該HandlerChecker.run()方法, 在該方法中調用monitor(),執行完成後會設置mCompleted = true.
那麼當handler消息池處理當前的消息, 致使遲遲沒有機會執行monitor()方法, 則會觸發watchdog.
其中postAtFrontOfQueue(this),該方法輸入參數爲Runnable對象,根據消息機制, 最終會回調HandlerChecker中的run方法,該方法會循環遍歷全部的Monitor接口,具體的服務實現該接口的monitor()方法。
可能的問題,若是有其餘消息不斷地調用postAtFrontOfQueue()也可能致使watchdog沒有機會執行;或者是每一個monitor消耗一些時間,累加起來超過1分鐘形成的watchdog. 這些都是很是規的Watchdog.
Watchdog處理流程
public void run() { while (true) { synchronized (this) { ... //獲取被阻塞的checkers 【見小節4.1.1】 blockedCheckers = getBlockedCheckersLocked(); // 獲取描述信息 【見小節4.1.2】 subject = describeCheckersLocked(blockedCheckers); allowRestart = mAllowRestart; } EventLog.writeEvent(EventLogTags.WATCHDOG, subject); ArrayList<Integer> pids = new ArrayList<Integer>(); pids.add(Process.myPid()); if (mPhonePid > 0) pids.add(mPhonePid); //第二次以追加的方式,輸出system_server和3個native進程的棧信息【見小節4.2】 final File stack = ActivityManagerService.dumpStackTraces( !waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST); //系統已被阻塞1分鐘,也不在意多等待2s,來確保stack trace信息輸出 SystemClock.sleep(2000); if (RECORD_KERNEL_THREADS) { //輸出kernel棧信息【見小節4.3】 dumpKernelStackTraces(); } //觸發kernel來dump全部阻塞線程【見小節4.4】 doSysRq('l'); //輸出dropbox信息【見小節4.5】 Thread dropboxThread = new Thread("watchdogWriteToDropbox") { public void run() { mActivity.addErrorToDropBox( "watchdog", null, "system_server", null, null, subject, null, stack, null); } }; dropboxThread.start(); try { dropboxThread.join(2000); //等待dropbox線程工做2s } catch (InterruptedException ignored) { } IActivityController controller; synchronized (this) { controller = mController; } if (controller != null) { //將阻塞狀態報告給activity controller, try { Binder.setDumpDisabled("Service dumps disabled due to hung system process."); //返回值爲1表示繼續等待,-1表示殺死系統 int res = controller.systemNotResponding(subject); if (res >= 0) { waitedHalf = false; continue; //設置ActivityController的某些狀況下,可讓發生Watchdog時繼續等待 } } catch (RemoteException e) { } } //當debugger沒有attach時,才殺死進程 if (Debug.isDebuggerConnected()) { debuggerWasConnected = 2; } if (debuggerWasConnected >= 2) { Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } else if (debuggerWasConnected > 0) { Slog.w(TAG, "Debugger was connected: Watchdog is *not* killing the system process"); } else if (!allowRestart) { Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process"); } else { Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject); //遍歷輸出阻塞線程的棧信息 for (int i=0; i<blockedCheckers.size(); i++) { Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:"); StackTraceElement[] stackTrace = blockedCheckers.get(i).getThread().getStackTrace(); for (StackTraceElement element: stackTrace) { Slog.w(TAG, " at " + element); } } Slog.w(TAG, "*** GOODBYE!"); //殺死進程system_server【見小節4.6】 Process.killProcess(Process.myPid()); System.exit(10); } waitedHalf = false; } }
Watchdog檢測到異常的信息收集工做:
收集完信息後便會殺死system_server進程。此處allowRestart默認值爲true, 當執行am hang
操做則設置不容許重啓(allowRestart =false), 則不會殺死system_server進程.
將全部執行時間超過1分鐘的handler線程或者monitor都記錄下來.
Blocked in handler
,意味着相應的線程處理當前消息時間超過1分鐘;Blocked in monitor
,意味着相應的線程處理當前消息時間超過1分鐘,或者monitor遲遲拿不到鎖;對於觸發watchdog時,生成的dropbox文件的tag是system_server_watchdog,內容是traces以及相應的blocked信息。
當殺死system_server進程,從而致使zygote進程自殺,進而觸發init執行重啓Zygote進程,這便出現了手機framework重啓的現象。
總結
Watchdog是一個運行在system_server進程的名爲」watchdog」的線程::
mHandlerCheckers
記錄全部的HandlerChecker對象的列表,包括foreground, main, ui, i/o, display線程的handler;mHandlerChecker.mMonitors
記錄全部Watchdog目前正在監控Monitor,全部的這些monitors都運行在foreground線程。Watchdog監控
:
如下狀況,即便觸發了Watchdog,也不會殺掉system_server進程:
對於Looper Checker而言,會判斷線程的消息隊列是否處於空閒狀態。 若是被監測的消息隊列一直閒不下來,則說明可能已經阻塞等待了很長時間
對於Monitor Checker而言,會調用實現類的monitor方法,譬如上文中提到的AMS.monitor()方法, 方法實現通常很簡單,就是獲取當前類的對象鎖,
若是當前對象鎖已經被持有,則monitor()會一直處於wait狀態,直到超時,這種狀況下,極可能是線程發生了死鎖
Watchdog監控的線程有:
(默認地DEFAULT_TIMEOUT=60s
,調試時才爲10s方便找出潛在的ANR問題)
目前watchdog會監控system_server進程中的以上8個線程:
可以被Watchdog監控的系統服務都實現了Watchdog.Monitor接口,並實現其中的monitor()方法。運行在android.fg
線程, 系統中實現該接口類主要有:
watchdog在check過程當中出現阻塞1分鐘的狀況,則會輸出: