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 进程主要做了如下工作:
- 创建虚拟机,加载系统 Java 类以及注册系统类所依赖的 JNI 方法;
- 预加载应用程序进程所需的 drawable 和 color 资源,准备 WebView 和 OpenGL;
- 创建 socket 服务端,以便接收和处理创建应用进程的请求;
- 启动 system_server 服务进程,用于承载整个 framework 层运行的系统服务;
- 待命以随即处理到来的任务请求。
参考相关资料,对 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 将在如下情况下重启:
- servicemanager 进程死亡(启动配置中包含
onrestart restart zygote
); - surfaceflinger 进程死亡(启动配置中包含
onrestart restart zygote
); - Zygote 死亡(启动配置中为非 oneshot);
- 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
函数做了如下工作:
- 创建了
AppRuntime
对象,传入虚拟机所需的选项; - 解析 init.rc 文件的
zygote
启动参数; - 调用
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
下面进入 AppRuntime
的 start
函数中,以 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";