浅谈 Zygote 和 SystemServer

4,058 阅读2分钟

一: Zygote概述

Zygote 进程是Android层面第一个进程(第一个art虚拟机),俗称 进程孵化器,android中所有的进程都是通过 Zygote 分裂(fork)出来的。主要是通过socket的方式与SystemServer通讯的。主要责任是:

  • 预加载通用类, drawable和color资源,openGL以及共享库以及WebView
  • 创建 system_server 进程
  • 创建 socket,runSelectLoop 无限循环,来接收 system_server 的创建进程的命令,来分裂进程

谁创建的 Zygote 进程

Android 系统是基于 Linux系统,在android系统下,当开机的时候 Linux 会创建第一个用户空间进程 init进程。在 init 进程中 会初始化好多东西,init进程的工作是 解析 init.rc 文件,初始化很多服务

init进程 进程作用

  1. servic_emanager :启动 binder IPC,管理所有的 Android 系统服务
  2. media_server:音视频解码器
  3. zygote:进程孵化器,启动 jvm虚拟机 和 分裂 systemserver ,用于android中进程的孵化功能 注册底层功能的 JNI 函数到虚拟机 预加载 Java 类和资源 fork 并启动 system_server 核心进程 作为守护进程监听处理“孵化新进程”的请求

Zygote代码跟踪 android28

当zygote进程创建完毕时会执行 /frameworks/base/cmds/app_process/app_main.cpp 下面的代码 里面会加载 ZygoteInit.java 和RuntimeLnit.java两个类。 然后我们看 ZygoteInit.java 文件的main方法,下面的代码不是所有的代码,我只复制了一些关键的点

 public static void main(String argv[]) {
 	// 创建 ZygoteServer,ZygoteServer作用是用来创建 Socket ,用来接受 创建(fork)子进程的命令
    ZygoteServer zygoteServer = new ZygoteServer();
    
    // 告诉jvm,Zygote 要开始创建了
     ZygoteHooks.startZygoteNoThreadCreation();
    //开启DDMS
    RuntimeInit.enableDdms();
   
   //是否是启动 SystemServer 进程的标志
    boolean startSystemServer = false;
    
   //是否是 让 Zygote 懒加载一些资源的命令
   boolean enableLazyPreload = false;
    for (int i = 1; i < argv.length; i++) {
    	// 是启动 SystemServer 的命令
        if ("start-system-server".equals(argv[i])) {
            startSystemServer = true;
        }else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
        }
        //...
    }
    
    //注册Socket监听,用来接受 创建(fork)子进程的命令
    zygoteServer.registerServerSocketFromEnv(socketName);
    // In some configurations, we avoid preloading resources and classes eagerly.
    // In such cases, we will preload things prior to our first fork.
    // 有些情况是需要预先加载一些类和资源的
    if (!enableLazyPreload) {
        bootTimingsTraceLog.traceBegin("ZygotePreload");
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
            SystemClock.uptimeMillis());
        // 预加载 /system/etc/preloaded-classes 类
        // 预加载资源 图片 和 颜色
       // 预加载OpenGL 等等
        preload(bootTimingsTraceLog);
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
            SystemClock.uptimeMillis());
        bootTimingsTraceLog.traceEnd(); // ZygotePreload
    } else {
        Zygote.resetNicePriority();
    }
    
    // 执行 System.gc();
    gcAndFinalize();
    
    //访问安全
    Zygote.nativeSecurityInit() 
    //沙盒存储 
    Zygote.nativeUnmountStorageOnInit();
    
    // 告诉虚拟机 可以在zygote进程中创建线程了
    ZygoteHooks.stopZygoteNoThreadCreation();
    
    // fork SystemServer 进程
    if (startSystemServer) {
        Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
        // child (system_server) process.
        if (r != null) {
            r.run();
            return;
        }
    }
    
    // socket 进入无线循环中,来接受创建进程的命令
    caller = zygoteServer.runSelectLoop(abiList);

然后看 Zygote 里面的主要两个方法

  • forkAndSpecialize():fork 一个新的进程
  • forkSystemServer():fork 出 SystemServer进程

为什么 Zygote 要用 socket ,而不用 binder的机制呢?

fork是有规则限制的,多线程程序里不准使用fork。然后 binder 的机制是基于多线程的。参考

二:SystemServer

服务进程:是由 Zygote 分裂出来的第一个进程,Android系统多个重要的服务,比如 ActivityManagerService、PackageManagerService、WindowManagerService等等 都是在这里开启的。

SystemServer 代码

SystemServer.main的入口

