欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

<Android开发>Android内核系统开发-启动过程详解

时间:2023-07-09
<Android开发> Android内核系统开发-启动过程详解(第2部分 系统关键服务的启动简析)

继上一篇介绍语法后,接下来详细看看init进程解析init.rc后启动的一些关键的系统服务进程,其中最重要的有ServiceManager、Zygote和SystemServer。

一、Android的“DNS服务器”--------ServiceManager
ServiceManager是Binder机制中的“DNS服务器”,负责域名(某Binder服务在ServiceManager注册时提供的名称) 到IP地址(有底层Binder驱动分配的值)的解析。
在高通8155 LA.1.1 中 ServiceManager是在init.rc里由init进程启动。如下:

on init #init事件.......略 # Start logd before any other services run to ensure we capture all of their logs. # 在任何其他服务运行之前启动 logd 以确保我们捕获它们的所有日志。 start logd # 这个命令将启动一个服务 logd ,如果它没有处于运行状态的话 # Start essential services. # 启动基本服务。 start servicemanager # 这个命令将启动一个服务 servicemanager ,如果它没有处于运行状态的话 start hwservicemanager # 这个命令将启动一个服务 hwservicemanager ,如果它没有处于运行状态的话 start vndservicemanager # 这个命令将启动一个服务 vndservicemanager ,如果它没有处于运行状态的话 ......略

有servicemanager文件可看出,servicemanager是一个 Linux程序的执行文件。它在设备中的存储路径是“/system/bin/servicemanager”(需要进入root才能查询到,如下图),源码路径则是“frameworks/native/cmds/servicemanager”。

servicemanager的启动描述则在servicemanager.rc文件里,.rc文件位于“frameworks/native/cmds/servicemanager/servicemanager.rc”。高通8155的LA.1.1基线代码对于servicemanager的描述和启动的位置分在两个不同的.rc文件。servicemanager.rc具体启动描述内容如下:

service servicemanager /system/bin/servicemanager class core animation #所属类是 core 和 animation user system #在启动服务前将用户切换至 system ,默认是root group system readproc #在启动服务前将用户组切换至 system 和 readproc critical #表明这是对设备至关重要的一个服务,如果4分钟内退出超过4次,则设备将重启进入恢复模式 onrestart restart healthd #当servicemanager重启时,重启 healthd 进程 onrestart restart zygote #当servicemanager重启时,重启 zygote 进程 onrestart restart audioserver #当servicemanager重启时,重启 audioserver 进程 onrestart restart media #当servicemanager重启时,重启 media 进程 onrestart restart surfaceflinger #当servicemanager重启时,重启 surfaceflinger 进程 onrestart restart inputflinger #当servicemanager重启时,重启 inputflinger 进程 onrestart restart drm #当servicemanager重启时,重启 drm 进程 onrestart restart cameraserver #当servicemanager重启时,重启 cameraserver 进程 onrestart restart keystore #当servicemanager重启时,重启 keystore 进程 onrestart restart gatekeeperd #当servicemanager重启时,重启 gatekeeperd 进程 onrestart restart thermalservice #当servicemanager重启时,重启 thermalservice 进程 writepid /dev/cpuset/system-background/tasks # 当fork一个子进程时,写子进程的pid到一个给定的文件。是给cgroup/cpuset使用 #设置服务进程的关闭行为。如果未指定此选项,则在关闭过程中通过使用SIGTERM和SIGKILL终止服务。 #shutdown_behavior为"critical"时,服务在关闭期间不会被杀死,直到关闭超时为止。 #当服务进程关闭超时时,即使标记为"shutdown critical"的服务也将被杀死。 #当shutdown行为启动时,标有"shutdown critical"的服务未运行时,它将启动。 shutdown critical #服务在关闭期间不会被杀死,直到关闭超时为止

由servicemanager.rc可看出,servicemanager所属class是core,其它同类的系统进程包括ueventd、console(/system/bin/sh)、adbd等。根据core组的特性,这些进程会同时被启动或停止。另外,critical选项说明它是系统的关键进程,意味着如果进程不幸在4分钟异常退出4次,则设备将重启进入还原模式。每当servicemanager重启时,其它关键进程也会被重启,如:healthd、zygote、audioserver、media、surfaceflinger、inputflinger、drm、cameraserver、keystore、gatekeeperd、thermalservice等。

二、Zygote—“孕育”新的线程和进程
Zygote这个词的字面意思时“受精卵”,因而可以“孕育”出一个“新生命”。在Android中大多数应用进程和系统进程都是通过Zygote来生成的。下面具体分析Zygote时如何启动的。
同servicemanager类似,Zygote也是由init解析rc脚本时启动的。在早期的Android版本中Zygote的启动命令是直接被写在init.rc中。但随着硬件等的不断升级换代,Android系统不得不面对32位和64位机器同时存在的状况,因而,对Zygote的启动也需要根据不同的情况区分对待,在高通平台中,在init.rc中加载Zygote的脚本描述如下:

import /init.environ.rcimport /init.usb.rcimport /init.${ro.hardware}.rcimport /vendor/etc/init/hw/init.${ro.hardware}.rcimport /init.usb.configfs.rcimport /init.${ro.zygote}.rc

根据系统属性ro.zygote的具体值,init.rc中加载不同的描述zygote的rc脚本,zygote的描述脚本包含“init.zygote32_64.rc”、“init.zygote32.rc”、“init.zygote64_32.rc”、“init.zygote64.rc”,具体文件如下:(目录:system/core/rootdir)

其中zygote32和zygote64分别对应32位和64位机器的情况,而zygote32_64和zygote64_32,则是Primary Arch和Secondary Arch的组合。
组合介绍如下:

路径:device/qcom/msmnile_au/BoardConfig.mk
BoardConfig.mk用于指定目标平台相关的不少属性,咱们能够在这个脚本中同时指定Primary和Secondary的CPU Arch和ABI:

与Primary Arch相关的变量有TARGET_ARCH、TARGET_ARCH_VARIANT、TARGET_CPU_VARIANT等,具体范例以下:

TARGET_ARCH := arm64TARGET_ARCH_VARIANT := armv8-aTARGET_CPU_ABI := arm64-v8aTARGET_CPU_ABI2 :=TARGET_CPU_VARIANT := generic

与Secondary Arch相关的变量有TARGET_2ND_ARCH、TARGET_2ND_ARCH_VARIANT、TARGET_2ND_CPU_VARIANT等,具体范例以下:

TARGET_2ND_ARCH := armTARGET_2ND_ARCH_VARIANT := armv7-a-neonTARGET_2ND_CPU_ABI := armeabi-v7aTARGET_2ND_CPU_ABI2 := armeabiTARGET_2ND_CPU_VARIANT := cortex-a9

