1 watchdog分析

Watchdog就是“看门狗”。其最初存在的意义是因为以前嵌入式设备上的程序经常跑飞(电磁干扰之类的),所以专门设置了一个硬件看门狗,每个一段时间,看门狗就去检查一下某个参数是否被设置了,如果发现该参数没有被设置,则判断为系统出错,然后就会强制重启。

在软件层面上,Android对Systemserver的参数是否被设置也很谨慎,所以专门为它增加了一条看门狗,它主要看几个重要service的门。一旦发现service出现问题,就会kill system_server进程,进而导致zygote进程自杀,最后导致java世界重启。

我们先把systemServer使用watchdog的调用流程总结一下,然后以此为切入点来分析watchdog。SS和watchdog的交互流程可以总结如下:

①watchdog.getInstance.Init()

②watchdog.getInstance.start()

③watchdog.getInstance.addMonitor()

1.1 创建和初始化watchdog

GetInstance用于创建watchdog,代码如下:

public static Watchdog getInstance() {

if (sWatchdog == null) {

sWatchdog = new Watchdog(); //使用了单实例模式。

}

return sWatchdog;

}

//构造函数

private Watchdog() {

super("watchdog");

/*为每一个我们想检查的普通线程初始化一个handler检测器。需要注意的是:我们并不马上检查后台线程,因为这样可能会执行更长的操作且无法保证这些操作的耗时是合适的。

我们大家共享的前台线程是主要的检查者,同时我们也会派遣监视器进行检查并做一些其他的工作。

Handler是系统消息处理的地方,会在后面进行详细的分析*/

mMonitorChecker = new HandlerChecker(FgThread.getHandler(),

"foreground thread", DEFAULT_TIMEOUT);

mHandlerCheckers.add(mMonitorChecker);

//为主线程添加一个checker,鉴于可能会是一个UI正运行在主线程中,所以我们只在这里做一个快速的检查

mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),

"main thread", DEFAULT_TIMEOUT));

// 为共享的UI线程添加一个checker

mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),

"ui thread", DEFAULT_TIMEOUT));

// 同时为io线程添加一个checker

mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),

"i/o thread", DEFAULT_TIMEOUT));

}

在看门狗诞生后,再来看看init函数:

public void init(Context context, BatteryService battery,

PowerManagerService power, AlarmManagerService alarm,

ActivityManagerService activity) {

mResolver = context.getContentResolver();

mBattery = battery;

mPower = power;

mAlarm = alarm;

mActivity = activity;

/*注册一个广播接受者,这个接受者只接收ACTION标记为REBOOT的广播,并且这个接受者拥有重启系统的权限*/

context.registerReceiver(new RebootRequestReceiver(),

new IntentFilter(Intent.ACTION_REBOOT),

android.Manifest.permission.REBOOT, null);

}

1.2 watchdog跑起来

Systemserver调用watchdog的start函数,这将导致watchdog的run函数在另一个线程中被执行:

@Override

