从源码角度看WatchDog机制

简介

Android系统中,普通开发者最常见的还是ANR,即AMS中的四大组件没有响应,这个问题常常是由于APP自身质量问题,在主线程中做耗时的操作导致。那么不知道大家有没有想过,ANR是Android Framework对普通应用的约束,不允许应用为所欲为的随意在重要的线程做耗时的任务,以免导致用户体验过差,那么运行在system_server进程中的服务呢,也可以无拘无束么?

看过我先前写过的文章的读者应该都知道,四大组件中的大部分操作是需要应用和system_server进程的服务交互来完成的,比方说启动一个Activity,那么不仅仅需要应用端调用onCreate, onStart这些方法,同时也需要在AMS服务端完成创建ActivityRecord、管理Stack和Task的操作。如果说此时类似AMS这类重要的服务或者线程出现了因为异常导致的耗时与阻塞,用户不是也会有糟糕的体验么?这时系统会作出什么样的回应来应对这种情况呢?Android Framework当然考虑到了这一点,引入了WatchDog机制,用来监测所有的系统服务和各种重要的系统线程,如果这些中的任何一个出现超时导致系统hang机,WatchDog线程将会重启手机系统

本篇文章,我将从先列出WatchDog机制涉及的主要类并对每个类进行大概的解释,随后再列举出主要的被监测服务与线程,方便大家参考用;最后带大家走入细节分析源码,每个重要步骤的源码最后都会放出一张逻辑图,不想看源码的读者可以直接参考这些图

整体类图

查看大图

  • WatchDog: 本身是一个线程,在SystemServer.startOtherServices中被启动,启动之后直接进入一个无限循环,监测系统的重要服务和线程的状态;这个类是WatchDog机制的大管家,以单例的形式存在在系统
  • HandlerChecker: 在WatchDog被实例化时,会初始化几个重要线程的监测对象,它是以线程和Handler一一对应存在的,WatchDog维护着多个HandlerChecker, 当触发监测操作时,实际上是HandlerChecker实例进行实际操作的
  • Monitor: 被各种需要监测的服务实现的接口,当monitor方法迟迟不返回时,就会判定这个服务已经超时

WatchDog监控职责

WatchDog主要监测着系统中的重要服务和重要线程,如果其中的服务没有回应或者说线程被阻塞,那么就会触发WatchDog重启

系统Service

系统Service 职务 判断是否超时方法
ActivityManagerService 四大组件与进程的管理 ActivityManagerService.class类锁是否有被释放
InputManagerService 输入管理 mInputFilerLock是否有被释放
WindowManagerService 窗口管理 mWindowMap是否有被释放
PowerManagerService 电源管理 mLock是否有被释放
MountService 设备存储连接与管理服务 内部两个连接器的mDaemonLock锁是否被都被释放
NetworkmanagermentService 网络服务 内部连接器的mDaemonLock锁是否被释放

以上只列举出比较常见的服务,还有一些没有列举出来,判断服务是否有做超时的方式其实很简单,就是判断这个服务中的重要锁是否一直在阻塞状态,如果长时间没有拿到这个锁的持有权,那么也就意味着这个服务一直在做某项耗时的操作,迟迟没有返回。

WatchDog采用这样的方式来监听系统服务中的超时现象,也是因为Android系统中的确定义了很多重要的锁,列如AMS,PMS这两把类锁。这种方式即方便但却又是致命的。例如系统常用的四大组件,每个运行中的APP都是有可能掺和一脚进来的,如果某个APP做了恶意的耗时操作并且频繁请求,那么系统只要稍微考虑不周,就可能会对这几把系统服务的大锁造成影响,进而牵一发而动全身,导致系统卡顿频繁

值得一提的是,WatchDog监控者几个重要系统服务之外,也监控着system_server Binder线程池的情况。WatchDog的内部类通过调用native方法blockUntilThreadAvailable来进行实现,如果所有Binder线程始终不能被访问到,那么也会导致系统出现WatchDog异常

系统重要线程

线程 优先级 作用
android.fg THREAD_PRIORITY_DEFAULT 系统专用的线程,可以用来做比较耗时的任务
system_server 主线程 THREAD_PRIORITY_FOREGROUND 用来做system_serverUI操作
android.ui THREAD_PRIORITY_FOREGROUND 适合用来做很快就能完成的操作
android.io THREAD_PRIORITY_DEFAULT 用来做IO操作的线程
android.display THREAD_PRIORITY_DISPLAY 用来做与显示有关的任务,常常被WindowManager, WindowManager等使用
PackageManager THREAD_PRIORITY_BACKGROUND 用来做PMS相关的操作
ActivityManagerService THREAD_PRIORITY_FOREGROUND 用来做AMS相关的操作
PowerManagerService THREAD_PRIORITY_DISPLAY 用来做PowerManagerService相关的操作

源码分析

初始化

[frameworks/base/services/core/java/com/android/server/Watchdog.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private Watchdog() {
super("watchdog");
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
"foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
"main thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
"ui thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
"i/o thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));
addMonitor(new BinderThreadMonitor());
}
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);
}
}
public void addThread(Handler thread) {
addThread(thread, DEFAULT_TIMEOUT);
}