所以,由BoardConfig.mk可知,高通8155的LA.1.1基线中的“init.rc“-》“import /init.${ro.zygote}.rc“-》ro.zygote的值为“zygote64_32”,即Primary Arch为64,Secondary Arch为32。接下来详细看zygote64_32的内容,如下:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main #所属类是 main priority -20 #设置服务进程的优先级.优先级取值范围为-20~19,默认是0.可以通过setpriority()设置 user root #在启动服务前将用户切换至 root ,默认是 root group root readproc reserved_disk #在启动服务前将用户组切换至 root 和 readproc 和 reserved_disk socket zygote stream 660 root system #创建一个名为 /dev/socket/zygote 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system socket usap_pool_primary stream 660 root system #创建一个名为 /dev/socket/usap_pool_primary 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system onrestart write /sys/android_power/request_state wake #当 zygote 重启时,写 wake 到 /sys/android_power/request_state onrestart write /sys/power/state on #当 zygote 重启时,写 on 到 /sys/power/state onrestart restart audioserver #当 zygote 重启时,重启 audioserver 进程 onrestart restart cameraserver #当 zygote 重启时,重启 cameraserver 进程 onrestart restart media #当 zygote 重启时,重启 media 进程 onrestart restart netd #当 zygote 重启时,重启 netd 进程 onrestart restart wificond #当 zygote 重启时,重启 wificond 进程 writepid /dev/cpuset/foreground/tasks # 当fork一个子进程时,写子进程的pid到一个给定的文件。是给cgroup/cpuset使用service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload class main #所属类是 main priority -20 #设置服务进程的优先级.优先级取值范围为-20~19,默认是0.可以通过setpriority()设置 user root #在启动服务前将用户切换至 root ,默认是 root group root readproc reserved_disk #在启动服务前将用户组切换至 root 和 readproc 和 reserved_disk socket zygote_secondary stream 660 root system #创建一个名为 /dev/socket/zygote_secondary 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system socket usap_pool_secondary stream 660 root system #创建一个名为 /dev/socket/usap_pool_secondary 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system onrestart restart zygote #当 zygote_secondary 重启时,重启 zygote 进程 writepid /dev/cpuset/foreground/tasks # 当fork一个子进程时,写子进程的pid到一个给定的文件。是给cgroup/cpuset使用

从上面这段脚本描述可以看出:
存在两个服务 zygote 和 zygote_secondary;
zygote的path:/system/bin/app_process64
zygote_secondary的path:/system/bin/app_process32
zygote的Arguments:-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
zygote_secondary的Arguments:-Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload

zygote和zygote_secondary所属class都为main,而不是core。同class的系统进程有netd、debuggerd、rild等。从两者的路径可以看出,它们所在的程序名分别叫“ app_process64” 和 “ app_process32”,而不像ServiceManager一样在一个独立的程序中。通过指定–zygote 参数,app_process可以识别出用户是否需要启动zygote。那么app_process又是什么东东呢?app_process的源码路径在:frameworks/base/cmds/app_process中,先看看其Android.mk的内容,如下:

LOCAL_PATH:= $(call my-dir)app_process_common_shared_libs := libandroid_runtime libbinder libcutils libdl libhidlbase liblog libnativeloader libutils # This is a list of libraries that need to be included in order to avoid# bad apps、This prevents a library from having a mismatch when resolving# new/delete from an app shared library.# See b/21032018 for more details.# 这是为了避免不良应用程序需要包含的库列表。 这可以防止库在从应用程序共享库中解析新/删除时出现不匹配。# 详情请参阅 b/21032018。app_process_common_shared_libs += libwilhelm app_process_common_static_libs := libsigchain app_process_src_files := app_main.cpp app_process_cflags := -Wall -Werror -Wunused -Wunreachable-codeapp_process_ldflags_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamicapp_process_ldflags_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamicinclude $(CLEAR_VARS)LOCAL_SRC_FILES:= $(app_process_src_files)LOCAL_LDFLAGS_32 := $(app_process_ldflags_32) #32位程序的ld标志LOCAL_LDFLAGS_64 := $(app_process_ldflags_64) #64位程序的ld标志LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs) #共享库LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs) #静态库LOCAL_MODULE:= app_process #模块名称LOCAL_MULTILIB := both #用于针对的硬件平台架构,可选项:"both":同时 "32":针对32 "64":针对64 " ":由系统根据其它变量决定LOCAL_MODULE_STEM_32 := app_process32 #指定32位系统下的应用程序LOCAL_MODULE_STEM_64 := app_process64 #指定64位系统下的应用程序LOCAL_CFLAGS += $(app_process_cflags)# In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse# the same module)、Using the same module also works around an issue with make: binaries# that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.## Also pull in the asanwrapper helper.# 在 SANITIZE_LITE 模式下,我们在单独的位置创建经过清理的二进制文件(但重用相同的模块)。 # 使用相同的模块也可以解决 make 的问题:依赖于已清理库的二进制文件将被重新链接,即使它们设置 LOCAL_SANITIZE := never。# 同时引入 asanwrapper 助手。ifeq ($(SANITIZE_LITE),true)LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asanLOCAL_REQUIRED_MODULES := asanwrapperendifinclude $(BUILD_EXECUTABLE)# Create a symlink from app_process to app_process32 or 64# depending on the target configuration.# 根据目标配置创建从 app_process 到 app_process32 或 64 的符号链接。ifneq ($(SANITIZE_LITE),true)include $(BUILD_SYSTEM)/executable_prefer_symlink.mkendif

从上面的描述可看到,app_process其实扮演的类似一个外壳,实际是去调用 app_process64 或app_process32程序。那么app_process具体内容有哪些呢?下面分析app_process.cpp中的main主函数的实现,内容如下:

