文章目录
1. 介绍
- 最早引入Watchdog是在单片机系统中,由于单片机的工作环境容易受到外界磁场的干扰,导致程序“跑飞”,造成整个系统无法正常工作,因此,引入了一个“看门狗”,对单片机的运行状态进行实时监测,针对运行故障做一些保护处理,譬如让系统重启。这种Watchdog属于硬件层面,必须有硬件电路的支持。
- Linux也引入了Watchdog,在Linux内核下,当Watchdog启动后,便设定了一个定时器,如果在超时时间内没有对/dev/Watchdog进行写操作,则会导致系统重启。通过定时器实现的Watchdog属于软件层面
- Android设计了一个软件层面Watchdog,用于保护一些重要的系统服务,当出现故障时,通常会让Android系统重启。由于这种机制的存在,就经常会出现一些system_server进程被Watchdog杀掉而发生手机重启的问题
2 watchdog 机制
2.1 初始化
Android的Watchdog是一个单例线程,在System Server时就会初始化Watchdog。Watchdog在初始化时,会构建很多HandlerChecker.
注意英文注释
/frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("startBootstrapServices");
// Start the watchdog as early as possible so we can crash the system server
// if we deadlock during early boot
t.traceBegin("StartWatchdog");
final Watchdog watchdog = Watchdog.getInstance();
watchdog.start();
t.traceEnd();
...
t.traceBegin("InitWatchdog");
watchdog.init(mSystemContext, mActivityManagerService);
t.traceEnd();
...
}
private Watchdog() {
//线程名为watchdog
super("watchdog");
/* This handler will be used to post message back onto the main thread */
// private final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();
//将fg thread 单独提出作为主要的checker
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
"foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
//创建主线程的checker
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
"main thread", DEFAULT_TIMEOUT));
//创建UI thread 的checker
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
"ui thread", DEFAULT_TIMEOUT));
//创建Io thread 的checker
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
"i/o thread", DEFAULT_TIMEOUT));
//创建display thread 的checker
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));
//创建animation thread 的checker
mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
"animation thread", DEFAULT_TIMEOUT));
//创建surface animation thread 的checker
mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
"surface animation thread", DEFAULT_TIMEOUT));
//fg thread的checker 中添加对binder 的checker
addMonitor(new BinderThreadMonitor());
// 添加对watchdog 相关目录的监控
mOpenFdMonitor = OpenFdMonitor.create();
mInterestingJavaPids.add(Process.myPid());
// See the notes on DEFAULT_TIMEOUT.
assert DB ||
DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
}
初始化时会构建很多HandlerChecker,大致分为两类
- mMonitorChecker,用于检查是Monitor对象可能发生的死锁, 通过monitor函数 AMS, PKMS, WMS等核心的系统服务都是Monitor对象
- Looper Checker,用于检查线程的消息队列是否长时间处于工作状态。Watchdog自身的消息队列,Ui, Io, Display这些全局的消息队列都是被检查的对象。此外,一些重要的线程的消息队列,也会加入到Looper Checker中,譬如AMS, PKMS,这些是在对应的对象初始化时加入的
Monitor Checker预警我们不能长时间持有核心系统服务的对象锁,否则会阻塞很多函数的运行; Looper Checker预警我们不能长时间的霸占消息队列,否则其他消息将得不到处理。这两类都会导致系统卡住(System Not Responding)。
2.2 添加Watchdog监测对象
Watchdog初始化以后,就可以作为system_server进程中的一个单独的线程运行了。但这个时候,还不能触发Watchdog的运行,因为AMS, PKMS等系统服务还没有加入到Watchdog的监测集。 所谓监测集,就是需要Watchdog关注的对象,Android中有成千上万的消息队列在同时运行,然而,Watchdog毕竟是系统层面的东西,它只会关注一些核心的系统服务。
Watchdog提供两个方法,分别用于添加Monitor Checker对象和Looper Checker对象:
//Watchdog.java
public void addMonitor(Monitor monitor) {
synchronized (mLock) {
//通过此接口会将monitor添加到fg thread中
mMonitorChecker.addMonitorLocked(monitor);
}
}
//HandlerChecker
void addMonitorLocked(Monitor monitor) {
// We don't want to update mMonitors when the Handler is in the middle of checking
// all monitors. We will update mMonitors on the next schedule if it is safe
//private final ArrayList<Monitor> mMonitorQueue = new ArrayList<Monitor>();
mMonitorQueue.add(monitor);
}
//通过此接口新建HandlerChecker
public void addThread(Handler thread) {
addThread(thread, DEFAULT_TIMEOUT);
}
public void addThread(Handler thread, long timeoutMillis) {
synchronized (mLock) {
final String name = thread.getLooper().getThread().getName();
mHandlerCheckers.add