Android系统启动流程(三)解析SyetemServer进程启动过程

刘望舒 等级 1208 2 0

上一篇我们学习了Zygote进程,并且知道Zygote进程启动了SyetemServer进程,那么这一篇我们就来学习Android7.0版本的SyetemServer进程的启动过程。" tag:

  • Android框架层
  • Android系统启动 categories:
  • Android框架层

本文首发于微信公众号「刘望舒」

前言

上一篇我们学习了Zygote进程,并且知道Zygote进程启动了SyetemServer进程,那么这一篇我们就来学习Android7.0版本的SyetemServer进程的启动过程。

1.Zygote启动SyetemServer进程

在上一篇文章中我们讲到在ZygoteInit.java的startSystemServer函数中启动了SyetemServer进程,如下所示。 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

 private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
     ...
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }

在startSystemServer函数中调用handleSystemServerProcess来启动SyetemServer进程。

2.SyetemServer进程启动过程

handleSystemServerProcess函数的代码如下所示。

  private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {
        closeServerSocket();//1
      ...
        if (parsedArgs.invokeWith != null) {
           ...
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                cl = createSystemServerClassLoader(systemServerClasspath,
                                                   parsedArgs.targetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);//2
        }
    }

SyetemServer进程是复制了Zygote进程的地址空间,因此也会得到Zygote进程创建的Socket,这个Socket对于SyetemServer进程没有用处,因此,需要注释1处的代码来关闭该Socket。在注释2处调用RuntimeInit的zygoteInit函数,它的代码如下所示。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();
        commonInit();
        nativeZygoteInit();//1
        applicationInit(targetSdkVersion, argv, classLoader);//2
    }

注释1处调用nativeZygoteInit函数,一看函数的名称就知道调用Native层的代码。

启动Binder线程池

接着我们来查看nativeZygoteInit函数对用的JNI文件,如下所示。 frameworks/base/core/jni/AndroidRuntime.cpp

static const JNINativeMethod gMethods[] = {
    { "nativeFinishInit", "()V",
        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
    { "nativeZygoteInit", "()V",
        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
    { "nativeSetExitWithoutCleanup", "(Z)V",
        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};

通过JNI的gMethods数组,可以看出nativeZygoteInit函数对应的是JNI文件AndroidRuntime.cpp的com_android_internal_os_RuntimeInit_nativeZygoteInit函数:

...
static AndroidRuntime* gCurRuntime = NULL;
...
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

这里gCurRuntime是AndroidRuntime类型的指针,AndroidRuntime的子类AppRuntime在app_main.cpp中定义,我们来查看AppRuntime的onZygoteInit函数,代码如下所示。 frameworks/base/cmds/app_process/app_main.cpp

 virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();//1
    }

注释1处的代码用来启动一个Binder线程池,这样SyetemServer进程就可以使用Binder来与其他进程进行通信了。看到这里我们知道RuntimeInit.java的nativeZygoteInit函数主要做的就是启动Binder线程池。

invokeStaticMain

我们再回到RuntimeInit.java的代码,在注释2处调用了applicationInit函数,代码如下所示。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

  private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
...
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

applicationInit函数中主要调用了invokeStaticMain函数:

   private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;
        try {
            cl = Class.forName(className, true, classLoader);//1
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });//2
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }
        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);//3
    }

注释1处className为“com.android.server.SystemServer",因此通过反射返回的cl为SystemServer类。注释2处找到SystemServer中的main函数。在注释3处将找到的main函数传入到MethodAndArgsCaller异常中并抛出该异常。截获MethodAndArgsCaller异常的代码在ZygoteInit.java的main函数中,如下所示。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

  public static void main(String argv[]) {
       ...
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();//1
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

在注释1处调用了MethodAndArgsCaller的run函数:

   public void run() {
        try {
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
         ...
        }
    }
}

这里mMethod指的就是SystemServer的main函数,因此main函数被动态调用。

3.解析SyetemServer进程

我们先来查看SystemServer的main函数: frameworks/base/services/java/com/android/server/SystemServer.java

 public static void main(String[] args) {
        new SystemServer().run();
    }

main函数中只调用了SystemServer的run函数,如下所示。

 private void run() {
        ...
            System.loadLibrary("android_servers");//1
        ...
            mSystemServiceManager = new SystemServiceManager(mSystemContext);//2
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        ...    
         try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();//3
            startCoreServices();//4
            startOtherServices();//5
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
        ...
    }