int main(int argc, char* const argv[]){ if (!LOG_NDEBUG) { String8 argv_String; for (int i = 0; i < argc; ++i) { argv_String.append("""); argv_String.append(argv[i]); argv_String.append("" "); } ALOGV("app_process main with argv: %s", argv_String.string()); } //Android运行时环境 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments 处理命令行参数 // ignore argv[0] 忽略 argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name、All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. // // As an exception to the above rule, anything in "spaced commands" // goes to the vm even though it has a space in it. // 直到 '--' 或第一个非 '-' arg 的所有内容都进入 vm。 // VM args 后面的第一个参数是“父目录”,目前未使用。 // 在父目录之后,我们期望一个或多个以下内部参数: // --zygote : 以 zygote 模式启动 // --start-system-server : 启动系统服务器。 // --application : 以应用程序(独立,非 zygote)模式启动。 // --nice-name : 这个进程的好名字。 // 对于非 zygote 启动,这些参数后跟主类名。所有剩余的参数都传递给这个类的 main 方法。 // 对于 zygote 启动,所有剩余的参数都传递给 zygote。 // 主功能。 // 请注意,我们必须复制参数字符串值,因为当我们将 nice 名称应用于 argv0 时,我们将重写整个参数块。 // 作为上述规则的一个例外,“间隔命令”中的任何内容都会进入 vm,即使其中有空格。 const char* spaced_commands[] = { "-cp", "-classpath" }; // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s). // 允许“间隔命令”通过恰好 1 个参数(不管 -s)。 bool known_command = false; int i; for (i = 0; i < argc; i++) { if (known_command == true) { //判断参数是否存在 runtime.addOption(strdup(argv[i])); //将参数传给runtime // The static analyzer gets upset that we don't ever free the above // string、Since the allocation is from main, leaking it doesn't seem // problematic、NOLINTNEXTLINE // 静态分析器对我们没有释放上面的字符串感到不安。 由于分配来自 main,因此泄漏它似乎没有问题。 NOLINTNEXTLINE ALOGV("app_process main add known option '%s'", argv[i]); known_command = false; continue; } for (int j = 0; j < static_cast(sizeof(spaced_commands) / sizeof(spaced_commands[0])); ++j) { if (strcmp(argv[i], spaced_commands[j]) == 0) { //比较判断argv中的参数是否存在 和 spaced_commands中一样的部分 known_command = true; //标记阐述存在 ALOGV("app_process main found known command '%s'", argv[i]); } } if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --、 跳过 --开头的 break; } runtime.addOption(strdup(argv[i])); //将参数传给runtime // The static analyzer gets upset that we don't ever free the above // string、Since the allocation is from main, leaking it doesn't seem // problematic、NOLINTNEXTLINE // 静态分析器对我们没有释放上面的字符串感到不安。 由于分配来自 main,因此泄漏它似乎没有问题。 NOLINTNEXTLINE ALOGV("app_process main add option '%s'", 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 表示当前进程承载 zygote zygote = true; //标记 niceName = ZYGOTE_NICE_NAME; //别名 } else if (strcmp(arg, "--start-system-server") == 0) { //判断参数存在 --start-system-server 表示需要启动 system server startSystemServer = true; //标记 } else if (strcmp(arg, "--application") == 0) { //判断参数存在 --application 表示启动进入独立的程序模式 application = true; //标记 } else if (strncmp(arg, "--nice-name=", 12) == 0) { //判断参数存在 --nice-name= 表示设置进程别名为 = 后面的字串 niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { //判断参数存在 -- 表示设置className 增加 --后面字串 作为数据 className.setTo(arg); break; } else { --i; //倒叙检索参数 break; } } Vector args; if (!className.isEmpty()) { //判断 非zygote // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main()、Make // copies of them before we overwrite them with the process name. // 我们不是在 zygote 模式下,我们需要传递给 RuntimeInit 的唯一参数是应用程序参数。 // args 的剩余部分被传递给启动类 main()。 在我们用进程名称覆盖它们之前制作它们的副本。 args.add(application ? String8("application") : String8("tool")); //如果参数 包含 application 则添加application作为数据 否则为tool runtime.setClassNameAndArgs(className, argc - i, argv + i); //设置Android运行时环境 runtime 的类名和参数 //调试信息,输出类名和参数 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("" "); } ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string()); } } else { // We're in zygote mode. // 我们处于 zygote 模式。 maybeCreateDalvikCache(); if (startSystemServer) { //判断 startSystemServer 参数存在 args.add(String8("start-system-server")); //添加参数 start-system-server } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { //ABI属性列表获取 列表参数 LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); //无法从属性中确定 ABI 列表 return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); //abi标志列表 最加prop args.add(abiFlag); //将列表 加入到 参数列表中 // In zygote mode, pass all remaining arguments to the zygote // main() method. // 在 zygote 模式下,将所有剩余的参数传递给 zygote main() 方法。 for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { //判断别名 runtime.setArgv0(niceName.string(), true ); //设置runtime的setArgv0参数,即别名 } if (zygote) { //判断是 zygote ,启动zygote进程 传入args参数列表 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { //非zygote 情况下,运行RuntimeInit进程 , 传入args参数列表 runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { //否则都不是,错误:没有提供类名或 --zygote。 fprintf(stderr, "Error: no class name or --zygote supplied.n"); app_usage(); //输出 启动命令的用法 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); }}

这个函数用于解析启动app_process时传入的参数,具体参数如下:
–zygote:表示当前进行用于承载zygote
–start-system-server:是否需要启动system server
–application:启动进入独立的程序模式
–nice-name:此进程的“别名”

对于非zygote的情况下,在上述参数的末尾会跟上main class的名称,而后的其它参数则属于这个class的主函数传入的参数;
对于zygote的情况,所有参数则会作为它的主函数传入参数使用;

在前面的 init.zegote64_32.rc中指定了 “–zygote“选项,因而app_process接下来将启动“com.android.internal.os.ZygoteInit ”,并传入“start-system-server”。之后ZygoteInit会运行于Java虚拟机上,那为什么呢?
原因就是runtime这个变量,它实际上是一个AndroidRuntime对象,其start函数源码如下:

void AndroidRuntime::start(const char* className, const Vector& options, bool zygote){ ALOGD(">>>>>> START %s uid %d <<<<<FindClass("java/lang/String"); //找 string 类 assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); //新建string类的对象的队列 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); } char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'n", slashClassName); } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'n", className); } else { env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env);#endif } } free(slashClassName); ALOGD("Shutting down VMn"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main threadn"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanlyn");}

对于虚拟机的具体启动和运行过程,等作者学习了后续在出相关文章讲解。
按照正常的启动流程,VM成功启动,并进入ZygoteInit执行;ZygoteInit执行源码如下:

public static void main(String argv[]) { ZygoteServer zygoteServer = null; // Mark zygote start、This ensures that thread creation will throw // an error. // 标记zygote开始。 这确保线程创建将引发错误。 ZygoteHooks.startZygoteNoThreadCreation(); // Zygote goes into its own process group. // Zygote 进入它自己的进程组。 try { Os.setpgid(0, 0); } catch (ErrnoException ex) { throw new RuntimeException("Failed to setpgid(0,0)", ex); } Runnable caller; try { // Report Zygote start time to tron unless it is a runtime restart // 向 tron 报告 Zygote 启动时间,除非是运行时重启 if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { MetricsLogger.histogram(null, "boot_zygote_init", (int) SystemClock.elapsedRealtime()); } String bootTimetag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimetag, Trace.TRACE_TAG_DALVIK); bootTimingsTraceLog.traceBegin("ZygoteInit"); RuntimeInit.enableDdms(); boolean startSystemServer = false; String zygoteSocketName = "zygote"; String abiList = null; boolean enableLazyPreload = false; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; //标记,需要启动 SystemServer } else if ("--enable-lazy-preload".equals(argv[i])) { enableLazyPreload = true; //标记, 使能 LazyPreload } else if (argv[i].startsWith(ABI_LIST_ARG)) { //abi列表参数 abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { //socket名参数 zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } // 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()); preload(bootTimingsTraceLog); //预加载资源 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } else { Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup // 启动后执行初始 gc 清理 bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC bootTimingsTraceLog.traceEnd(); // ZygoteInit // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. // 禁用跟踪,以便分叉的进程不会从 Zygote 继承陈旧的跟踪标记。 Trace.setTracingEnabled(false, 0); Zygote.initNativeState(isPrimaryZygote); ZygoteHooks.stopZygoteNoThreadCreation(); zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { //启动一个 SystemServer 进程 Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. // {@code r == null} 在父 (zygote) 进程中,{@code r != null} 在子 (system_server) 进程中。 if (r != null) { r.run(); return; } } Log.i(TAG, "Accepting command socket connections"); // The select loop returns early in the child process after a fork and // loops forever in the zygote. // select 循环在 fork 之后的子进程中尽早返回,并在 zygote 中永远循环。 caller = zygoteServer.runSelectLoop(abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer != null) { zygoteServer.closeServerSocket(); } } // We're in the child process and have exited the select loop、Proceed to execute the // command. if (caller != null) { caller.run(); } }

ZygoteInit的主函数主要完成以下几点:
—Socket—
zygote是一个孵化器,一旦有新程序需要运行时,系统会通过这个socket(完整名称为:zygote 、Zygote.PRIMARY_SOCKET_NAME))第一时间通知“总管事”Zygote,并由它负责实际的进程孵化过程。

—Preload预加载资源—
通过enableLazyPreload判断是否预加载资源。加载虚拟机运行时所需的资源,包括:
preloadClasses();
cacheNonBootClasspathClassLoaders();
preloadResources();
nativePreloadAppProcessHALs();
maybePreloadGraphicsDriver();
preloadSharedLibraries();
preloadTextResources();
从对应的名称可看出每个preload函数的作用。以preloadClasses为例,它负责加载和初始化常用的一些classes。这些需要预加载的classes被记录在"out/target/product/msmnile_au/system/etc/preloaded-classes"中,在高通8155的LA.1.1中如下所示:

# Preloaded-classes filter file for phones.# Classes in this file will be allocated into the boot image, and forcibly initialized in# the zygote during initialization、This is a trade-off, using virtual address space to share# common heap between apps.# This file has been derived for mainline phone (and tablet) usage.#android.R$styleableandroid.accessibilityservice.AccessibilityServiceInfo$1android.accessibilityservice.AccessibilityServiceInfoandroid.accounts.Account$1android.accounts.Accountandroid.accounts.AccountManager$10android.accounts.AccountManager$11android.accounts.AccountManager$18android.accounts.AccountManager$1android.accounts.AccountManager$20android.accounts.AccountManager$2android.accounts.AccountManager$AmsTask$1android.accounts.AccountManager$AmsTask$Responseandroid.accounts.AccountManager$AmsTaskandroid.accounts.AccountManager$baseFutureTask$1android.accounts.AccountManager$baseFutureTask$Response....略

从输出文件中可以看出preloaded-classes中包含多达上千个classes,而且包括了libcore里面的重要基础资源,如:android.system、android.util等。另外,这个记录表通过“frameworks/base/tools/preload/WritePreloadedClassFile.java”生成。

—启动System Server—
如果app_process的调用参数中带有“start-system-server”,那么此时就会通过“forkSystemServer”来启动“SystemServer”。

Zygote在前期主要担当启动系统服务的工作,后期则又负责“程序孵化”的任务。但是Zygote只在init.rc中被启动一次,它又是如何协调这两者的工作关系呢?从前面的过程中,大致推断,上述中的“forkSystemServer”应该会新建一个专门的进程来承载系统服务的运行,而后app_process所在的进程转化为Zygote的“孵化器”守护进程。那么具体如何呢?接下来分析“forkSystemServer”的内容,如下:

private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { 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, OsConstants.CAP_BLOCK_SUSPEND ); StructCapUserHeader header = new StructCapUserHeader( OsConstants._LINUX_CAPABILITY_VERSION_3, 0); StructCapUserData[] data; try { data = Os.capget(header); } catch (ErrnoException ex) { throw new RuntimeException("Failed to capget()", ex); } capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32); String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; ZygoteArguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteArguments(args); Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); boolean profileSystemServer = SystemProperties.getBoolean( "dalvik.vm.profilesystemserver", false); if (profileSystemServer) { parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER; } pid = Zygote.forkSystemServer( //此处fork一个新的进程(子进程) parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } if (pid == 0) { //子进程,即System Server所承载进程 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); //启动各个 System Server } return null; }

上述代码段中又出现了我们熟悉的fork流程,forkSystemServer在内部利用UNIX的fork机制创建了一个新的进程;而这个“新生儿”(即pid=0分支)会在随后的执行过程中通过“handleSystemServerProcess”来启动各种支撑系统运行的 System Server。

在跟踪 System Server的具体启动过程之前,先来为Zygote接下来的工作做个分析,与我们之前所见的fork处理流程不同的是,ZygoteInit.java-》main()-》forkSystemServer()函数中并没有为父进程专门开辟一个代码分支,因而这个函数最后会通过return handleSystemServerProcess(parsedArgs) 返回到ZygoteInit.java-》main()中。在main()接着就是语句:
caller = zygoteServer.runSelectLoop(abiList);
从runSelectLoop的函数名可猜到,这很可能会是一个“死循环”,除非Zygote退出或者出现异常才会跳出循环,runSelectLoop函数内容如下:

** * Runs the zygote process's select loop、Accepts new connections as * they happen, and reads commands from connections one spawn-request's * worth at a time. */ Runnable runSelectLoop(String abiList) { ArrayList socketFDs = new ArrayList(); ArrayList peers = new ArrayList(); socketFDs.add(mZygoteSocket.getFileDescriptor()); peers.add(null); //添加null是为了保存fds和peers的一致性 while (true) { //死循环 fetchUsapPoolPolicyPropsWithMinInterval(); int[] usapPipeFDs = null; StructPollfd[] pollFDs = null; // Allocate enough space for the poll structs, taking into account // the state of the USAP pool for this Zygote (could be a // regular Zygote, a WebView Zygote, or an AppZygote). // 为轮询结构分配足够的空间,同时考虑此 Zygote 的 USAP 池的状态 //(可以是常规 Zygote、WebView Zygote 或 AppZygote)。 if (mUsapPoolEnabled) { usapPipeFDs = Zygote.getUsapPipeFDs(); pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length]; } else { pollFDs = new StructPollfd[socketFDs.size()]; } int pollIndex = 0; for (FileDescriptor socketFD : socketFDs) { pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = socketFD; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; } final int usapPoolEventFDIndex = pollIndex; if (mUsapPoolEnabled) { pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = mUsapPoolEventFD; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; for (int usapPipeFD : usapPipeFDs) { FileDescriptor managedFd = new FileDescriptor(); managedFd.setInt$(usapPipeFD); pollFDs[pollIndex] = new StructPollfd(); pollFDs[pollIndex].fd = managedFd; pollFDs[pollIndex].events = (short) POLLIN; ++pollIndex; } } try { Os.poll(pollFDs, -1); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } boolean usapPoolFDRead = false; while (--pollIndex >= 0) { // if ((pollFDs[pollIndex].revents & POLLIN) == 0) { continue; } if (pollIndex == 0) { //有新的连接请求 // Zygote server socket // Zygote 服务器套接字 ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); socketFDs.add(newPeer.getFileDescriptor()); } else if (pollIndex < usapPoolEventFDIndex) { //已建立的连接中有客户端发过来的数据需要处理 // Session socket accepted from the Zygote server socket // 从 Zygote 服务器套接字接受的会话套接字 try { ZygoteConnection connection = peers.get(pollIndex); final Runnable command = connection.processOneCommand(this); // TODO (chriswailes): Is this extra check necessary? // TODO (chriswailes): 这个额外的检查是必要的吗? if (mIsForkChild) { // We're in the child、We should always have a command to run at this // stage if processoneCommand hasn't called "exec". // 我们在孩子里面。 如果 processoneCommand 没有调用“exec”,我们应该始终有一个命令在这个阶段运行。 if (command == null) { throw new IllegalStateException("command == null"); } return command; } else { // We're in the server - we should never have any commands to run. // 我们在服务器中——我们不应该运行任何命令。 if (command != null) { throw new IllegalStateException("command != null"); } // We don't know whether the remote side of the socket was closed or // not until we attempt to read from it from processOneCommand、This // shows up as a regular POLLIN event in our regular processing loop. // 在我们尝试从 processoneCommand 中读取之前,我们不知道套接字的远程端是否已关闭。 // 这在我们的常规处理循环中显示为常规 POLLIN 事件。 if (connection.isClosedByPeer()) { connection.closeSocket(); peers.remove(pollIndex); socketFDs.remove(pollIndex); } } } catch (Exception e) { if (!mIsForkChild) { // We're in the server so any exception here is one that has taken place // pre-fork while processing commands or reading / writing from the // control socket、Make a loud noise about any such exceptions so that // we know exactly what failed and why. // 我们在服务器中,所以这里的任何异常都是在处理命令或从控制套接字读取/写入时发生的 pre-fork。 // 对任何此类异常大声喧哗,以便我们确切知道失败的原因和原因。 Slog.e(TAG, "Exception executing zygote command: ", e); // Make sure the socket is closed so that the other end knows // immediately that something has gone wrong and doesn't time out // waiting for a response. // 确保套接字已关闭,以便另一端立即知道出现问题并且不会超时等待响应。 ZygoteConnection conn = peers.remove(pollIndex); conn.closeSocket(); socketFDs.remove(pollIndex); } else { // We're in the child so any exception caught here has happened post // fork and before we execute ActivityThread.main (or any other main() // method)、Log the details of the exception and bring down the process. // 我们在子进程中,所以这里捕获的任何异常都发生在分叉后和 // 执行 ActivityThread.main(或任何其他 main() 方法)之前。 记录异常的详细信息并关闭该过程。 Log.e(TAG, "Caught post-fork exception in child process.", e); throw e; } } finally { // Reset the child flag, in the event that the child process is a child- // zygote、The flag will not be consulted this loop pass after the Runnable // is returned. // 如果子进程是子zygote,则重置子标志。 在 Runnable 返回后,将不会在此循环过程中查询标志。 mIsForkChild = false; } } else { //出错情况 // Either the USAP pool event FD or a USAP reporting pipe. // If this is the event FD the payload will be the number of USAPs removed. // If this is a reporting pipe FD the payload will be the PID of the USAP // that was just specialized. // USAP 池事件 FD 或 USAP 报告管道。 // 如果这是事件 FD,则有效载荷将是移除的 USAP 的数量。 // 如果这是一个报告管道 FD,则有效载荷将是刚刚专门化的 USAP 的 PID。 long messagePayload = -1; try { byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(buffer)); messagePayload = inputStream.readLong(); } else { Log.e(TAG, "Incomplete read from USAP management FD of size " + readBytes); continue; } } catch (Exception ex) { if (pollIndex == usapPoolEventFDIndex) { Log.e(TAG, "Failed to read from USAP pool event FD: " + ex.getMessage()); } else { Log.e(TAG, "Failed to read from USAP reporting pipe: " + ex.getMessage()); } continue; } if (pollIndex > usapPoolEventFDIndex) { Zygote.removeUsapTableEntry((int) messagePayload); } usapPoolFDRead = true; } } // Check to see if the USAP pool needs to be refilled. // 检查是否需要重新填充 USAP 池。 if (usapPoolFDRead) { int[] sessionSocketRawFDs = socketFDs.subList(1, socketFDs.size()) .stream() .mapToInt(fd -> fd.getInt$()) .toArray(); final Runnable command = fillUsapPool(sessionSocketRawFDs); if (command != null) { return command; } } } }}

从上述程序可看到,runSelectLoop函数的主体部分确实是一和while循环,它将作为zygoted 守护体存在。因为zygote此时运行在虚拟机环境中,所以需要处理USAP 池的分配与管理的问题。
在mZygoteSocket.getFileDescriptor()获取的是Server socket的文件描述符,并添加到 ArrayList socketFDs ,这意味着zygote中不光只有一个socket产生。具体而言,while会先通过下面句子判断当前哪个fd处于可读状态。

try { Os.poll(pollFDs, -1); //判断 当前轮训到的 pollFDs中的socketFD 是否处于可读状态 } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); }

当pollFDs中的socketFD指示的某个文件有可读数据时,pollFDs的revents成员的值会被修改。
pollIndex表示当前轮训的第几个socket,从最大值开始轮训。pollIndex大于或等于0时进入循环。

首先判断当前socket的事件 是否 时进入轮训状态,是的话进入重新循环,否则继续运行下面的判断。

if ((pollFDs[pollIndex].revents & POLLIN) == 0) { //轮训 continue; }

pollIndex = 0
此时表示有新的客户端连接,需要通过“ZygoteConnection newPeer = acceptCommandPeer(abiList);”接受来自客户端的连接,产生一个新的ZygoteConnection,然后分别更新peers和socketFDs,为了保证这两个列表中的对象序列号保存一致,可以看到peer在初始化时专门添加了一个null,对应的是Zygote Server Socket 这个“监听者”。

pollIndex < usapPoolEventFDIndex
usapPoolEventFDIndex是记录了socketFDs的数量的。此时说明已经建立Socket连接中有来自客户端的数据需要处理,完成具体工作的是connection.processoneCommand(this),该函数具体内容如下:

Runnable processOneCommand(ZygoteServer zygoteServer) { String args[]; ZygoteArguments parsedArgs = null; FileDescriptor[] descriptors; try { args = Zygote.readArgumentList(mSocketReader); // TODO (chriswailes): Remove this and add an assert. // TODO (chriswailes): 删除它并添加一个断言。 descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { throw new IllegalStateException("IOException on command socket", ex); } // readArgumentList returns null only when it has reached EOF with no available // data to read、This will only happen when the remote socket has disconnected. // readArgumentList 仅在到达 EOF 且没有可读取的数据时才返回 null。 这只会在远程套接字断开连接时发生。 if (args == null) { isEof = true; return null; } int pid = -1; FileDescriptor childPipeFd = null; FileDescriptor serverPipeFd = null; parsedArgs = new ZygoteArguments(args); if (parsedArgs.mAbiListQuery) { handleAbiListQuery(); return null; } if (parsedArgs.mPidQuery) { handlePidQuery(); return null; } if (parsedArgs.mUsapPoolStatusSpecified) { return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled); } if (parsedArgs.mPreloadDefault) { handlePreload(); return null; } if (parsedArgs.mPreloadPackage != null) { handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs, parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey); return null; } if (canPreloadApp() && parsedArgs.mPreloadApp != null) { byte[] rawParcelData = base64.getDecoder().decode(parsedArgs.mPreloadApp); Parcel appInfoParcel = Parcel.obtain(); appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length); appInfoParcel.setDataPosition(0); ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel); appInfoParcel.recycle(); if (appInfo != null) { handlePreloadApp(appInfo); } else { throw new IllegalArgumentException("Failed to deserialize --preload-app"); } return null; } if (parsedArgs.mApiBlacklistExemptions != null) { return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions); } if (parsedArgs.mHiddenApiAccessLogSampleRate != -1 || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) { return handleHiddenApiAccessLogSampleRate(zygoteServer, parsedArgs.mHiddenApiAccessLogSampleRate, parsedArgs.mHiddenApiAccessStatslogSampleRate); } if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities) + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities)); } Zygote.applyUidSecurityPolicy(parsedArgs, peer); Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer); Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); int[][] rlimits = null; if (parsedArgs.mRLimits != null) { rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D); } int[] fdsToIgnore = null; if (parsedArgs.mInvokeWith != null) { try { FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; Os.fcntlInt(childPipeFd, F_SETFD, 0); fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; } catch (ErrnoException errnoEx) { throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx); } } int [] fdsToClose = { -1, -1 }; FileDescriptor fd = mSocket.getFileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } fd = zygoteServer.getZygoteSocketFileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); } fd = null; pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion); try { if (pid == 0) { // in child //在子进程 zygoteServer.setForkChild(); //mIsForkChild 值为true zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.mStartChildZygote); } else { // In the parent、A pid < 0 indicates a failure and will be handled in // handleParentProc. // 在父级中。 pid < 0 表示失败,将在 handleParentProc 中处理。 IoUtils.closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, descriptors, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }

函数processOneCommand比较长,其中重点内容是函数的后面部分,我们重点关注两点:

创建承载应用程序的新进程
这个是在意料之中的,zygote需要为每个新启动的应用程序生成自己独立的进程。不过processOneCommand中并没有直接使用fork来父进程的“收尾”工作
执行完上述的任务后,父进程还需要做一些清尾工作才算“大功告成”。包括:将子进程加入进程组;正确关闭文件;调用方返回结果值等。

Specialize的字面意思是“专门化”,表达了“forkAndSpecialize”在“孵化”的同时也把它转变为Android应用程序的目标。函数forkAndSpecialize的处理分为3个阶段,即 preFork、nativeForkAndSpecialize以及postForkCommon。函数内容如下:

public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. // 重置 zygote 进程的优先级。 resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); // Enable tracing as soon as possible for the child process. // 尽快为子进程启用跟踪。 if (pid == 0) { Zygote.disableExecuteOnly(targetSdkVersion); Trace.setTracingEnabled(true, runtimeFlags); // Note that this event ends at the end of handleChildProc, // 注意这个事件在handleChildProc结束时结束, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } ZygoteHooks.postForkCommon(); return pid; }

preFork分析
preFork在Zygote中对应的实现如下:

static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) { Runtime* runtime = Runtime::Current(); CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote"; runtime->PreZygoteFork(); // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable. // 在 fork 之前抓取线程可能会使 Thread::pthread_key_self_ 不可用。 return reinterpret_cast(ThreadForEnv(env));}

这里的Runtime实例具体而言指的是 Zygote进程中的运行环境(后续如果讲解虚拟机时在详细讲解)。而runtime->PreZygoteFork()又会间接调用Heap::PreZygoteFrok,从而完成堆栈空间的初始化。
函数nativeForkAndSpecialize是一个native方法。具体对应的实现是com_android_internal_os_Zygote_nativeForkAndSpecialize,后者有进一步调用了 ForkCommon 和 SpecializeCommon。
com_android_internal_os_Zygote_nativeForkAndSpecialize 函数内容如下:

static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { ZygoteFailure(env, "zygote", nice_name, "Zygote received a null fds_to_close vector."); } std::vector fds_to_close = ExtractJIntArray(env, "zygote", nice_name, managed_fds_to_close).value(); std::vector fds_to_ignore = ExtractJIntArray(env, "zygote", nice_name, managed_fds_to_ignore) .value_or(std::vector()); std::vector usap_pipes = MakeUsapPipeReadFDVector(); fds_to_close.insert(fds_to_close.end(), usap_pipes.begin(), usap_pipes.end()); fds_to_ignore.insert(fds_to_ignore.end(), usap_pipes.begin(), usap_pipes.end()); fds_to_close.push_back(gUsapPoolSocketFD); if (gUsapPoolEventFD != -1) { fds_to_close.push_back(gUsapPoolEventFD); fds_to_ignore.push_back(gUsapPoolEventFD); } pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir); } return pid;}

ForkCommon函数的内容如下:

// Utility routine to fork a process from the zygote.// 从 zygote 派生一个进程的实用程序。static pid_t ForkCommon(JNIEnv* env, bool is_system_server, const std::vector& fds_to_close, const std::vector& fds_to_ignore) { SetSignalHandlers(); // Curry a failure function. // Curry 一个失败函数。 auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote", nullptr, _1); // Temporarily block SIGCHLD during forks、The SIGCHLD handler might // log, which would result in the logging FDs we close being reopened. // This would cause failures because the FDs are not whitelisted. // // Note that the zygote process is single threaded at this point. // 在分叉期间临时阻塞 SIGCHLD。 SIGCHLD 处理程序可能会记录日志, // 这将导致我们关闭的日志记录 FD 被重新打开。 这将导致失败,因为 FD 未列入白名单。 // 注意此时zygote进程是单线程的。 BlockSignal(SIGCHLD, fail_fn); // Close any logging related FDs before we start evaluating the list of // file descriptors. // 在我们开始评估文件描述符列表之前,关闭所有与日志记录相关的 FD。 __android_log_close(); stats_log_close(); // If this is the first fork for this zygote, create the open FD table、 If // it isn't, we just need to check whether the list of open files has changed // (and it shouldn't in the normal case). // 如果这是此 zygote 的第一个分叉,则创建打开的 FD 表。 // 如果不是,我们只需要检查打开文件列表是否发生了变化(正常情况下不应该)。 if (gOpenFdTable == nullptr) { gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn); } else { gOpenFdTable->Restat(fds_to_ignore, fail_fn); } android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level(); pid_t pid = fork(); //这里真正孵化出一个新的进程 if (pid == 0) { // The child process. // 子进程。 PreApplicationInit(); // Clean up any descriptors which must be closed immediately // 清理所有必须立即关闭的描述符 DetachDescriptors(env, fds_to_close, fail_fn); // Invalidate the entries in the USAP table. // 使 USAP 表中的条目无效。 ClearUsapTable(); // Re-open all remaining open file descriptors so that they aren't shared // with the zygote across a fork. // 重新打开所有剩余的打开文件描述符,这样它们就不会通过 fork 与 zygote 共享。 gOpenFdTable->ReopenOrDetach(fail_fn); // Turn fdsan back on. // 重新打开 fdsan。 android_fdsan_set_error_level(fdsan_error_level); } else { //父进程不做任何事,应为在 “frameworks/base/core/java/com/android/internal/os/ZygoteServer.java”中 connection.processoneCommand(this)里有处理 ALOGD("Forked child process %d", pid); } // We blocked SIGCHLD prior to a fork, we unblock it here. // 我们在分叉之前阻塞了 SIGCHLD,我们在这里解除阻塞。 UnblockSignal(SIGCHLD, fail_fn); return pid;}

SpecializeCommon的内容如下:

// Utility routine to specialize a zygote child process.// 用于专门化 zygote 子进程的实用程序。static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities, jint mount_external, jstring managed_se_info, jstring managed_nice_name, bool is_system_server, bool is_child_zygote, jstring managed_instruction_set, jstring managed_app_data_dir) { const char* process_name = is_system_server ? "system_server" : "zygote"; auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); auto se_info = extract_fn(managed_se_info); auto nice_name = extract_fn(managed_nice_name); auto instruction_set = extract_fn(managed_instruction_set); auto app_data_dir = extract_fn(managed_app_data_dir); // Keep capabilities across UID change, unless we're staying root. // 保持跨 UID 更改的功能,除非我们保持 root。 if (uid != 0) { EnableKeepCapabilities(fail_fn); } SetInheritable(permitted_capabilities, fail_fn); DropCapabilitiesBoundingSet(fail_fn); bool use_native_bridge = !is_system_server && instruction_set.has_value() && android::NativeBridgeAvailable() && android::NeedsNativeBridge(instruction_set.value().c_str()); if (use_native_bridge && !app_data_dir.has_value()) { // The app_data_dir variable should never be empty if we need to use a // native bridge、 In general, app_data_dir will never be empty for normal // applications、 It can only happen in special cases (for isolated // processes which are not associated with any app)、 These are launched by // the framework and should not be emulated anyway. // 如果我们需要使用本地网桥,app_data_dir 变量永远不应该为空。 // 通常,对于普通应用程序,app_data_dir 永远不会为空。 // 它只能在特殊情况下发生(对于与任何应用程序无关的隔离进程)。 // 这些是由框架启动的,无论如何都不应该被模拟。 use_native_bridge = false; ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr."); } MountEmulatedStorage(uid, mount_external, use_native_bridge, fail_fn); // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. // 如果这个 zygote 不是 root,它将无法创建进程组,因为该目录是由 root 拥有的。 if (!is_system_server && getuid() == 0) { const int rc = createProcessGroup(uid, getpid()); if (rc == -EROFS) { ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); } else if (rc != 0) { ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0, strerror(-rc)); } } SetGids(env, gids, is_child_zygote, fail_fn); SetRLimits(env, rlimits, fail_fn); if (use_native_bridge) { // Due to the logic behind use_native_bridge we know that both app_data_dir // and instruction_set contain values. // 由于 use_native_bridge 背后的逻辑,我们知道 app_data_dir 和 instruction_set 都包含值。 android::PreInitializeNativeBridge(app_data_dir.value().c_str(), instruction_set.value().c_str()); } if (setresgid(gid, gid, gid) == -1) { fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); } // Must be called when the new process still has CAP_SYS_ADMIN, in this case, // before changing uid from 0, which clears capabilities、 The other // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that // breaks SELinux domain transition (see b/71859146)、 As the result, // privileged syscalls used below still need to be accessible in app process. // 必须在新进程仍有 CAP_SYS_ADMIN 时调用,在这种情况下,在将 uid 从 0 更改为清除功能之前。 // 另一种选择是在之后调用 prctl(PR_SET_NO_NEW_PRIVS, 1),但这会中断 SELinux 域转换(参见 b/71859146)。 // 因此,下面使用的特权系统调用仍然需要在应用程序进程中访问。 SetUpSeccompFilter(uid, is_child_zygote); if (setresuid(uid, uid, uid) == -1) { fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); } // The "dumpable" flag of a process, which controls core dump generation, is // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective // user or group ID changes、See proc(5) for possible values、In most cases, // the value is 0, so core dumps are disabled for zygote children、However, // when running in a Chrome OS container, the value is already set to 2, // which allows the external crash reporter to collect all core dumps、Since // only system crashes are interested, core dump is disabled for app // processes、This also ensures compliance with CTS. // 当有效用户或组 ID 更改时,控制核心转储生成的进程的“dumpable”标志被 /proc/sys/fs/suid_dumpable 中的值覆盖。 // 有关可能的值,请参见 proc(5)。 在大多数情况下,该值为 0,因此对 zygote 子项禁用核心转储。 // 但是,在 Chrome OS 容器中运行时,该值已设置为 2,这允许外部崩溃报告器收集所有核心转储。 // 由于只对系统崩溃感兴趣,因此对应用程序进程禁用核心转储。 这也确保符合 CTS。 int dumpable = prctl(PR_GET_DUMPABLE); if (dumpable == -1) { ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); } if (dumpable == 2 && uid >= AID_APP) { if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) { ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed"); } } // Set process properties to enable debugging if required. // 如果需要,设置进程属性以启用调试。 if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) { EnableDebugger(); } if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) { // simpleperf needs the process to be dumpable to profile it. // simpleperf 需要进程可转储以对其进行分析。 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed"); } } if (NeedsNoRandomizeWorkaround()) { // Work around ARM kernel ASLR lossage (http://b/5817320). // 解决 ARM 内核 ASLR 丢失问题 (http://b/5817320)。 int old_personality = personality(0xffffffff); int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE); if (new_personality == -1) { ALOGW("personality(%d) failed: %s", new_personality, strerror(errno)); } } SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn); SetSchedulerPolicy(fail_fn); __android_log_close(); stats_log_close(); const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr; const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr; if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) { fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, "%s", "%s") failed", uid, is_system_server, se_info_ptr, nice_name_ptr)); } // Make it easier to debug audit logs by setting the main thread's name to the // nice name rather than "app_process". // 通过将主线程的名称设置为好听的名称而不是“app_process”,可以更轻松地调试审计日志。 if (nice_name.has_value()) { SetThreadName(nice_name.value()); } else if (is_system_server) { SetThreadName("system_server"); } // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers). // 取消设置 SIGCHLD 处理程序,但继续忽略 SIGHUP(SetSignalHandlers 中的基本原理)。 UnsetChldSignalHandler(); if (is_system_server) { env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks); if (env->ExceptionCheck()) { fail_fn("Error calling post fork system server hooks."); } // Prefetch the classloader for the system server、This is done early to // allow a tie-down of the proper system server selinux domain. // 预取系统服务器的类加载器。 这是尽早完成以允许绑定适当的系统服务器 selinux 域。 env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader); if (env->ExceptionCheck()) { // Be robust here、The Java code will attempt to create the classloader // at a later point (but may not have rights to use AoT artifacts). // 这里要健壮。 Java 代码稍后将尝试创建类加载器(但可能无权使用 AoT 工件)。 env->ExceptionClear(); } // TODO(oth): Remove hardcoded label here (b/117874058). // TODO(oth):在此处删除硬编码标签 (b/117874058)。 static const char* kSystemServerLabel = "u:r:system_server:s0"; if (selinux_android_setcon(kSystemServerLabel) != 0) { fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel)); } } env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); }}

首先在ForkCommon函数内,会先fork一个新进程,并在pid=0这一分支中为孵化出的进程完成一系列初始化操作,而后在SpecializeCommon函数内执行CallStaticVoidMethod函数。CallStaticVoidMethod函数的参数 gZygoteClass对应的是“com/android/internal/os/Zygote”,而gCallPostForkChildHooks则是Zygote这个类中的成员函数callPostForkChildHooks,从名称可看出其是用于执行孵化后的一些处理工作。
ForkCommon和SpecializeCommon都没有涉及与应用程序相关的具体业务,这部分由 “frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java”->processOneCommand中的handleChildProc()来完成。
函数handleChildProc的内容如下:

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, boolean isZygote) { closeSocket(); if (descriptors != null) { try { Os.dup2(descriptors[0], STDIN_FILENO); Os.dup2(descriptors[1], STDOUT_FILENO); Os.dup2(descriptors[2], STDERR_FILENO); for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } } catch (ErrnoException ex) { Log.e(TAG, "Error reopening stdio", ex); } } if (parsedArgs.mNiceName != null) { //存在子进程的别名 Process.setArgV0(parsedArgs.mNiceName); //设置子进程的别名 } // End of the postFork event. // postFork 事件结束。 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (parsedArgs.mInvokeWith != null) { WrapperInit.execApplication(parsedArgs.mInvokeWith, // 执行应用程序,正常情况下不返回 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.mRemainingArgs); // Should not get here. // 不应该到这里。 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); //WrapperInit.execApplication 意外返回 } else { //否则重新初始化zygote if (!isZygote) { return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mRemainingArgs, null ); } else { return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mRemainingArgs, null ); } } }

这个函数的任务是,处理参数后调用WrapperInit.execApplication(),执行应用程序。Android系统中所有应用程序理论上都是由zygote启动的, 从前面的分析来看,不难发现zygote会为新启动的应用程序fork一个进程。不过和传统的内核中的fork+exec的作法不同的地方是,Zygote中并不会执行exec()。在这种情况下就会造成一些障碍,比如无法使用valgrind来监控程序的内存泄漏情况。android系统提供了一种Wrapper实现,并通过parsedArgs.mInvokeWith 来加以控制。有兴趣的读者可查阅相关资料。

在高通的这个基线代码中execApplication函数主要是分析参数后,调用shell执行运行程序的命令。execApplication的内容如下:

public static void execApplication(String invokeWith, String niceName, int targetSdkVersion, String instructionSet, FileDescriptor pipeFd, String[] args) { StringBuilder command = new StringBuilder(invokeWith); final String appProcess; if (VMRuntime.is64BitInstructionSet(instructionSet)) { appProcess = "/system/bin/app_process64"; } else { appProcess = "/system/bin/app_process32"; } command.append(' '); command.append(appProcess); // Generate bare minimum of debug information to be able to backtrace through JITed code. // We assume that if the invoke wrapper is used, backtraces are desirable: // * The wrap.sh script can only be used by debuggable apps, which would enable this flag // without the script anyway (the fork-zygote path)、 So this makes the two consistent. // * The wrap.* property can only be used on userdebug builds and is likely to be used by // developers (e.g、enable debug-malloc), in which case backtraces are also useful. // 生成最少的调试信息,以便能够通过 JITed 代码进行回溯。 // 我们假设如果使用调用包装器,则需要回溯: wrap.sh 脚本只能由可调试的应用程序使用, // 这将在没有脚本的情况下启用此标志(fork-zygote 路径)。 所以这使得两者一致。 // wrap.* 属性只能在 userdebug 构建中使用,并且很可能被开发人员使用(例如启用 debug-malloc),在这种情况下回溯也很有用。 command.append(" -Xcompiler-option --generate-mini-debug-info"); command.append(" /system/bin --application"); if (niceName != null) { command.append(" '--nice-name=").append(niceName).append("'"); } command.append(" com.android.internal.os.WrapperInit "); command.append(pipeFd != null ? pipeFd.getInt$() : 0); command.append(' '); command.append(targetSdkVersion); Zygote.appendQuotedShellArgs(command, args); preserveCapabilities(); Zygote.execShell(command.toString()); }

在前面的handleChildProc这个函数中,会有一些会参数的处理,详细的了解需要对应用程序的启动由一个全局的认识。所以可以穿插阅读其它有关文档文章(后续作者也会持续更新)。这里假设运行的流程已经到了ActivityManagerService。

由于文章篇幅太长,本部分先讲解到这。后面文章将紧接这部分讲解分析流程。

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。