前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >android进阶之Watchdog检查系统异常机制

android进阶之Watchdog检查系统异常机制

作者头像
见得乐
发布2022-09-08 15:43:46
1.3K0
发布2022-09-08 15:43:46
举报
文章被收录于专栏:LearnPath

Watchdog简介

Watchdog是Android系统提供的以后总检查系统异常的机制,正如其名,“看门狗”,它看的是Android框架层的几个核心服务。Watchdog一旦发现的AMS、WMS和PMS等核心服务的主线程阻塞,就清除systemserver进程,我们知道,一单SystemServer进程停止,Zygote进程就会自杀,系统就会重启。

Watchdog继承Thread,它是一个线程类,它的监控任务运行在独立的线程中,其中有两个非常重要的ArrayList变量,分别是mMonitors和mHandlerCheckers。变量mMonitors存放的是对象Monitor的子类,如AMS、PMS等。对于这类的监控主要是判断它们是否死锁。而对于变量mHandlerCheckers是ArrayList集合,里面存放的是HandlerChecker的对象,Watchdog主要是监控它里面重要的线程的handler是否阻塞,即监控重要线程的消息队列是否阻塞。mMonitors是一个HandlerChecker类型的对象。实际上,HandlerChecker类是Watchdog的核心,它负责对各个监控对象进行监控。具体的对应关系如下图所示: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zNHRFETi-1657612777635)(http://otpesi023.bkt.clouddn.com/Watchdog.jpg)]

Watchdog的启动

Watchdog在SystemServer系统服务进程中被初始化和启动,接下来看看SystemServer怎么把它初始化和启动起来:

代码语言:javascript
复制
public final class SystemServer {
    .....
    public static void main(String[] args) {
        new SystemServer().run();
    }
    .....
    private void run() {
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
        .....
    }
    private void startOtherServices() {
        final Context context = mSystemContext;
        ........
        final Watchdog watchdog = Watchdog.getInstance();
        watchdog.init(context, mActivityManagerService);
        .....
        Watchdog.getInstance().start();
        .....
    }
    ......
}

当SystemServer进程启动之后,就会进入它的main()方法,而它的main()方法有调用了startOtherService()方法,这个方法就把Watchdog启动起来了。startOtherService()方法首先通过Watchdog的getInstance()方法获得Watchdog对象,使用的是单例模式。接着调用init()方法来做进一步操作,最后调用Watchdog的start()方法启动线程进行监控。

代码语言:javascript
复制
public class Watchdog extends Thread {
    static final boolean DB = false;
    //调试用,默认为false
    static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
    static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
    //这两个变量非常重要,由于DB为false,所以DEFAULT_TIMEOUT为60秒,
    //主要线程blocked了60秒,watchdog就会去kill进程systemServer。
    //CHECK_INTERVAL为30秒,意思是每隔30秒去check一次
}
代码语言:javascript
复制
    private Watchdog() {
        super("watchdog");
        //监听foreground thread,NetworkManagerService、NativeDaemonConnector、
        //MountService属于foreground thread
        mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
                "foreground thread", DEFAULT_TIMEOUT);
        mHandlerCheckers.add(mMonitorChecker);
        //监听SystemServer主线程
        mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
                "main thread", DEFAULT_TIMEOUT));
        //监听UI线程,包括ActivityManagerService、WindowManagerService、PointerEventDispatcher和DisplayManagerService
        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
                "ui thread", DEFAULT_TIMEOUT));
        //监听IO线程,包括BluetoothManagerService、MountService、PacManager等
        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
                "i/o thread", DEFAULT_TIMEOUT));
        //监听display thread线程,包括DIsplayManagerService、InputManagerService、WindowManagerService
        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
                "display thread", DEFAULT_TIMEOUT));

        //monitor可用的binder线程
        addMonitor(new BinderThreadMonitor());
    }

接下来看看Watchdog的init()方法:

代码语言:javascript
复制
    public void init(Context context, ActivityManagerService activity) {
        mResolver = context.getContentResolver();
        mActivity = activity;

        context.registerReceiver(new RebootRequestReceiver(),
                new IntentFilter(Intent.ACTION_REBOOT),
                android.Manifest.permission.REBOOT, null);
    }

