init进程是android启动的第一个进程 进程pid为1.其主要做了如下几件事:
*解析配置文件
*根据配置文件执行操作early_init init early_boot boot
*设置属性服务
本节主要内容讲解如何解析init.rc文件和运行zygote.
1.解析init.rc配置文件
/**init.c*/
在main函数中,执行如下函数:
init_parse_config_file("/init.rc");/**init_parse.c*/
int init_parse_config_file(const char *fn){ char *data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); DUMP(); return 0;}static void parse_config(const char *fn, char *s);
parse_config函数主要找到一个SECTION的节点开始解析if (kw_is(kw, SECTION)) { state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args);}
kw_is函数执行了keywords文件 并找处指定标示 k_##symbol
/**keywords.h*/
1>定义枚举.枚举值为k_class k_mkdir等2>定义结构体数组keyword_info,把KEYOWRD宏改变成结构体,通过宏定义找出symbol与func解析init.rc文件
如关键字section的symbol为chdir 则找到如int do_chdir(int nargs, char **args)的声明查看对应定义
>>>关键字有:OPTION,COMMAND,SECTION
/**init.rc*/
on init #表示on的SECTION名称为init 基本步骤为early-init init early-boot boot
#从一个section开始 到下一个section开始标签前结束
export ANDROID_ROOT /system #表示export为一个COMMAND
*如下图
2.分析zygote
/**init.rc配置文件*/
在该文件中 zygote被定义为需要执行4个操作并且拥有一个socket为660的服务,他是init的一个子进程.
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd
---------------Service定义信息------------------
-维护所有生成Service的一个双向链表listnode
-service的name zygote的name为init.svc.zygote
-className 默认"default"
-属性flag pid uid gid io优先级 参数(个数)
-time_started time_crashed nr_crashed 上次启动死亡时 总死亡次数
-socketinfo(socket环境变量信息) svcenvinfo(进程所需环境变量信息)
-struct action onrestart; 保存OPTION后面的COMMAND信息
------------------------------------------------
---------------onrestart定义信息------------------
struct action { /* node in list of all actions */ struct listnode alist; /* node in the queue of pending actions */ struct listnode qlist; /* node in list of actions for a trigger */ struct listnode tlist; unsigned hash; const char *name; struct listnode commands; struct command *current;//保存restart里面的COMMOND动作};
------------------------------------------------
#主要执行parse_service 和parse_line_service
//创建service结构体主要框架,并添加到service_list双向链表中
//socketinfo是一个单向链表 zygote只有一个660 的TCP scoket
//onrestart通过commond指向一个commonds链表 zygote如上在init.rc中可以看出有4个commond
static void *parse_service(struct parse_state *state, int nargs, char **args){ struct service *svc; svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); if (!svc) { parse_error(state, "out of memory\n"); return 0; } svc->name = args[1]; svc->classname = "default"; memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs; svc->onrestart.name = "onrestart"; list_init(&svc->onrestart.commands); list_add_tail(&service_list, &svc->slist); return svc;}
static void parse_line_service(struct parse_state *state, int nargs, char **args){ struct service *svc = state->context; nargs--; args++; kw = lookup_keyword(args[0]); //创建Commond结构体 cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); //添加到双向列表中 list_add_tail(&svc->onrestart.commands, &cmd->clist);}
**********init 启动zygote**********
1)init.c::main>
// 将boot的commond加入到执行队列中 因为zygote 包含在boot动作中
action_for_each_trigger("boot", action_add_queue_tail);
//执行队列中的commond 并统一执行所有section的commond
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
2)Bultins.c::do_class_start>
//因为class_start是一个COMMOND所以他会被执行 在这里zygote是一个 "default"的className
//所以执行service_start_if_not_disabled函数
//如果service的flag被明确规定为disable 那么执行该service必须单独再执行
service_for_each_class(args[1],service_start_if_not_disabled);
3)Bultins.c::service_start_if_not_disabled>
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);//之前设置没有创建flags 表示该service还未启用 执行service_start
}
4)init.c::service_start>
>>判断文件进程/system/bin/process文件是否存在 一般service有自己的进程
rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
>>启动init子进程
pid = fork();
>>添加进程环境变量信息
>>添加socket环境变量信息并创建socket
>>设置uid gid并启动/system/bin/app_process文件的main函数
>>设置service的启动时间 pid等等
>>绑定操作 响应事件
1)init.c::main>>
queue_builtin_action(signal_init_action, "signal_init");
2)init.c::signal_init_action>>
signal_init();
3)signal_handler::signal_init>>
struct sigaction act;//绑定2个方法 sigchld_handler handle_signal 其结构体还包括了一个sa_flags标示
>>zygote死后父进程init调用sigchld_handler
1)signal_handler::sigchld_handler>>
write(signal_fd, &s, 1);//往signal_fd中写数据 signal_fd是socketpair中两条socket中的一条
2)init.c::main>>
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
3)signal_handler::handle_signal>>
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0)) ;
4)signal_handler::wait_for_one_process>>
//杀掉zygote的所有子进程
//清除我们将要重建的scoket
//将所有onrestart的commond(zygote中有4个)添加到svc中的action结构体列表中
//改变svc状态为restarting
5)init.c::main>>
//poll后进入下一轮循环 又执行main
execute_one_command();//执行所有COMMOND
restart_processes();//改变flag标识