系统中的大管家—SystemServer进程

简介: 上篇说到Android系统的启动流程,Zygote进程fork的第一个进程就是SystemServer进程。

前言


上篇说到Android系统的启动流程,Zygote进程fork的第一个进程就是SystemServer进程。


这个进程负责启动和管理JavaFramework层,也就是提供了框架层的很多服务,比如我们熟知的AMS,PMS,WMS,还有DisplayManagerService、CameraService等等,也就是说它掌握了Android系统中的命脉,是Android系统中的大管家。

一起瞅瞅吧~


(本文源码基于Android9.0)


诞生


之前在Android系统的启动过程中🈶️说到,SystemServer进程是由Zygote进程fork而来。


fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,可以理解为COPY了一个进程出来,而这个新进程就是它的子进程。


而关于SystemServer的诞生,还要从ZygoteInitforkSystemServer方法说起...(只保留主要代码)


private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        //... 
        // 1
        int pid;
        pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        /* For child process */
        if (pid == 0) {
            //2
            zygoteServer.closeServerSocket();
            //3
            return handleSystemServerProcess(parsedArgs);
        }
        return true;
    }
    /**
     * Finish remaining work for the newly forked system server process.
     */
    private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
            //... 
            /*
             * Pass the remaining arguments to SystemServer.
             */
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }
    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        //...
     //4 
        RuntimeInit.commonInit();
        //5
        ZygoteInit.nativeZygoteInit();
        //6
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }


startSystemServer方法中:


  • 1、调用forkSystemServer方法创建了子进程——SystemServer进程
  • 2、fork之后,这里判断了fork的返回值pid是否等于0,如果等于0,就代表fork成功,就处在SystemServer进程中了。然后关闭了从Zygote进程fork带来的Socket对象。
  • 3、然后调用了handleSystemServerProcess方法,并最终走到zygoteInit,做了一些新进程的初始化工作。


zygoteInit方法中:


  • 4、commonInit方法就是做了一些进程通用的初始化工作,比如设置时区,重置log配置。
  • 5、nativeZygoteInit方法通过JNI会走到native层,主要的工作就是创建了新的Binder线程池,这样SystemServer才能和各大app进程进行通信。
  • 6、applicationInit方法,最终会走到findStaticMain方法中,通过反射调用SystemServer类的main方法,简单贴下代码:


protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;
        try {
            cl = Class.forName(className, true, classLoader);
        } 
        //...
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } 
        //...
        return new MethodAndArgsCaller(m, argv);
    }


工作


SystemServer进程创建出来了,并且做了一些初始化工作,接下来就来到了main方法了,顾名思义,肯定要开始正经主要的工作了。


public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run() {
        try {
            //...
            // 1
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            // 2
            System.loadLibrary("android_servers");
            // 3
            performPendingShutdown();
            // 4
            createSystemContext();
            // 5
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd(); 
        }
        //...
        // Start services.
        try {
            //6
            startBootstrapServices();
            //7
            startCoreServices();
            //8
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } 
        //...
        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }


  • 1、准备主线程,Looper。
  • 2、加载动态库。
  • 3、检测上次关机过程是否失败。
  • 4、初始化系统上下文。


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);
    }


在这个方法中,创建了ActivityThread类,获取了上下文,并设置了一些系统主题。


  • 5、创建SystemServiceManager,用于后续的系统服务管理创建等工作。

run方法最后的工作就是启动三个服务类型的服务,也是我们重点关注的,分别是引导服务,核心服务,其他服务


这些服务一共有100多个,关系着Android整个应用生态,下面我们具体说下。


  • 6、启动引导服务


private void startBootstrapServices() {
        //安装APK服务
        traceBeginAndSlog("StartInstaller");
        Installer installer = mSystemServiceManager.startService(Installer.class);
        traceEnd();
        //AMS,负责四大组件的启动调度等工作
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        traceEnd();
        // 管理和显示背光LED等服务
        traceBeginAndSlog("StartLightsService");
        mSystemServiceManager.startService(LightsService.class);
        traceEnd();
        //PMS,负责APK安装,解析卸载等工作
        traceBeginAndSlog("StartPackageManagerService");
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        traceEnd();
        //...
    }


引导服务中,有几个我们毕竟熟悉的,比如AMS、PMS。


  • 7、启动核心服务


private void startCoreServices() {
        traceBeginAndSlog("StartBatteryService");
        // 管理电池相关服务
        mSystemServiceManager.startService(BatteryService.class);
        traceEnd();
        // 收集用户使用时长服务
        traceBeginAndSlog("StartUsageService");
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));
        traceEnd();
        // Webview更新服务
        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
            traceBeginAndSlog("StartWebViewUpdateService");
            mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
            traceEnd();
        }
        //...
    }


  • 8、启动其他服务


private void startOtherServices() {
   //...
            //电话管理服务
            traceBeginAndSlog("StartTelephonyRegistry");
            telephonyRegistry = new TelephonyRegistry(context);
            ServiceManager.addService("telephony.registry", telephonyRegistry);
            traceEnd();    
            //WMS,窗口管理服务,也是打交道比较多的
            traceBeginAndSlog("StartWindowManagerService");
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
            mSensorServiceStart = null;
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());
            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            traceEnd();
            //输入事件管理服务
            traceBeginAndSlog("StartInputManager");
            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
            inputManager.start();
            traceEnd();     
            //...     
}


启动了这么多服务,我们再看一下服务都是怎么具体启动的:


