前言
复杂的东西往往很难掌握,但是我们可以把问题进行拆解,拆解成一个个容易理解的小模块,当每个小模块都掌握后,整个大模块也就迎刃而解了。
本章主要讲解WatchDog的启动流程,把整个启动脉络理清楚,具体详细的分析会单独开新的章节梳理。
SystemServer启动时会在startBootstrapServices中启动WatchDog并进行初始化,如下:
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("startBootstrapServices");
// Start the watchdog as early as possible so we can crash the system server
// if we deadlock during early boot
t.traceBegin("StartWatchdog");
// 1. WatchDog使用了单利模式,必然调用了构造函数
final Watchdog watchdog = Watchdog.getInstance();
// 2. 调用start()方法
watchdog.start();
t.traceEnd();
......
t.traceBegin("InitWatchdog");
// 3. 调用init方法
watchdog.init(mSystemContext, mActivityManagerService);
t.traceEnd();
......
}
下面对关键步骤1,2,3进行分析。
Watchdog.getInstance()
// 很简单的单例模式
public static Watchdog getInstance() {
if (sWatchdog == null) {
sWatchdog = new Watchdog();
}
return sWatchdog;
}
// 继续看下构造函数
private Watchdog() {
// 1. 初始化mThread线程
mThread = new Thread(this::run, "watchdog");
// Initialize handler checkers for each common thread we want to check. Note
// that we are not currently checking the background thread, since it can
// potentially hold longer running operations with no guarantees about the timeliness
// of operations there.
// The shared foreground thread is the main checker. It is where we
// will also dispatch monitor checks and do other work.
// 2. 初始化mMonitorChecker和mHandlerCheckers,这两个后面详细分析
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
"foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
// Add checker for main thread. We only do a quick check since there
// can be UI running on the thread.
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
"main thread", DEFAULT_TIMEOUT));
// Add checker for shared UI thread.
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
"ui thread", DEFAULT_TIMEOUT));
// And also check IO thread.
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
"i/o thread", DEFAULT_TIMEOUT));
// And the display thread.
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));
// And the animation thread.
mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
"animation thread", DEFAULT_TIMEOUT));
// And the surface animation thread.
mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
"surface animation thread", DEFAULT_TIMEOUT));
// Initialize monitor for Binder threads.
// 3. 将一个BinderThreadMonitor对象添加到Monitor中,这个函数我们后面章节详细分析
addMonitor(new BinderThreadMonitor());
// 4. mInterestingJavaPids是一个ArrayList,目前为空,这里加入第一个元素
mInterestingJavaPids.add(Process.myPid());
// See the notes on DEFAULT_TIMEOUT.
// 5. DEFAULT_TIMEOUT必须大于WRAPPED_PID_TIMEOUT_MILLIS(默认30毫秒),后面会详细分析DEFAULT_TIMEOUT的逻辑
assert DB ||
DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
// 6. 初始化mTraceErrorLogger,内部使用了Trace来记录日志
mTraceErrorLogger = new TraceErrorLogger();
}
可以看出,在WatchDog的构造函数中,主要进行了一些初始化动作,我们重点关注的对象有mThread、mMonitorChecker和mHandlerCheckers。
private final Thread mThread;
private final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();
private final HandlerChecker mMonitorChecker;
// HandlerChecker是一个Runnable对象
public final class HandlerChecker implements Runnable {
WatchDog.start()
public void start() {
mThread.start();
}
start函数启动了mThread线程,此时必然会调用run函数。
这里是WatchDog的核心部分,代码量占到了整个类的四分之一左右。可以看到,整个函数跑在一个死循环当中,waitedHalf初始值为false。这个run函数大概180多行,我们后面章节详细分析。
WatchDog.init
public void init(Context context, ActivityManagerService activity) {
mActivity = activity;
context.registerReceiver(new RebootRequestReceiver(),
new IntentFilter(Intent.ACTION_REBOOT),
android.Manifest.permission.REBOOT, null);
}
注册了一个监听广播Intent.ACTION_REBOOT的广播,mActivity为ActivityManagerService,所有init函数必须要等AMS注册完成才能调用。看下Receiver的实现:
final class RebootRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
if (intent.getIntExtra("nowait", 0) != 0) {
rebootSystem("Received ACTION_REBOOT broadcast");
return;
}
Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent);
}
}
nowait参数不等于0时调用rebootSystem函数:
void rebootSystem(String reason) {
Slog.i(TAG, "Rebooting system because: " + reason);
IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE);
try {
pms.reboot(false, reason, false);
} catch (RemoteException ex) {
}
}
可以看到直接调用了PMS的reboot函数。
目前没有找到发送广播并且nowait为1的地方,能想到的一个使用场景是系统进程或者系统应用拥有android.Manifest.permission.REBOOT权限的可以通过发送这个广播实现重启系统的功能。
本章完