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");
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));
mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
"animation thread", DEFAULT_TIMEOUT));
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
@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;
boolean mSFHang = false;
while (true) {
...
synchronized (this) {
...
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
hc.scheduleCheckLocked();
}
...
long start = SystemClock.uptimeMillis();
while (timeout > 0) {
...
try {
wait(timeout);
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
...
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
}
final int waitState = evaluateCheckerCompletionLocked();
if (waitState == COMPLETED) {
...
continue;
} else if (waitState == WAITING) {
...
continue;
} else if (waitState == WAITED_HALF) {
...
continue;
}
blockedCheckers = getBlockedCheckersLocked();
subject = describeCheckersLocked(blockedCheckers);
allowRestart = mAllowRestart;
}
...
Slog.w(TAG, "*** GOODBYE!");
Process.killProcess(Process.myPid());
System.exit(10);
}
......
}
以上代码片段主要的运行逻辑如下:
- Watchdog运行后,便开始无限循环,依次调用每一个HandlerChecker的scheduleCheckLocked()方法
- 调度完HandlerChecker之后,便开始定期检查是否超时,每一次检查的间隔时间由CHECK_INTERVAL常量设定,为30秒
- 每一次检查都会调用evaluateCheckerCompletionLocked()方法来评估一下HandlerChecker的完成状态:
- COMPLETED表示已经完成
- WAITING和WAITED_HALF表示还在等待,但未超时
- OVERDUE表示已经超时。默认情况下,timeout是1分钟,但监测对象可以通过传参自行设定,譬如PKMS的Handler Checker的超时是10分钟
- 如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息
- 保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal 9
只要Watchdog没有发现超时任务,HandlerChecker就会被不停的调度。
7.HandlerChecker的运作:
public final class HandlerChecker implements Runnable {
public void scheduleCheckLocked() {
if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) {
mCompleted = true;
return;
}
...
mHandler.postAtFrontOfQueue(this);
}
@Override
public void run() {
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问题的分析流程等遇到了再说吧。
|