Watchdog実現原理


転入先http://mp.weixin.qq.com/s/5kO8Hgdp1MrfJvaz7avcMg
1.Watchdog起動
前回の記事ではWatchdogの定義を簡単に紹介し、Watchdogがシステムの再起動を引き起こす問題の分析を一例で紹介し、Watchdogに対して感性的な認識を持たせた.本文はWatchdogの動作原理を紹介し、理性的な認識を持つことを目的としています.
まずWatchdogの主要メンバーのクラス継承関係を整理します.
Watchdog实现原理_第1张图片
WatchdogはThreadに継承され、実際にはsystem_で実行されています.serverプロセスのスレッドで、起動コード:
[frameworks/base/services/java/com/android/server/SystemServer.java]
private void startOtherServices() {
    ... ...        
   final Watchdog watchdog = Watchdog.getInstance();    watchdog.init(context, mActivityManagerService);    mActivityManagerService.systemReady(new Runnable() {        @Override            
       public void run() {            ... ...                
           // Watchdog            Watchdog.getInstance().start();
           ... ...        }    }    ... ... }
  • Watchdogクラスの実装はjavaでよく使われる単一のモードを採用している.getInstance()メソッドでクラスオブジェクトを構築します.
  • Androidシステムの起動が完了するとmActivityManagerServicesが呼び出されます.SystemReady()メソッドは、start()を介してWatchdogスレッドを動作させます.

  • Watchdog構築方法:
    [frameworks/base/services/core/java/com/android/server/Watchdog.java]
    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));    addMonitor(new BinderThreadMonitor()); }

    2.Watchdog動作原理
    まずWatchdogの全体的なブロック図を見てみましょう.
    Watchdog实现原理_第2张图片
  • FgThread,UiThread,IoThread,DisplayThreadはAndroidシステムで実現される特殊なスレッドであり、名前からだいたい
  • の役割がわかる
  • Looper.getMainLooper()は実はsystem_サーバこのプロセスのmain looperは、SystemServerのためです.JAvaにはLooperが呼び出されていますprepareMainLooper()
  • 実際にWatchdogによって直接モニタリングされているのは、上記の5つのスレッドのlooperが正常かどうかであり、もちろんaddThread()によってモニタリングが必要なlooper
  • も追加される.
  • FgThreadスレッドのlooperはまた、AMS、PMSなどの重要なシステムサービスがデッドロックしているかどうかを監視する責任を負います.
    AMSを例に、Watchdogがデッドロックかどうかを監視する方法を見てみましょう.まず、Activity Management Servicesを見てみましょう.JAvaクラスでは、どのような特殊な処理が行われていますか.
    [frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java]
    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このインタフェース
  • AMSでWatchdogを実現する.Monitorインタフェースのmonitor()メソッドは、1つのロック操作を実現するだけで
  • addMonitor()メソッドにより、AMSをmMonitorCheckerというHandlerCheckerクラスオブジェクトに
  • 追加する
    Androidシステムの起動完了後、Watchdogスレッドが実行を開始し、Watchdogに入る.JAvaのrun()メソッド.
    [frameworks/base/services/core/java/com/android/server/Watchdog.java]
    public void run() {        
       while(true) {            
           long timeout = CHECK_INTERVAL;            
           for (int i=0; i            
           while (timeout > 0) {            wait(timeout);        }            
               
           final int waitState = evaluateCheckerCompletionLocked();            
           if (waitState == COMPLETED) {            waitedHalf = false;                
               continue;        } else if (waitState == WAITING) {                
               continue;        } else if (waitState == WAITED_HALF) {                
               if (!waitedHalf) {                ArrayList pids = new ArrayList();                pids.add(Process.myPid());                ActivityManagerService.dumpStackTraces(true, pids, null, null,                        NATIVE_STACKS_OF_INTEREST);                waitedHalf = true;            }                
               continue;        }        blockedCheckers = getBlockedCheckersLocked();        subject = describeCheckersLocked(blockedCheckers);            
           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 {            Process.killProcess(Process.myPid());        }    } }
  • Watchdogスレッドのrun()メソッドでは、mHandlerCheckersの各HandlerCheckerオブジェクトのscheduleCheckLocked()メソッドを1回ずつ呼び出して、もちろんmMonitorChecker
  • を含む
  • CHECKを待つINTERVAL時間(CHECK_INTERVALは真のTIMEOUT時間の半分)を呼び出し、evaluateCheckerCompletionLocked()メソッドを呼び出して試行操作後の結果を表示します.ここでは、すべてのHandlerCheckerオブジェクトの結果の中で最も遅れた値
  • を返します.
  • 試した結果WAITED_HALFでは、Activity Management Servicesが呼び出されます.dumpStackTraces()は、traceファイルにスタックを印刷し、次に、試行動作
  • を行う.
  • で2番目のCHECK_INTERVAL時間後の戻り値がOVERDUEである場合、getBlockedCheckersLocked()およびdescribeCheckersLocked()メソッドによりblockされたlooperおよびmonitor情報が取得する、Process.killProcess(Process.myPid()殺しsystem_serverプロセス
  • 2.1 hc.scheduleCheckLocked()
    public void scheduleCheckLocked() {        
       if (mMonitors.size() == 0 &&
           mHandler.getLooper().getQueue().isPolling()) {        mCompleted = true;            
           return;    }        
           
       if (!mCompleted) {            
           return;    }    mCompleted = false;    mCurrentMonitor = null;    mStartTime = SystemClock.uptimeMillis();    mHandler.postAtFrontOfQueue(this); }

    AMSはmonitorオブジェクトとしてmMonitorCheckerオブジェクトに存在するため、試行操作時にmHandlerが呼び出される.postAtFrontOfQueue(this)メソッドは、mMonitorCheckerのrun()メソッドの実行を待つ.
    public void run() {        
       final int size = mMonitors.size();        
           
       for (int i = 0 ; i < size ; i++) {            
           synchronized (Watchdog.this) {            mCurrentMonitor = mMonitors.get(i);        }        mCurrentMonitor.monitor();    }        
           
       synchronized (Watchdog.this) {        mCompleted = true;        mCurrentMonitor = null;    } }

    mMonitorsにはAMSがあるのでrun()メソッドではAMSのmonitorが呼び出されますが、前述したようにAMSのmonitor()メソッドは等持ロック操作synchronized(this){}であり、AMSにデッドロックが発生するとrun()メソッドは実行できず、mCompletedもtrueにはなりません.
    ここでは、WatchdogがmMonitor Checkerが表すlooperを監視するほか、monitorがないスレッドlooperもあります(AndroidシステムのすべてのmonitorはmMonitor Checkerにあります).これらのlooperについては、この2つのコードを見ると、それらの試行操作は主にlooperのqueueがブロックされているかどうかを見ることによって判断され、queueがブロックされている場合、上記のrun()メソッドは実行できないことがわかります.
    2.2 evaluateCheckerCompletionLocked()
    private int evaluateCheckerCompletionLocked() {        
       int state = COMPLETED;        
       for (int i=0; i    return state; }

    evaluateCheckerCompletionLocked()メソッドの戻り値は、mHandlerCheckersセット内のすべてのHandlerCheckerオブジェクトの中で最もヒステリシスの状態値です.
    public int getCompletionStateLocked() {        
       if (mCompleted) {            
           return COMPLETED;    } else {            
           long latency = SystemClock.uptimeMillis() - mStartTime;            
           if (latency < mWaitMax/2) {                
               return WAITING;        } else if (latency < mWaitMax) {                
               return WAITED_HALF;        }    }        
           
       return OVERDUE; }

    HandlerCheckerオブジェクトの現在の状態値は、mCompletedの値を判断し、HandlerCheckerの待ち時間と組み合わせることによって決定される.
    2.3タイムアウト後
    Watchdogのデフォルトのタイムアウト時間は1分で、デッドロックやブロックが1分を超えるとWatchdogはタイムアウトとみなされます.この時はシステムを直接殺すのが普通ですサーバですが、再起動しない場合は2つあります
  • debuggerWasConnected>0、つまりデバッガが接続され、システムは
  • にデバッグされています.
  • allowRestart=false、am hangコマンドでこの値
  • を変更できます.
    3.まとめ
    上はコードの面からWatchdogの原理を話して、もしあなたがコードがどのように実現したのかを理解したくないならば、それは上の内容を無視して、直接ここの結論を見ることができます.
  • Watchdogは実際にはsystem_で実行されるスレッドですserverプロセスにおける
  • Watchdogはスレッドのlooper状態を直接監視しているが、その中の1つのlooperはFgThreadスレッドの中にあり、そのHandlerCheckerを代表するmMonitorCheckerであり、システムにおける重要なシステムサービスの状態
  • を監視している.
  • Watchdogではlooperのqueueとmonitorの状態を探り続け、1分以上応答しなければデッドロックが発生したと判断し、traceファイルにsystem_を印刷しますserverプロセスのスタック情報
  • デッドロックが発生した後、Watchdogはデバッガ接続があるかどうかと「am hang」を設定するかどうかによってsystemを殺すかどうかを決定します.server.