一、在嵌入式设备上的应用
Watch Dog的中文意思是“看门狗”,最初是应用子啊嵌入式设备上的,目的是为了防止程序跑飞,所以专门设置了一个硬件看门狗,每隔一段时间,看门狗就会去检查一下某个参数是不是被设置了,如果发现该参数设置出错,就会强制重启程序。
二、在Android上的应用
Android对SystemServer参数是否被设置时很谨慎的,所以专门为它增加了看门狗,可他到底看哪个门呢?就是看几个重要的Service门,如果Android一旦发现几个重要的Service门出问题,就会马上杀掉进程system_server,而这也会使zygote一起自杀,最后导致重启Java世界。
三、Android中的Watchdog分析
我们先把SystemServer使用Watchdog的调用流程总结一下,然后以为为切入点来分析Watchdog。system_server和Watchdog的交互流程可以总结为一下三个步骤:
a、Watchdog.getInstance().init();
b、Watchdog.getInstance().start();
c、Watchdog.getInstance().addMonitor();
这三个步骤都很简单。先看第一步。
getInstance用户创建Watchdog,代码如下:
【-->Watchdog.java】
public static Watchdog getInstance(){
if(sWatchdog == null){
sWatchdog = new Watchdog();//使用了单例模式
}
return sWatchdog;
public class Watchdog extends Thread{
//Watchdog从线程类派生,所以它会在一个单独的线程中执行
private Watchdog(){
mHandler = new HeartbeatHandler();
//GlobalPssCollected和内存信息有关
mGlobalPsCollected = new GlobalPssCollected();
}
public void init(Context context,BatteryService battery,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(){
boolean waitedHalf = false;
while(true){
mCompleted = false;//false表示各国服务的检查还未完成。
//mHandler的消息处理是在另外一个线程中,这里将给那个线程发消息,请求Watchdog检查Service是否正常工作。
mHandler.sendEmptyMessage(MONITOR);
synchronized(this){
long timeout = TIME_TO_MAIT;
long start = SystemClock.uptimeMillis();
//注意这个小while循环的条件,mForceKillSystem为true时也会导致推出循环。
while(timeout > 0 && !mForceKillSystem){
try{
wait(timeout);//等待检查的结果
}catch{
}
timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
}
//mCompleted为true,表示service一切正常
if(mCompleted && !mForceKillSystem){
waitedHalf = false;
continue;
}
//如果mCompleted不为true,看门狗会尽责的再检查一次。
if(!waitedHalf){
......
waitedHalf = true;
continue;//再检查一次
}
}
//已经检查两次了,如果再出现,这回真的有问题了,所以system_server需要将自己干掉。
if(!Debug.idDebuggerConncted()){
Process.killProcess(Process.myPid());
System.exit(10);//干掉自己
}
......
waiteHalf = false;
}
}
上面Run方法里的意思是:
隔一段时间给另外一个线程发送一条MONITOR消息,哪个线程将检查各个Service的健康情况。而看门狗会等待检查结果,如果第二次还没有返回结果,那么就会杀死进程systen_server。
下面我们看看线程是怎么检查Service的。
3、列队检查
这么多的Service,看门狗到底是检查哪个呢?答案是一共有三个Service需要交给Watchgod检查:
a、ActivityManagerService
b、PowerManagerService
c、WindowManagerService
要想支持看门狗的检查,就需要让这些Service实现monitor接口,然后Watchdog就会调用它们的monitor函数进行检查了。检查的地方时在HeartbeatHandler类的handleMessage中,代码如下:
【-->Watchdog.java::HeartbeatHandler】
final class HearbeatHandler extends Handler{
@Overode
public void handleMessage(Message msg){
switch(msg.what){
......
case MONITOR:{
......
logg now = SystemClock.uptimeMillis();
final int size = mMontitors.size();
//检查各个服务,并设置当前检查对象为mCurrentMonitor。
for(int i = 0;i<size,i++){
mCurrentMonitor = mMonitors.get(i);
mCurrentMonitor .monitor();//检查这个对象
}
//如果没问题,则设置mCurrentMonitor.monitor();//检查这个对象
synchronized(Watchdog.this){
mCompleted = true;
mCurrentMonitor = null;
}
} break;
}
}
}
那么Service的健康状况是怎么判读呢?我们以PowerManagerService为例,先看看它是怎么把自己交给看门狗检查的,代码入下:
【-->PowerManagerService.java】
PowerManagerService(){
......
//z在构造函数中把自己加入Watchdog的检查队列
Watchdog.getInstance().addMonitor(this);
}
而Watchdog调用各个monitor函数到底又检查了些什么呢?看看它的实现monitor函数吧!
【-->PowerManagerService.java】
public void monitor(){
//原来monitor检查的就是这些Service是否发生死锁了!
synchronized(mLocks){}
}
原来,Watchdog最怕系统服务死锁了,对于这种情况也只能采取杀死进程的办法了。