图解 Android 系列(二)深刻理解 init 与 zygote 进程

介绍

这是一个连载的系列「图解 Android 系列」,我将持续为你们提供尽量通俗易懂的 Android 源码分析。html

全部引用的源码片断,我都会在第一行标明源文件完整路径。为了文章篇幅考虑源码中间可能有删减,删减部分会用省略号代替。java

本系列源码基于:Android Oreo(8.0)linux

init 进程

在上篇文章 揭秘 Android 系统启动过程 中介绍到,init 进程启动分为先后两部分,前一部分是在内核启动的,主要是完成建立和内核初始化工做,内容都是跟 Linux 内核相关的;后一部分是在用户空间启动的,主要完成 Android 系统的初始化工做。android

Android 系统通常会在根目录下放一个 init 的可执行文件,也就是说 Linux 系统的 init 进程在内核初始化完成后,就直接执行 init 这个文件,这个文件的源代码在 /system/core/init/init.cppios

init 进程

init 进程是 Linux 系统中用户空间的第一个进程(pid = 1),咱们熟悉的 App 应用程序都是以它为父进程的,init 进程入口函数是 main 函数。这个函数作的事情仍是比较多的,主要分为三个部分:c++

  • init 进程第一阶段
  • init 进程第二阶段
  • init.rc 文件解析

第一阶段

咱们先来看第一阶段主要有如下内容:。git

  • ueventd/watchdogd 跳转及环境变量设置。
  • 挂载文件系统并建立目录。
  • 初始化日志输出、挂载分区设备。
  • 启用 SELinux 安全策略。
  • 开始第二阶段前的准备。
//system/core/init/init.cpp

int main(int argc, char** argv) {
  if (!strcmp(basename(argv[0]), "ueventd")) {
    // 1 表示 true,也就执行 ueventd_main,ueventd
    // 主要是负责设备节点的建立、权限设定等一些列工做
    return ueventd_main(argc, argv);
  }
  // watchdogd 俗称看门狗,用于系统出问题时重启系统
  if (!strcmp(basename(argv[0]), "watchdogd")) {
    return watchdogd_main(argc, argv);
  }

  if (REBOOT_BOOTLOADER_ON_PANIC) {
    //初始化重启系统的处理信号,内部经过 sigaction 注册信号,
    //当监听到该信号时重启系统
    install_reboot_signal_handlers();
  }
  //注册环境变量PATH
  add_environment("PATH", _PATH_DEFPATH);
  // init 的 main 方法会执行两次,由 is_first_stage 控制,
  // first_stage 就是第一阶段要作的事
  bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
  // 只执行一次,由于在方法体中有设置 INIT_SECOND_STAGE
  if (is_first_stage) {
    // 清空文件权限
    umask(0);
    // on / and then we'll let the rc file figure out the rest.
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
    mkdir("/dev/socket", 0755);
    mount("devpts", "/dev/pts", "devpts", 0, NULL);
    #define MAKE_STR(x) __STRING(x)
    mount("proc", "/proc", "proc", 0, 
          "hidepid=2,gid=" MAKE_STR(AID_READPROC));
    // Don't expose the raw commandline to unprivileged processes.
    chmod("/proc/cmdline", 0440);
    gid_t groups[] = { AID_READPROC };
    setgroups(arraysize(groups), groups);
    mount("sysfs", "/sys", "sysfs", 0, NULL);
    mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
    mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
    mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
    mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
    // 初始化日志输出
    InitKernelLogging(argv);

    LOG(INFO) << "init first stage started!";

    if (!DoFirstStageMount()) {
      LOG(ERROR) << "Failed to mount required partitions early ...";
      panic();
    }
    // 在刷机模式下初始化avb的版本,不是刷机模式直接跳过
    SetInitAvbVersionInRecovery();

    // 加载S ELinux policy,也就是安全策略
    selinux_initialize(true);

    // We're in the kernel domain, so re-exec init to transition to the init domain now
    // that the SELinux policy has been loaded.
    if (restorecon("/init") == -1) {
      PLOG(ERROR) << "restorecon failed";
      security_failure(); // 失败则重启系统
    }

    setenv("INIT_SECOND_STAGE", "true", 1);

    static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
    uint64_t start_ms = start_time.time_since_epoch().count()
      / kNanosecondsPerMillisecond;
    setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);

    char* path = argv[0];
    char* args[] = { path, nullptr };
    execv(path, args); // 从新执行 main 方法,进入第二阶段

    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(ERROR) << "execv(\"" << path << "\") failed";
    security_failure();
  }

  // ...
}
复制代码

