笔记:Zygote和SystemServer进程启动过程

简述

Android设备启动过程中,先是Linux内核加载完,接着Android中的第一个进程init启动,它会启动一些需要开机启动的进程。 Zygote就是进程init启动起来的。Android中所有应用程序进程,以及运行系统关键服务的System进程都是由Zygote创建的。它通过复制自身的形式创建其它进程。Zygote在启动时会在内部创建一个虚拟机实例,因此,通过复制Zygote得到的其它应用程序进程和System进程都可以快速地在内部获得一个虚拟机地拷贝。Zygote启动完成后就立即将System进程启动,以便各种关键服务被启动运行。

Zygote的启动

它以服务的形式被启动。

创建虚拟机

进程内创建一个虚拟机实例,并注册一系列JNI方法。 frameworks/base/core/jni/AndroidRuntime.cpp

/* start the virtual machine. */
startVM(&mJavaVM, &env);
/* Register android functions. */
startReg(env);

接下来执行“com.android.internal.os.ZygoteInit”Java类的main方法继续执行启动。

ZygoteInit.main

package com.android.internal.os;
import android.net.LocalServerSocket;
...
public class ZygoteInit {
  private static LocalServerSocket sServerSocket;

  public static void main(String argv[]) {
    ...
    registerZygoteSocket();
    ...
    if (argv[1].equals("true")) {
        startSystemServer();
    } else if (!argv[1].equals("false")) {
        throw new RuntimeException(argv[0] + USAGE_STRING);
    }
    ...
    if (ZYGOTE_FORK_MODE) {
        runForkMode();
    } else {
        runSelectLoopMode();
    }
    ...
    closeServerSocket();
    ...
  }
}

创建Socket

Zygote调用registerZygoteSocket();创建一个LocalServerSocket sServerSocket的Server端Socket,等待以后运行在System进程中的服务ActivityManagerService创建的Client端Socket连接,然后通过Socket进程间通信通知Zygote创建新的应用程序进程。

创建System进程

/**
 * Prepare the arguments and fork for the system server process.
 */
