Android系统init进程启动过程

1. init进程启动前系统的启动流程
在引入init进程前,我们需要大致了解系统是如何走到init进程的。大致步骤如下:
启动电源和系统启动
按下电源,让设备开机时引导芯片代码会从预定义的地方开始执行。加载引导程序BootLoader到RAM中。
BootLoader
BootLoader只是Android系统开始前的一个引导程序,主要作用是将OS系统拉起来并运行。
启动Linux内核
当内核启动时,会先去设置缓存、加载驱动等,在系统设置完成后,会在系统文件中寻找init.rc文件,并启动init进程。
启动init进程
经过前面的步骤,到这一步,init就被正式启动。
init进程启动后,下面就看下它里面的一些重要的职责工作。
2. init进程main函数
main函数是init进程的入口函数,代码位置在:
/system/core/init.cpp
1
深入到init.cpp的main函数中:
int main(int argc, char** argv) {
...省略...
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// Clear the 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);
...省略...
}
...省略...
//创建一块共享的内存空间,用于对属性服务进行初始化
property_init();
...省略...
//创建epoll句柄
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(ERROR) << "epoll_create1 failed";
exit(1);
}
//初始化子进程退出的信号处理函数
//如果子进程异常退出,init进程会调用该函数中设定的信号处理函数来进程处理
//防止子进程成为僵尸进程
signal_handler_init();
//加载default.prop文件,导入默认的环境变量
property_load_boot_defaults();
export_oem_lock_status();
//启动属性服务器,会调用epoll_ctl设置property fd可读的回调函数
start_property_service();
...省略...
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);
}
...省略...
//不要在充电器模式下挂载文件系统或启动核心系统服务
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) {
// 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进程执行完成后,就进入循环等待epoll_wait的状态。init的main函数中做了大量初始化工,比较复杂。我主要学习了如下几个关键点:
创建和挂载启动的文件
属性服务
进程信号处理
解析init.rc文件
init启动Zygote
3. 创建和挂载启动的文件
在最开始的时候就创建和挂载启动所需要的文件目录,其中挂载了:
tempfs
devpts
proc
sysfs
selinuxfs
共挂载了这五个系统,这些都是系统运行时的目录,只有当系统运行时才会存在,当系统停止时,这些目录就不会存在。
4. 属性服务
在Windows上有一个注册表管理器,主要采用的是键值对的形式来记录用户、软件的一些信息。即使系统或软件重启,还是能根据之前注册表中的记录,进行初始化工作。在Android系统中,也有一个类似的机制,叫作属性服务。
当某个进程通过property_set()方法修改属性后,init进程会先检查权限,当权限验证通过后,就会去修改相应的属性值,而属性值一旦改变,就会触发相应的触发器(即rc文件中的on开头的语句),在Android Shared Memmory(共享内存区)中有一个_system_property_area_区域,里面存储这所有的属性值。某个进程通过property_get()方法,获取的也是这个共享内存区域的属性值。
在init.cpp的main函数中与属性服务相关的代码有如下两行:
路径:system/core/init/init.cpp
property_init();
start_property_service();
这两行代码主要是初始化属性服务配置并启动属性服务。
4.1 初始化共享内存并启动属性服务
4.1.1 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()方法,初始化跨进程的共享内存。
4.1.2 start_property_service
深入到/system/core/init/property_service.cpp中:
void start_property_service() {
property_set("ro.property_service.version", "2");
property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0666, 0, 0, NULL);//注释1
if (property_set_fd == -1) {
PLOG(ERROR) << "start_property_service socket creation failed";
exit(1);
}
listen(property_set_fd, 8);//注释2
register_epoll_handler(property_set_fd, handle_property_set_fd);//注释3
}
注释解析说明:
注释1:创建名为“property_service”的Socket。
注释2:调用listen函数对property_set_fd进行监听,这里的Socket就成为了server,即属性服务。其中,参数8表示可以同时为8个试图设置属性的用户提供服务。
注释3:将property_set_fd放入到epoll中,用epoll来监听property_set_fd,当property_set_fd中有数据变动时,init进程将调用handle_property_set_fd函数进行处理。
其中,epoll是Linux内核为处理大批量文件描述符而做了改进的poll,能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
4.2 服务端请求属性服务处理数据
上面说了当客户端请求属性服务处理数据时,会调用handle_property_set_fd函数进行处理。
4.2.1 handle_property_set_fd
深入到/system/core/init/property_service.cpp的handle_property_set_fd方法中:
static void handle_property_set_fd() {
static constexpr uint32_t kDefaultSocketTimeout = 2000; /
ms /
...省略...
uint32_t timeout_ms = kDefaultSocketTimeout;//设置2秒超时
uint32_t cmd = 0;
if (!socket.RecvUint32(&cmd, &timeout_ms)) {
PLOG(ERROR) << "sys_prop: error while reading command from the socket";
socket.SendUint32(PROP_ERROR_READ_CMD);
return;
}
switch (cmd) {
case PROP_MSG_SETPROP: {
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
//如果2秒内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;
}
...省略...
}
}
从上面可以看到Android8.0继续封装了handle_property_set方法去处理数据。
4.2.2 handle_property_set
深入到/system/core/init/property_service.cpp的handle_property_set方法中:
static void handle_property_set(SocketConnection& socket,
const std::string& name,
const std::string& value,
bool legacy_protocol) {
const char
cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
if (!is_legal_property_name(name)) {//检查属性名是否合法,不合法直接return
LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
socket.SendUint32(PROP_ERROR_INVALID_NAME);
return;
}
struct ucred cr = socket.cred();
char* source_ctx = nullptr;
getpeercon(socket.socket(), &source_ctx);
//如果属性名称以“ctl.”开头,则说明是控制属性
if (android::base::StartsWith(name, "ctl.")) {
//检查权限
if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
//如果满足权限,则直接设置以ctl.开头的属性
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 {//不是以“ctl.”开头,则说明是普通属性
if (check_mac_perms(name, source_ctx, &cr)) {
//调用property_set方法来设置普通属性
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);
}
综上所述,会先检查属性名是否合法,在满足合法的条件后;判断属性名是否是以“ctl.”开头;如果是,则通过handle_control_message去设值;如果不是,则通过调用property_set方法来设值。
4.2.3 property_set
深入到/system/core/init/property_service.cpp的property_set方法中:
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;
}
//属性名不能过长
if (valuelen >= PROP_VALUE_MAX) {
LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
<< "value too long";
return PROP_ERROR_INVALID_VALUE;
}
if (name == "selinux.restorecon_recursive" && valuelen > 0) {
if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
LOG(ERROR) << "Failed to restorecon_recursive " << value;
}
}
//从属性存储空间中查找该属性
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;
}
综上所述,property_set主要是处理普通属性。先判断属性名是否合法,属性名长度是否过长?在满足一系列条件判断后,再到存储空间中去查找是否有该属性;如果有,且是以“.ro”开头的,表示只读,不能修改,直接return,如果有,但不是以“.ro”开头,则去update;如果存储空间中没有该属性,则添加该属性,并赋值。最后还调用了write_persistent_property方法处理了以“persist.”开头的属性名。需要注意的是persist用于持久保存某些属性值,但会带来额外的IO操作。
如果是以“ctl.”开头,则表示控制消息,控制消息主要用来执行一些命令,例如:
查看开机动画(setprop ctl.start bootanim)
关闭开机动画(setprop ctl.stop bootanim)
进入recovery模式(setprop ctl.start pre-recovery)
5. 进程信号处理
在/system/core/init/init.cpp的main方法中,通过调用signal_handler_init方法来初始化信号处理进程。
5.1 signal_handler_init
深入到/system/core/init/signal_handler.cpp的signal_handler_init方法中:
void signal_handler_init() {
// 创建socket pair
int s[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
PLOG(ERROR) << "socketpair failed";
exit(1);
}
signal_write_fd = s[0];
signal_read_fd = s[1];
// 当捕获到信号SIGCHLD,则写入signal_write_fd
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIGCHLD_handler;
//SA_NOCLDSTOP使init进程只有在其子进程终止时才会收到SIGCHLD信号
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, 0);
//进入waitpid来处理子进程是否退出的情况
ServiceManager::GetInstance().ReapAnyOutstandingChildren();//详情见5.2
//调用epoll_ctl方法来注册epoll的回调函数
register_epoll_handler(signal_read_fd, handle_signal);//详情见5.3
}
init进程是所有用户空间进程的父进程,当子进程终止时会产生SIGCHLD信号,此时init进程会调用信号安装函数sigaction,然后将SIGCHLD作为参数传递给sigaction结构体,从而完成信号处理的过程。
其中,SIGCHLD_handler是写入数据的函数:
static void SIGCHLD_handler(int) {
//向signal_write_fd写入1,直到成功为止
if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
PLOG(ERROR) << "write(signal_write_fd) failed";
}
}
handle_signal是读取数据的函数:
static void handle_signal() {
// Clear outstanding requests.
char buf[32];
//读取signal_read_fd中的数据,并放入buf
read(signal_read_fd, buf, sizeof(buf));
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
}
5.2 ServiceManager::GetInstance().ReapAnyOutstandingChildren
下面来看看处理子进程是否退出的流程:
深入到/system/core/init/service.cpp的ServiceManager::ReapAnyOutstandingChildren中:
void ServiceManager::ReapAnyOutstandingChildren() {
while (ReapOneProcess()) {
}
}
继续深入到ReapOneProcess方法中:
bool ServiceManager::ReapOneProcess() {
int status;
//等待任意子进程,如果子进程没有退出则返回0,否则则返回该子进程pid
pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
if (pid == 0) {
return false;
} else if (pid == -1) {
PLOG(ERROR) << "waitpid failed";
return false;
}
//根据pid查找到相应的service
Service* svc = FindServiceByPid(pid);
std::string name;
std::string wait_string;
if (svc) {
name = android::base::StringPrintf("Service '%s' (pid %d)",
svc->name().c_str(), pid);
if (svc->flags() & SVC_EXEC) {
wait_string =
android::base::StringPrintf(" waiting took %f seconds", exec_waiter_->duration_s());
}
} else {
name = android::base::StringPrintf("Untracked pid %d", pid);
}
if (WIFEXITED(status)) {
LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
} else if (WIFSIGNALED(status)) {
LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
} else if (WIFSTOPPED(status)) {
LOG(INFO) << name << " stopped by signal " << WSTOPSIG(status) << wait_string;
} else {
LOG(INFO) << name << " state changed" << wait_string;
}
if (!svc) {
return true;
}
svc->Reap();
//当flags为EXEC时,重置相应的服务
if (svc->flags() & SVC_EXEC) {
exec_waiter_.reset();
}
//当flags为EXEC时,释放相应的服务
if (svc->flags() & SVC_TEMPORARY) {
RemoveService(*svc);
}
return true;
}
5.3 register_epoll_handler
register_epoll_handler是用来注册epoll的回调函数
深入到/system/core/init/init.cpp的register_epoll_handler方法中:
void register_epoll_handler(int fd, void (fn)()) {
epoll_event ev;
ev.events = EPOLLIN;
ev.data.ptr = reinterpret_cast<void
>(fn);
//将fd的可读事件加入到epoll_fd的监听队列中
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
PLOG(ERROR) << "epoll_ctl failed";
}
}
当fd为可读的时候,则会触发调用(fn)函数。
5.4 要点总结:
5.4.1 signal_handler_init的作用
主要是防止init进程的子进程成为僵尸进程,系统会在子进程暂停或停止的时候发出SIGCHLD信号,而signal_handler_init方法会对系统发出的SIGCHLD信号进行处理,这样就防止了僵尸进程的出现。
5.4.2 什么是僵尸进程?
在Linux中,父进程是通过fork的方式创建子进程,在子进程终止的时候,如果父进程不知道子进程已经停止,那么此时就算子进程退出,在系统进程表中还会保留一些子进程的信息(如进程号、运行时间、状态等),那么这个子进程就成为了所谓的僵尸进程。但系统进程表中的资源空间是有限的,如果被僵尸进程耗尽,系统就无法创建新的进程。
6. 解析init.rc文件
init.rc是由Android初始化语言(Android Init Language)编写的脚本。rc文件的语法是以行尾为单位,以空格间隔,用#开始代表注释行。rc文件主要包含了5中类型的语句,分别是:Action、Command、Option、Service和Import。init.rc文件的目录在system/core/rootdir/init.rc中。
6.1 Action
Action类型的语句是通过触发器触发,格式如下:
on <trigger> [&& <trigger>] //设置触发器
<command>
<command> //动作触发后要执行的命令
即以on开头的语句来决定执行相应service的时机,具体时机有如下几个:
on early-init 在初始化早期触发
on init 在初始化时触发
on late-init 在初始化晚期触发
on boot/charger 当系统启动或充电时触发
on property:= 当属性值满足条件时触发
6.2 Command
列举一些常用的命令:
loglevel : 设置log级别
start : 启动指定的服务,如果已经启动则跳过
stop : 停止正在运行的服务
export : 设定环境变量
setprop : 设置属性值
write : 向文件path中写入字符串
6.3 Service
以service开头的是由init进程启动,一般都是运行在init的某个子进程中。
service类型的语句,格式如下:
service <name> <pathname> [<argument>]
//<service的名><执行程序的路径><传递参数>