init 进程第一阶段作的主要工做是挂载分区,建立设备节点和一些关键目录,初始化日志输出系统,启用 SELinux 安全策略。github

第二阶段

咱们接着看第二阶段,主要有如下内容:数组

  • 建立进程会话密钥并初始化属性系统。
  • 进行 SELinux 第二阶段并恢复一些文件安全上下文。
  • 新建 epoll 并初始化子进程终止信号处理函数。
  • 设置其余系统属性并开启系统属性服务。
//system/core/init/init.cpp

int main(int argc, char** argv) {
  // 一样进行 ueventd/watchdogd 跳转及环境变量设置
  // 以前准备工做时将 INIT_SECOND_STAGE设 置为 true,
  // 已经不为 nullptr,因此 is_first_stage 为 false
  bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
  // is_first_stage为false,直接跳过
  if (is_first_stage) {
    // ...
  }
  // 初始化日志输出
  InitKernelLogging(argv);
  // ...
  // 初始化属性系统,并从指定文件读取属性
  property_init();
  // ...
  // 初始化子进程退出的信号处理函数
  signal_handler_init();
  // 加载 default.prop 文件
  property_load_boot_defaults();
  export_oem_lock_status();
  // 启动属性服务器
  start_property_service();
  set_usb_controller();
  //...
}
复制代码

init 进程第二阶段主要工做是初始化属性系统,解析 SELinux 的匹配规则,处理子进程终止信号,启动系统属性服务,能够说每一项都很关键。若是说第一阶段是为属性系统、SELinux 作准备,那么第二阶段就是真正去把这些落实的。缓存

解析 init.rc 文件

//system/core/init/init.cpp

