深刻Android系统(九)Android系统的核心-SystemServer进程

SystemServerAndroid系统的核心之一,大部分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()函数forkSystemServer进程
    • 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进程的forkZygote进程会经过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()来调用SystemServermain()方法了

咱们看看SystemServermain()方法干了啥socket

SystemServer初始化

SystemServermain()方法以下: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
    • SystemContextSystemServiceManager的初始化
  • 另外一个是SystemServer的启动阶段:

    • 执行startBootstrapServicesstartCoreServicesstartOtherServices启动全部的系统服务
    • 调用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是应用程序的主线程类
  • 启动应用最后执行到的就是ActivityThreadmain()方法

关键是SystemServer为何要建立ActivityThread对象呢?
实际上SystemServer不只仅是一个单纯的后台进程,它也是一个运行着组件Service的进程,不少系统对话框就是从SystemServer中显示出来的,所以SystemServer自己也须要一个和APK应用相似的上下文环境,建立ActivityThread是获取这个环境的第一步

可是ActivityThreadSystemServer进程中与普通进程仍是有区别的,这里主要是经过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()方法在systemtrue的状况下:

  • 设置进程在DDMS中的名称
  • 建立了ContextImplApplication对象
  • 最后调用了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的成员变量就会发现分别对应了mSystemUiContextmSystemContext。这部分在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种,咱们先总结上面的代码规律。

能够发现,服务的启动基本上都是经过SystemServiceManagerstartService()方法。跟踪代码咱们会找到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(直接继承或者提供相应的内部类),InstallerAppWidgetService分别表明了两种实现方式
    • grep查看相应的继承类,足足有86种之多
  • 系统服务的启动经过SystemServiceManagerstartService(systemservice)函数
    • startService(systemservice)函数会把要启动的systemservice添加到mServices集合中
    • 而后会回调SystemServiceonStart抽象方法启动服务
  • SystemServer的启动阶段以mActivityManagerService.systemReady()方法为终点,这个函数比较吸引人的是:
    • 传入了一个Runnable对象,对一些服务进行了额外的处理,这个对象主要是用来:
      • 启动SystemUIWatchdog等服务
      • 执行一些服务的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接口
  • 构造方法中的FgThreadUiThreadIoThreadDisplayThread都是继承自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对象来完成
    • mMonitorCheckerWatchdog对象初始化时就建立完成

经过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()方法中是一个无限循环,每次循环中主要进行:

  • 调用HandlerCheckerscheduleCheckLocked方法给全部受监控的线程发送消息,代码以下:
    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对象先判断mMonitorssize是否为0
      • 0说明当前HandlerChecker对象没有监控服务
      • 若是此时被监控线程的消息队列处于空闲状态,说明线程运行良好,直接返回
    • 不为0:
      • 则先把mCompleted设为false,而后记录消息发送时间mStartTime
      • 而后调用postAtFrontOfQueue给被监控线程发送一个Runnable消息
  • postAtFrontOfQueue()发送的消息的处理方法就是HandlerCheckerrun()方法:
    @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()调用每一个HandlerCheckergetCompletionStateLocked()方法来获取对象的状态值,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()阅读起来太痛苦了,好在:

  • 在服务列表中看到了不少眼熟的服务,像ActivityManagerServicePackageManagerService等服务,不至于特别枯燥,让后续的学习有了些盼头

  • 关于Watchdog的学习上,基于HandlerThread构建的监听模式很值得学习

下一篇开始学习PackageManagerService相关的知识,go go go!

相关文章
相关标签/搜索