csharp
system/core/init/
init.cpp
init_parser.cpp
signal_handler.cpp
builtins.cpp
system/core/rootdir/
init.rc
init进程(pid=1)是Linux系统中用户空间的第一个进程
主要工作如下:
- 创建一块共享的内存空间,用于属性服务器;
- 解析各个rc文件,并启动相应属性服务进程;
- 初始化epoll,依次设置signal、property、keychord这3个fd可读时相对应的回调函数;
- 进入无限循环状态,执行如下流程:
- 检查action_queue列表是否为空,若不为空则执行相应的action;
- 检查是否需要重启的进程,若有则将其重新启动;
- 进入epoll_wait等待状态,直到系统属性变化事件(property_set改变属性值),或者收到子进程的信号SIGCHLD,再或者keychord 键盘输入事件,则会退出等待状态,执行相应的回调函数。
init.cpp
scss
static int epoll_fd = -1;
int main(int argc, char** argv) {
...
//设置文件属性0777
umask(0);
//初始化内核log,位于节点/dev/kmsg
klog_init();
//设置输出的log级别
klog_set_level(KLOG_NOTICE_LEVEL);
//创建一块共享的内存空间,用于属性服务
property_init();
//初始化epoll功能
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
//初始化子进程退出的信号处理函数,并调用epoll_ctl设置signal fd可读的回调函数
signal_handler_init();
//加载default.prop文件
property_load_boot_defaults();
//启动属性服务器,此处会调用epoll_ctl设置property fd可读的回调函数【见小节5.2】
start_property_service();
//解析init.rc文件
init_parse_config_file("/init.rc");
//执行rc文件中触发器为on early-init的语句
action_for_each_trigger("early-init", action_add_queue_tail);
//等冷插拔设备初始化完成
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
//设备组合键的初始化操作,此处会调用epoll_ctl设置keychord fd可读的回调函数
queue_builtin_action(keychord_init_action, "keychord_init");
// 屏幕上显示Android静态Logo
queue_builtin_action(console_init_action, "console_init");
//执行rc文件中触发器为on init的语句
action_for_each_trigger("init", action_add_queue_tail);
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
char bootmode[PROP_VALUE_MAX];
//当处于充电模式,则charger加入执行队列;否则late-init加入队列。
if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0)
{
action_for_each_trigger("charger", action_add_queue_tail);
} else {
action_for_each_trigger("late-init", action_add_queue_tail);
}
//触发器为属性是否设置
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
while (true) {
if (!waiting_for_exec) {
execute_one_command();
//根据需要重启服务
restart_processes();
}
int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action) {
timeout = 0;
}
epoll_event ev;
//循环等待事件发生
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
if (nr == -1) {
ERROR("epoll_wait failed: %s\n", strerror(errno));
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
1.解析init.rc
rc文件语法是以行尾单位,以空格间隔的语法,以#开始代表注释行。rc文件主要包含Action、Service、Command、Options,其中对于Action和Service的名称都是唯一的,对于重复的命名视为无效。
Action
Action: 通过触发器trigger,即以on开头的语句来决定执行相应的service的时机,具体有如下时机:
- on early-init; 在初始化早期阶段触发;
- on init; 在初始化阶段触发;
- on late-init; 在初始化晚期阶段触发;
- on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
- on property:=: 当属性值满足条件时触发;
Service
服务Service,以 service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过fork方式生成子进程。
例如: service servicemanager /system/bin/servicemanager代表的是服务名为servicemanager,服务执行的路径为/system/bin/servicemanager。
Command
下面列举常用的命令
- class_start <service_class_name>: 启动属于同一个class的所有服务;
- start <service_name>: 启动指定的服务,若已启动则跳过;
- stop <service_name>: 停止正在运行的服务
- setprop :设置属性值
- mkdir :创建指定目录
- symlink <sym_link>: 创建连接到的<sym_link>符号链接;
- write : 向文件path中写入字符串;
- exec: fork并执行,会阻塞init进程直到程序完毕;
- exprot :设定环境变量;
- loglevel :设置log级别
Options
Options是Service的可选项,与service配合使用
- disabled: 不随class自动启动,只有根据service名才启动;
- oneshot: service退出后不再重启;
- user/group: 设置执行服务的用户/用户组,默认都是root;
- class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
- onrestart:当服务重启时执行相应命令;
- socket: 创建名为/dev/socket/的socket
- critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式
2启动服务
execute_one_command()
执行每个action中携带的command对应的执行函数。
csharp
on nonencrypted
class_start main //启动那些classname为main的Service,以zygote为例
class_start late_start
其中class_start是一个Command,对应的函数为do_class_start。 builtins.cpp
arduino
int do_class_start(int nargs, char **args)
{
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
*/
service_for_each_class(args[1], service_start_if_not_disabled);
return 0;
}
static void service_start_if_not_disabled(struct service *svc)
{
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);
} else {
svc->flags |= SVC_DISABLED_START;
}
}
init.cpp中service_start
ini
void service_start(struct service *svc, const char *dynamic_args)
{
pid_t pid = fork();
if (pid == 0) {
struct socketinfo *si;
struct svcenvinfo *ei;
char tmp[32];
int fd, sz;
if (!dynamic_args) {
if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
}
} else {
char *arg_ptrs[INIT_PARSER_MAXARGS+1];
int arg_idx = svc->nargs;
char *tmp = strdup(dynamic_args);
char *next = tmp;
char *bword;
/* Copy the static arguments */
memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
while((bword = strsep(&next, " "))) {
arg_ptrs[arg_idx++] = bword;
if (arg_idx == INIT_PARSER_MAXARGS)
break;
}
arg_ptrs[arg_idx] = NULL;
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
}
_exit(127);
}
svc->NotifyStateChange("running");
}
通过调用pid =fork()
创建子进程,通过execve(svc->args[0], (char**)svc->args, (char**) ENV)
,进入App_main.cpp的main()函数。故zygote是通过fork和execv共同创建的。