int main(int argc, char** argv) {
  // ...
  const BuiltinFunctionMap function_map;
  // 将 function_map 存放到 Action 中做为成员属性
  Action::set_function_map(&function_map);
  // 解析 init.rc 文件
  Parser& parser = Parser::GetInstance();
  parser.AddSectionParser("service",std::make_unique<ServiceParser>());
  parser.AddSectionParser("on", std::make_unique<ActionParser>());
  parser.AddSectionParser("import", std::make_unique<ImportParser>());
  std::string bootscript = GetProperty("ro.boot.init_rc", "");
  // 若是 ro.boot.init_rc 没有对应的值,
  // 则解析 /init.rc 以及 /system/etc/init、/vendor/etc/init、
  // /odm/etc/init 这三个目录下的 .rc 文件
  if (bootscript.empty()) {
    parser.ParseConfig("/init.rc");
    parser.set_is_system_etc_init_loaded(
      parser.ParseConfig("/system/etc/init"));
    parser.set_is_vendor_etc_init_loaded(
      parser.ParseConfig("/vendor/etc/init"));
    parser.set_is_odm_etc_init_loaded(
      parser.ParseConfig("/odm/etc/init"));
  } else { // 若是 ro.boot.init_rc 属性有值就解析属性值
    parser.ParseConfig(bootscript);
    parser.set_is_system_etc_init_loaded(true);
    parser.set_is_vendor_etc_init_loaded(true);
    parser.set_is_odm_etc_init_loaded(true);
  }

  // ...
  ActionManager& am = ActionManager::GetInstance();
  am.QueueEventTrigger("early-init");

  // 等冷插拔设备初始化完成
  am.QueueBuiltinAction(wait_for_coldboot_done_action,
                        "wait_for_coldboot_done");
  // ... so that we can start queuing up actions that require stuff from /dev.
  am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, 
                        "mix_hwrng_into_linux_rng");
  am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
  am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
  // 设备组合键的初始化操做
  am.QueueBuiltinAction(keychord_init_action, "keychord_init");
  // 屏幕上显示 Android 静态 Logo,很熟悉的感受有没有
  am.QueueBuiltinAction(console_init_action, "console_init");

  // Trigger all the boot actions to get us started.
  am.QueueEventTrigger("init");

  // 执行 rc 文件中触发器为 on init 的语句
  am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, 
                        "mix_hwrng_into_linux_rng");

  // 当处于充电模式,则 charger 加入执行队列,不然 late-init 加入队列。
  std::string bootmode = GetProperty("ro.bootmode", "");
  if (bootmode == "charger") {
    am.QueueEventTrigger("charger");
  } else {
    am.QueueEventTrigger("late-init"); // 触发 late-init
  }

  // 触发器为属性是否设置
  am.QueueBuiltinAction(queue_property_triggers_action, 
                        "queue_property_triggers");

  while (true) {
    // By default, sleep until something happens.
    int epoll_timeout_ms = -1;

    if (!(waiting_for_prop 
          || ServiceManager::GetInstance().IsWaitingForExec())) {
      am.ExecuteOneCommand();
    }
    if (!(waiting_for_prop 
          || ServiceManager::GetInstance().IsWaitingForExec())) {
      // 根据须要重启服务 
      restart_processes();

      // If there's a process that needs restarting, wake up in time for that.
      if (process_needs_restart_at != 0) {
        epoll_timeout_ms =
          (process_needs_restart_at - time(nullptr)) * 1000;
        if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
      }

      // If there's more work to do, wake up again immediately.
      if (am.HasMoreCommands()) epoll_timeout_ms = 0;
    }

    epoll_event ev;
    // 循环等待事件发生
    int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, 
                                           epoll_timeout_ms));
    if (nr == -1) {
      PLOG(ERROR) << "epoll_wait failed";
    } else if (nr == 1) {
      ((void (*)()) ev.data.ptr)();
    }
  }

  return 0;
}
复制代码

这一阶段 init 进程作了许多重要的事情,好比解析 init.rc 文件,这里配置了全部须要执行的 action 和须要启动的 service,init 进程根据语法一步步去解析 init.rc,将这些配置转换成一个个数组、队列,而后开启无限循环去处理这些数组、队列中的 command 和 service,而且经过 epoll 监听子进程结束和属性设置。

init.rc 文件

init.rc 文件是 Android 系统的重要配置文件,位于 /system/core/rootdir/ 目录中。 主要功能是定义了系统启动时须要执行的一系列 action 及执行特定动做、设置环境变量和属性和执行特定的 service。

//system/core/rootdir/init.rc

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc // 稍后分析

on early-init
    // ... 
on init
    // ...
on late-init
    // ...
    trigger zygote-start
on post-fs // 挂载文件系统
    load_system_props
    # start essential services
    start logd
    // 熟悉的 servermanager,后面章节再讨论
    start servicemanager
    start hwservicemanager
    start vndservicemanager
    // ...
on post-fs-data // 挂载 data
    # We chown/chmod /data again so because mount is run as root + defaults
    chown system system /data
    chmod 0771 /data
    # We restorecon /data in case the userdata partition has been reset.
    restorecon /data

    # Make sure we have the device encryption key.
    start vold
    // ...

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted // 启动 zygote,稍后分析
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on boot
    // ...
    # Start standard binderized HAL daemons
    class_start hal

    class_start core

复制代码

init 进程会解析 .rc 文件,而后获得一些 service 去启动,这些 service 一般不是普通的服务,文档里面的称呼是daemon(守护进程)。

所谓守护进程就是这些服务进程会在系统初始化时启动,并一直运行于后台,直到系统关闭时终止。

到这里 init 进程的主要流程已经分析完了,咱们总结下 init 进程启动主要作了哪些工做。

init 进程启动流程

首先在 Kernel 内核加载完后会调用 /system/core/init/init.cpp 文件中的 main() 方法。该方法执行分为三个阶段,前两个的阶段都是初始化环境,咱们主要关注下第三个阶段 解析 .rc 文件。

