Watchdog機制概述

1. Watchdog初始

Watchdog的中文的「看門狗」,有保護的意思。最先引入Watchdog是在單片機系統中,因爲單片機的工做環境容易受到外界磁場的干擾,致使程序「跑飛」,形成整個系統沒法正常工做,所以,引入了一個「看門狗」,對單片機的運行狀態進行實時監測,針對運行故障作一些保護處理,譬如讓系統重啓。這種Watchdog屬於硬件層面,必須有硬件電路的支持。java

Linux也引入了Watchdog,在Linux內核下,當Watchdog啓動後,便設定了一個定時器,若是在超時時間內沒有對/dev/Watchdog進行寫操做,則會致使系統重啓。經過定時器實現的Watchdog屬於軟件層面。android

Android設計了一個軟件層面Watchdog,用於保護一些重要的系統服務,當出現故障時,一般會讓Android系統重啓。因爲這種機制的存在,就常常會出現一些system_server進程被Watchdog殺掉而發生手機重啓的問題。ide

本文指望回答如下問題:函數

  1. Watchdog是怎麼工做的?這涉及到Watchdog的工做機制。
  2. 遇到Watchdog的問題該怎麼辦?這涉及到分析Watchdog問題的慣用方法。

2. Watchdog機制剖析

咱們以frameworks/base/services/core/java/com/android/server/Watchdog.java爲藍本,分析Watchdog的實現邏輯。爲了描述方便,ActivityManagerService, PackageManagerService, WindowManagerService會分別簡稱爲AMS, PKMS, WMS。oop

2.1 Watchdog的初始化

Android的Watchdog是一個單例線程,在System Server時就會初始化Watchdog。Watchdog在初始化時,會構建不少HandlerChecker,大體能夠分爲兩類:post

  • Monitor Checker,用於檢查是Monitor對象可能發生的死鎖, AMS, PKMS, WMS等核心的系統服務都是Monitor對象。ui

  • Looper Checker,用於檢查線程的消息隊列是否長時間處於工做狀態。Watchdog自身的消息隊列,Ui, Io, Display這些全局的消息隊列都是被檢查的對象。此外,一些重要的線程的消息隊列,也會加入到Looper Checker中,譬如AMS, PKMS,這些是在對應的對象初始化時加入的。this

private 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)); mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread", DEFAULT_TIMEOUT)); mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", DEFAULT_TIMEOUT)); mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(), "display thread", DEFAULT_TIMEOUT)); ... }

兩類HandlerChecker的側重點不一樣,Monitor Checker預警咱們不能長時間持有核心繫統服務的對象鎖,不然會阻塞不少函數的運行; Looper Checker預警咱們不能長時間的霸佔消息隊列,不然其餘消息將得不處處理。這兩類都會致使系統卡住(System Not Responding)。google

2.2 添加Watchdog監測對象

Watchdog初始化之後,就能夠做爲system_server進程中的一個單獨的線程運行了。但這個時候,還不能觸發Watchdog的運行,由於AMS, PKMS等系統服務尚未加入到Watchdog的監測集。 所謂監測集,就是須要Watchdog關注的對象,Android中有成千上萬的消息隊列在同時運行,然而,Watchdog畢竟是系統層面的東西,它只會關注一些核心的系統服務。lua

Watchdog提供兩個方法,分別用於添加Monitor Checker對象和Looper Checker對象:

public void addMonitor(Monitor monitor) { // 將monitor對象添加到Monitor Checker中, // 在Watchdog初始化時,能夠看到Monitor Checker自己也是一個HandlerChecker對象 mMonitors.add(monitor); } public void addThread(Handler thread, long timeoutMillis) { synchronized (this) { if (isAlive()) { throw new RuntimeException("Threads can't be added once the Watchdog is running"); } final String name = thread.getLooper().getThread().getName(); // 爲Handler構建一個HandlerChecker對象,其實就是**Looper Checker** mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis)); } }

被Watchdog監測的對象,都須要將本身添加到Watchdog的監測集中。如下是AMS的類定義和構造器的代碼片斷:

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { public ActivityManagerService(Context systemContext) { ... Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); } public void monitor() { synchronized (this) { } } }

