init是Linux系统中用户空间的第一个进程。init进程主要实现系统初始化,一个是解析init.rc文件,根据文件内容做相应初始化,如创建系统其它关键进程zygote;一个是提供属性服务,最后通过poll调用进入无限循环,保持响应系统各种外部事件。

Android源代码位置:

1
/system/core/init/init.c的main函数

解析init.rc文件

1
parse_config_file("/init.rc");

parse_config_file的实现在/system/core/init/parser.c文件,函数里面实际调用的是parse_config。基本思路是先找到配置文件的一个section,再根据不同section使用不同解析函数来解析出对应的service, action对象。其中比较有趣的是keywords.h被引入两次,引入前有没有定义KEYWORD关键字实现不同动作。

执行“early-init”阶段的操作

1
2
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();

执行设备初始化,系统属性初始化,加载初始化动画

1
2
device_fd = device_init();
property_init();

执行“init”阶段的操作

1
2
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();

启动属性服务,子进程退出通知的socketpair

1
2
3
4
5
6
7
8
9
property_set_fd = start_property_service();
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
signal_fd = s[0];
signal_recv_fd = s[1];
fcntl(s[0], F_SETFD, FD_CLOEXEC);
fcntl(s[0], F_SETFL, O_NONBLOCK);
fcntl(s[1], F_SETFD, FD_CLOEXEC);
fcntl(s[1], F_SETFL, O_NONBLOCK);
}

执行“early-boot”和“boot”阶段的操作

1
2
3
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
drain_action_queue();

根据当前系统属性状态运行触发的操作

1
2
queue_all_property_triggers();
drain_action_queue()

在无限循环中通过poll轮询等待IO事件,让程序一直运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
for(;;) {
int nr, i, timeout = -1;

for (i = 0; i < fd_count; i++)
ufds[i].revents = 0;

drain_action_queue();
restart_processes();

if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}

nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;

if (ufds[2].revents == POLLIN) {
/* we got a SIGCHLD - reap and restart as needed */
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0))
;
continue;
}

if (ufds[0].revents == POLLIN)
handle_device_fd(device_fd);

if (ufds[1].revents == POLLIN)
handle_property_set_fd(property_set_fd);
if (ufds[3].revents == POLLIN)
handle_keychord(keychord_fd);
}