在第三阶段中经过解析 .rc 文件启动了 servicemanagerzygote 等服务,最后 init 进程进入了 loop。

zygote 进程

zygote 进程就是 daemon 其中之一,zygote 进程主要负责建立 Java 虚拟机,加载系统资源,启动 SystemServer 进程,以及在后续运行过程当中启动普通的应用程序。

zygote 进程启动流程

在 init.rc 文件头部有这么一句:

import /init.${ro.zygote}.rc
复制代码

其中 ${ro.zygote} 会被替换成 ro.zyogte 的属性值,这个是由不一样的硬件厂商本身定制的。 有四个值:zygote3二、zygote6四、zygote32_6四、zygote64_32 ,也就是说可能有四种 .rc 文件,分别是:

  • init.zygote32.rc:zygote 进程对应的执行程序是 app_process(纯 32bit 模式)。
  • init.zygote64.rc:zygote 进程对应的执行程序是 app_process64(纯 64bit 模式)。
  • init.zygote32_64.rc:启动两个 zygote 进程(名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process32(主模式)、app_process64。
  • init.zygote64_32.rc:启动两个 zygote 进程(名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process64(主模式)、app_process32。

为何要定义这么多种状况呢?直接定义一个不就行了,这主要是由于 Android 5.0 之后开始支持 64 位程序,为了兼容 32 位和 64 位才这样定义。

不一样的 zygote.rc 内容大体相同,主要区别体如今启动的是 32 位,仍是 64 位的进程。init.zygote32_64.rc 和 init.zygote64_32.rc 会启动两个进程,且存在主次之分。咱们以init.zygote64_32.rc 为例。

//system/core/rootdir/init.zygote64_32.rc

// 进程名称是 zygote,运行的二进制文件在 /system/bin/app_process64,稍后分析
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    //建立一个 socket,名字叫 zygote,以 tcp 形式
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
    
// 另外一个 service,名字 zygote_secondary
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks
复制代码

在 init.rc 文件中能够找到一句 start zygote,这是调用 zygote 服务的启动方式。

//system/core/rootdir/init.rc

// ...
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
// 启动 zygote,稍后分析
on zygote-start && property:ro.crypto.state=unencrypted
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary
复制代码

在 init.zygote64_32.rc 文件中的头部咱们能够看到 zygote 对应的二进制文件是 /system/bin/app_process64 (以此为例),咱们看一下对应的mk文件, 对应的目录在 platform/frameworks/base/cmds/app_process/Android.mk,其实不论是 app_process、app_process32 仍是 app_process64,对应的源文件都是 app_main.cpp。

//frameworks/base/cmds/app_process/Android.mk

// ...
app_process_src_files := \
    app_main.cpp \
// ...
LOCAL_SRC_FILES:= $(app_process_src_files)
// ...
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
// ...
复制代码

app_main.cpp

在 app_main.cpp 的 main 函数中,主要作的事情就是参数解析。 这个函数有两种启动模式:

  • 一种是 zygote 模式,也就是初始化 zygote 进程,传递的参数有 --start-system-server --socket-name=zygote,前者表示启动 SystemServer,后者指定 socket 的名称。
  • 一种是 application 模式,也就是启动普通应用程序,传递的参数有 class 名字以及 class 带的参数。

二者最终都是调用 AppRuntime 对象的 start 函数,加载 ZygoteInit 或 RuntimeInit 两个 Java 类,并将以前整理的参数传入进去。

//frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[]) {
  // 将参数 argv 放到 argv_String 字符串中,而后打印出来
  if (!LOG_NDEBUG) { 
    String8 argv_String;
    for (int i = 0; i < argc; ++i) {
      argv_String.append("\"");
      argv_String.append(argv[i]);
      argv_String.append("\" ");
    }
  }

  AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
  // Process command line arguments
  // ignore argv[0]
  argc--;
  argv++;

  // 全部在 "--" 后面的非 "-" 开头的参数都将传入 vm, 
  // 可是有个例外是 spaced commands 数组中的参数
  const char* spaced_commands[] = { "-cp", "-classpath" };
  // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
  bool known_command = false;

  int i;
  for (i = 0; i < argc; i++) {
    // 将 spaced_commands 中的参数额外加入 VM
    if (known_command == true) {
      runtime.addOption(strdup(argv[i]));
      known_command = false;
      continue;
    }

    for (int j = 0;
         j < static_cast<int>(sizeof(spaced_commands) 
                              / sizeof(spaced_commands[0]));
         ++j) {
      if (strcmp(argv[i], spaced_commands[j]) == 0) {
        known_command = true;
      }
    }

    if (argv[i][0] != '-') {
      break;
    }
    if (argv[i][1] == '-' && argv[i][2] == 0) {
      ++i; // Skip --.
      break;
    }

    runtime.addOption(strdup(argv[i]));
  }

  // Parse runtime arguments.  Stop at first unrecognized option.
  bool zygote = false;
  bool startSystemServer = false;
  bool application = false;
  String8 niceName;
  String8 className;

  ++i;  // Skip unused "parent dir" argument.
  while (i < argc) {
    const char* arg = argv[i++];
    if (strcmp(arg, "--zygote") == 0) {
      zygote = true;
      niceName = ZYGOTE_NICE_NAME;
    } else if (strcmp(arg, "--start-system-server") == 0) {
      startSystemServer = true;
    } else if (strcmp(arg, "--application") == 0) {
      // 表示是 application 启动模式,也就是普通应用程序
      application = true;
    } else if (strncmp(arg, "--nice-name=", 12) == 0) {
      // 进程别名
      niceName.setTo(arg + 12);
    } else if (strncmp(arg, "--", 2) != 0) {
      // application 启动的 class
      className.setTo(arg);
      break;
    } else {
      --i;
      break;
    }
  }

  Vector<String8> args;
  if (!className.isEmpty()) {
    // className 不为空,说明是 application 启动模式
    args.add(application ? String8("application") : String8("tool"));
    // 将 className 和参数设置给 runtime
    runtime.setClassNameAndArgs(className, argc - i, argv + i);

    if (!LOG_NDEBUG) {
      String8 restOfArgs;
      char* const* argv_new = argv + i;
      int argc_new = argc - i;
      for (int k = 0; k < argc_new; ++k) {
        restOfArgs.append("\"");
        restOfArgs.append(argv_new[k]);
        restOfArgs.append("\" ");
      }
    }
  } else { // zygote 启动模式
    // We're in zygote mode.
    maybeCreateDalvikCache(); // 新建 Dalvik 的缓存目录

    if (startSystemServer) { // 加入 start-system-server 参数
      args.add(String8("start-system-server"));
    }

    char prop[PROP_VALUE_MAX];
    if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
      LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                       ABI_LIST_PROPERTY);
      return 11;
    }

    String8 abiFlag("--abi-list=");
    abiFlag.append(prop);
    args.add(abiFlag); // 加入 --abi-list= 参数

    // In zygote mode, pass all remaining arguments to the zygote
    // main() method.
    for (; i < argc; ++i) {
      args.add(String8(argv[i]));
    }
  }

  if (!niceName.isEmpty()) { // 设置进程别名
    runtime.setArgv0(niceName.string(), true /* setProcName */);
  }

  if (zygote) { // 若是是 zygote 启动模式,则加载 ZygoteInit
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
  } else if (className) {
    // 若是是 application 启动模式,则加载 RuntimeInit
    runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
  } else {
    fprintf(stderr, "Error: no class name or --zygote supplied.\n");
    app_usage();
    LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
  }
}
复制代码