run函数代码很多,关键就是在注释1处加载了libandroid_servers.so。接下来在注释2处创建SystemServiceManager,它会对系统的服务进行创建、启动和生命周期管理。启动系统的各种服务,在注释3中的startBootstrapServices函数中用SystemServiceManager启动了ActivityManagerService、PowerManagerService、PackageManagerService等服务。在注释4处的函数中则启动了BatteryService、UsageStatsService和WebViewUpdateService。注释5处的startOtherServices函数中则启动了CameraService、AlarmManagerService、VrManagerService等服务,这些服务的父类为SystemService。从注释3、4、5的函数可以看出,官方把系统服务分为了三种类型,分别是引导服务、核心服务和其他服务,其中其他服务为一些非紧要和一些不需要立即启动的服务。系统服务大约有80多个,这里列出部分系统服务以及它们的作用如下表所示:

引导服务 作用
Installer 系统安装apk时的一个服务类,启动完成Installer服务之后才能启动其他的系统服务
ActivityManagerService 负责四大组件的启动、切换、调度。
PowerManagerService 计算系统中和Power相关的计算,然后决策系统应该如何反应
LightsService 管理和显示背光LED
DisplayManagerService 用来管理所有显示设备
UserManagerService 多用户模式管理
SensorService 为系统提供各种感应器服务
PackageManagerService 用来对apk进行安装、解析、删除、卸载等等操作
核心服务
BatteryService 管理电池相关的服务
UsageStatsService 收集用户使用每一个APP的频率、使用时常
WebViewUpdateService WebView更新服务
其他服务
CameraService 摄像头相关服务
AlarmManagerService 全局定时器管理服务
InputManagerService 管理输入事件
WindowManagerService 窗口管理服务
VrManagerService VR模式管理服务
BluetoothService 蓝牙管理服务
NotificationManagerService 通知管理服务
DeviceStorageMonitorService 存储相关管理服务
LocationManagerService 定位管理服务
AudioService 音频相关管理服务
... ....

比如要启动PowerManagerService则会调用如下代码:

mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

SystemServiceManager的startService函数启动了PowerManagerService,startService函数如下所示。

frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

  public <T extends SystemService> T startService(Class<T> serviceClass) {
  ...
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);//1
            } catch (InstantiationException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service could not be instantiated", ex);
            }
...
            // Register it.
            mServices.add(service);//2
            // Start it.
            try {
                service.onStart();
            } catch (RuntimeException ex) {
                throw new RuntimeException("Failed to start service " + name
                        + ": onStart threw an exception", ex);
            }
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

注释1处的代码用来创建SystemService,这里的SystemService是PowerManagerService,在注释2处将PowerManagerService添加到mServices中,这里mServices是一个存储SystemService类型的ArrayList。接着调用PowerManagerService的onStart函数启动PowerManagerService并返回,这样就完成了PowerManagerService启动的过程。 除了用mSystemServiceManager的startService函数来启动系统服务外,也可以通过如下形式来启动系统服务,以PackageManagerService为例:

 mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

直接调用了PackageManagerService的main函数: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.
    PackageManagerServiceCompilerMapping.checkProperties();
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);//1
    m.enableSystemUserPackages();
    // Disable any carrier apps. We do this very early in boot to prevent the apps from being
    // disabled after already being started.
    CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
            UserHandle.USER_SYSTEM);
    ServiceManager.addService("package", m);//2
    return m;
}

注释1处直接创建PackageManagerService并在注释2处将PackageManagerService注册到ServiceManager中,ServiceManager用来管理系统中的各种Service,用于系统C/S架构中的Binder机制通信:Client端要使用某个Service,则需要先到ServiceManager查询Service的相关信息,然后根据Service的相关信息与Service所在的Server进程建立通讯通路,这样Client端就可以使用Service了。还有的服务是直接注册到ServiceManager中的,如下所示。

frameworks/base/services/java/com/android/server/SystemServer.java

  telephonyRegistry = new TelephonyRegistry(context);
  ServiceManager.addService("telephony.registry", telephonyRegistry);

4.总结SyetemServer进程

SyetemServer在启动时做了如下工作: 1.启动Binder线程池,这样就可以与其他进程进行通信。 2.创建SystemServiceManager用于对系统的服务进行创建、启动和生命周期管理。 3.启动各种系统服务。

收藏
评论区

相关推荐

