4.5.3 Watchdog分析
最后更新于:2022-04-02 05:49:31
本章我们没有对SystemServer做更进一步的分析,不过做为拓展内容,这里想介绍一下Watchdog。Watch Dog的中文意思是“看门狗”。我依稀记得,其最初存在的意义是因为早期嵌入式设备上的程序经常“跑飞”(比如说电磁干扰等),所以专门有个硬件看门狗,每隔一段时间,看门狗就去检查一下某个参数是不是被设置了,如果发现该参数没有被设置,则判断为系统出错,然后就会强制重启。
软件层面上Android对SystemServer对参数是否被设置也很谨慎,专门为它增加了一条看门狗,可它看的是哪个门呢?对了,就是看几个重要Service的门,一旦发现Service出了问题,就会杀掉system_server,这样就使zygote随其一起自杀,最后导致重启Java世界。
我们先把SystemServe使用Watchdog的调用流程总结一下,然后以这个为切入点来分析Watchdog。SS和Watchdog的交互流程可以总结为以下三个步骤:
- Watchdog. getInstance().init()
- Watchdog.getInstance().start()
- Watchdog. getInstance().addMonitor()
这三个步骤都非常简单。先看第一步:
1. 创建和初始化Watchdog
getInstance用于创建Watchdog,一起来看看,代码如下所示:
**Watchdog.java**
~~~
public static Watchdog getInstance() {
if(sWatchdog == null) {
sWatchdog= new Watchdog(); //使用了单例模式。
}
returnsWatchdog;
}
public class Watchdog extends Thread
//Watchdog从线程类派生,所以它会在单独的一个线程中执行
private Watchdog() {
super("watchdog");
//构造一个Handler,Handler的详细分析见第5章,读者可以简单地把它看做是消息处理的地方。
//它在handleMessage函数中处理消息
mHandler = new HeartbeatHandler();
//GlobalPssCollected和内存信息有关。
mGlobalPssCollected= new GlobalPssCollected();
}
~~~
这条看门狗诞生后,再来看看init函数,代码如下所示:
**Watchdog.java**
~~~
public void init(Context context, BatteryServicebattery,
PowerManagerService power, AlarmManagerService alarm,
ActivityManagerService activity) {
mResolver = context.getContentResolver();
mBattery = battery;
mPower = power;
mAlarm = alarm;
mActivity = activity;
......
mBootTime = System.currentTimeMillis();//得到当前时间
......
}
~~~
至此,看门狗诞生的知识就介绍完了,下面我们就让它动起来。
2. 看门狗跑起来
SystemServer调用Watchdog的start函数,这将导致Watchdog的run在另外一个线程中被执行。代码如下所示:
**Watchdog.java**
~~~
public void run() {
booleanwaitedHalf = false;
while(true) {//外层while循环
mCompleted= false; //false表明各个服务的检查还没完成。
/*
mHandler的消息处理是在另外一个线程上,这里将给那个线程的消息队列发条消息
请求Watchdog检查Service是否工作正常。
*/
mHandler.sendEmptyMessage(MONITOR);
synchronized (this) {
long timeout = TIME_TO_WAIT;
long start = SystemClock.uptimeMillis();
//注意这个小while循环的条件,mForceKillSystem为true也会导致退出循环
while (timeout > 0 && !mForceKillSystem) {
try {
wait(timeout); //等待检查的结果
} catch(InterruptedException e) {
}
timeout = TIME_TO_WAIT -(SystemClock.uptimeMillis() - start);
}
//mCompleted为true,表示service一切正常
if (mCompleted &&!mForceKillSystem) {
waitedHalf = false;
continue;
}
//如果mCompleted不为true,看门狗会比较尽责,再检查一次
if (!waitedHalf) {
......
waitedHalf = true;
continue;//再检查一次
}
}
//已经检查过两次了,还是有问题,这回是真有问题了。所以SS需要把自己干掉。
if (!Debug.isDebuggerConnected()) {
Process.killProcess(Process.myPid());
System.exit(10); //干掉自己
}
......
waitedHalf = false;
}
}
~~~
OK,这个run函数还是比较简单的,就是:
· 隔一段时间给另外一个线程发送一条MONITOR消息,那个线程将检查各个Service的健康情况。而看门狗会等待检查结果,如果第二次还没有返回结果,那么它会杀掉SS。
好吧,来看看检查线程究竟是怎么检查Service的。
3. 列队检查
这么多Service,哪些是看门狗比较关注的呢?一共有三个Service是需要交给Watchdog检查的:
- ActivityManagerService
- PowerManagerService
- WindowManagerService
要想支持看门狗的检查,就需要这些Service实现monitor接口,然后Watchdog就会调用它们的monitor函数进行检查了。检查的地方是在HeartbeatHandler类的handleMessage中,代码如下所示:
**Watchdog.java::HeartbeatHandler**
~~~
final class HeartbeatHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
......
case MONITOR: {
......
long now =SystemClock.uptimeMillis();
final int size =mMonitors.size();
//检查各个服务,并设置当前检查的对象为mCurrentMonitor
for (int i = 0 ; i [info]**说明**:这种情况,我只碰到过一次,原因是有一个函数占着锁,但长时间没有返回。没返回的原因是这个函数需要和硬件交互,而硬件又没有及时返回。
关于Watchdog,我们就介绍到这里。另外,它还能检查内存的使用情况,这一部分内容读者可以自行研究。
';