咱们看到,在最后调用的是 runtime.start 函数,这个就是要启动虚拟机了,接下来咱们分析 start 函数。

建立虚拟机

//frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, 
                           const Vector<String8>& options, bool zygote) {
  // ...
  // 打印一些日志,获取 ANDROID_ROOT 环境变量
  // ...

  /* start the virtual machine */
  JniInvocation jni_invocation;
  // 初始化JNI,加载 libart.so
  jni_invocation.Init(NULL);
  JNIEnv* env;
  // 建立虚拟机
  if (startVm(&mJavaVM, &env, zygote) != 0) {
    return;
  }
  // 表示虚拟建立完成,可是里面是空实现
  onVmCreated(env);

  /* * Register android functions. * 注册 JNI 函数 */
  if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
  }
  // JNI 方式调用 ZygoteInit 类的 main 函数
  // ...
}
复制代码

虚拟机建立完成后,咱们就能够用 JNI 反射调用 Java 了,其实接下来的语法用过 JNI 的都应该比较熟悉了,直接是 CallStaticVoidMethod 反射调用 ZygoteInit 的 main 函数。

//frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options,
                           bool zygote) {
  // 接下来的这些语法你们应该比较熟悉了,都是 JNI 里的语法,
  // 主要做用就是调用 ZygoteInit 类的 main 函数 
  jclass stringClass;
  jobjectArray strArray;
  jstring classNameStr;

  stringClass = env->FindClass("java/lang/String");
  assert(stringClass != NULL);
  strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
  assert(strArray != NULL);
  classNameStr = env->NewStringUTF(className);
  assert(classNameStr != NULL);
  env->SetObjectArrayElement(strArray, 0, classNameStr);

  for (size_t i = 0; i < options.size(); ++i) {
    jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
    assert(optionsStr != NULL);
    env->SetObjectArrayElement(strArray, i + 1, optionsStr);
  }

  /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */
  // 将 "com.android.internal.os.ZygoteInit" 
  // 转换为 "com/android/internal/os/ZygoteInit"
  char* slashClassName = toSlashClassName(className);
  // 找到 class
  jclass startClass = env->FindClass(slashClassName);
  if (startClass == NULL) {
    ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    /* keep going */
  } else {
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                                  "[Ljava/lang/String;)V");
    if (startMeth == NULL) {
      ALOGE("JavaVM unable to find main() in '%s'\n", className);
      /* keep going */
    } else {// 调用 ZygoteInit.main() 方法
      env->CallStaticVoidMethod(startClass, startMeth, strArray);

      #if 0
      if (env->ExceptionCheck())
        threadExitUncaughtException(env);
      #endif
    }
  }
  free(slashClassName);

  ALOGD("Shutting down VM\n");
  // 退出当前线程
  if (mJavaVM->DetachCurrentThread() != JNI_OK)
    ALOGW("Warning: unable to detach main thread\n");
  // 建立一个线程,该线程会等待全部子线程结束后关闭虚拟机
  if (mJavaVM->DestroyJavaVM() != 0) 
    ALOGW("Warning: VM did not shut down cleanly\n");
}
复制代码