Android开发 常见异常和解决办法(一)
Android Studio是Android开发的理想工具,但是由于版本的更新和配置的差异,会出现很多问题,下面是以《第一行代码 第二版》为基础进行开发学习可能遇见的一些问题及其解决办法。 1.Android Studio 3.0及以上版本找不到Android Device Monitor: 解决办法: (1)在Android Studio中打开终端,如下
安卓内存优化
Android内存 1.Android内存分配与回收机制 从Application Framework、Dalvik/Art、Linux内核三个部分来讲解关于Androd内存相关的知识 (1)Application Framework (https://imghelloworld.osscnbeijing.a
Android系统启动流程(三)解析SyetemServer进程启动过程
上一篇我们学习了Zygote进程,并且知道Zygote进程启动了SyetemServer进程,那么这一篇我们就来学习Android7.0版本的SyetemServer进程的启动过程。"tag: Android框架层 Android系统启动categories: Android框架层本文首发于微信公众号「刘望舒」 前言上一
Android系统启动流程(四)Launcher启动过程与系统启动流程
Android框架层 Android系统启动categories: Android框架层本文首发于微信公众号「刘望舒」 前言此前的文章我们学习了init进程、Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三
Android AOSP基础(一)VirtualBox 安装 Ubuntu
AOSP基础 Android框架层本文首发于微信公众号「刘望舒」 前言在Android进阶三部曲第二部《Android进阶解密》的第一章,我介绍了两种阅读源码的方式,其中一种是从百度网盘:https://pan.baidu.com/s/1ngsZs 将源码下载下来,然后用SouceInsight来查看,这种方式很便捷,适合去阅读源码,但是有两个弊端,一个是无
Android包管理机制(四)PMS的创建过程
Android框架层 Android包管理机制 Android框架层本文首发于微信公众号「刘望舒」<!more 前言PMS的创建过程分为两个部分进行讲解,分别是SyetemServer处理部分和PMS构造方法。其中SyetemServer处理部分和AMS和WMS的创建过程是类似的,可以将它们进行对比,这样可以更好的理解和记忆这一知识点。 1. SyetemS
Java后端部署以及与Android通信注意事项
1 概述 ==== 本文列举了一些`Android`+后端`Java`通信/部署时的问题以及注意事项,覆盖的问题包括但不限于安全组、数据库、路径等,如果各位读者的`Android`端不能正常访问`Java`后端,希望这里的解决方案能帮助到您。 2 分类 ==== 这里将问题分为三类: * `Java`端问题 * `Android`端问题 *
java编程中使用二进制进行权限或状态控制
直接看代码以及注释吧。 @Test public void main() { // PC WEB端 int pc = 1 << 0;// ...0001=1 // Android端 int android = 1 <<
Android二维码扫码ZXing,barcodescanner和BGAQRCode
**Android二维码扫码ZXing,barcodescanner和BGAQRCode-Android技术比较** Android二维码扫描是一种常见的功能开发,但是技术选型不当会造成初期开发难度大、后期维护成本高。常见的Android二维码扫码解决方案很多,比如ZXing,barcodescanner和BGAQRCode-Android等等。以下给出这
2020年了,Android后台保活还有戏吗?看我如何优雅的实现!
1、引言 ======= 对于移动端IM应用和消息推送应用的开发者来说,Android后台保活这件事是再熟悉不过了。 自从Android P(即Android 8.0)出现以后,Android已经从系统层面将后台保活这条路给堵死了(详见:《[Android P正式版即将到来:后台应用保活、消息推送的真正噩梦](https://www.oschina
2020年了,Android后台保活还有戏吗?看我如何优雅的实现!
1、引言 ======= 对于移动端IM应用和消息推送应用的开发者来说,Android后台保活这件事是再熟悉不过了。 自从Android P(即Android 8.0)出现以后,Android已经从系统层面将后台保活这条路给堵死了(详见:《[Android P正式版即将到来:后台应用保活、消息推送的真正噩梦](https://www.oschina
Android 开发技术周报 Issue#294
### 新闻 1. [以隐私安全之名 Android 11砍掉了第三方相机应用选择器](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.cnbeta.com%2Farticles%2Ftech%2F1017621.htm) 2. [Android端自动填充功能现支持生
AndroidStudio环境安装与配置
前言 == 大家好,给大家带来`AndroidStudio环境安装与配置`的概述,希望你们喜欢 AndroidStudio IDE下载 ------------------- 我们选择用Android Studio开发Android的App,Android Studio提供给Windows、MacOS、Linux三个平台 官方下载地址:[Android
Android的消息处理机制(图+源码分析)——Looper,Handler,Message
作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了。这不,前几天为了了解android的消息处理机制,我看了**Looper,Handler,
DCloud
**ylbtech-DCloud-MUI:Hello mui** MUI-最接近原生App体验的前端框架 **1.** 返回顶部 1、 MUI-最接近原生App体验的前端框架 **极小** 100k的js文件,60k的css文件。原生编写,不依赖任何三方框架 **极强** xcode和Android studio里所有原生控件都具备 **高