public void run() {

boolean waitedHalf = false;

while (true) {//外层while循环

final ArrayList<HandlerChecker> blockedCheckers;

final String subject;

final boolean allowRestart;

synchronized (this) {

long timeout = CHECK_INTERVAL; // 检查的间隔时间,=2500

//对每一个checker进行轮询,scheduleCheckLocked会调用handler的postAtFrontOfQueue(Runnable r)函数,这个函数发送的消息会在另一个线程中得到处理,该线程触发 monitor去检查server的状态(是否死锁).

for (int i=0; i<mHandlerCheckers.size(); i++) {

HandlerChecker hc = mHandlerCheckers.get(i);

hc.scheduleCheckLocked();

}

long start = SystemClock.uptimeMillis(); //检查的开始时间

//在CHECK_INTERVAL时间内循环等待检查结果

while (timeout > 0) {

try {

wait(timeout); //等待检查的结果

} catch (InterruptedException e) {

Log.wtf(TAG, e);

}

timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);

}

/* waitState共有四种状态:COMPLETED = 0;WAITING = 1;WAITED_HALF = 2;

OVERDUE = 3; evaluateCheckerCompletionLocked函数的作用是:遍历所有的checkers,返回这些checkers中最大的State值——值越大就说明该checker检查到的状态越严重*/

final int waitState = evaluateCheckerCompletionLocked();

if (waitState == COMPLETED) {

// 表明经过所有检查后,发现一切service正常,本轮检查后,系统不处于waitedHalf状态

waitedHalf = false;

continue;

} else if (waitState == WAITING) {

// 有某些checker还在它们的间隔时间内等待检查结果,那么就直接返回,重新检查,waitedHalf状态值不改变

continue;

} else if (waitState == WAITED_HALF) {//已经有某些个checker处于WAITED_HALF状态了

if (!waitedHalf) { //如果当前总的检查状态并不处于waitedHalf状态,那么就pull一个栈跟踪到ActivityManagerService中,并将waitedHalf状态置为真,然后继续检查;否则直接继续检查

ArrayList<Integer> pids = new ArrayList<Integer>();

pids.add(Process.myPid());

ActivityManagerService.dumpStackTraces(true, pids, null, null,

NATIVE_STACKS_OF_INTEREST);

waitedHalf = true;

}

continue;

}

//说明watchdog已经处于OVERDUE状态了,就可能需要重启了

blockedCheckers = getBlockedCheckersLocked();

subject = describeCheckersLocked(blockedCheckers);

allowRestart = mAllowRestart;

}

/*代码运行到这里就说明watchdog已经处于OVERDUE状态了(即系统极可能已经挂起了~),那么我们首先收集SS进程中所有线程的栈跟踪信息,然后杀掉SS进程,这样就会导致系统重启了~*/

EventLog.writeEvent(EventLogTags.WATCHDOG, subject);

……..

if (controller != null) { //如果第一次检查的时候发现controller可以处理这种情况,那么就不需要重启,重新检查即可

Slog.i(TAG, "Reporting stuck state to activity controller");

try {

Binder.setDumpDisabled("Service dumps disabled due to hung system process.");

// 1 = keep waiting, -1 = kill system

int res = controller.systemNotResponding(subject);

if (res >= 0) {

Slog.i(TAG, "Activity controller requested to coninue to wait");

waitedHalf = false;

continue;

}

} catch (RemoteException e) {

}

}

// 已经检查过两次了,还是有问题,那么说明这次是真的有问题了,所以SS就自杀

if (Debug.isDebuggerConnected()) {

Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");

}

……..

Process.killProcess(Process.myPid());

System.exit(10);

}

//检查发现没有问题了,就将waitedHalf值置为假

waitedHalf = false;

}

}

总结:watchdog隔一段时间就会向另一个线程的消息队列头发送一条消息,那个线程将检查各个service的状况。而watchdog会等待检查的结果,如果第二次还是没有正确的返回结果,那么就杀掉SS。

1.3 列队检查

这么多service,哪些是watchdog比较关注的呢?一共有3个:

①activityManagerService

②powerManagerService

③windowManagerService

要想支持watchdog的检查,就需要让这些service实现monitor接口,然后watchdog就会调用它们的monitor函数进行检查了。检查的地方是在watchdog::HandlerChecker类的run中:

public void run() {

// mMonitors是所有monitor的集合

final int size = mMonitors.size();

//检查各个service

for (int i = 0 ; i < size ; i++) {

synchronized (Watchdog.this) {

mCurrentMonitor = mMonitors.get(i);

}

mCurrentMonitor.monitor(); //调用该service的monitor函数

}

synchronized (Watchdog.this) {

//如果没有问题,就设置mCompleted为真

mCompleted = true;

mCurrentMonitor = null;

}

}

那么,service是如何判断自己的健康状况的呢?我们以ActivityManagerService为例,先看看它是如何把自己交给watchdog检查的:

①在其构造函数中有:

Watchdog.getInstance().addMonitor(this); //把自己加入到watchdog的检查队列中

②ActivityManagerService自己重载的monitoe函数:

public void monitor() { //执行死锁检查

synchronized (this) { }

}

原来,watchdog最怕系统服务死锁,对于这种情况也只能采取杀系统的方法了~

1.4总结