zygote 进程启动主要建立了 Java 虚拟机,有了虚拟机,就能够执行 Java 代码了。

ZygoteInit.java

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

public static void main(String argv[]) {
  ZygoteServer zygoteServer = new ZygoteServer();

  // 标记 zygote 进程已启动
  ZygoteHooks.startZygoteNoThreadCreation();

  // 进入 Zygote 进程
  try {
    Os.setpgid(0, 0);
  } catch (ErrnoException ex) {
    throw new RuntimeException("Failed to setpgid(0,0)", ex);
  }

  try {
    RuntimeInit.enableDdms(); // 开启 DDMS 功能

    boolean startSystemServer = false;
    String socketName = "zygote";
    String abiList = null;
    boolean enableLazyPreload = false;
    for (int i = 1; i < argv.length; i++) {
      if ("start-system-server".equals(argv[i])) {
        startSystemServer = true;
      } else if ("--enable-lazy-preload".equals(argv[i])) {
        enableLazyPreload = true;
      } else if (argv[i].startsWith(ABI_LIST_ARG)) {
        abiList = argv[i].substring(ABI_LIST_ARG.length());
      } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
        socketName = argv[i].substring(SOCKET_NAME_ARG.length());
      } else {
        throw new RuntimeException("Unknown command line argument: "
                                   + argv[i]);
      }
    }

    if (abiList == null) {
      throw new RuntimeException("No ABI list supplied.");
    }

    // 为 zygote 注册 socket
    zygoteServer.registerServerSocket(socketName);
    // 预加载处理
    if (!enableLazyPreload) {
      // zygote 预加载,下面介绍
      preload(bootTimingsTraceLog);
    } else {
      Zygote.resetNicePriority();
    }

    gcAndFinalize(); // GC 操做

    // Zygote process unmounts root storage spaces.
    Zygote.nativeUnmountStorageOnInit();

    // Set seccomp policy
    Seccomp.setPolicy();

    ZygoteHooks.stopZygoteNoThreadCreation();

    if (startSystemServer) { // 启动 system_server,下面介绍
      startSystemServer(abiList, socketName, zygoteServer);
    }

    // 进入循环模式,下面介绍
    zygoteServer.runSelectLoop(abiList);

    zygoteServer.closeServerSocket();
  } catch (Zygote.MethodAndArgsCaller caller) {
    caller.run();
  } catch (Throwable ex) {
    zygoteServer.closeServerSocket();
    throw ex;
  }
}
复制代码