init()方法的实现比较简单,主要是给mActivity对象赋值,mActivity是一个全局的AMS对象,init()方法中会注册重启广播接收器RebotRequestReceiver,用来负责接收系统内部发出的系统重启请求。

Watchdog的监听

Watchdog继承Thread,所以调用start()方法之后,就会进入Watchdog的run()方法,它来做监控工作。

Watchdog主要提供了addMonitor()方法来添加监控服务对象,而在添加这些服务对象到Watchdog监控之前,这些服务必须要实现Watchdog.Monitor接口。比如AMS就首先实现了Watchdog.Monitor接口,然后在它的构造方法里把自己添加到Watchdog中,让Watchdog检测自己是否死锁,代码如下:

代码语言:javascript
复制
public ActivityManagerService(Context systemContext) {
    .......
    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);
}

通过addMonitor()方法和addThread()方法,分别把AMS和mHandler添加到Watchdog中。mHandler是一个AMS中的Handler对象,意思是Watchdog不仅要监控AMS是否死锁,还要监控mHandler分发消息的时候是否阻塞。接下来看看Watchdog的addMonitor()方法:

代码语言:javascript
复制
    public void addMonitor(Monitor monitor) {
        synchronized (this) {
            if (isAlive()) {
                throw new RuntimeException("Monitors can't be added once the Watchdog is running");
            }
            mMonitorChecker.addMonitor(monitor);
        }
    }

AMS实现了Watchdog.Monitor接口,所以这个monitor就是AMS对象。mMontorChecker是一个HandlerChecker对象,HandlerChecker类实现了java的Runnable类:

代码语言:javascript
复制
    public final class HandlerChecker implements Runnable {
        .......
        private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
        ......
        public void addMonitor(Monitor monitor) {
            mMonitors.add(monitor);
        }
    }

mMontors是一个Monitor类型的ArrayList,系统启动完成之后,系统服务都会添加到这个mMonitors中。AMS中还调用了Watchdog的addThread()方法,下面了解一下:

代码语言:javascript
复制
    public void addThread(Handler thread, long timeoutMillis) {
        synchronized (this) {
            if (isAlive()) {
                throw new RuntimeException("Threads can't be added once the Watchdog is running");
            }
            final String name = thread.getLooper().getThread().getName();
            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
        }
    }

mHandlerCheckers是一个HandlerChecker的ArrayList:

代码语言:javascript
复制
    final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();

通过mHandlerCheckers的add()方法把Handler添加进去,从而监控那些重要的线程里的Handler是否阻塞。

当调用Watchdog.getInstance().start()时,则进入线程“watchdog”的run()方法, 该方法分成两部分:

  • 前半段用于监测是否触发超时
  • 后半段当触发超时时输出各种信息,最后杀死SystemServer进程

接下来进入Watchdog的run()方法:

代码语言:javascript
复制
public void run() {
    boolean waitedHalf = false;
    while (true) {
        final ArrayList<HandlerChecker> blockedCheckers;
        final String subject;
        final boolean allowRestart;
        int debuggerWasConnected = 0;
        synchronized (this) {
            long timeout = CHECK_INTERVAL; //CHECK_INTERVAL=30s
            for (int i=0; i<mHandlerCheckers.size(); i++) {
                HandlerChecker hc = mHandlerCheckers.get(i);
                //执行所有的Checker的监控方法, 每个Checker记录当前的mStartTime
                hc.scheduleCheckLocked();
            }

            if (debuggerWasConnected > 0) {
                debuggerWasConnected--;
            }

            long start = SystemClock.uptimeMillis();
            //通过循环,保证执行30s才会继续往下执行
            while (timeout > 0) {
                if (Debug.isDebuggerConnected()) {
                    debuggerWasConnected = 2;
                }
                try {
                    wait(timeout); //触发中断,直接捕获异常,继续等待.
                } catch (InterruptedException e) {
                    Log.wtf(TAG, e);
                }
                if (Debug.isDebuggerConnected()) {
                    debuggerWasConnected = 2;
                }
                timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
            }
            
            //评估Checker状态
            final int waitState = evaluateCheckerCompletionLocked();
            if (waitState == COMPLETED) {
                waitedHalf = false;
                continue;
            } else if (waitState == WAITING) {
                continue;
            } else if (waitState == WAITED_HALF) {
                if (!waitedHalf) {
                    //首次进入等待时间过半的状态
                    ArrayList<Integer> pids = new ArrayList<Integer>();
                    pids.add(Process.myPid());
                    //输出system_server和3个native进程的traces
                    ActivityManagerService.dumpStackTraces(true, pids, null, null,
                            NATIVE_STACKS_OF_INTEREST);
                    waitedHalf = true;
                }
                continue;
            }
            ... //进入这里,意味着Watchdog已超时
        }
        ...
    }
}

