本系列主要介绍Android8.0系统启动过程中涉及到的init、Zygote、SystemServer和Launcher。
- init启动前准备
- init函数分析
- init函数解析
- init启动Zygote
一、init启动前准备
init进程是Android系统的第一个进程,其进程号为1,该进程启动后,主要处理一些重要的初始化工作,比如创建Zygote和各种属性服务。在电源按键,按下后,经历如下几个步骤后,便开始引入init进程:
1. 启动电源及系统:电源按下后,引导芯片开始将固化在ROM中的BootLoader加载至RAM中,并执行该程序;
2. 引导程序BootLoader:引导程序BootLoader是在Android操作系统开始运行前,执行的一个小程序,其主要作用是把系统OS拉起来并运行;
3. Linux内核启动:内核启动时,设置缓存、被保护存储器、计划列表和加载驱动等,完成设置后,开始加载init.rc文件;
4. init进程启动:开始初始化和启动属性服务,创建Zygote进程。
二、 init函数分析
在Linux内核加载完成后,开始查找init.rc文件,并启动init进程,其主要代码如下:
system/core/init/init.cpp
int main(int argc, char** argv) {
...
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// 清理 umask.
umask(0);
// 创建和挂载所需的文件
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));
// 初始化Kernel日志
InitKernelLogging(argv);
...
}
...
//属性服务初始化
property_init();
...
//创建epoll句柄
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
...
//设置子进程的处理函数
signal_handler_init();
//导入默认的环境变量
property_load_boot_defaults();
export_oem_lock_status();
//启动属性服务
start_property_service();
set_usb_controller();
...
if (bootscript.empty()) {
//解析init.rc文件
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 {
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);
}
...
return 0;
}
该流程分析如下:
1. 挂载文件:通过设置umask值,屏蔽一些权限后,开始挂载和创建所需的文件;
2. 属性服务:通过property_init()属性服务初始化,调用start_property_service()启动属性服务;
3. 子进程的处理函数: signal_handler_init()主要作用是防止出现僵尸进程,子进程在暂停和终止后,会发出SIGCHLD的信号,signal_handler_init()接收到该信号后,会对该进程进行回收处理,防止占用系统进程资源;
4. 解析init.rc配置:在8.0中对init.rc文件进行了拆分,可查看system\core\rootdir目录,包括:
init.zygote32.rc:Zygote对应的执行程序是app_process(纯32位模式);
init.zygote64.rc:Zygote对应的执行程序是app_process64(纯64位模式);
init.zygote32_64.rc:启动两个Zygote进程( zygote 和 zygote_secondary),对应的执行程序是app_process32(主模式)和app_process64;
init.zygote64_32.rc:启动两个Zygote进程( zygote 和 zygote_secondary),对应的执行程序是app_process64(主模式)和app_process32。
三、 init函数解析
\system\core\rootdir\init.rc
init.rc配置文件,是由Android初始化语言(Android Init Language)编写的脚本,主要包括5种语言类型:Action、Command、Service、Option和Import。
同时,需要注意init.rc仅仅是配置文件,类似于xml,没有解析的顺序而言(不是自上而下运行),是通过程序调用,获取相应的配置信息,真正加载运行的程序是在上部分提到的init.cpp文件。
import:指令是用于类似于java语言,主要用于扩展配置,格式如下:
import 一个init配置文件,扩展当前配置
filename一般是init.XXX.rc的形式,源码中例如:
import /init.environ.rc
Action:一系列命令的开始,其格式如下:
on [&& ]*
...
每个Action都至少有一个触发器(trgger),该触发器决定何时执行该Action,即后面的command...指令,其要通过ActionParser解析,其实现代码在\system\core\init\action.cpp,其格式如下:
# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
rm /dev/.booting
Service:以service开头,由init进程启动的,一般运行于init的子进程中,在启动该service前需要判断对应的可执行文件是否存在,并通过fork方式生成子进程。其主要通过ServiceParser解析,其实现代码在\system\core\init\service.cpp,其格式如下:
service [ ]*
其中name:服务的名称,pathname:当前服务对应程序的位置,option:当前服务设置的选项,argument:可选参数。例如:
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
shutdown critical
四 、init启动Zygote
\system\core\rootdir\init.rc
\system\core\init\init.cpp
\system\core\init\builtins.cpp
\ frameworks\base\cmds\app_process\app_main.cpp
在init.rc中,关于Zygote的启动在如下部分:
\system\core\rootdir\init.rc
on nonencrypted
class_start main
class_start late_start
其中 main指的就是Zygote的服务名称,其中class_start函数是指builtins.cpp中的函数:
\system\core\init\builtins.cpp
static int do_class_start(const std::vector& args) {
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
return 0;
}
其中ForEachServiceInClass函数会遍历Service链表,查找classname为main的Zygote,并执行service.cpp中的StartIfNotDisabled函数,如下所示:
\system\core\init\service.cpp
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
如果该service没有在其对应的rc文件中设置disable选项,则会执行Start()方法,启动该Service,在init.zygote64.rc中没有设置disable选项,因此可以正常启动该Service。
\system\core\init\builtins.cpp
bool Service::Start() {
..
//是否正在运行
if (flags_ & SVC_RUNNING) {
return false;
}
...
//启动的路径是否存在
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
scon = ComputeContextFromExecutable(name_, args_[0]);
if (scon == "") {
return false;
}
}
//如果该进程未启动,调用fork启动该进程
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {
umask(077);
...
}
if (pid < 0) {
PLOG(ERROR) << "failed to fork for '" << name_ << "'";
pid_ = 0;
return false;
}
....
//启动该进程
SetProcessAttributes();
if (!ExpandArgsAndExecve(args_)) {
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
_exit(127);
NotifyStateChange("running");
return true;
}
其主要流程如下:
- 是否正在运行,如正在运行,直接返回;
- 子进程是否启动,如未启动,调用fork并返回pid值;
- 如果以上正常,则调用ExpandArgsAndExecve启动该进程,完成Zygote的启动。
启动Zygote进程真正执行的路径为frameworks\base\cmds\app_process\app_main.cpp下的main函数,如下所示:
\ frameworks\base\cmds\app_process\app_main.cpp
int main(int argc, char* const argv[])
{
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//启动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.");
}
...
}