Android读取init.rc配置文件parse_config函数解析
来源:互联网 发布:网络销售的意义 编辑:程序博客网 时间:2024/04/19 17:54
Android源代码版本:4.0.3
static void parse_config(const char *fn, char *s)函数在Android的init程序启动过程中用于解析init.rc文件。init.rc文件是安卓系统的初始化文件,其中的内容可以分为三大类:
1. Action:一个action表示一个动作,以关键字on作为开头,并加上action的名称,接下来的是对应于这个action的各种command,而command就是一些基本点linux命令。一个action可以包含有多个command,每个command被独立的执行。
init.rc文件中一条action的格式如下:
on early-init write /proc/1/oom_adj -16 setcon u:r:init:s0 start ueventd setsebool debugfs 1上述信息配置了一个名称为early-init的action,包含了4条command。在安卓源码中,action的对应的结构体如下:
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;/* action名称 */ struct listnode commands;/* 所有command组成的链表 */ struct command *current;/* 当前执行的command,方便定位 */};
2. Service:一个service代表一个服务,以service作为关键字开头,代表一个守护进程,例如zygote、sysmon、servicemanager等都会在init.rc文件中配置。
init.rc中的一条service的格式如下:
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 onrestart restart sensorhubservice onrestart restart bootchecker onrestart restart gsiff_daemon第一行表示要启动一个名称为zygote的service,相应的执行命令为“/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server”,一个service至少包含三个部分(service + name + path),参数项不是必须的。
安卓源码中的service结构体如下所示:
struct service { /* list of all services */ struct listnode slist; const char *name; const char *classname; unsigned flags; pid_t pid; time_t time_started; /* time of last start */ time_t time_crashed; /* first crash within inspection window */ int nr_crashed; /* number of times crashed within window */ uid_t uid; gid_t gid; gid_t supp_gids[NR_SVC_SUPP_GIDS]; size_t nr_supp_gids; struct socketinfo *sockets; struct svcenvinfo *envvars; struct action onrestart; /* Actions to execute on restart. */ /* keycodes for triggering this service via /dev/keychord */ int *keycodes; int nkeycodes; int keychord_id; int ioprio_class; int ioprio_pri; int nargs; /* "MUST BE AT THE END OF THE STRUCT" */ char *args[1];}; /* ^-------'args' MUST be at the end of this struct! */所以根据上面的init.rc中的service记录,系统会创建一个名称为zygote的service,并根据内容设置他的name、classname、sockets以及onrestart变量。
3. import:一个import等于包含一个新文件,以import关键字区分,类似于c中的include。
init.rc中的import格式如下所示:
import /init.environ.rcimport /init.usb.rcimport /init.${ro.hardware}.rcimport /init.trace.rcimport /init.carrier.rcimport /init.container.rc
在init程序中,首先会调用init_parse_config_file函数载入并解析init.rc文件,该函数首先通过read_file将文件载入内存,并在文件尾部增加一个换行符和休止符,方便解析过程。解析函数parse_config是本文的重点。
parse_config:
static void parse_config(const char *fn, char *s) /*在上面操作中已经将文件读取到了data中*/{ struct parse_state state; /* 定义一个解析状态变量 */ char *args[INIT_PARSER_MAXARGS]; 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)) { /*判断下一个最小解析单元类型,这个单元可以是一个换行、结束符、一个单词等*/ case T_EOF: /*如果读到了文件底部返回*/ state.parse_line(&state, 0, 0); /*解析最后一行数据*/ return; /* newline表示是新的一行,有两种情况会返回T_NEWLINE * 上一行有效数据已经读完了,但是还未解析,下一次调用next_tokern会返回T_NEWLINE * 读到了换行符,会直接返回T_NEWLINE */case T_NEWLINE: state.line++; if (nargs) { /* nargs表示还未解析的那一行的单词个数,如果nargs大于0,表示还有有效数据需要解析 *//* 根据每一行开头单词判断本行类型 */ int kw = lookup_keyword(args[0]);/* 如果起始单词是on、import、service的话,说明是一个新的section */ if (kw_is(kw, SECTION)) { state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { /* 这行是一个子语句,此时的函数指针被指向相应的处理函数。 * service对应parse_line_service, * action对应parse_line_action, * 其它的是空操作*/ state.parse_line(&state, nargs, args); } nargs = 0; } break; case T_TEXT: /*每一行有效数据会存储在args中,每一个单词占一个位置,nargs表示目前读取的这一行数据读了几个单词*/ if (nargs < INIT_PARSER_MAXARGS) { args[nargs++] = state.text; } break; } } }
首先定义一个状态结构体用来保存当前的解析状态,包括当前解析到哪里(ptr)以及当前解析的是属于action还是service(parse_line,不同的类别函数指针不同)等。然后循环调用next_token函数从文件中尝试获取下一个处理单元,一个处理单元可以是:新的一行,文件末尾以及一行中的一个单词。根据返回值的不同类型执行不同的操作。
1. 如果是EOF:表示读取到了文件尾部,将最后一行解析完毕后返回。
2. 如果是一个TEXT:表示读取到了一个有效单词,但是本行还未读完,由于是按照行来解析数据,将其存入args数组中并将计数器nargs加1。
3. 如果是NEXLINE:表示是一个新的行,分两种情况:
a). 在读取行时还没有读到单词就遇到了换行符,会直接返回T_NEWLINE,这时nargs等于0。没有有效数据,直接进行下一次循环。
b). 如果正在读取有效数据(已经读取了一些单词),遇到了换行符,会将state的nexttoken成员设置完T_NEWLINE,下一次调用的时候会直接返回T_NEWLINE。这种情况下计数器nargs是大于1的。然后调用lookup_keyword,并将本行的第一个单词作为参数传递。lookup_keyword根据参数判断本行数据的标签内容,如果是import、on、service的话,表示这是一个新的section,需要在parse_config中调用parse_new_section。最后将计数器nargs置为0为解析下一行做准备。
parse_new_section:
void parse_new_section(struct parse_state *state, int kw, int nargs, char **args){ printf("[ %s %s ]\n", args[0], nargs > 1 ? args[1] : ""); switch(kw) {/* 是一条service */ case K_service: /* 通过调用service_find_by_name函数从service_list中根据名称查找 * 是否有对应的struct service,不能打开相同的service,如果没有找 * 到,通过调用calloc分配内存,初始化struct service参数,然后调 * 用list_add_tail将该service加入service_list循环双链表中,最后返回 * 新建的service */ state->context = parse_service(state, nargs, args); if (state->context) { /* 不为空表示是新建的service,将state的函数指针变换为parse_line_service, * 从这一行开始的语句将会用service函数进行解析 */ state->parse_line = parse_line_service; return; } break; /* 是一条action */ case K_on: /*类似的将相应的action添加到action_list*/ state->context = parse_action(state, nargs, args); if (state->context) { /*action不为空的话将state的函数指针变为parse_line_action,接下来是解析action子语句,即command*/ 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]);/*import的是类似于init.environ.rc的文件,也调用read_file和parse_config将其加载*/ if (ret) ERROR("could not import file %s\n", args[1]); } } state->parse_line = parse_line_no_op;}可以看到在parse_new_section函数中不仅会新建service、action,也会把state的函数指针parse_line指向相应的解析函数。在parse_config函数中调用parse_line的实际执行过程也会改变,解析方式非常的灵活。。
- Android读取init.rc配置文件parse_config函数解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- Android init.rc解析
- 项目总结-SpringMVC细节问题
- try catch 以及return 的使用
- Spring 让 LOB 数据操作变得简单易行
- jsp技术之购物车---look.jsp
- UART 和 USART 有区别
- Android读取init.rc配置文件parse_config函数解析
- MS SQL数据库创建作业时报c001f011错误
- 管道命令
- springMVC分页
- 关于打不开百度首页问题
- 免费的DNS
- 2014-12-23 百度文库 504 Gateway Time-out
- BroadcastReceiver的两种实现方式
- Python字符编码问题