介绍
这是一个连载的系列「图解 Android 系列」,我将持续为大家提供尽可能通俗易懂的 Android 源码分析。
所有引用的源码片段,我都会在第一行标明源文件完整路径。为了文章篇幅考虑源码中间可能有删减,删减部分会用省略号代替。
本系列源码基于:Android Oreo(8.0)
init 进程
在上篇文章 揭秘 Android 系统启动过程 中介绍到,init 进程启动分为前后两部分,前一部分是在内核启动的,主要是完成创建和内核初始化工作,内容都是跟 Linux 内核相关的;后一部分是在用户空间启动的,主要完成 Android 系统的初始化工作。
Android 系统一般会在根目录下放一个 init 的可执行文件,也就是说 Linux 系统的 init 进程在内核初始化完成后,就直接执行 init 这个文件,这个文件的源代码在 /system/core/init/init.cpp
。
init 进程是 Linux 系统中用户空间的第一个进程(pid = 1),我们熟悉的 App 应用程序都是以它为父进程的,init 进程入口函数是 main 函数。这个函数做的事情还是比较多的,主要分为三个部分:
- init 进程第一阶段
- init 进程第二阶段
- init.rc 文件解析
第一阶段
我们先来看第一阶段主要有以下内容:。
- 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 安全策略。
第二阶段
我们接着看第二阶段,主要有以下内容:
- 创建进程会话密钥并初始化属性系统。
- 进行 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());
parser.AddSectionParser("on", std::make_unique());
parser.AddSectionParser("import", std::make_unique());
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 进程启动主要做了哪些工作。
首先在 Kernel 内核加载完后会调用 /system/core/init/init.cpp
文件中的 main()
方法。该方法执行分为三个阶段,前两个的阶段都是初始化环境,我们主要关注下第三个阶段 解析 .rc
文件。
在第三阶段中通过解析 .rc 文件启动了 servicemanager
和 zygote
等服务,最后 init 进程进入了 loop。
zygote 进程
zygote 进程就是 daemon 其中之一,zygote 进程主要负责创建 Java 虚拟机,加载系统资源,启动 SystemServer 进程,以及在后续运行过程中启动普通的应用程序。
在 init.rc 文件头部有这么一句:
import /init.${ro.zygote}.rc
复制代码
其中 ${ro.zygote}
会被替换成 ro.zyogte 的属性值,这个是由不同的硬件厂商自己定制的。 有四个值:zygote32、zygote64、zygote32_64、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(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 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& 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& 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 技术,如下:
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 fds = new ArrayList();
ArrayList peers = new ArrayList();
// 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 系统启动的流程:
当我们按下电源按键后会启动 Bootloader,Bootloader 会加载 Kernel 内核到内存中,然后会启动内核中的 idle 进程,idle 进程会启动 kthreadd 和 init 两个进程。
init 进程在启动的时候会初始化运行环境,然后解析 init.rc 文件,解析 init.rc 文件的过程中会启动 servicemanager、zygote 等服务,最后进入 loop 状态。
zygote 服务启动时会创建 Java 虚拟机并初始化 Java 运行环境,然后启动 SystemServer 服务,最后进入 loop 状态。
这篇文章我们分析到这里,下一篇我们接着分析 zygote 进程启动中调用 startSystemServer() 方法后 SystemServer 进程启动的流程。
参考资料
- Android内核开发:图解Android系统的启动过程
- Android 8.0 : 系统启动流程之Linux内核
- Android bootloader/fastboot mode and recovery mode explained/Android boot process
- Android is NOT just 'Java on Linux'
- Android 启动流程简介
我的 Github
github.com/jeanboydev/…
我的公众号
欢迎关注我的公众号,分享各种技术干货,各种学习资料,职业发展和行业动态。
技术交流群
欢迎加入技术交流群,来一起交流学习。