一 概述
Watchdog 中文翻译是“看门狗”,有保护,监控的意思。最早引入 Watchdog 是在单片机系统中,由于单片机的工作环境容易受到外界磁场的干扰,导致程序“跑飞”,造成整个系统无法正常工作,因此,引入了一个“看门狗”,对单片机的运行状态进行实时监测,针对运行故障做一些保护处理,譬如让系统重启。这种 Watchdog 属于硬件层面,必须有硬件电路的支持。
Linux 也引入了 Watchdog,在 Linux 内核下,当 Watchdog 启动后,便设定了一个定时器,如果在超时时间内没有对 /dev/Watchdog 进行写操作,则会导致系统重启。通过定时器实现的 Watchdog 属于软件层面。
Android 在 framework 层设计了一个软件层面的 Watchdog,用于定期检测一些重要的系统服务,当出现故障(系统核心服务和重要线程处于 Blocked 状态)时,通常会让 Android 系统重启。由于这种机制的存在,就经常会出现 system_server 进程被 Watchdog 杀掉而发生手机重启的问题。
watchdog 的源码很简单,主要有以下两个功能:
- 监控 system_server 中几个关键的锁,原理是在 android_fg 线程中尝试加锁
- 监控几个常用线程的执行时间,原理是在这几个线程中执行任务
二 WatchDog初始化
2.1 startBootstrapServices
SystemServer.java
private void startBootstrapServices() {
......
//创建watchdog
final Watchdog watchdog = Watchdog.getInstance();
watchdog.start();
......
//待AMS启动后注册reboot广播
watchdog.init(mSystemContext, mActivityManagerService);
......
}
system_server 进程在启动的过程中初始化 WatchDog,主要有:
- 创建 watchdog 对象,该对象本身继承于 Thread
- 调用 start() 开始工作
- 注册 reboot 广播
2.2 Watchdog.getInstance
Watchdog.java
public static Watchdog getInstance() {
if (sWatchdog == null) {
sWatchdog = new Watchdog();//单例模式,创建实例对象
}
return sWatchdog;
}
2.3 创建Watchdog
Watchdog.java
public class Watchdog extends Thread {
//所有的HandlerChecker对象组成的列表
//This handler will be used to post message back onto the main thread
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));
// 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));
//Initialize monitor for Binder threads
addMonitor(new BinderThreadMonitor());
mOpenFdMonitor = OpenFdMonitor.create();
// See the notes on DEFAULT_TIMEOUT.
assert DB ||
DEFAULT_TIMEOUT >
ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
}
......
}
Watchdog 是一个单例线程,继承于 Thread,创建的线程名为 ”watchdog”。在 SystemServer 启动过程中初始化 Watchdog。Watchdog 在初始化时,会构建很多 HandlerChecker,大致可以分为两类:
- Monitor Checker,用于检查 Monitor 对象可能发生的死锁,AMS,IMS,WMS PMS 等核心的系统服务都是 Monitor 对象
- Looper Checker,用于检查线程的消息队列是否长时间处于工作状态。Watchdog 自身的消息队列,ui,io, Display 这些全局的消息队列都是被检查的对象。此外,一些重要的线程的消息队列,也会加入到 Looper Checker中,譬如 AMS,WMS 这些是在对应的对象初始化时加入的
两类 HandlerChecker 的侧重点不同,Monitor Checker 预警我们不能长时间持有核心系统服务的对象锁,否则会阻塞很多函数的运行;Looper Checker 预警我们不能长时间的霸占消息队列,否则其他消息将得不到处理。这两类都会导致系统卡住 (System Not Responding)。
2.3.1 Watchdog.HandlerChecker
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 final ArrayList<Monitor> mMonitorQueue =
new ArrayList<Monitor>();
private boolean mCompleted;//开始检查时先设置成false
private Monitor mCurrentMonitor;
private long mStartTime;//开始准备检查的时间点
private int mPauseCount;
HandlerChecker(Handler handler, String name, long waitMaxMillis) {
mHandler = handler;
mName = name;
mWaitMax = waitMaxMillis;
mCompleted = true;
}
void addMonitorLocked(Monitor monitor) {
mMonitorQueue.add(monitor);
}
public void scheduleCheckLocked() {
if (mCompleted) {
mMonitors.addAll(mMonitorQueue);
mMonitorQueue