AMS實現了Watchdog.Monitor接口,這個接口只有一個方法,就是monitor(),它的做用後文會再解釋。這裏能夠看到在AMS的構造器中,將本身添加到Monitor Checker對象中,而後將本身的handler添加到Looper Checker對象中。 其餘重要的系統服務添加到Watchdog的代碼邏輯都與AMS差很少。

整個Android系統中,被monitor的對象並很少,十個手指頭就能數出來Watchdog.Monitor的實現類的個數。

2.3 Watchdog的監測機制

Watchdog自己是一個線程,它的run()方法實現以下:

@Override public void run() { boolean waitedHalf = false; while (true) { ... synchronized (this) { ... // 1. 調度全部的HandlerChecker for (int i=0; i<mHandlerCheckers.size(); i++) { HandlerChecker hc = mHandlerCheckers.get(i); hc.scheduleCheckLocked(); } ... // 2. 開始按期檢查 long start = SystemClock.uptimeMillis(); while (timeout > 0) { ... try { wait(timeout); } catch (InterruptedException e) { Log.wtf(TAG, e); } ... timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); } // 3. 檢查HandlerChecker的完成狀態 final int waitState = evaluateCheckerCompletionLocked(); if (waitState == COMPLETED) { ... continue; } else if (waitState == WAITING) { ... continue; } else if (waitState == WAITED_HALF) { ... continue; } // 4. 存在超時的HandlerChecker blockedCheckers = getBlockedCheckersLocked(); subject = describeCheckersLocked(blockedCheckers); allowRestart = mAllowRestart; } ... // 5. 保存日誌,判斷是否須要殺掉系統進程 Slog.w(TAG, "*** GOODBYE!"); Process.killProcess(Process.myPid()); System.exit(10); } // end of while (true) }

以上代碼片斷主要的運行邏輯以下:

  1. Watchdog運行後,便開始無限循環,依次調用每個HandlerChecker的scheduleCheckLocked()方法
  2. 調度完HandlerChecker以後,便開始按期檢查是否超時,每一次檢查的間隔時間由CHECK_INTERVAL常量設定,爲30秒
  3. 每一次檢查都會調用evaluateCheckerCompletionLocked()方法來評估一下HandlerChecker的完成狀態:
    • COMPLETED表示已經完成
    • WAITING和WAITED_HALF表示還在等待,但未超時
    • OVERDUE表示已經超時。默認狀況下,timeout是1分鐘,但監測對象能夠經過傳參自行設定,譬如PKMS的Handler Checker的超時是10分鐘
  4. 若是超時時間到了,還有HandlerChecker處於未完成的狀態(OVERDUE),則經過getBlockedCheckersLocked()方法,獲取阻塞的HandlerChecker,生成一些描述信息
  5. 保存日誌,包括一些運行時的堆棧信息,這些日誌是咱們解決Watchdog問題的重要依據。若是判斷須要殺掉system_server進程,則給當前進程(system_server)發送signal 9

只要Watchdog沒有發現超時的任務,HandlerChecker就會被不停的調度,那HandlerChecker具體作一些什麼檢查呢? 直接上代碼:

public final class HandlerChecker implements Runnable { public void scheduleCheckLocked() { // Looper Checker中是不包含monitor對象的,判斷消息隊列是否處於空閒 if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) { mCompleted = true; return; } ... // 將Monitor Checker的對象置於消息隊列以前,優先運行 mHandler.postAtFrontOfQueue(this); } @Override public void run() { // 依次調用Monitor對象的monitor()方法 for (int i = 0 ; i < size ; i++) { synchronized (Watchdog.this) { mCurrentMonitor = mMonitors.get(i); } mCurrentMonitor.monitor(); } ... } }
  • 對於Looper Checker而言,會判斷線程的消息隊列是否處於空閒狀態。 若是被監測的消息隊列一直閒不下來,則說明可能已經阻塞等待了很長時間

  • 對於Monitor Checker而言,會調用實現類的monitor方法,譬如上文中提到的AMS.monitor()方法, 方法實現通常很簡單,就是獲取當前類的對象鎖,若是當前對象鎖已經被持有,則monitor()會一直處於wait狀態,直到超時,這種狀況下,極可能是線程發生了死鎖

至此,咱們已經分析了Watchdog的工做機制,回答了咱們提出的第一個問題:

Watchdog定時檢查一些重要的系統服務,舉報長時間阻塞的事件,甚至殺掉system_server進程,讓Android系統重啓。

相關文章
相關標籤/搜索