其实watchdog是周期性地调用需要进行状态检查的服务自己的monitor函数来判断该服务是否死锁。然后根据返回结果来判断系统是否需要重启。

android2.2 watchdog分析的更多相关文章

  1. OpenFaaS实战之五:大话watchdog

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. [深入理解Android卷一全文-第四章]深入理解zygote

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的所有内容. ...

  3. android -- WatchDog看门狗分析

    在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生 ...

  4. Watchdog问题实例分析

    1.日志获取 Watchdog相关的问题甚至需要以下所有的日志: logcat 通过adb logcat命令输出Android的一些当前运行日志,可以通过logcat的 -b 参数指定要输出的日志缓冲 ...

  5. Android2.2源码属性服务分析

    属性服务property service 大家都知道,在windows中有个注册表,里面存储的是一些键值对.注册表的作用就是:系统或者应用程序将自己的一些属性存储在注册表中,即使系统或应用程序重启,它 ...

  6. Android2.2源码init机制分析

    1 源码分析必备知识 1.1 linux内核链表 Linux内核链表的核心思想是:在用户自定义的结构A中声明list_head类型的成员p,这样每个结构类型为A的变量a中,都拥有同样的成员p,如下: ...

  7. android2.3 View视图框架源码分析之一:android是如何创建一个view的?

    View是所有控件的一个基类,无论是布局(Layout),还是控件(Widget)都是继承自View类.只不过layout是一个特殊的view,它里面创建一个view的数组可以包含其他的view而已. ...

  8. 《深入理解Android2》读书笔记(四)

    接上篇<深入理解Android2>读书笔记(三) ActivityManagerService(AMS) 1.AMS由ActivityManagerNative(AMN)类派生,并实现Wa ...

  9. [原] KVM虚拟机网络闪断分析

    背景 公司云平台的机器时常会发生网络闪断,通常在10s-100s之间. 异常情况 VM出现问题时,表现出来的情况是外部监控系统无法访问,猜测可能是由于系统假死,OVS链路问题等等.但是在出现网络问题的 ...

随机推荐

  1. nginx下配置Yii2 rewrite、pathinfo等

    环境说明: 我试用的lnmp安装包安装的nginx,nginx版本是1.14.1 server { listen ; server_name www.baidu.com; #access_log /d ...

  2. Freemaker基于word模板动态导出压缩文件汇总整理

    Freemaker基于word模板动态导出压缩文件汇总整理 Freemaker基于word模板动态导出单个文件思路和代码详情见连接: https://www.cnblogs.com/lsy-blogs ...

  3. 在Ubuntu下配置jdk+maven

    1.在官网上下载对应Linux版本的jdk 2.在终端输入命令将下载好的jdk解压并且转移到指定的路径如:首先执行 tar -zxvf jdk-8u181-linux-x64.tar.gz    然后 ...

  4. python3.7 迭代器和生成器

    #!/usr/bin/env python __author__ = "lrtao2010" #python3.7 迭代器和生成器 #迭代器协议: ''' 1.迭代器协议是指:对象 ...

  5. Why I get “No connection associated with this command”?

  6. Appium环境搭建及“fn must be a function”问题解决

    由于appium在线安装比较困难,大多数应该是由于FQ造成的吧,索性直接下载appium安装包:http://pan.baidu.com/s/1bpfrvjD nodejs下载也很缓慢,现提供node ...

  7. Android BadgeView 工具包

    前言:消息未读,显示红点或者红色数字,其实就是一个TextView,有推送一般就有badgeView. Step 1 因为在github上看到了一些类似的第三方库,嫌麻烦,不如直接封装一个类,直接使用 ...

  8. 17,基于scrapy-redis两种形式的分布式爬虫

    redis分布式部署 1.scrapy框架是否可以自己实现分布式? - 不可以.原因有二. 其一:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls ...

  9. P3386 【模板】二分图匹配(匈牙利&最大流)

    P3386 [模板]二分图匹配 题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正 ...

  10. heap&stack的区别

    1. heap (堆)是一个可动态申请的内存空间,一般所有创建的对象和数组都放在这里.stack (栈)是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量.stack (栈)的空间小 ...