WatchDog在被初始化会创建多个HandlerChecker并保存在mHandlerCheckers这个队列中,通过调用addMonitor系统服务监测monitor都会被添加到mMonitorChecker这个成员变量中的列表中。通过调用addThread可以检测指定的线程是否长期不可用。

[frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java]

1
2
3
4
5
6
public ActivityManagerService(Context systemContext) {
...
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}

以上代码为ActivityManagerService在初始化时,将自己添加到WatchDog监测之列,同时也监测着自己内部常用的线程情况

检查机制

[frameworks/base/services/core/java/com/android/server/Watchdog.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Override
public void run() {
boolean waitedHalf = false;
// 进入无限循环,监测系统状态
while (true) {
final ArrayList<HandlerChecker> blockedCheckers;
synchronized (this) {
long timeout = CHECK_INTERVAL;
// 触发检查
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
hc.scheduleCheckLocked();
}
long start = SystemClock.uptimeMillis();
while (timeout > 0) {
try {
// 等待监测完成
wait(timeout);
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
}
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进程堆栈信息进行打印
ActivityManagerService.dumpStackTraces(true, pids, null, null,
NATIVE_STACKS_OF_INTEREST);
waitedHalf = true;
}
continue;
}
// 走到这里说明系统进入hang机状态了
blockedCheckers = getBlockedCheckersLocked();
subject = describeCheckersLocked(blockedCheckers);
allowRestart = mAllowRestart;
}
...
}

以上的监测代码很简单,就是触发每个HandlerChecker的监测机制,然后等待它们的执行结果,根据结果来判断系统是否出现了严重超时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public void scheduleCheckLocked() {
// 如果monitor列表为空,并且线程队列一切正常,那么不需要检测了
if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
mCompleted = true;
return;
}
// 防重入
if (!mCompleted) {
return;
}
mCompleted = false;
mCurrentMonitor = null;
// 初始化检测开始时间
mStartTime = SystemClock.uptimeMillis();
// 将监测操作抛入队列首端
mHandler.postAtFrontOfQueue(this);
}
@Override
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;
}
}

如果monitor方法,也就是各个服务实现的方法,始终没有返回,那么久不会将mCompleted这个flag置为true了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private int evaluateCheckerCompletionLocked() {
int state = COMPLETED;
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
// 确保返回的状态是最差的状态,如果有一个checker的状态返回为OVERDUE则判定整体的watchdog都超时了
state = Math.max(state, hc.getCompletionStateLocked());
}
return state;
}
public int getCompletionStateLocked() {
if (mCompleted) {
return COMPLETED;
} else {
// 如果当前checker没有完成,则根据时间来判断是超时了一般还是正在超时状态中
long latency = SystemClock.uptimeMillis() - mStartTime;
if (latency < mWaitMax/2) {
return WAITING;
} else if (latency < mWaitMax) {
return WAITED_HALF;
}
}
// 如果以上状态都不符合,则判定为超时
return OVERDUE;
}

最终,每个HandlerChecker都会被调用到getCompletionStateLocked方法,它的状态是根据monitor方法返回的时间来进行计算的

查看大图

处理hang机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
@Override
public void run() {
boolean waitedHalf = false;
while (true) {
synchronized (this) {
...
// 获取所有超时的checker
blockedCheckers = getBlockedCheckersLocked();
// 构造输出的字符信息
subject = describeCheckersLocked(blockedCheckers);
allowRestart = mAllowRestart;
}
// 输出watchdog EventLog
EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
// 打印出system_server进程堆栈信息
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
if (mPhonePid > 0) pids.add(mPhonePid);
final File stack = ActivityManagerService.dumpStackTraces(
!waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST);
// 系统hang机2秒,确保堆栈被打印
SystemClock.sleep(2000);
// 打印出内核堆栈信息
if (RECORD_KERNEL_THREADS) {
dumpKernelStackTraces();
}
// 将异常信息写入到dropbox
Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
public void run() {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null,
subject, null, stack, null);
}
};
dropboxThread.start();
try {
dropboxThread.join(2000); // wait up to 2 seconds for it to return.
} catch (InterruptedException ignored) {}
if (debuggerWasConnected >= 2) {
Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
} else if (debuggerWasConnected > 0) {
Slog.w(TAG, "Debugger was connected: Watchdog is *not* killing the system process");
} else if (!allowRestart) {
Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
} else {
Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
// 打印出所有超时的线程堆栈
for (int i=0; i<blockedCheckers.size(); i++) {
Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:");
StackTraceElement[] stackTrace
= blockedCheckers.get(i).getThread().getStackTrace();
for (StackTraceElement element: stackTrace) {
Slog.w(TAG, " at " + element);
}
}
Slog.w(TAG, "*** GOODBYE!");
// 杀死system_server进程,重启手机
Process.killProcess(Process.myPid());
System.exit(10);
}
waitedHalf = false;
}
}

查看大图

扫码支持0.99元,您的支持将鼓励我继续创作!