这里 startSystemServer() 方法会抛出一个 Zygote.MethodAndArgsCaller 异常,而后调用到 caller.run(),这里会在 SystemServer 章节继续分析。

preload()

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

static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
  // ...
  // 预加载位于 /system/etc/preloaded-classes 文件中的类
  preloadClasses();
  // 预加载资源,包含 drawable 和 color 资源
  preloadResources();
  // 预加载 OpenGL
  preloadOpenGL();
  // 经过 System.loadLibrary() 方法,
  // 预加载 "android","compiler_rt","jnigraphics" 这 3 个共享库
  preloadSharedLibraries();
  // 预加载 文本链接符资源
  preloadTextResources();
  // 仅用于 zygote 进程,用于内存共享的进程
  WebViewFactory.prepareWebViewInZygote();
  endIcuCachePinning();
  warmUpJcaProviders();
  Log.d(TAG, "end preload");

  sPreloadComplete = true;
}
复制代码

执行 zygote 进程的初始化,对于类加载,采用反射机制 Class.forName() 方法来加载。对于资源加载,主要是 com.android.internal.R.array.preloaded_drawables 和 com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以 com.android.internal.R.xxx 开头的资源,即是此时由 Zygote 加载到内存的。

zygote 进程内加载了 preload() 方法中的全部资源,当须要 fork 新进程时,采用 copy on write 技术,以下:

zygote 进程 fork 进程

startSystemServer()

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

private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller, RuntimeException {
  long capabilities = posixCapabilitiesAsBits(
    OsConstants.CAP_IPC_LOCK,
    OsConstants.CAP_KILL,
    OsConstants.CAP_NET_ADMIN,
    OsConstants.CAP_NET_BIND_SERVICE,
    OsConstants.CAP_NET_BROADCAST,
    OsConstants.CAP_NET_RAW,
    OsConstants.CAP_SYS_MODULE,
    OsConstants.CAP_SYS_NICE,
    OsConstants.CAP_SYS_PTRACE,
    OsConstants.CAP_SYS_TIME,
    OsConstants.CAP_SYS_TTY_CONFIG,
    OsConstants.CAP_WAKE_ALARM
  );
  /* Containers run without this capability, so avoid setting it in that case */
  if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER,
                                   false)) {
    capabilities |= 
      posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
  }
  /* 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,1032,3001,3002,3003,3006,3007,3009,3010",
    "--capabilities=" + capabilities + "," + capabilities,
    "--nice-name=system_server",
    "--runtime-args",
    "com.android.server.SystemServer",
  };
  ZygoteConnection.Arguments parsedArgs = null;

  int pid;

  try {
    // 用于解析参数,生成目标格式
    parsedArgs = new ZygoteConnection.Arguments(args);
    ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
    ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

    /* Request to fork the system server process */
    // fork 子进程,用于运行 system_server
    pid = Zygote.forkSystemServer(
      parsedArgs.uid, parsedArgs.gid,
      parsedArgs.gids,
      parsedArgs.debugFlags,
      null,
      parsedArgs.permittedCapabilities,
      parsedArgs.effectiveCapabilities);
  } catch (IllegalArgumentException ex) {
    throw new RuntimeException(ex);
  }

  /* For child process */
  // 进入子进程 system_server
  if (pid == 0) {
    if (hasSecondZygote(abiList)) {
      waitForSecondaryZygote(socketName);
    }

    zygoteServer.closeServerSocket();
    // 完成 system_server 进程剩余的工做
    handleSystemServerProcess(parsedArgs);
  }

  return true;
}
复制代码

