1. 前言
本文主要是学习了Watchdog机制以及问题分析这篇文章,作者详细阐述了Android watchdog的实现机制,并用实际案例说明一次watch dog重启发生的原因,个人认为非常有帮助。
Android在软件层面设计了Watchdog,主要目的是检测各个重要的系统服务,防止出现死锁等问题导致系统服务卡死,如果发现有系统服务长时间无法退出,就会杀死系统服务,导致系统重启。
2. watchdog主要机制
Android的Watchdog是一个单例线程,在System Server时就会初始化Watchdog,初始化时会主要创建两种handler:
Monitor Checker主要监控系统服务可能发生的死锁;
Looper Checker主要检测全局及各个线程的消息队列是否长时间工作。
对于Monitor Checker,各个主要的系统服务在初始化时会通过addMonitor向watchdog注册monitor监控对象,watchdog线程会每隔一段时间循环调度各个系统服务注册的monitor处理函数执行,由于系统服务持有锁,而moniitor也尝试持有相同的锁,如果monitor申请持有锁成功,则可以正常退出,表示系统服务线程还在运行 , 如果monitor不能获取锁,60S后就会触发watchdog重启。
注:
1.一般monitor都是空的,一般系统服务的monitor会直接调用native的monitor, 如storageMangaerService会调用VoldNativeService的monitor
2.对于需要同步的情况,各个系统服务执行操作时会申请锁,monitor函数执行时也会尝试持有锁
3.不管monitor是空的,还是申请锁的情况,如果系统服务长时间工作持有锁或系统服务得不到调度,monitor函数无法得到执行,超过60s就会触发watchdog。
3. 根据log定位问题
系统测试会产生如下几种log:
system log
anr log
tracer log
1.对于watchdog重启问题,在system log中首先会打印WATCHDOG KILLING SYSTEM PROCESS,以确认是watchdog重启,其中可以看出是哪个进程发生的monitor超时,如下打印显示为android.fg
*** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.StorageManagerService on foreground thread (android.fg) 18
名为android.fg的线程在StorageManagerService 的monitor()方法被阻塞了。这里隐含了两层意思:
1.StorageManagerService 实现了Watchdog.Monitor这个接口,并将自己作为Monitor Checker的对象加入到了Watchdog的监测集中
2.monitor()方法是运行在android.fg线程中的。Android将android.fg设计为一个全局共享的线程,意味着它的消息队列可以被其他线程共享, Watchdog的Monitor Checker就是使用的android.fg线程的消息队列。因此,出现Monitor Checker的超时,肯定是android.fg线程阻塞在monitor()方法上。
2.找到Watchddog出现之前的traces.txt文件,它会将Android重启前的所有进程的调用栈以及锁的使用情况打印出来,根据1在traces.txt中搜索android.fg
注:
1.tracer文件是由两个anr文件合并而来,并加入了一些其它的信息;
2.watchdog会30S检测一次,首次检测到后会先生成一个anr文件,第二次进入后如果仍然无法获取锁会生成第二份anr文件,并执行watchdog重启,两份anr文件之间可以确认服务被block的一个时间段;
3.因为Watchdog默认的超时时间是1分钟,因此"WATCHDOG KILLING SYSTEM PROCESS"打印时间和tracer文件中记录的时间差最好不要超过1分钟,一般tracer文件记录时间早于"WATCHDOG KILLING SYSTEM PROCESS"打印时间;
4.这里也可以通过tracer文件的system server pid与system log中的system server pid比较,如果一致,则说明此pid是watchdog重启发生前的
通过android.fg线程调用栈,我们可以得到几个关键的信息:
-这个线程当前状态是否是阻塞?
-什么原因引起的阻塞?是否是等待锁?等待哪个锁?锁当前被哪个进程持有?
-如果是锁被持有,找到持有锁的进程,检查状态
3.如果是别的进程持有锁,则搜索到此进程,检查它的状态,可以看到此进程在java层block在哪里
4.继续跟踪需要进一步查看内核空间block在哪里,从而做进一步分析