Android zygote 进程启动分析

本文详细分析了Android系统中zygote进程的启动过程,包括zygote如何由init进程创建,创建虚拟机,预加载资源,注册JNI方法,启动system_server以及待命处理任务请求等关键步骤。通过对Android 6.0.1系统中zygote启动的解析,揭示了Java层系统服务和应用进程启动的基础。
摘要由CSDN通过智能技术生成

Android zygote 进程启动分析

前言

zygote 进程是 Android 系统中第一个拥有 Java 运行环境的进程,它由用户空间 1 号进程 init 进程通过解析 init.rc 文件创建,从 init 进程 fork 而来。从 zygote(受精卵)这个富含生物意义的名字可以知道,它是一个孵化器。Android 系统中所有运行在 Java 虚拟机中的系统服务以及应用均由 zygote 进程孵化而来。

理解 zygote 进程的启动过程以及所做的工作,将为理解 Java 层系统服务以及所有应用的进程启动流程打下基础。

概述

zygote 通过克隆(fork)的方式创建子进程,fork 出来的子进程将继承父进程的所有资源,基于这个特性,zygote 进程在启动过程将创建 Java ART 虚拟机,预加载一个 Java 进程需要的所有系统资源,之后子进程被创建后,就可以直接使用这些资源运行了。

自 Android 5.0 系统开始,zygote 不再是一个进程,而是两个进程,一个是 32 位 zygote,负责孵化 32 位进程(为了兼容使用了 armeabi 和 armeabi-v7a 等 32 位架构的本地动态库的应用),另一个是 64 位 zygote 进程,负责孵化 64 位应用进程(可加载 arm64-v8a 等 64 位架构本地库)。

zygote 进程主要做了如下工作:

  1. 创建虚拟机,加载系统 Java 类以及注册系统类所依赖的 JNI 方法;
  2. 预加载应用程序进程所需的 drawable 和 color 资源,准备 WebView 和 OpenGL;
  3. 创建 socket 服务端,以便接收和处理创建应用进程的请求;
  4. 启动 system_server 服务进程,用于承载整个 framework 层运行的系统服务;
  5. 待命以随即处理到来的任务请求。

参考相关资料,对 Android 6.0.1 系统中 zygote 进程启动关键流程进行分析。

zygote 进程启动

zygote 进程由 init 解析 init.rc 文件启动,首先看一下启动 zygote 的 rc 文件内容:

32 位 zygote 启动内容在 init.zygote32.rc 文件中,64 位 zygote 启动内容在 init.zygote64.rc 中:

提示:自 Android 9.0 系统开始,两个 zygote 启动配置放在一个文件中:init.zygote64_32.rc。

# init.zygote32.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks
# init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

两者的唯一区别只在于可执行文件的不同,/system/bin/app_process/system/bin/app_process64

zygote 将在如下情况下重启:

  1. servicemanager 进程死亡(启动配置中包含 onrestart restart zygote);
  2. surfaceflinger 进程死亡(启动配置中包含 onrestart restart zygote);
  3. Zygote 死亡(启动配置中为非 oneshot);
  4. system_server 进程死亡;

zygote 进程入口

zygote 可执行文件 app_process 的实现代码在 frameworks/base/cmds/app_process/app_main.cpp 中,入口为 main 函数:

// app_main.cpp

// ...
#if defined(__LP64__)
// 如果为 64 位进程,则进程名为 "zygote64",否则为 "zygote"
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif

int main(int argc, char* const argv[])
{
   
  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
   
    // 旧版内核不识别 PR_SET_NO_NEW_PRIVS,将返回 EINVAL,避免在旧版内核上死掉
    if (errno != EINVAL) {
   
      LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
      return 12;
    }
  }

  // argv[0] = "/system/bin/app_process"
  AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
  // 跳过 argv[0] 参数
  argc--;
  argv++;

  // 直到遇到 '-' 或第一个非 '-' 的参数为止的所有内容都将提供给虚拟机作为 options。
  //
  // --zygote:             启动到 zygote 模式
  // --start-system-server:启动 system server
  // --application:	    以应用程序模式启动 (独立启动, 非 zygote)
  // --nice-name:	    给进程起一个好名字
  //
  // 对于非 zygote 启动,这些参数后面将是主类名,所有其余的参数都传递给此类的 main 方法;
  // 对于 zygote 启动,所有剩余的参数都传递给 zygote 的 main 方法。

  int i;
  for (i = 0; i < argc; i++) {
   
    if (argv[i][0] != '-') {
   
      break;
    }
    if (argv[i][1] == '-' && argv[i][2] == 0) {
   
      ++i;
      break;
    }
    runtime.addOption(strdup(argv[i]));
  }

  bool zygote = false;
  bool startSystemServer = false;
  bool application = false;
  String8 niceName;
  String8 className;

  ++i;
  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 = true;
    } else if (strncmp(arg, "--nice-name=", 12) == 0) {
   
      niceName.setTo(arg + 12);
    } else if (strncmp(arg, "--", 2) != 0) {
   
      className.setTo(arg);
      break;
    } else {
   
      --i;
      break;
    }
  }

  Vector<String8> args;
  if (!className.isEmpty()) {
   
    // 没有处于 zygote 模式
    args.add(application ? String8("application") : String8("tool"));
    runtime.setClassNameAndArgs(className, argc - i, argv + i);
  } else {
   
    // className 为空,处于 zygote 模式

    // 创建 /data/dalvik-cache/ 目录
    maybeCreateDalvikCache();

    if (startSystemServer) {
   
      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);
    // 获取支持的 abi 列表
    args.add(abiFlag);

    // 在 zygote 模式下,将所有剩余参数传递给 zygote 的 main() 方法。
    for (; i < argc; ++i) {
   
      args.add(String8(argv[i]));
    }
  }

  if (!niceName.isEmpty()) {
   
    // 设置进程名字
    runtime.setArgv0(niceName.string());
    set_process_name(niceName.string());
  }

  if (zygote) {
   
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
  } else if (className) {
   
    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.");
    return 10;
  }
}

AppRuntime.main 函数做了如下工作:

  1. 创建了 AppRuntime 对象,传入虚拟机所需的选项;
  2. 解析 init.rc 文件的 zygote 启动参数;
  3. 调用 AppRuntime.start 函数,根据启动 zygote 还是命令行(className),进入 ZygoteInit 或者 RuntimeInit 参数分支。

提示:app_process 可使用命令行调用,启动一个 Java 类,并调用 main 方法,此时有 className 参数,处于非 zygote 模式。

格式:

app_process [可选参数] 命令所在路径 启动的类名 [可选参数]

示例:

app_process -Djava.class.path=Hello.dex /data/local/ com.example.Hello

AppRuntim.start

下面进入 AppRuntimestart 函数中,以 ZygoteInit 参数分支为路径进行分析:

// AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
   
  ALOGD(">>>>>> START %s uid %d <<<<<<\n",
          className != NULL ? className : "(unknown)", getuid());

  static const String8 startSystemServer("start-system-server");

  for (size_t i = 0; i < options.size(); ++i) {
   
    if (options[i] == startSystemServer) {
   
      const int LOG_BOOT_PROGRESS_START = 3000;
      LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
    }
  }

  const char* rootDir = getenv("ANDROID_ROOT");
  if (rootDir == NULL) {
   
    rootDir = "/system";
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值