能够看到 zygote 进程 fork 出一个新进程名为 system_server 也就是 SystemServer 进程。该方法是 SystemServer 进程启动的起点,关于 SystemServer 启动流程咱们在后面的章节在讨论,这里先分析完 zygote 的主要流程。

runSelectLoop()

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

void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
  ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
  ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  // mServerSocket 是 socket 通讯中的服务端,即 zygote 进程。保存到 fds[0]
  fds.add(mServerSocket.getFileDescriptor());
  peers.add(null);

  while (true) {
    StructPollfd[] pollFds = new StructPollfd[fds.size()];
    for (int i = 0; i < pollFds.length; ++i) {
      pollFds[i] = new StructPollfd();
      pollFds[i].fd = fds.get(i);
      pollFds[i].events = (short) POLLIN;
    }
    try {
      // 处理轮询状态,当 pollFds 有事件到来则往下执行,不然阻塞在这里
      Os.poll(pollFds, -1);
    } catch (ErrnoException ex) {
      throw new RuntimeException("poll failed", ex);
    }
    for (int i = pollFds.length - 1; i >= 0; --i) {
      // 采用 I/O 多路复用机制,当接收到客户端发出链接请求
      // 或者数据处理请求到来,则往下执行;
      // 不然进入continue,跳出本次循环。
      if ((pollFds[i].revents & POLLIN) == 0) {
        continue;
      }
      if (i == 0) {
        ZygoteConnection newPeer = acceptCommandPeer(abiList);
        peers.add(newPeer);
        fds.add(newPeer.getFileDesciptor());
      } else {
        // i>0,则表明经过 socket 接收来自对端的数据,并执行相应操做
        boolean done = peers.get(i).runOnce(this);
        if (done) {
          peers.remove(i);
          fds.remove(i); // 处理完则从 fds 中移除该文件描述符
        }
      }
    }
  }
}
复制代码

zygote 采用高效的 I/O 多路复用机制,保证在没有客户端链接请求或数据处理时休眠,不然响应客户端的请求。在调用 runSelectLoop() 后 zygote 进入了轮询状态,随时待命当接收到请求建立新进程请求时,当即唤醒并执行相应工做。

总结

到这里 zygote 进程已经启动完成了,Android 系统到目前已经启动了第一个用户进程 zygote。咱们来回顾下目前 Android 系统启动的流程:

zygote 启动流程

当咱们按下电源按键后会启动 Bootloader,Bootloader 会加载 Kernel 内核到内存中,而后会启动内核中的 idle 进程,idle 进程会启动 kthreadd 和 init 两个进程。

init 进程在启动的时候会初始化运行环境,而后解析 init.rc 文件,解析 init.rc 文件的过程当中会启动 servicemanager、zygote 等服务,最后进入 loop 状态。

zygote 服务启动时会建立 Java 虚拟机并初始化 Java 运行环境,而后启动 SystemServer 服务,最后进入 loop 状态。

这篇文章咱们分析到这里,下一篇咱们接着分析 zygote 进程启动中调用 startSystemServer() 方法后 SystemServer 进程启动的流程。

参考资料

个人 Github

github.com/jeanboydev/…

个人公众号

欢迎关注个人公众号,分享各类技术干货,各类学习资料,职业发展和行业动态。

Android 波斯湾

技术交流群

欢迎加入技术交流群,来一块儿交流学习。

QQ 技术交流群

QQ 技术交流群
相关文章
相关标签/搜索