Android启动之init.c文件main函数分析
最后更新于:2022-04-01 15:54:03
源码位置:/syste/core/init/init.c文件
~~~
int main(int argc, char **argv)
{
int fd_count = 0;
struct pollfd ufds[4];
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
init_parse_config_file("/init.rc"); // 解析/init.rc文件
/* pull the kernel commandline and ramdisk properties file in */
import_kernel_cmdline(0, import_kernel_nv); // 从/proc/cmdline获取参数
chmod("/proc/cmdline", 0440);
get_hardware_name(hardware, &revision);
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); // 根据硬件名字,获取对应的rc文件
init_parse_config_file(tmp);
// 对于service,这里会为每个服务建立一个struct service结构体,全部加入service_list链表之后,在init的最后循环中按照顺序启动
// 检查解析出的命令行当中是否有early-init阶段的动作,加入到action_queue中,马上执行
// init动作执行分为4个阶段:early-init、init、early-boot、boot
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(property_init_action, "property_init");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
queue_builtin_action(set_init_properties_action, "set_init_properties");
// 触发init阶段的动作
action_for_each_trigger("init", action_add_queue_tail);
// 如果是充电启动,则跳过下面这些动作
if (strcmp(bootmode, "charger") != 0) {
action_for_each_trigger("early-fs", action_add_queue_tail);
action_for_each_trigger("fs", action_add_queue_tail);
action_for_each_trigger("post-fs", action_add_queue_tail);
action_for_each_trigger("post-fs-data", action_add_queue_tail);
}
// 启动属性服务,加载属性文件
queue_builtin_action(property_service_init_action, "property_service_init");
// 信号处理这里会通过socketpair创建两个socket套接字,一个用于接收,一个用于发送
queue_builtin_action(signal_init_action, "signal_init");
// 检查开机状况
queue_builtin_action(check_startup_action, "check_startup");
if (!strcmp(bootmode, "charger")) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
// 触发early-boot和boot阶段的动作
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
}
// 启动所有依赖于当前时间属性的操作,即:启动那些根据属性值来判断是否执行的动作
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
for(;;) {
int nr, i, timeout = -1;
// 循环中执行动作,并重启那些死去的进程
execute_one_command();
restart_processes();
// init 处理来自三个方面的消息
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
if (!signal_fd_init && get_signal_fd() > 0) {
ufds[fd_count].fd = get_signal_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
signal_fd_init = 1;
}
if (!keychord_fd_init && get_keychord_fd() > 0) {
ufds[fd_count].fd = get_keychord_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
keychord_fd_init = 1;
}
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action)
timeout = 0;
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
// 处理这三个方面的消息
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
}
return 0;
}
~~~
**1)解析配置文件:**
根据前面所知,在init中系统会解析两个配置文件,一个是/init.rc系统配置文件,另外一个是与硬件平台相关的配置文件。调用的都是同一个函数:
~~~
int init_parse_config_file(const char*fn)
{
char*data;
data = read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data);
return 0;
}
struct parse_state
{
char* ptr; // 读指针
char* text; // 文本
int line; // 第几行
int nexttoken; // 下一个标示符
void* context;
void (*parse_line)(struct parse_state* state, int nargs, char**args); // 解析函数
const char* filename;
};
static void parse_config(const char *fn, char *s)
{
struct parse_state state;
char *args[INIT_PARSER_MAXARGS]; // 最多64个参数
int nargs;
nargs = 0;
state.filename = fn;
state.line = 0;
state.ptr = s;
state.nexttoken = 0;
state.parse_line = parse_line_no_op; // 设置解析函数,不同内容对应不同的解析函数
for (;;)
{
switch (next_token(&state)) // 获取配置文件中特殊标识,如文件结尾:T_EOF, 换行符:T_NEWLINE, 文本:T_TEXT
{
case T_EOF:
state.parse_line(&state, 0, 0);
return;
case T_NEWLINE:
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) { // 判断关键字类型是不是为SECTION
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
break;
case T_TEXT:
if (nargs < INIT_PARSER_MAXARGS) {
args[nargs++] = state.text;
}
break;
}
}
}
这里parse_config,首先会找到配置文件的一个section,然后针对不同的section使用不同的解析函数来解析。
下面我们看看关键字的定义:keywords.h文件中
#ifndef KEYWORD // 如果没有定义KEYWORD这个宏
int do_class_start(int nargs, char**args);
int do_class_stop(int nargs, char**args);
int do_class_reset(int nargs, char**args);
...
#define __MAKE_KEYWORD_ENUM__ // 定义一个宏
#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
enum {
K_UNKNOWN,
#endif
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(on, SECTION, 0, 0)
....
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
};
#undef __MAKE_KEYWORD_ENUM__
#undef KEYWORD
#endif
在parser.c文件中:
#define SECTION 0x01
#define COMMAND 0x02
#define OPTION 0x04
#include "keywords.h"
// 第一次包含ketwords.h文件,由于没有定义宏KEYWORD所以,相当于:
/*
int do_class_start(int nargs, char**args);
int do_class_stop(int nargs, char**args);
int do_class_reset(int nargs, char**args);
...
enum {
K_UNKNOWN, // 0
K_class,
K_class_start,
K_on,
....
KEYWORD_COUNT,
};
得到了一个枚举的定义
*/
// 自己定义了一个宏
#define KEYWORD(symbok, flags, nargs, func) [ K_##symbol ] = {#symbol, func, nargs+1, flags,},
struct {
const char* name; // 关键字名字
int (*func)(int args, char**args); // 对应关键字的处理函数
unsigned char nargs;
unsigned char flags; // 关键字属性:COMMAND、OPTION、SECTION
} keyword_info[KEYWORD_COUNT] = {
[ K_UNKNOWN] = {"unknown", 0, 0, 0},
// #include "keyword.h" //第二次包含keywords.h文件,由于已经定义了KEYWORD所以相当于:
// KEYWORD(class, OPTION, 0, 0)
// KEYWORD(class_start, COMMAND, 1, do_class_start)
// KEYWORD(service, SECTION, 0, 0)
/***宏替换之后为 ***/
[ K_class ] = {"class", 0, 1, OPTION,},
[ k_class_start ] = {"class_start", do_class_start, 2, COMMAND,},
[ k_service ] = {"service", 0, 1, SECTION},
.....
};
#indef KEYWORD
同时我们还定义了一些辅助的宏:
#define kw_is(kw, type) (keyword_info[kw].flags & (type))
#define kw_name(kw) (keyword_info[kw].name)
#define kw_func(kw) (keyword_info[kw].func)
#define kw_nargs(kw) (keyword_info[kw].nargs)
这样我们就得到了一个全局的数组keyword_info,以前面枚举值为索引,存储对应的关键字信息,包括关键字名称、处理函数、参数个数、属性等等。
下面我们根据上面定义的数组ketword_info来看看init.rc文件,如 Zygote:
// service是一个section 的标志,名字为zygote 参数个数为5
service zygote /system/bin/app_process -Xzygote /system/bin -zygote --start-system-server
// 下面socket 和 onrestart 都是表示OPTION
// write 和 restart都是COMMAND
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
找到section之后我们的入口函数时parse_new_section:
void parse_new_section(struct parse_state *state, int kw, int nargs, char **args)
{
switch(kw) {
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
case K_import:
if (nargs != 2) {
ERROR("single argument needed for import\n");
} else {
int ret = init_parse_config_file(args[1]);
if (ret)
ERROR("could not import file %s\n", args[1]);
}
}
state->parse_line = parse_line_no_op;
}
对于service这里我们看到主要就是调用两个函数:parse_service 和 parse_line_service,在这之前我们首先看看init是怎么组织这些service的。
struct service {
struct listnode slist; // 用于将结构体连接成一个双向链表,Init 中有一个全局链表service_list 专门用来保存service
const char* name; // service 名字
const char* classname; // 默认 default
unsigned char flags;
pid_t pid;
...
struct socketinfo *sockets; // 保存service用到的socket,也是一个链表
struct svcenvinfo *envvars; // 描述创建这个进程时需要的环境变量信息
struct action onrestart; // 存储command信息
int nargs; // 参数个数
char *nargs[1]; // 存储参数
};
struct action {
// 一个action 存放在三个双向链表中,alist 存储所有的action
// qlist 存储那些等待执行的action
// tlist 存储那些等待某些条件满足后需要执行的action
struct listnode alist;
struct listnode qlist;
struct listnode tlist;
unsigned hash;
const char* name;
struct listnode commands;
struct command* current;
};
struct command
{
struct listnode clist; // command 链表
int (*func)(int nargs, char**args);
int nargs;
char *args[1];
};
//parse_service:创建service对象,解析定义的service行,设置默认class为default
static void* parse_service(struct parse_state* state, int nargs, char**args)
{
struct service *svc;
svc = service_find_by_name(argv[1]); // 如果这个服务已经存在
if (svc) return 0;
nargs -= 2;
svc = calloc(1, sizeof(*svc) + sizeof(char*)*nargs);
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); // 将这个service加到全局链表service_list的尾部
return svc;
}
// 根据服务名字查找链表
struct service* service_find_by_name(const char*name)
{
struct listnode* node;
struct service* svc;
list_for_each(node, &service_list) {
svc = node_to_item(node, struct service, slist);
if (!strcmp(svc->name, name))
return svc;
}
/* 宏替换相当于:
for(node = service_list->next; node != service_list; node = node->next)
{
svc = (struct srevice*)(((char*)node) - offsetof(struct service, slist));
// svc = (strcut service*)( ((char*)node) - (size_t)&((struct service)0)->slist)
// 就是根据链表中的node找到对应的service结构体
if (!strcmp(svc->name, name))
return svc;
}
*/
return 0;
}
/*
这里的service_list是一个全局的双向循环链表,static list_declare(service_list);宏替换后为:
struct listnode service_list = { .next = &service_lsit, .prev = &service_list,};
*/
// 双向链表添加程序
void list_add_tail(struct listnode *head, struct listnode *item)
{
item->next = head;
item->prev = head->prev;
head->prev->next = item;
head->prev = item;
}
/* 当添加了3个节点a,b,c到链表之后相当于:
service_list->next = a;
a->next = b;
b->next= c;
c->next = service_list;
*/
//parse_line_service: 解析service中的option
static void parse_line_service(struct parse_state* state, int nargs, char**args)
{
struct service *svc = state->context;
struct command* cmd;
int i, kw, kw_nargs;
svc->ioptro_class = IoSchedClass_NONE;
kw = lookup_keyword(args[0]);
switch(kw) {
case K_capability:
break;
case K_class:
...
case K_onrestart:{ // onrestart write /sys/android_power/request_state wake
nargs--;
args++;
kw = lookup_keyword(args[0]); // 返回K_write 作为索引
if(!kw_id(kw, COMMAND)) break; // 根据前面的keyword_info数组判断write是不是command
kw_nargs = kw_nargs(kw); // 判断write需要几个参数
cmd = malloc(sizeof(*cmd) + sizeof(char*)*nargs);
cmd->func = kw_func(kw); // 这里应该是do_write函数
cmd->nargs = nargs; // 3
memcpy(cmd->args, args, sizeof(char*)*nargs); // onrestart write /sys/android_power/request_state wake
list_add_tail(&svc->onrestart.commands, &cmd->clist);
break;
}
case K_socket: { // socket zygote stream 666
struct socketinfo* si;
si = calloc(1, sizeof(*st));
si->name = args[1]; // zygote
si->type = args[2]; // stream
si->perm = strtoul(args[3], 0, 8); // 666
if(nargs > 4)
....
si->next = svc->sockets; // 前向插入到svc->sockets这个链表中
svc->sockets = si;
break;
}
default:
psrse_error("");
}
}
~~~
这样通过解析init.rc和init.hardware.rc之后我们将所有的service通过一个全局链表service_list连接起来了,同理将所有action通过一个全局链表action_list连接起来。
**2)判断各个阶段工作开始执行**
~~~
action_for_each_trigger("early-init", action_add_queue_tail);
action_for_each_trigger("init", action_add_queue_tail);
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
// 这里我们通过分析early-init为例:
void action_for_each_trigger(const char* trigger, void (*func)(struct action* act))
{
struct listnode *node;
struct action *act;
list_for_each(node, &action_list){
act = node_to_item(node, struct action, alist);
if(!strcmp(act->name, trigger))
func(act);
}
}
//同前面的service分析,这里通过全局链表action_list,找到对应节点的action,如果节点的名字属性为early-init,执行func这个回调函数。
void action_add_queue_tail(struct action* act)
{
list_add_tail(&action_queue, &act->qlist);
}
//我在网上看到很多说上面的action_for_each_trigger函数是执行early-init阶段的action,但是我分析发现:这里也是将这些那些等待执行链表qlist中的action加入到action_queue这个全局链表中,action_queue也是通过宏声明的list_declare(action_queue)。并没有立即执行!!!
同理后面的action_for_each_trigger("init",...)等都是将不同阶段的action加入到action_queue这个链表中。
~~~
**3)属性服务初始化和信号处理初始化**
~~~
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(property_init_action, "property_init");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
queue_builtin_action(set_init_properties_action, "set_init_properties");
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signale_init_action, "signale_init");
queue_builtin_action(check_startup_action, "check_startup");
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
void queue_builtin_action(int (*func)(int nargs, char**args), char *name)
{
struct action* act;
struct command *cmd;
act = calloc(1, sizeof(*act));
act->name = name;
list_init(&act->commands);
// 将这个命令加到action的commands里面
cmd = calloc(1, sizeof(*cmd));
cmd->func = func;
cmd->args[0] = name;
list_add_tail(&act->commands, &cmd->clist);
// 将这个action加到全局链表action_list中去
list_add_tail(&action_list, &act->alist);
// 将这个action的等待执行的链表qlist加入到action_queue中
action_add_queue_tail(act);
}
~~~
**4)进入死循环执行**
~~~
for(;;)
{
execute_command();
restart_processes();
for(i = 0; i < fd_count; i++) {
if(ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if(ufds[i].fd == get_keychord_fd())
handle_keychord();
else if(ufds[i].fd == get_signale_fd())
handle_signale();
}
}
}
// 这里主要关心属性设置、组合按键输入、信号三个事件。
handle_property_set_fd();
handle_keychord();
handle_signale();
~~~
下面我们主要来看看execute_command() 函数 和 restart_processes()函数
~~~
static struct action *cur_action = NULL;
static struct command *cur_command = NULL;
execute_one_command()
{
// 第一次进来肯定为NULL
if(!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
cur_action = action_remove_queue_head(); // 获得action
cur_command = NULL;
if (!cur_action)
return;
cur_command = get_first_command(cur_action); // 根据action获得command
} else {// 如果一个action包含多个command的情况就需要多次调用才能执行完成
cur_command = get_next_command(cur_action, cur_command);
}
if (!cur_command)
return;
cur_command->func(cur_command->nargs, cur_command->args); // 调用当前command的func函数
}
// 从链表action_queue头部开始获取action
void action_remove_queue_head()
{
if(list_empty(&action_queue))
return 0;
else {
struct listnode* node = list_head(&action_queue);
struct action *act = node_to_item(node, struct action, qlist);
list_remove(node);
return act;
}
}
// 根据action获得包含的第一个command
static struct command* get_first_command(struct action* act)
{
struct listnode* node;
node = list_head(&act->commands);
if (!node || list_empty(&act->commands))
return NULL;
return node_to_item(node, struct command, clist);
}
// 重新启动那些死去的进程
restart_processes()
{
process_needs_restart = 0;
service_for_each_flags(SVC_RESTARTING, restart_servce_if_needed);
}
// 这里根据init.rc里面服务service的标志位flag判断如果死亡是否需要重启,最后调用的service_start函数
~~~