private static boolean startSystemServer()
        throws MethodAndArgsCaller, RuntimeException {
    /* Hardcoded command line to start the system server */
    String args[] = new String[] {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006",
            "--capabilities=130104352,130104352",
            "--rlimit=8,",
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ...
    ZygoteConnection.Arguments parsedArgs = null;
    int pid;

    try {
        parsedArgs = new ZygoteConnection.Arguments(args);

        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids, debugFlags, rlimits,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

变量args保存启动System进程的参数。 Zygote.forkSystemServer()复制当前进程来创建子进程。 handleSystemServerProcess()继续处理System进程的启动。

轮询等待AMS请求创建App进程

private static void runSelectLoopMode() throws MethodAndArgsCaller {
  ArrayList<FileDescriptor> fds = new ArrayList();
  ArrayList<ZygoteConnection> peers = new ArrayList();
  FileDescriptor[] fdArray = new FileDescriptor[4];

  fds.add(sServerSocket.getFileDescriptor());
  peers.add(null);

  while (true) {
    ...
      try {
          fdArray = fds.toArray(fdArray);
          index = selectReadable(fdArray);
      } catch (IOException ex) {
          throw new RuntimeException("Error in select()", ex);
      }

      if (index < 0) {
          throw new RuntimeException("Error in select()");
      } else if (index == 0) {
          ZygoteConnection newPeer = acceptCommandPeer();
          peers.add(newPeer);
          fds.add(newPeer.getFileDesciptor());
      } else {
          boolean done;
          done = peers.get(index).runOnce();

          if (done) {
              peers.remove(index);
              fds.remove(index);
          }
      }
  }
}

/**
 * Waits for and accepts a single command connection. Throws
 * RuntimeException on failure.
 */
private static ZygoteConnection acceptCommandPeer() {
    try {
        return new ZygoteConnection(sServerSocket.accept());
    } catch (IOException ex) {
        throw new RuntimeException(
                "IOException during accept()", ex);
    }
}

无限循环,等待来自AMS创建的Socket连接。 sServerSocket在fds[0]位置。 每当accept()返回一个连接后,将对应此连接的newPeer.getFileDesciptor()套接字描述添加到fds(第0位置后),下一次读取到数据时,若在fds[0]以后的,说明是前面的newPeer连接收到的AMS的创建新应用程序进程的请求。 runOnce()用来处理AMS创建新应用程序进程的请求。

System进程的启动

ZygoteInit.handleSystemServerProcess()执行System进程的启动操作。

ZygoteInit.handleSystemServerProcess()

private static void handleSystemServerProcess(
      ZygoteConnection.Arguments parsedArgs)
      throws ZygoteInit.MethodAndArgsCaller {

  closeServerSocket();

  /*
   * Pass the remaining arguments to SystemServer.
   * "--nice-name=system_server com.android.server.SystemServer"
   */
  RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
  /* should never reach here */
}

Zygote复制自身创建的子进程做为System进程,这样它得到了Zygote的Server Socket,但是用不到,所以第一句closeServerSocket()关闭此套接字。

RuntimeInit.zygoteInit

package com.android.internal.os;

public class RuntimeInit {
  public static final void zygoteInit(String[] argv)
          throws ZygoteInit.MethodAndArgsCaller {
      ...
      commonInit();
      zygoteInitNative();
      ...
      // Remaining arguments are passed to the start class's static main
      String startClass = argv[curArg++];
      String[] startArgs = new String[argv.length - curArg];

      System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
      invokeStaticMain(startClass, startArgs);
  }  
}

zygoteInitNative()在System进程中启动一个Binder线程池。 RuntimeInit.invokeStaticMain()静态方法调用"com.android.server.SystemServer"的main方法。

SystemServer.main

传递调用native方法init1():

class SystemServer {
  /**
     * This method is called from Zygote to initialize the system. This will cause the native
     * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
     * up into init2() to start the Android services.
     */
    native public static void init1(String[] args);
}

init1()的工作: 注册Service Manager的死亡通知:调用binderDied()。System进程执行kill结束自己。

创建SurfaceFlinger、和SensorService两个服务。

返回SystemServer.init2()继续启动java语言开发的系统服务。

SystemServer.init2

public static final void init2() {
    Thread thr = new ServerThread();
    thr.setName("android.server.ServerThread");
    thr.start();
}

ServerThread继承自Thread。

ServerThread.run

class ServerThread extends Thread {
  @Override
  public void run() {
      Looper.prepare();
      ...
      // Critical services...
      try {
          ...
          Slog.i(TAG, "Activity Manager");
          context = ActivityManagerService.main(factoryTest);
          ...
          Slog.i(TAG, "Package Manager");
          pm = PackageManagerService.main(context,
                  factoryTest != SystemServer.FACTORY_TEST_OFF);
          ...
          Slog.i(TAG, "Content Manager");
          ContentService.main(context,
                  factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
          ...
          Slog.i(TAG, "Window Manager");
          wm = WindowManagerService.main(context, power,
                  factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
          ServiceManager.addService(Context.WINDOW_SERVICE, wm);
          ...
          ((ActivityManagerService)ServiceManager.getService("activity"))
                  .setWindowManager(wm);
          ...
      } catch (RuntimeException e) {
          Slog.e("System", "Failure starting core service", e);
      }
      ...
      Looper.loop();
      Slog.d(TAG, "System ServerThread is exiting!");
  }
}

启动各个Service然后注册到ServiceManager。 各个服务都使用Binder和其它服务使用者进程进行就行交互。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏辣子鸡的技术分享

Mybatis自动代码生成器的实现

原博地址https://laboo.top/2018/11/26/a-db/#more

13360
来自专栏刘望舒

Android PMS的创建过程

PMS的创建过程分为两个部分进行讲解,分别是SyetemServer处理部分和PMS构造方法。其中SyetemServer处理部分和AMS和WMS的创建过程是类...

12730
来自专栏iOS 开发杂谈

iOS 开发小技巧

在使用view的缩放的时候,layer.border.width随着view的放大,会出现锯齿化的问题,解决这个问题需要设置这个属性。

14630
来自专栏JackeyGao的博客

Django小技巧20: 使用多个settings模块

通常来说, 为了保持项目的配置简单,我们会避免使用多个配置文件。但理想很丰满, 现实是随着项目越来越大, settings.py可能也会变得相当复杂. 在那种情...

79010
来自专栏社区的朋友们

Node 架构从三层到 N 层,实现代码重用和解耦

三层架构通常意义上是将整个业务应用划分为:控制层、业务逻辑层以及数据访问层,三层架构在 Java Web 项目中很常见,那么这种架构能否运用在 Node 项目中...

2.3K20
来自专栏FreeBuf

远程RPC溢出EXP编写实战之MS06-040

0x01 前言 MS06-040算是个比较老的洞了,在当年影响十分之广,基本上Microsoft大部分操作系统都受到了影响,威力不亚于17年爆出的”永恒之蓝”漏...

342100
来自专栏SDNLAB

Ryu:如何在LLDP中添加自定义LLDPDU

在许多实验场景中,都需要使用链路发现协议(LLDP)来发现链路,从而构建网络拓扑。然而LLDP协议不仅仅可以用来发现拓扑,也可以用于时延检测等业务。LLDP通过...

43060
来自专栏Golang语言社区

写在学习golang一个月后

连接池。由于PHP没有连接池,当高并发时就会有大量的数据库连接直接冲击到MySQL上,最终导致数据库挂掉。虽然Swoole有连接池,但是Swoole只是PHP的...

29720
来自专栏Bug生活2048

.net core下配置、数据库访问等操作实现

.net core下读取配置还是有点麻烦的,本身没有System.Configuration.dll,所以在进行配置前需要自行引用Microsoft.Exten...

9520
来自专栏北京马哥教育

Linux ext4无法使用超过16T磁盘的解决办法

系统环境:Centos6.7 x86_64 己updte 磁盘:12*4T raid5 +hot 说明:操作系统与归档都使用同一个raid5 应用环境:邮局系统...

40960

扫码关注云+社区

领取腾讯云代金券