public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            // Create the service.
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } //...
            startService(service);
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }
    // 所有系统服务的集合
    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();    
    public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }


可以看到,首先通过反射创建了对应的Service类,然后把对应的Service加入到mServices集合中,完成注册。然后调用onStart方法启动对应的Service,完成初始化工作。


到这里,SystemServer的启动工作就完成了,再来回顾下,这个过程,到底干了些啥?


  • 首先,Zygote fork了SystemServer这个子进程,然后关闭了原有的socket,创建了新的Binder线程池。
  • 其次,做了一些初始化工作,创建了Context对象,创建了SystemServiceManager类,用于管理所有的系统服务。
  • 最后,启动了三类系统服务,分别是引导服务,核心服务和其他服务。


体系知识延伸


Socket和Binder


我们注意到,在SystemServer被fork出来之后,做了一个操作就是关闭了Sokcet,启动了Binder线程池用于进程间通信。问题来了,为啥Zygote进程是用Socket通信,而SystemServer进程是用Binder进行通信呢?


其实这是两个问题,第一个问题是问为什么Android获取系统服务是用的Binder进程通信呢?


这就涉及到Binder的知识点了,Binder之所以被设计出来,就是因为它有区别于其他IPC方式的两大优点:


  • 性能高,效率高:传统的IPC(套接字、管道、消息队列)需要拷贝两次内存、Binder只需要拷贝一次内存、共享内存不需要拷贝内存。
  • 安全性好:接收方可以从数据包中获取发送发的进程Id和用户Id,方便验证发送方的身份,其他IPC想要实验只能够主动存入,但是这有可能在发送的过程中被修改。


第二个问题就是,为什么Zygote进程不用Binder而用Socket通信呢?这也是wanAndroid中的一个问题:


每日一问 | Activity启动流程中,大部分都是用Binder通讯,为啥跟Zygote通信的时候要用socket呢?(https://www.wanandroid.com/wenda/show/10482)


评论区主要有以下观点:


  • ServiceManager不能保证在zygote起来的时候已经初始化好,所以无法使用Binder。
  • Socket 的所有者是 root,只有系统权限用户才能读写,多了安全保障。
  • Binder工作依赖于多线程,但是fork的时候是不允许存在多线程的,多线程情况下进程fork容易造成死锁,所以就不用Binder了。


Binder线程池


Binder线程池到底是什么?之前有读者也问过类似的问题。


  • Binder线程池位于服务端,它的主要作用就是将每个业务模块的Binder请求统一转发到远程Servie中去执行,从而避免了重复创建Service的过程。也就是服务端只有一个,但是可以处理多个不同客户端的Binder请求。


AMS,PMS,WMS


在SystemServer进程启动的过程中,也启动了很多系统服务,其中就包括和应用交互比较多的三个服务:


  • AMS,ActivityManagerService,负责四大组件的启动,切换,调度工作。
  • PMS,PackageManagerService,负责APK的安装,解析,卸载工作。
  • WMS,WindowManagerService,负责窗口启动,添加,删除等工作。


Android体系架构


思维导图链接


参考


《Android进阶解密》


https://www.wanandroid.com/wenda/show/10482https://blog.csdn.net/yiranfeng/article/details/103550262

目录
相关文章
|
10天前
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第7天】麒麟系统mate-indicators进程占用内存过高问题解决
65 2
|
1月前
|
监控
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
MASM32写的免费软件“ProcView/系统进程监控” V1.4.4003 说明和下载
|
12天前
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第5天】麒麟系统mate-indicators进程占用内存过高问题解决
58 0
|
1月前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
38 1
|
1月前
|
安全 开发者 Python
揭秘Python IPC:进程间的秘密对话,让你的系统编程更上一层楼
【9月更文挑战第8天】在系统编程中,进程间通信(IPC)是实现多进程协作的关键技术。IPC机制如管道、队列、共享内存和套接字,使进程能在独立内存空间中共享信息,提升系统并发性和灵活性。Python提供了丰富的IPC工具,如`multiprocessing.Pipe()`和`multiprocessing.Queue()`,简化了进程间通信的实现。本文将从理论到实践,详细介绍各种IPC机制的特点和应用场景,帮助开发者构建高效、可靠的多进程应用。掌握Python IPC,让系统编程更加得心应手。
29 4
|
29天前
|
监控 API
【原创】用Delphi编写系统进程监控程序
【原创】用Delphi编写系统进程监控程序
|
2月前
|
Linux Python
在Linux中,如何查找系统中占用CPU最高的进程?
在Linux中,如何查找系统中占用CPU最高的进程?
|
2月前
|
Linux
在Linux中,如何查看系统上运行的进程?
在Linux中,如何查看系统上运行的进程?
|
2月前
|
数据安全/隐私保护 异构计算 Windows
【Azure 环境】 介绍两种常规的方法来监视Window系统的CPU高时的进程信息: Performance Monitor 和 Powershell Get-Counter
【Azure 环境】 介绍两种常规的方法来监视Window系统的CPU高时的进程信息: Performance Monitor 和 Powershell Get-Counter
|
2月前
|
Linux Perl
在Linux中,系统目前有许多正在运行的任务,在不重启机器的条件下,有什么方法可以把所有正在运行的进程移除呢?
在Linux中,系统目前有许多正在运行的任务,在不重启机器的条件下,有什么方法可以把所有正在运行的进程移除呢?

相关实验场景

更多