SystemServer
是Android
系統的核心之一,大部分Android
提供的服務都運行在這個進程裏。java
爲了防止應用進程對系統形成破壞,Android
的應用進程沒有權限直接訪問設備的底層資源,只能經過SystemServer
中的服務代理訪問。android
本篇重點是瞭解SystemServer
的啓動過程以及它的Watchdog
模塊shell
SystemServer
的建立過程SystemServer
的建立能夠分爲兩部分:bootstrap
Zygote
進程中fork
並初始化SystemServer
進程的過程SystemServer
類的main
方法來啓動系統服務的過程SystemServer
進程在Zygote進程
一篇中咱們已經知道init.rc
文件中定義了Zygote進程
的啓動參數,以下:設計模式
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
......
複製代碼
其中定義了--start-system-server
參數,所以,在ZygoteInit
類的main
方法中,會執行到forkSystemServer()
函數:markdown
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
複製代碼
forkSystemServer()
函數以下:多線程
private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) {
......
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
......
int pid;
try {
......
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
......
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
複製代碼
在上面的方法中,主要作了以下事項:app
Systemserver
的啓動參數:
進程ID
和 組ID
設置爲 1000
system_server
Systemserver
的執行類com.android.server.SystemServer
Zygote
類的forkSystemServer()
函數fork
出SystemServer
進程
Zygote
類也是經過native層
的函數來完成實際的工做,函數以下static jint com_android_internal_os_Zygote_nativeForkSystemServer(...) {
pid_t pid = ForkAndSpecializeCommon(...);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
gSystemServerPid = pid;
// There is a slight window that the system server process has crashed
// but it went unnoticed because we haven't published its pid yet. So
// we recheck here just to make sure that all is well.
int status;
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
}
......
}
return pid;
}
複製代碼
native層
的函數來看,對於SystemServer
進程的fork
,Zygote
進程會經過waitpid()
函數來檢查SystemServer
進程是否啓動成功,若是不成功 ,Zygote
進程會退出重啓native層
的ForkAndSpecializeCommon()
中:static pid_t ForkAndSpecializeCommon(......) {
SetSignalHandlers();
......
}
static void SetSignalHandlers() {
struct sigaction sig_chld = {};
sig_chld.sa_handler = SigChldHandler;
......
}
// This signal handler is for zygote mode, since the zygote must reap its children
static void SigChldHandler(int /*signal_number*/) {
pid_t pid;
......
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
......
if (pid == gSystemServerPid) {
ALOGE("Exit zygote because system server (%d) has terminated", pid);
kill(getpid(), SIGKILL);
}
}
......
}
複製代碼
SystemServer
進程fork
後,在fork
出的子進程中:
Zygote進程
繼承來的socket
handleSystemServerProcess()
來初始化SystemServer
進程,流程以下:/** * Finish remaining work for the newly forked system server process. */
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
// set umask to 0077 so new files and directories will default to owner-only permissions.
// 設置umask爲0077(權限的補碼)
// 這樣SystemServer建立的文件屬性就是0700,只有進程自己能夠訪問
Os.umask(S_IRWXG | S_IRWXO);
......
if (parsedArgs.invokeWith != null) {
// 通常狀況不會走到這裏,invokeWith基本上都爲null
......
// 經過 app_process 來啓動,進程不會return
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
......
// 經過查找啓動類的main方法,而後打包成Runnable對象返回
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
}
複製代碼
invokeWith
一般爲null
,因此基本都是經過ZygoteInit.zygoteInit()
函數來處理,返回打包好的Runnable
對象。後面就是執行r.run()
來調用SystemServer
的main()
方法了咱們看看SystemServer
的main()
方法幹了啥socket
SystemServer
初始化SystemServer
的main()
方法以下:ide
public static void main(String[] args) {
new SystemServer().run();
}
複製代碼
main()
方法中建立了一個SystemServer
的對象並調用run()
函數,函數代碼以下,刪減版:
private void run() {
// System Server 啓動前的準備階段
try {
// 設置系統時間
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
...... // 省略時區,語言、國家的設置
...... // 省略 Binder、Sqlite相關屬性設置
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
int uptimeMillis = (int) SystemClock.elapsedRealtime();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
......
// 設置當前虛擬機的運行庫路徑
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// 調整內存
VMRuntime.getRuntime().clearGrowthLimit();
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
...... //省略一些系統屬性的設置
// 設置進程相關屬性
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
// 初始化Looper相關
Looper.prepareMainLooper();
Looper.getMainLooper().setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
// 加載libandroid_services.so
System.loadLibrary("android_servers");
.....
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
......
} finally {
traceEnd(); // InitBeforeStartServices
}
// System Server 的啓動階段
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
......
} catch (Throwable ex) {
......
throw ex;
} finally {
traceEnd();
}
......
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
複製代碼
run()
方法主要分爲兩個階段:
一個是SystemServer
啓動前的準備階段,主要進行了:
libandroid_services.so
庫Looper
SystemContext
與SystemServiceManager
的初始化另外一個是SystemServer
的啓動階段:
startBootstrapServices
、startCoreServices
、startOtherServices
啓動全部的系統服務Looper.loop()
循環處理消息咱們先來看下準備階段SystemContext
的初始化過程
createSystemContext()
初始化函數以下:
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
final Context systemUiContext = activityThread.getSystemUiContext();
systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
複製代碼
createSystemContext()
方法的流程比較簡單:
ActivityThread
的靜態方法systemMain()
來獲得一個ActivityThread
對象ActivityThread
對象的getSystemContext()/getSystemUiContext()
方法來獲得對應的Context
對象Context
對象設置一個默認的theme
因此重點仍是ActivityThread.systemMain()
方法:
public static ActivityThread systemMain() {
// The system process on low-memory devices do not get to use hardware
// accelerated drawing, since this can add too much overhead to the
// process.
if (!ActivityManager.isHighEndGfx()) {
ThreadedRenderer.disable(true);
} else {
ThreadedRenderer.enableForegroundTrimming();
}
ActivityThread thread = new ActivityThread();
thread.attach(true, 0);
return thread;
}
複製代碼
方法內容並不複雜,首先判斷是否須要啓動硬件渲染,而後建立了一個ActivityThread
對象。
關於ActivityThread
,在Zygote進程
學習的時候咱們已經知道:
ActivityThread
是應用程序的主線程類ActivityThread
的main()
方法關鍵是SystemServer
爲何要建立ActivityThread
對象呢?
實際上SystemServer
不只僅是一個單純的後臺進程,它也是一個運行着組件Service
的進程,不少系統對話框就是從SystemServer
中顯示出來的,所以SystemServer
自己也須要一個和APK
應用相似的上下文環境,建立ActivityThread
是獲取這個環境的第一步
可是ActivityThread
在SystemServer
進程中與普通進程仍是有區別的,這裏主要是經過attach(boolen system,int seq)
方法的參數system
來標識,函數以下:
// system = true 表示這是在 SystemServer 中建立的
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
// 正常應用的啓動纔會走到這裏
......
} else {
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
// 設置在DDMS中的應用名稱
android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());
try {
// 建立Instrumentation對象
// 一個ActivityThread對應一個,能夠監視應用的生命週期
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
// 建立Context對象
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
複製代碼
attach()
方法在system
爲true
的狀況下:
DDMS
中的名稱ContextImpl
和Application
對象Application
對象的onCreate
方法這裏在模仿應用啓動有木有,是哪個APK
呢?
在ContextImpl
對象建立時,使用的是getSystemContext().mPackageInfo
來獲取的Apk
信息,咱們看看:
public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
mSystemContext = ContextImpl.createSystemContext(this);
}
return mSystemContext;
}
}
複製代碼
再看下createSystemContext()
方法:
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
......
return context;
}
複製代碼
createSystemContext()
方法建立了一個LoadedApk
的對象,也就是mPackageInfo
,咱們來看看它只有一個參數的構造方法:
LoadedApk(ActivityThread activityThread) {
mActivityThread = activityThread;
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.packageName = "android";
mPackageName = "android"; // 設置包名爲 android
......
}
複製代碼
LoadedApk
對象用來保存一個已經加載了的apk
文件的信息,上面的構造方法將使用的包名指定爲android
。
還記得Android資源管理篇
的framewok-res.apk
麼,它的包名就是android
。。。
getSystemContext().mPackageInfo
指明的是framwork-res.apk
的信息
還要記得,
framwork-res.apk
的相關資源 在Zygote進程
中的preloading
環節就已經加載完成了喲
因此,createSystemContext()
方法的初始化至關於建立了一個framwork-res.apk
的上下文環境,而後再進行相應的Theme
設置
而對於getSystemUiContext()
和getSystemContext()
這兩個方法,咱們查看ActivityThread
的成員變量就會發現分別對應了mSystemUiContext
和mSystemContext
。這部分在5.0
的源碼中還未出現,應該是Android
後面進行了優化拆分,暫不追究,哈哈哈
到這裏,SystemServer
準備階段的工做已經完成,後面就是啓動一系列的Service
了
SystemServer
啓動階段啓動階段分紅了三步:
startBootstrapServices();
startCoreServices();
startOtherServices();
複製代碼
startBootstrapServices()
startBootstrapServices()
啓動的都是一些很基礎關鍵的服務,這些服務都有很複雜的相互依賴性,咱們來簡單看下:
private void startBootstrapServices() {
......
// Installer 會經過binder關聯 installd 服務
// installd 在Init進程中就會被啓動,很重要,因此放在第一位
// installd 支持不少指令,像ping、rename都是在其中定義的
// 後面在APK安裝篇幅單獨介紹
Installer installer = mSystemServiceManager.startService(Installer.class);
traceEnd();
......
// 添加設備標識符訪問策略服務
mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
......
// 啓動 ActivityManagerService,並進行一些關聯操做
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
// 啓動 PowerManagerService
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
......
// 初始化mActivityManagerServicede的電源管理相關功能
mActivityManagerService.initPowerManagement();
......
// 啓動 RecoverySystemService
// recovery system也是很重要的一個服務
// 能夠觸發ota,設置或清除bootloader相關的數據
mSystemServiceManager.startService(RecoverySystemService.class);
......
// 標記啓動事件
RescueParty.noteBoot(mSystemContext);
// 啓動LightsService,管理LED、背光顯示等
mSystemServiceManager.startService(LightsService.class);
// 通知全部服務當前狀態
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
......// 省略一些看上去不重要的service
// 啓動PackageManagerService
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
......
// 啓動 OverlayManagerService
OverlayManagerService overlayManagerService = new OverlayManagerService(
mSystemContext, installer);
mSystemServiceManager.startService(overlayManagerService);
......
// 啓動 SensorService 這是一個native方法
// SensorService 提供的是各類傳感器的服務
startSensorService();
}
複製代碼
單單startBootstrapServices
啓動的服務就不止10
種,咱們先總結上面的代碼規律。
能夠發現,服務的啓動基本上都是經過SystemServiceManager
的startService()
方法。跟蹤代碼咱們會找到SystemServiceManager
的一個成員變量ArrayList<SystemService> mServices
。
SystemServiceManager
管理的其實就是SystemService
的集合,SystemService
是一個抽象類
若是咱們想定義一個系統服務,就須要實現SystemService
這個抽象類
PackageManagerService
有點特殊,不過這並不影響這種設計模式,後面的章節會單獨學習到它的獨特之處
startCoreServices()
咱們接着看下startCoreServices()
,相對簡潔了不少:
private void startCoreServices() {
// Tracks the battery level. Requires LightService.
// 啓動電池管理service,依賴bootstrap中的LightService
// 該服務會按期廣播電池的相關狀態
mSystemServiceManager.startService(BatteryService.class);
// 啓動 應用使用狀況數據收集服務
mSystemServiceManager.startService(UsageStatsService.class);
// ActivityManagerService 又來橫插一腳,無處不在的傢伙
mActivityManagerService setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class));
......
// 啓動WebView service
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
......
// 啓動 binder 調用的耗時統計服務
BinderCallsStatsService.start();
}
複製代碼
startCoreServices()
啓動的服務看上去也沒那麼核心
不是。
startOtherServices()
再看下startOtherServices()
足足有1000
多行,咱們找下重點
/** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */
// google 形容這部分是混亂的,有待整理重構,確實噁心啊
// 不少服務會依賴其餘的服務,好比NotificationManager會依賴StorageManager......
// 讓咱們來精簡下
private void startOtherServices() {
......// 初始化一些比較基礎的服務
// WindowManagerService、NetworkManagementService
// WatchDog、NetworkPolicyManagerService等
.....// 初始化 UI 相關的服務
// InputMethodManagerService、AccessibilityManagerService
// StorageManagerService、NotificationManagerService
// UiModeManagerService等
......// 此處省略了約800行的各式各樣的服務的初始化
// 有點心疼當時寫這個方法的前輩,預祝聖誕快樂。。。。
// These are needed to propagate to the runnable below.
// 將上面初始化好的一些必要的服務在ActivityManagerService的systemReady中進行進一步的處理
// 須要進一步處理的服務就是下面這些
final NetworkManagementService networkManagementF = networkManagement;
.....
final IpSecService ipSecServiceF = ipSecService;
final WindowManagerService windowManagerF = wm;
// 執行 ActivityManagerService 的 systemReady 方法
mActivityManagerService.systemReady(() -> {
......
// 標記狀態
mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
......
startSystemUi(context, windowManagerF);
......// 對前面建立好的服務作進一步的配置,大可能是執行一些systemReady操做,如:
// networkManagementF.systemReady()、ipSecServiceF.systemReady()、networkStatsF.systemReady()
// connectivityF.systemReady()、networkPolicyF.systemReady(networkPolicyInitReadySignal)
Watchdog.getInstance().start();
// Wait for all packages to be prepared
mPackageManagerService.waitForAppDataPrepared();
......
// 通知全部服務當前狀態
mSystemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
......// 嘗試初次執行一些服務,像定位、地區檢測等
// locationF.systemRunning()、countryDetectorF.systemRunning()、networkTimeUpdaterF.systemRunning()
......
}, BOOT_TIMINGS_TRACE_LOG);
}
複製代碼
註釋很簡潔詳細了哈!
從SystemServer
的啓動階段咱們能夠了解:
SystemServer
啓動的服務是真的多,並且大多數服務之間存在較強的依賴,有着相對嚴格的啓動順序com.android.server.SystemService
(直接繼承或者提供相應的內部類),Installer
和AppWidgetService
分別表明了兩種實現方式
grep
查看相應的繼承類,足足有86
種之多SystemServiceManager
的startService(systemservice)
函數
startService(systemservice)
函數會把要啓動的systemservice
添加到mServices
集合中SystemService
的onStart
抽象方法啓動服務SystemServer
的啓動階段以mActivityManagerService.systemReady()
方法爲終點,這個函數比較吸引人的是:
Runnable
對象,對一些服務進行了額外的處理,這個對象主要是用來:
SystemUI
、Watchdog
等服務systemReady()
和systemRunning()
方法
startHomeActivityLocked()
來廣播通知launcher
啓動好了,適可而止了,本篇是爲了梳理SystemServer
的啓動流程,Launcher
啓動什麼的留在後面詳細學習哈!
接下來看看WatchDog
相關的知識
SystemServer
中的Watchdog
在
Init進程
的學習中咱們介紹了watchdogd
守護進程,這個守護進程會在規定的時間內向硬件看門狗
發送消息表示本身沒出故障;超時看門狗就會重啓設備。
對於SystemServer
進程來講,運行的服務數量超過80種,是最有可能出現問題的進程,所以,有必要對SystemServer
中運行的各類線程實施監控。
可是,若是仿照硬件看門狗
的方式每一個線程定時去喂狗
,不但很是浪費資源,並且會致使程序設計更加複雜。所以,Android
開發了Watchdog
類做爲軟件看門狗
來監控SystemServer
中的線程。一旦發現問題,Watchdog
會殺死SystemServer
進程。
前面在Zygote
進程部分的學習咱們知道:
SystemServer
的父進程Zygote
進程接收到SystemServer
的死亡信號後會殺死本身。Zygote
進程的死亡信號會傳遞給Init
進程,Init
進程會殺死Zygote
進程的全部子進程並重啓Zygote
進程。這樣,整個系統的基礎服務都會重啓一遍。這種軟啓動
的方式能解決大部分問題,而且速度更快。那麼讓咱們來學習下怎麼實現的吧
Watchdog
Watchdog
是繼承自Thread
,在SystemServer
中建立Watchdog
對象是在startOtherServices()
中,代碼以下:
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);
複製代碼
Watchdog
是單例的運行模式,第一次調用getInstance()
會建立Watchdog
對象並保存到全局變量sWatchdog
中,咱們看下構造方法:
private 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());
mOpenFdMonitor = OpenFdMonitor.create();
}
複製代碼
Watchdog
構造方法的主要工做是建立幾個HandlerChecker
對象,並添加到mHandlerCheckers
集合中。
HandlerChecker
對象對應一個被監控的HandlerThread
線程,經過獲取到對應線程的Handler
來與其通訊。HandlerChecker
類的簡要結構以下:public final class HandlerChecker implements Runnable {
private final Handler mHandler;
private final String mName;
private final long mWaitMax;
private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
......
HandlerChecker(Handler handler, String name, long waitMaxMillis) {
mHandler = handler;
mName = name;
mWaitMax = waitMaxMillis;
......
}
public void addMonitor(Monitor monitor) {
mMonitors.add(monitor);
}
}
public interface Monitor {
void monitor();
}
複製代碼
Monitor
接口,若是一個服務須要經過Watchdog
來監控,它必須實現這個Monitor
接口FgThread
、UiThread
、IoThread
、DisplayThread
都是繼承自HandlerThread
。
Android
用它們分別執行不一樣類型的任務,Io相關
、UI相關
等Handler
相關的那一套,你們看看HandlerThread
類就知道了。Watchdog
對象建立後,接下來會調用init()
方法進行初始化,代碼以下:
public void init(Context context, ActivityManagerService activity) {
mResolver = context.getContentResolver();
mActivity = activity;
context.registerReceiver(new RebootRequestReceiver(),
new IntentFilter(Intent.ACTION_REBOOT),
android.Manifest.permission.REBOOT, null);
}
複製代碼
init()
註冊了廣播接收器,當收到Intent.ACTION_REBOOT
的廣播後,會執行重啓操做。
最後,在startOtherServices()
的mActivityManagerService.systemReady()
階段,執行Watchdog
的啓動:
mActivityManagerService.systemReady(() -> {
...
Watchdog.getInstance().start();
...
},...);
複製代碼
Watchdog
監控的服務和線程Watchdog
主要監控線程,在SystemServer
進程中運行着不少線程,它們負責處理一些重要模塊的消息。若是一個線程陷入死循環或者和其餘線程相互死鎖了,Watchdog
須要有辦法識別出它們。
Watchdog
中提供了兩個方法addThread()
和addMonitor()
分別用來增長鬚要監控的線程和服務:
addThread()
用來添加線程監聽:
public void addThread(Handler thread, long timeoutMillis) {
synchronized (this) {
if (isAlive()) {
throw new RuntimeException("Threads can't be added once the Watchdog is running");
}
final String name = thread.getLooper().getThread().getName();
mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
}
}
複製代碼
HandlerChecker
對象並添加到mHandlerCheckers
集合中addMonitor()
用來添加服務的監聽:
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);
}
}
複製代碼
Android
使用mMonitorChecker
一個HandlerChecker
對象來完成mMonitorChecker
在Watchdog
對象初始化時就建立完成經過addThread()
添加監控的線程有:
主線程
FgThread
UiThread
IoThread
DisplayThread
PowerManagerService
的線程PackageManagerService
的線程PermissionManagerService
的線程ActivityManagerService
的線程經過addMonitor()
添加監控的服務有:
NetworkManagementService.java
StorageManagerService.java
ActivityManagerService.java
InputManagerService.java
MediaRouterService.java
MediaSessionService.java
MediaProjectionManagerService.java
PowerManagerService.java
TvRemoteService.java
WindowManagerService.java
複製代碼
Watchdog
監控的原理前面講過,
Binder
調用是在某個Binder
線程中執行的,可是執行的線程並不固定,所以,Watchdog
不能用監控一個普通線程的方法來判斷某個Binder
服務是否正常
若是運行在Binder
線程中的方法使用了全局的資源,就必須創建臨界區
來實施保護。一般的作法是使用synchronized
關鍵字。如:
synchronized (mLock){
......
}
複製代碼
這種狀況下,咱們可使用鎖mLock
持有的時間是否超時來判斷服務是否正常。
而Watchdog
的思想就是:給線程發送消息,若是發送的消息不能在規定的時間內獲得處理,即代表線程被不正常的佔用了。
咱們看下Watchdog
總體流程的實現:
static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
@Override
public void run() {
boolean waitedHalf = false;
while (true) {
final List<HandlerChecker> blockedCheckers;
final String subject;
final boolean allowRestart;
int debuggerWasConnected = 0;
synchronized (this) {
long timeout = CHECK_INTERVAL;
// 經過scheduleCheckLocked給監控的線程發送消息
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
hc.scheduleCheckLocked();
}
......
// 休眠特定的時間,默認爲30s
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) {
// The monitors have returned; reset
waitedHalf = false;
continue;
} else if (waitState == WAITING) {
// still waiting but within their configured intervals; back off and recheck
continue;
} else if (waitState == WAITED_HALF) {
if (!waitedHalf) {
// We've waited half the deadlock-detection interval. Pull a stack
// trace and wait another half.
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
ActivityManagerService.dumpStackTraces(true, pids, null, null,
getInterestingNativePids());
waitedHalf = true;
}
continue;
}
......
// If we got here, that means that the system is most likely hung.
// First collect stack traces from all threads of the system process.
// Then kill this process so that the system will restart.
......
{
Process.killProcess(Process.myPid());
System.exit(10);
}
waitedHalf = false;
}
}
複製代碼
run()
方法中是一個無限循環,每次循環中主要進行:
HandlerChecker
的scheduleCheckLocked
方法給全部受監控的線程發送消息,代碼以下: public void scheduleCheckLocked() {
if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
mCompleted = true;
return;
}
if (!mCompleted) {
// we already have a check in flight, so no need
return;
}
mCompleted = false;
mCurrentMonitor = null;
mStartTime = SystemClock.uptimeMillis();
mHandler.postAtFrontOfQueue(this);
}
複製代碼
HandlerChecker
對象先判斷mMonitors
的size
是否爲0
0
說明當前HandlerChecker
對象沒有監控服務0
:
mCompleted
設爲false
,而後記錄消息發送時間mStartTime
postAtFrontOfQueue
給被監控線程發送一個Runnable
消息postAtFrontOfQueue()
發送的消息的處理方法就是HandlerChecker
的run()
方法: @Override
public void run() {
final int size = mMonitors.size();
for (int i = 0 ; i < size ; i++) {
synchronized (Watchdog.this) {
mCurrentMonitor = mMonitors.get(i);
}
mCurrentMonitor.monitor();
}
synchronized (Watchdog.this) {
mCompleted = true;
mCurrentMonitor = null;
}
}
複製代碼
run()
能執行,說明受監控的線程自己沒有問題monitor()
方法檢查被監控服務的狀態
monitor()
方法的實現是獲取服務中的鎖,若是不能獲得,線程就會掛起,monitor()
一般實現以下:public void monitor(){
sychronized(mLock){}
}
複製代碼
mCompleted
沒法被設置爲true
了mCompleted
設置爲true
,說明HandlerChecker
對象監控的線程或者服務正常。不然就可能有問題。
wait
方法讓Watchdog
休眠特定的一段時間,默認爲30S
evaluateCheckerCompletionLocked()
逐個檢查是否有線程或服務出現問題,一旦發現問題,立刻殺死進程。方法代碼以下: private int evaluateCheckerCompletionLocked() {
int state = COMPLETED;
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
state = Math.max(state, hc.getCompletionStateLocked());
}
return state;
}
複製代碼
evaluateCheckerCompletionLocked()
調用每一個HandlerChecker
的getCompletionStateLocked()
方法來獲取對象的狀態值,getCompletionStateLocked
代碼以下:
public int getCompletionStateLocked() {
if (mCompleted) {
return COMPLETED;
} else {
long latency = SystemClock.uptimeMillis() - mStartTime;
if (latency < mWaitMax/2) {
return WAITING;
} else if (latency < mWaitMax) {
return WAITED_HALF;
}
}
return OVERDUE;
}
複製代碼
狀態值分爲4種:
COMPLETED
:值爲0,表示狀態良好WAITING
:值爲1,表示正在等待消息處理結果WAITED_HALF
:值爲2,表示正在等待而且等待的時間已經大於規定時間的一半,可是還未超過規定時間OVERDUE
:值爲3,表示等待時間已經超過了規定的時間evaluateCheckerCompletionLocked()
但願獲取到最壞的狀況,因此使用Math.max()
來進行比對過濾
SystemServer
自己沒有特別難理解的地方,比較費神的是它維持了太多的服務,start*Services()
閱讀起來太痛苦了,好在:
在服務列表中看到了不少眼熟的服務,像ActivityManagerService
、PackageManagerService
等服務,不至於特別枯燥,讓後續的學習有了些盼頭
關於Watchdog
的學習上,基於HandlerThread
構建的監聽模式很值得學習
下一篇開始學習PackageManagerService
相關的知識,go go go!