Android启动之init.c文件main函数分析

来源:互联网 发布:勃列日涅夫之吻 知乎 编辑:程序博客网 时间:2024/05/01 13:30

源码位置:/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)) {// 判断关键字类型是不是为SECTIONstate.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,#endifKEYWORD(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,// 0K_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 参数个数为5service zygote /system/bin/app_process -Xzygote /system/bin -zygote --start-system-server// 下面socket 和 onrestart 都是表示OPTION// write 和 restart都是COMMANDsocket zygote stream 666onrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart 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 专门用来保存serviceconst char* name;// service 名字const char* classname;// 默认 defaultunsigned 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 存储那些等待某些条件满足后需要执行的actionstruct 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为defaultstatic 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中的optionstatic 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 wakenargs--;args++;kw = lookup_keyword(args[0]);// 返回K_write 作为索引if(!kw_id(kw, COMMAND)) break;// 根据前面的keyword_info数组判断write是不是commandkw_nargs = kw_nargs(kw);// 判断write需要几个参数cmd = malloc(sizeof(*cmd) + sizeof(char*)*nargs);cmd->func = kw_func(kw);// 这里应该是do_write函数cmd->nargs = nargs;// 3memcpy(cmd->args, args, sizeof(char*)*nargs);//  onrestart write /sys/android_power/request_state wakelist_add_tail(&svc->onrestart.commands, &cmd->clist);break;}case K_socket: {// socket zygote stream 666struct socketinfo* si;si = calloc(1, sizeof(*st));si->name = args[1];// zygotesi->type = args[2];// streamsi->perm = strtoul(args[3], 0, 8);// 666if(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(){// 第一次进来肯定为NULLif(!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {cur_action = action_remove_queue_head();// 获得actioncur_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头部开始获取actionvoid 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获得包含的第一个commandstatic 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函数