稳定性三——wachdog机制与分析方法

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值