Watchdog机制原理

Watchdog机制

1.什么是SWT:

Softwere Watchdog Timeout,顾名思义就是软件超时监控狗。

Watchdog.java 位于frameworks/base/services/core/java/com/android/server/Watchdog.java

2.为什么需要SWT:

System Server 进程是Android的一个核心进程,里面为App运行提供了很多核心服务,如AMS、WMS、PKMS等等,如果这些核心的服务和重要的线程卡住,就会导致相应的功能异常。如果没有一种机制让这些服务复位的话,就会严重影响用户的体验,所以Google引入了System Server Watchdog 机制,用来监控这些核心服务和重要线程是否被卡住。

3.原理框架示意图:

在这里插入图片描述

4.Watchdog的初始化:

Watchdog的初始化是在SystemServer init的后期,如果SystemServer在init的过程中卡死了,那么就意味着Watchdog不会生效。

Watchdog是一个单例线程,在SystemServer启动时就会获取它并初始化和启动(init/start).

  private void startOtherServices() {
      ...
          traceBeginAndSlog("InitWatchdog");
      final Watchdog watchdog = Watchdog.getInstance();
      watchdog.init(context, mActivityManagerService);
      traceEnd();
      ...
          traceBeginAndSlog("StartWatchdog");
      Watchdog.getInstance().start();
      traceEnd();
      ...
  }

Watchdog在初始化的时候会构建很多的HandlerChecker

private Watchdog() {
	super("watchdog");
    // Initialize handler checkers for each common thread we want to check.  Note
    // that we are not currently checking the background thread, since it can
    // potentially hold longer running operations with no guarantees about the timeliness
    // of operations there.
    // The shared foreground thread is the main checker.  It is where we
    // will also dispatch monitor checks and do other work.
    mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
                   "foreground thread", DEFAULT_TIMEOUT);
    mHandlerCheckers.add(mMonitorChecker);
    // Add checker for main thread.  We only do a quick check since there
    // can be UI running on the thread.
    mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
                   "main thread", DEFAULT_TIMEOUT));
    // Add checker for shared UI thread.
    mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),"ui thread", DEFAULT_TIMEOUT));
	// And also check IO thread.
 	mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),"i/o thread", DEFAULT_TIMEOUT));
    // And the display thread.
    mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
                                            "display thread", DEFAULT_TIMEOUT));
    // And the animation thread.
    mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
                                            "animation thread", DEFAULT_TIMEOUT));
    // And the surface animation thread.
    mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
                                            "surface animation thread", DEFAULT_TIMEOUT));
	......
}

5.HandlerChecker分类:

大致可以分为两类

  • Montor Checker:用于检查Monitor对象是否发生死锁,AMP、PKMS、WMS等核心系统服务都是Monitor对象。所有需要被监控的Service都去实现了Watchdog的Monitor接口,该接口中只有一个方法 monitor()

与之对应的是addMonitor()方法,将Service放到mHandlerChecker的mMonitors列表中,该列表会不断调用Monitor.monitor()方法,这个方法的实现也比较简单,就是去获取对应的锁,如果获取到了就OK,如果线程死锁或者其它原因阻塞那么必然获取不到,monitor()方法也必然阻塞

WindowManagerService.java 
    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
    @Override
    public void monitor() {
    synchronized (mWindowMap) { }
    }
  • Lopper Checker,用于检查线程的消息队列是否长时间处于非空闲状态,Watchdog自身的消息队列,Ui, Io, Display这些全局的消息队列都是被检查的对象。此外,一些重要的线程的消息队列,也会加入到Looper Checker中,譬如AMS, PKMS,这些是在对应的对象初始化时加入的。

与之对应的方法是addThread(),将PowerManagerService、PackageManagerService、ActivityManagerService等几个主线程Handler保存到Watchdog.mHandlerCheckers列表中;同时还会把上面提到的mMonitorChecker也保存到Watchdog.mHandlerCheckers中;另外还会将foreground thread、ui thread、i/o thread 、display thread 、main thread的Handler也保存到Watchdog.mHandlerCheckers中来;

Watchdog会不断判断这些线程的Lopper是否空闲,如果一直非空闲,那么必然就被阻塞了。

6.Watchdog的运作:

Watchdog本身是一个线程,它的run()方法实现如下:

@Override
public void run() {
    boolean waitedHalf = false; //标识第一个30s超时
    boolean mSFHang = false; //标识surfaceflinger是否hang
    while (true) {
        ...
        synchronized (this) {
            ...
            // 1. 调度所有的HandlerChecker
            for (int i=0; i<mHandlerCheckers.size(); i++) {
                HandlerChecker hc = mHandlerCheckers.get(i);
                //shceduleCheckLocked()所做的事情可以想象成给所有的目标thread发放任务。
                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();
            //超了60秒,此时便出问题了,收集超时的HandlerChecker
            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就会被不停的调度。

7.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();
        }
        ...
    }
}

8.小结:

  • 对于Looper Checker而言,会判断线程的消息队列是否处于空闲状态。 如果被监测的消息队列一直闲不下来,则说明可能已经阻塞等待了很长时间。
  • 对于Monitor Checker而言,会调用实现类的monitor方法,比如上文中提到的AMS.monitor()方法, 方法实现一般很简单,就是获取当前类的对象锁,如果当前对象锁已经被持有,则monitor()会一直处于wait状态,直到超时,这种情况下,很可能是线程发生了死锁。

这基本就是Watchdog的监控原理,就先梳理这么多吧,后续的SWT/ANR问题的分析流程等遇到了再说吧。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值