// 入口
public static void main(String[] args) {
    new SystemServer().run();
}
private void run() {
    try {
       	 traceBeginAndSlog("InitBeforeStartServices");
            // If a device's clock is before 1970 (before 0), a lot of
            // APIs crash dealing with negative numbers, notably
            // java.io.File#setLastModified, so instead we fake it and
            // hope that time from cell towers or NTP fixes it shortly.
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            //
            // Default the timezone property to GMT if not set.
            //
            String timezoneProperty =  SystemProperties.get("persist.sys.timezone");
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                Slog.w(TAG, "Timezone not set; setting to GMT.");
                SystemProperties.set("persist.sys.timezone", "GMT");
            }

            // If the system has "persist.sys.language" and friends set, replace them with
            // "persist.sys.locale". Note that the default locale at this point is calculated
            // using the "-Duser.locale" command line flag. That flag is usually populated by
            // AndroidRuntime using the same set of system properties, but only the system_server
            // and system apps are allowed to set them.
            //
            // NOTE: Most changes made here will need an equivalent change to
            // core/jni/AndroidRuntime.cpp
            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();

                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

            // The system server should never make non-oneway calls
            Binder.setWarnOnBlocking(true);
            // The system server should always load safe labels
            PackageItemInfo.setForceSafeLabels(true);
            // Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
            SQLiteCompatibilityWalFlags.init(null);

            // Here we go!
            Slog.i(TAG, "Entered the Android system server!");
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
            if (!mRuntimeRestart) {
                MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
            }

            // In case the runtime switched since last boot (such as when
            // the old runtime was removed in an OTA), set the system
            // property so that it is in sync. We can | xq oqi't do this in
            // libnativehelper's JniInvocation::Init code where we already
            // had to fallback to a different runtime because it is
            // running as root and we need to be the system user to set
            // the property. http://b/11463182
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            // Mmmmmm... more memory!
            VMRuntime.getRuntime().clearGrowthLimit();

            // The system server has to run all of the time, so it needs to be
            // as efficient as possible with its memory usage.
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

            // Some devices rely on runtime fingerprint generation, so make sure
            // we've defined it before booting further.
            Build.ensureFingerprintProperty();

            // Within the system server, it is an error to access Environment paths without
            // explicitly specifying a user.
            Environment.setUserRequired(true);

            // Within the system server, any incoming Bundles should be defused
            // to avoid throwing BadParcelableException.
            BaseBundle.setShouldDefuse(true);

            // Within the system server, when parceling exceptions, include the stack trace
            Parcel.setStackTraceParceling(true);

            // Ensure binder calls into the system always run at foreground priority.
            BinderInternal.disableBackgroundScheduling(true);

            // Increase the number of binder threads in system_server
            BinderInternal.setMaxThreads(sMaxBinderThreads);
        // Prepare the main looper thread (this thread).
        android.os.Process.setThreadPriority(
            android.os.Process.THREAD_PRIORITY_FOREGROUND);
        android.os.Process.setCanSelfBackground(false);
        // 设置 SystemServer 线程的主 Looper
        Looper.prepareMainLooper();
        Looper.getMainLooper().setSlowLogThresholdMs(
                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

        // Initialize native services.
        System.loadLibrary("android_servers");

      
        // Initialize the system context.
        // 初始化 SystemContext 后面方法会写
        createSystemContext();

        // Create the system service manager.
        // 创建 SystemServiceManager,我们可以通过 SystemServiceManager 来获取到 各种各样的 xxServiceManager
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        mSystemServiceManager.setStartInfo(mRuntimeRestart,
                mRuntimeStartElapsedTime, mRuntimeStartUptime);
         // 把 SystemServiceManager.class 添加到 LocalServices里面
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
    } finally {
    }

    // 开始开启各种各样的服务
    try {
        
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
      
    }

    StrictMode.initVmDefaults(null);
    // Loop forever.
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

这里主要初始化了必要的一些环境参数,比如 系统时间,时区,语言,还有加载一些库,初始化 Looper等等,同样也创建了 SystemServiceManager 用来启动和管理 系统的服务

下面看一下createSystemContext()方法

private void createSystemContext() {
	//ActivityThread是每个android的入口类
    ActivityThread activityThread = ActivityThread.systemMain();
    mSystemContext = activityThread.getSystemContext();
    mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

    final Context systemUiContext = activityThread.getSystemUiContext();
    systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}

创建 SystemServer 中的 ActivityThread,实际上SystemServer不仅仅是一个单纯的后台进程, 它也是运行着组件Service的进程,很多系统的对话框就是从SystemServer中显示出来的,因此, SystemServer本身也需要一个和APK应用类似的上下文环境,创建ActivityThread在SystemServer进程中, 毕竟和普通进程中有区别,因此,这里调用attach()方法时参数为true,表示SystemServer中调用的,系统使用 摘自:SystemServer进程浅析

下面再看启动startBootstrapServices()方法

这个主要启动系统必须要的方服务,比如 AMS,PMS,DispalyMangerService,WMS。等等,下面就看一下怎么启动的这些服务

 private void startBootstrapServices() {
  mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
  
  // 初始化 AMS
 mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
 }
 // 初始化 PowerManagerService
 mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
 
 // 初始化 LightsService
 mSystemServiceManager.startService(LightsService.class);
 
  // 初始化 DisplayManagerService
 mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
 
 // 初始化 PackageManagerService
 mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();

参考

一个APP从启动到主页面显示经历了哪些过程?
一篇文章看明白 Android 系统启动时都干了什么
Android进程系列第二篇---Zygote进程的启动流程
SystemServer进程浅析