Init进程启动
Init进程是Android系统中用户空间的第一个进程,进程号为1。它被赋予很多重要的工作职责,比如创建Zygote(孵化器)和属性服务等。Init进程是由多个源文件共同组成的,文件位于源码目录:system/core/init中。
引入init进程
Android的整个系统启动流程如下图所示:
当电源按下时引导芯片从预定义的地方开始执行,加载引导程序BootLoader到Ram中执行。引导程序则是把系统OS拉起来运行。当系统内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。在内核完成系统设置后,它首先在系统文件中寻找 init.rc 文件,井启动 init 进程。init 进程做的工作比较多 ,主要用来初始化和启动属性服务,也用来启动Zygote进程。
Init入口函数
在Linux内核加载完成后,首先会在系统中寻找init.rc文件,并启动init进程,所以我们来看看init进程的入口函数main:
system/core/init/init.cpp
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
if (REBOOT_BOOTLOADER_ON_PANIC) {
install_reboot_signal_handlers();
}
add_environment("PATH", _PATH_DEFPATH);
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
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 Log
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
// 挂载分区
if (!DoFirstStageMount()) {
LOG(ERROR) << "Failed to mount required partitions early ...";
panic();
}
// AVB(Android Verified Boot),主要用于防止系统文件本身被篡改,还包含了防止系统回滚的功能
// AVB的初始化
SetInitAvbVersionInRecovery();
// SELinux初始化
selinux_initialize(true);
if (restorecon("/init") == -1) {
PLOG(ERROR) << "restorecon failed";
security_failure();
}
// 将环境变量INIT_SECOND_STAGE设置为1, 准备进入第二阶段
setenv("INIT_SECOND_STAGE", "true", 1);
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
// 设置环境变量INIT_STARTED_AT
setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args);
PLOG(ERROR) << "execv("" << path << "") failed";
security_failure();
}
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 1);
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
// 对属性服务进行初始化
property_init();
process_kernel_dt();
process_kernel_cmdline();
export_kernel_boot_props();
property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
const char* avb_version = getenv("INIT_AVB_VERSION");
if (avb_version) property_set("ro.boot.avb_version", avb_version);
unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
selinux_initialize(false);
selinux_restore_context();
// 创建epoll句柄
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(ERROR) << "epoll_create1 failed";
exit(1);
}
// 用于设置子进程信号处理函数,如果子进程( Zygote 进程)异常退出, in it 进程会调用该函数中设定的信号处理函数来进行处理
signal_handler_init();
// 导入默认的环境变量
property_load_boot_defaults();
export_oem_lock_status();
// 启动属性服务
start_property_service();
set_usb_controller();
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
std::string bootscript = GetProperty("ro.boot.init_rc", "");
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);
}
if (false) parser.DumpState();
ActionManager& am = ActionManager::GetInstance();
am.QueueEventTrigger("early-init");
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
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");
am.QueueBuiltinAction(console_init_action, "console_init");
am.QueueEventTrigger("init");
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) {
int epoll_timeout_ms = -1;
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
// 内部遍历执行每个action中携带的command对应的执行函数
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
// 重启死去的进程
restart_processes();
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 (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的main函数非常的复杂,在开始的时候创建和挂载启动所需的文件目录,挂载的目录包含:
tmpfs、devpts、proc sysfs、selinuxfs共5种文件系统
这些都是系统运行时目录,系统停止时会消失。
signal_ handler init 函数用于设置子进程信号处理函数,它被定义在 system/core/init/signal_ handler.cpp 中,主要用于防止init进程的子进程成为僵尸进程。
解析Init.rc
init.rc 个非常重要的配置文件,它是由 Android初始化语言(Android Init Language) 编写的脚本,这种语言主要包含5种类型语句:
Action、Command、Service、Option和Import
init.rc 的配置代码如下所示:
system/core/rootdir/init.rc
on init
sysclktz 0
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
copy /default.prop /dev/urandom
.....
on boot
# basic network init
ifup lo
hostname localhost
domainname localdomain
......
on init和on boot是Action类型语句,格式如下:
on <trigger> [&&<trigger>]* // 设置触发器
<command>
<command> // 动作触发之后要执行的命令
下面来看看Service类型的语句,它的格式如下所示:
service <name> <pathname> [ <argument> ] * // <service名称><执行程序路径><传递参数>
<option> // option是service的修饰词,影响何时或如何启动Service
<option>
......
在Android8.0中对init.rc文件进行拆分,每个服务对应一个rc文件,比如Zygote启动脚本则在init.zygoteXX.rc中定义。
systemfcore/rootdir/init.zygote64.rc
// Service 于通知init进程创建名为zygote的进程
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
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类型语句
init.rc中的 Action类型语句和Service类型语句都有相应的类来进行解析,Action类型语句采用ActionParser来解析,Service类型语句采用ServiceParser来解析。
ServiceParser的实现代码在system/core/init/service.cpp中,解析Service类型语句会用到两个重要的函数:
1、ParseSection():解析Service的rc文件,比如init.zygote64.rc等。
2、ParseLineSection():主要用于解析子项。
代码如下所示:
system/core/init/service.cpp
bool ServiceParser::ParseSection(const std::vector<std::string>& args, std::string* err) {
if (args.size() < 3) { // 判断Service是否有name与可执行程序
*err = "services must have a name and a program";
return false;
}
const std::string& name = args[1];
if (!IsValidName(name)) { // 检查Service的name是否有效
*err = StringPrintf("invalid service name '%s'", name.c_str());
return false;
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
// 根据参数构造出一个Service对象,它的classname为default。
service_ = std::make_unique<Service>(name, str_args);
return true;
}
bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const {
return service_ ? service_->ParseLine(args, err) : false;
}
接下来,我们查看函数的调用关系,ParseSection在init_parser.cpp类中解析数据的时候被调用,我们可以跟踪过去:
system/core/init/init_parser.cpp
void Parser::ParseData(const std::string& filename, const std::string& data) {
......
SectionParser* section_parser = nullptr;
std::vector<std::string> args;
for (;;) {
switch (next_token(&state)) {
case T_EOF: // 解析到最后一行会调用EndSection()函数
if (section_parser) {
section_parser->EndSection();
}
return;
case T_NEWLINE:
state.line++;
if (args.empty()) {
break;
}
if (section_parsers_.count(args[0])) {
if (section_parser) {
section_parser->EndSection();
}
section_parser = section_parsers_[args[0]].get();
std::string ret_err;
if (!section_parser->ParseSection(args, &ret_err)) {
parse_error(&state, "%s
", ret_err.c_str());
section_parser = nullptr;
}
} else if (section_parser) {
std::string ret_err;
if (!section_parser->ParseLineSection(args, state.filename,
state.line, &ret_err)) {
parse_error(&state, "%s
", ret_err.c_str());
}
}
args.clear();
break;
case T_TEXT:
args.emplace_back(state.text);
break;
}
}
}
从代码中可以看到,当进行到文件结束操作符T_EOF处则会调用EndSection()语句。
system/core/init/service.cpp
void ServiceParser::EndSection() {
if (service_) {
ServiceManager::GetInstance().AddService(std::move(service_));
}
}
EndSection函数中会调用 ServiceManage的AddService 函数,接着查看 AddService函数:
system/core/init/service. cpp
void ServiceManager::AddService(std::unique_ptr<Service> service) {
Service* old_service = FindServiceByName(service->name());
if (old_service) {
LOG(ERROR) << "ignored duplicate definition of service '" << service->name() << "'";
return;
}
// 将Service对象加入Service链表中
services_.emplace_back(std::move(service));
}
所以,Service解析过程总体就是根据参数创建Service对象,然后根据选项的内容填充Service对象,最后将Service对象加入vector类型的链表中。
Init启动Zygote
在Zygote的启动脚本中,我们可知 Zygote的class name为main 。在 init.rc中有如下配置代码:
system/core/rootdir/init. rc
......
on nonencrypted
// 启动那些classname为main的Service,这里是用来启动Zygote
class_start main
class_start late_start
......
class_start是一个COMMAND,对应的函数为 do_class_ start。doclass_start函数在builtins.cpp中定义,如下所示:
system/core/init/builtins.cpp
static int do_class_start(const std::vector<std::string>& args) {
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
*/
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
return 0;
}
ForEachServiceInClass函数会遍历Service链表,找到classname为main的Zygote,并执行StartIfNotDisabled函数。
system/core/init/service.cpp
void ServiceManager::ForEachServiceInClass(const std::string& classname,
void (*func)(Service* svc)) const {
for (const auto& s : services_) {
if (s->classnames().find(classname) != s->classnames().end()) {
func(s.get());
}
}
}
接下来,看看StartIfNotDisabled函数如下:
system/core/init/service.cpp
bool Service::StartIfNotDisabled() {
// 如果Service没有在其对应rc文件中设置disabled选项,则会调用Start函数启动该Service
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
Zygote对应的init.zygote64.rc中并没有设置disabled选项,因此我们可以跟踪查看Start函数的实现:
system/core/init/service.cpp
bool Service::Start() {
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// 如果Service已经运行,则不启动
if (flags_ & SVC_RUNNING) {
return false;
}
bool needs_console = (flags_ & SVC_CONSOLE);
if (needs_console) {
if (console_.empty()) {
console_ = default_console;
}
int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
if (console_fd < 0) {
PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
close(console_fd);
}
// 判断需要启动的Service对应执行文件是否存在,不存在则不启动
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
......
LOG(INFO) << "starting service '" << name_ << "'...";
// 如果子进程没有启动,则调用fork函数创建子进程
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
// 当前代码逻辑在子进程中允许
if (pid == 0) {
umask(077);
......
// 调用execve函数,Service子进程启动
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
}
_exit(127);
}
......
return true;
}
先判断Service是否允许,允许则不再启动,否则直接false。如果子进程没有启动就调用fork函数创建子进程并返回pid值。
从init.zygote64.rc 文件可以知道Zygote执行程序的路径是system/bin/app_process64,对应的文件为app main.cpp ,这样就会进入 app_main.cpp 的main 函数中,也就是在Zygote的main 函数中,代码如下:
int main(int argc, char* const argv[]) {
......
if (zygote) {
// 调用runtime的start函数启动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.
");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
至此,Zygote已经启动。
属性服务
Android中的属性服务类似于Windows平台的注册表管理器,用于记录用户、软件的一些使用信息。
在init.cpp的main函数中与属性服务相关的代码有如下两行:
system/core/init/init.cpp
// 对属性服务进行初始化
property_init();
process_kernel_dt();
这两行代码用来初始化属性服务配置井启动属性服务。
属性服务的启动
property_ init 函数的具体实现代码如下所示:
system/core/init/property_ service. cpp
void property_init() {
if (__system_property_area_init()) {
LOG(ERROR) << "Failed to initialize property area";
exit(1);
}
}
__system_property_area_init函数用来初始化属性内存区域。接下来查看 start_property service 函数的具体代码:
system/core/init/property_ service. cpp
void start_property_service() {
property_set("ro.property_service.version", "2");
// 创建非阻塞的Socket
property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0666, 0, 0, NULL);
if (property_set_fd == -1) {
PLOG(ERROR) << "start_property_service socket creation failed";
exit(1);
}
// 对property_set_fd进行监听操作,第二个参数表示最多可以提供服务的数量
listen(property_set_fd, 8);
// 将property_set_fd放入epoll中,通过epoll监听。
// 当property_set_fd中有数据到来时,init进程将调用handle_property_set_fd函数处理
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
epoll是Linux内核为处理大批量文件描述符而做改进的poll,是Linux下多路复用I/O接口select/poll的增强版本。它可以显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
epoll内部用于保存事件的数据类型是红黑树,查找速度快。
处理客户端请求
属性服务接收到客户端请求时,会调用 handle_property_set_fd函数进行处理:
system/core/init/p ope ty_se vice.cpp
static void handle_property_set_fd() {
......
switch (cmd) {
case PROP_MSG_SETPROP: {
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
// 如果Socket读取不到属性数据则返回
if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
!socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
return;
}
prop_name[PROP_NAME_MAX-1] = 0;
prop_value[PROP_VALUE_MAX-1] = 0;
// handle_property_set函数做进一步封装处理
handle_property_set(socket, prop_value, prop_value, true);
break;
}
......
}
接着跟踪handle_property_set函数,如下所示:
system/core/init/property_ service.cpp
static void handle_property_set(SocketConnection& socket,
const std::string& name,
const std::string& value,
bool legacy_protocol) {
......
// 如果属性名称以"ctl."开头,则说明是控制属性
if (android::base::StartsWith(name, "ctl.")) {
// 检查客户端权限
if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
// 设置控制属性
handle_control_message(name.c_str() + 4, value.c_str());
if (!legacy_protocol) {
socket.SendUint32(PROP_SUCCESS);
}
} else {
LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
<< " service ctl [" << value << "]"
<< " uid:" << cr.uid
<< " gid:" << cr.gid
<< " pid:" << cr.pid;
if (!legacy_protocol) {
socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
}
}
} else {
// 该分支是普通属性,检查客户端权限
if (check_mac_perms(name, source_ctx, &cr)) {
uint32_t result = property_set(name, value);
if (!legacy_protocol) {
socket.SendUint32(result);
}
} else {
LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
if (!legacy_protocol) {
socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
}
}
}
freecon(source_ctx);
}
系统属性分为两种类型:一种是普通属性,另外一种是控制属性(执行一些命令,比如开机动画)。
从代码分支中可以看到,如果是普通属性则会调用property_set(name, value)函数来对普通函数进行修改:
system/core/init/propey_service cpp
uint32_t property_set(const std::string& name, const std::string& value) {
size_t valuelen = value.size();
// 判断属性是否合法
if (!is_legal_property_name(name)) {
LOG(ERROR) << "property_set("" << name << "", "" << value << "") failed: bad name";
return PROP_ERROR_INVALID_NAME;
}
......
// 从属性存储空间查找该属性
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
// 如果属性存在
if (pi != nullptr) {
// 如果属性名称以"ro."开头,则表示只读,不能修改而直接返回
if (android::base::StartsWith(name, "ro.")) {
LOG(ERROR) << "property_set("" << name << "", "" << value << "") failed: "
<< "property already set";
return PROP_ERROR_READ_ONLY_PROPERTY;
}
// 如果属性存在则更新属性值
__system_property_update(pi, value.c_str(), valuelen);
} else {
// 如果属性不存在则添加该属性
int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
if (rc < 0) {
LOG(ERROR) << "property_set("" << name << "", "" << value << "") failed: "
<< "__system_property_add failed";
return PROP_ERROR_SET_FAILED;
}
}
// 属性名称以"persist."开头的处理部分
if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
write_persistent_property(name.c_str(), value.c_str());
}
property_changed(name, value);
return PROP_SUCCESS;
}
这里主要是对普通属性进行修改,判断属性合法并存在则更新属性值,否则就添加。
源码分析进行到这里,可以总结init进程启动做了很多工作,总体来说主要有三件事:
1、创建和挂载启动所有的文件目录。
2、初始化和启动属性服务。
3、解析init.rc配置文件,并启动Zygote进程。