<option>   //option是service的修饰词,影响什么时候、如何启动service <option> 注意:在Android8.0对init.rc文件进行拆分,每个服务对应一个rc文件。 这里以64位处理器为例,Zygote启动脚本则在init.zygote64.rc中定义。 init.zygote64.rc的代码如下:(目录:system/core/rootdir/init.zygote64.rc) 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类型语句格式大致解析下: service用于通知init进程创建名为zygote进程 执行程序的路径是/system/bin/app_process64 传递的参数是/system/bin --zygote --start-system-server class main 是指Zygote的classname为main init.rc中Action、Service语句都有相应的XXXParser类来解析。即Action类型会有ActionParser来进行解析,Service类型会有ServiceParser来解析。 因为后面分析Zygote,所以主要看下ServiceParser,ServiceParser的代码目录是: system/core/init/service.cpp 1 深入到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_ = std::make\_unique<Service>(name, str\_args);//注释1 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;//注释2 } void ServiceParser::EndSection() { if (service_) { ServiceManager::GetInstance().AddService(std::move(service_));//注释3 } } 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; } services_.emplace_back(std::move(service)); } 注释说明: 注释1:调用ParseSection方法,根据传入的参数创建出一个Service参数 注释2:调用ParseLineSection方法解析出Service语句中的每一个子项,并将内容添加到Service对象中 注释3:解析完所有数据后,调用EndSection函数,内部调用ServiceManager中的AddService函数,将Service对象加入vector类型的Service链表中。 6.4 Option option是配合service使用,是Service中的可选项。 \* socket : 创建名为/dev/socket/<name>的socket \* user : 设置执行服务的用户,默认是root \* group : 设置执行服务的用户组,默认是root \* onrestart : 当服务重启时执行相应的命令 \* oneshot : service退出后不再重启 \* disabled : 不随class自动启动,只有根据service名才启动 7\. init启动Zygote 这里我们同样以64位处理器为例,由前面可知,Zygote启动脚本在system/core/rootdir/init.zygote64.rc中: 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 从上面可知zygote的classname是main 在init.rc中有如下两行配置: 目录:system/core/rootdir/init.rc on nonencrypted class_start main //注释1 class\_start late\_start 其中,class\_start是一个COMMAND,对应的函数是do\_class_start。注释1处表明启动那些classname为main的service,而zygote的classname是main,所以这里是用来启动Zygote的。 深入到do\_class\_start函数中: 目录:system/core/init/builtins.cpp static int do\_class\_start(const std::vector<std::string>& args) { ServiceManager::GetInstance(). ForEachServiceInClass(args\[1\], \[\] (Service* s) { s->StartIfNotDisabled(); }); return 0; } do\_class\_start()函数中会遍历前面的Vector类型的Service链表,找到classname为main的Zygote,并调用system/core/init/service.cpp中的StartIfNotDisabled()函数: bool Service::StartIfNotDisabled() { if (!(flags_ & SVC_DISABLED)) { //注释1 return Start(); } else { flags_ |= SVC\_DISABLED\_START; } return true; } 在注释1处,如果Service中没有在其对应的rc文件中设置disabled选项,则会调用Start函数启动该Service,因为Zygote对应的init.zygote64.rc中没有设置disable选项,所以直接调用Start函数启动该Service bool Service::Start() { // 如果Service已经运行,则直接return if (flags_ & SVC_RUNNING) { return false; } ...省略... // 判断需要启动的Service的对应的执行文件是否存在,不存在则不启动该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; } ...省略... // 如果子进程没有启动,则调用fork函数创建子进程,并返回pid的值 pid_t pid = -1; if (namespace\_flags\_) { pid = clone(nullptr, nullptr, namespace\_flags\_ | SIGCHLD, nullptr); } else { pid = fork(); } // 如果pid=0,则表示当前代码逻辑在子进程中运行 if (pid == 0) { umask(077); ...省略... //调用execve函数,启动Service子进程 if (execve(strs\[0\], (char**) &strs\[0\], (char**) ENV) < 0) { //注释1 PLOG(ERROR) << "cannot execve('" << strs\[0\] << "')"; } _exit(127); } ...省略... NotifyStateChange("running"); return true; } 综上所述: 首先判断Service是否已经启动,如果运行了,则直接返回。 如果子进程没有启动,就调用fork函数创建子进程,并返回pid的值 如果返回pid的值是0,则表示当前代码逻辑在子进程中运行 注释1处在子进程中调用execve函数,Service子进程就会被启动,并进入到该Service的main函数中。 如果该Service是Zygote,从前面的system/core/rootdir/init.zygote64.rc文件中我们可以知道Zygote执行程序的路径是/system/bin/app\_process64,对应的文件是app\_main.cpp,这样就会进入app_main.cpp的main函数中,即Zygote的main函数中: 代码路径:frameworks/base/cmds/app\_process/app\_main.cpp main函数如下: int main(int argc, char* const argv\[\]) { ...省略... if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); //注释1 } 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."); } } 在注释1处调用runtime的start函数启动Zygote,到此Zygote进程就启动了。

转载于:https://my.oschina.net/u/4132401/blog/3048895

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值