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. Luogu [P1248] 加工生产调度

    题目链接 这个题可以贪心 我们首先想:对于所有产品,我们大致可以将其分为三类: ①.在A车间的时间要比B车间长. ②.两者一样. ③.在B车间的时间要比A车间长. 对于这三大类,怎么安排顺序? 可以看 ...

  2. C++ 无限定名称查找

    无限定名称查找 (关键字:懒惰,挑捡,using指令的特殊性) 无限定名称查找实际上就是指没有限定(名称空间和名称空间运算符)名存在的一个名字的出现,其中对于using指令,其内部包含的所有的声明是被 ...

  3. select * 比select column快很多奇怪案例分析

    遇到MYSQL傻傻的地方,下面给个案例,大家感受下: 注意以下两个sql只有select *和select g.id区别. SQL1:SELECT g.idFROM table1 gINNER JOI ...

  4. 【解决】ERROR in xxx.js from UglifyJs

    当我们运行打包脚本npm run build或者打包iosweexpack build ios有可能会遇到以下报错 ERROR in index.js from UglifyJs ![](https: ...

  5. 学习Spring框架系列(一):通过Demo阐述IoC和DI的优势所在

    Spring框架最核心东西便是大名鼎鼎的IoC容器,主要通过DI技术实现.下面我通过Demo的演变过程,对比学习耦合性代码,以及解耦和的过程,并深入理解面向接口编程的真正内涵. 这个例子包括如下几个类 ...

  6. KMP的正确使用法_x新疆网络赛Query on a string

    Query on a string 题意,给定一个大字符串,给定一个小模式串,定义 两种不同的任务模式,分别是查询和更改: 查询对应区间内,有多少个匹配到位的数字: 修改某一位的某一个字母. 于是直觉 ...

  7. Three Steps to Migrate Group Policy Between Active Directory Domains or Forests Using PowerShell

    Three Steps Ahead Have you ever wished that you had three legs? Imagine how much faster you could ru ...

  8. 成为Java高手的25个学习要点

    成为Java高手的25个学习要点 想成为Java大牛吗?不妨来学习这25个要点. 1. 你需要精通面向对象分析与设计(OOA/OOD).涉及模式(GOF,J2EEDP)以及综合模式.你应该了解UML, ...

  9. 设计模式之第4章-装饰模式(Java实现)

    设计模式之第4章-装饰模式(Java实现) “怎么了,鱼哥?” “唉,别提了,网购了一件衣服,结果发现和商家描述的差太多了,有色差就算了,质量还不好,质量不好就算了,竟然大小也不行,说好的3个X,邮的 ...

  10. IOS开发学习笔记022-imageView实现动画

    这里要播放的动画是很多张连续的动画,连续播放就会显示出动画效果. 大概过程是: 新建一个single view application ,然后添加一个image View控件到视图.给image vi ...