该方法主要功能:

  1. 执行所有的Checker的监控方法scheduleCheckLocked()
    • 当mMonitor个数为0(除了android.fg线程之外都为0)且处于poll状态,则设置mCompleted = true;
    • 当上次check还没有完成, 则直接返回.
  2. 等待30s后, 再调用evaluateCheckerCompletionLocked来评估Checker状态;
  3. 根据waitState状态来执行不同的操作:
    • 当COMPLETED或WAITING,则相安无事;
    • 当WAITED_HALF(超过30s)且为首次, 则输出system_server和3个Native进程的traces;
    • 当OVERDUE, 则输出更多信息.

接下来看看scheduleCheckLocked()方法:

代码语言:javascript
复制
public final class HandlerChecker implements Runnable {
    ...
    public void scheduleCheckLocked() {
        if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
            mCompleted = true; //当目标looper正在轮询状态则返回。
            return;
        }

        if (!mCompleted) {
            return; //有一个check正在处理中,则无需重复发送
        }
        mCompleted = false;
        
        mCurrentMonitor = null;
        // 记录当下的时间
        mStartTime = SystemClock.uptimeMillis();
        //发送消息,插入消息队列最开头, 见下方的run()方法
        mHandler.postAtFrontOfQueue(this);
    }
    
    public void run() {
        final int size = mMonitors.size();
        for (int i = 0 ; i < size ; i++) {
            synchronized (Watchdog.this) {
                mCurrentMonitor = mMonitors.get(i);
            }
            //回调具体服务的monitor方法
            mCurrentMonitor.monitor();
        }

        synchronized (Watchdog.this) {
            mCompleted = true;
            mCurrentMonitor = null;
        }
    }
}

该方法主要功能: 向Watchdog的监控线程的Looper池的最头部执行该HandlerChecker.run()方法, 在该方法中调用monitor(),执行完成后会设置mCompleted = true. 那么当handler消息池当前的消息, 导致迟迟没有机会执行monitor()方法, 则会触发watchdog

其中postAtFrontOfQueue(this),该方法输入参数为Runnable对象,根据消息机制, 最终会回调HandlerChecker中的run方法,该方法会循环遍历所有的Monitor接口,具体的服务实现该接口的monitor()方法。而monitor()方法只是简单获取锁,如AMS的monitor方法:

代码语言:javascript
复制
    public void monitor() {
        synchronized (this) { }
    }

因此,AMS判断是否死锁就是去看能不能拿到自己的锁

run()方法后面的实现则是当触发超时时输出各种信息,最后杀死SystemServer进程,此处就不继续贴出源码了。。。。

Watchdog总结

Watchdog是一个运行在system_server进程的名为”watchdog”的线程::

  • Watchdog运作过程,当阻塞时间超过1分钟则触发一次watchdog,会杀死system_server,触发上层重启;
  • mHandlerCheckers:记录所有的HandlerChecker对象的列表,包括foreground, main, ui, i/o, display线程的handler;
  • mHandlerChecker.mMonitors:记录所有Watchdog目前正在监控Monitor,所有的这些monitors都运行在foreground线程。
  • 有两种方式加入Watchdog的监控:
    • addThread():用于监测Handler对象,默认超时时长为60s.这种超时往往是所对应的handler线程消息处理得慢;
    • addMonitor(): 用于监控实现了Watchdog.Monitor接口的服务.这种超时可能是”android.fg”线程消息处理得慢,也可能是monitor迟迟拿不到锁;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Watchdog简介
  • Watchdog的启动
  • Watchdog的监听
  • Watchdog总结
相关产品与服务
消息队列 CMQ
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档