首页 > 技术知识 > 正文

1. 前言

基于上一篇继续说明 https://www.ebaina.com/articles/140000012378

2. init.rc目录结构

system/core/rootdir/ ├── Android.mk ├── etc │   ├── hosts │   ├── init.testmenu │   └── mountd.conf ├── init.environ.rc.in ├── init.rc ├── init.trace.rc ├── init.usb.rc ├── init.zygote32_64.rc ├── init.zygote32.rc ├── init.zygote64_32.rc ├── init.zygote64.rc └── ueventd.rc

Android 在system/core/init/readme.txt 文件中对rc脚本语言规则进行了说明.rc脚本主要包括了 Actions, Commands, Services, 和Options 4种类型声明. Init.rc文件基本组成单位是section.,有Actions和Services、Import三种类型。

3. init.rc脚本格式

(1)Actions

Android rc脚本文件中Action,以关键字on开始,在关键字on和下一个关键字on之间为一个section;Action中关键字on后面的字符串是trigger,用于决定Action执行的时机.Action被执行时,其中的Command也会被逐一运行. Actions格式如下:

on <trigger> <command> <command> <command> struct action { struct listnode alist; /* actions链表节点 */ struct listnode qlist; /*等待执行的actions链表节点 */ struct listnode tlist; /* trigger 链表*/ unsigned hash; const char *name; struct listnode commands; /* commands链表,用于挂载Action中所有的命令 */ struct command *current; /*当前正在被执行的command命令*/ };

(2)Service Android rc脚本文件中Service是一个后台程序,Options是Service的一个参数项,用于决定Service运行时机以及如何运行,Service格式如下

service <name> <pathname> [ <argument> ]* <option> <option> …

Inir进程中解析init.rc脚本中service section内容保存在struct service结构体实例中,结构体如下:

truct service { struct listnode slist; //插入全局链表service_list的节点list const char *name; //服务名称 const char *classname; //服务类名称,默认是“default“ unsigned flags; //服务keyword关键字类型 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; char *seclabel; struct socketinfo *sockets; struct svcenvinfo *envvars; //服务env环境变量 struct action onrestart; // 服务重启时需要执行的命令 int *keycodes; int nkeycodes; int keychord_id; int ioprio_class; int ioprio_pri; int nargs; //参数个数 char *args[1]; //服务值args[0]为脚本内容中第三个参数;args[1] = 0 };
<

(3)import 关键字 在一个.rc文件中引入其他的都rc文件.

import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /init.${ro.zygote}.rc import /init.trace.rc

实际在根目录下存在的*.rc文件如下

init.common.rc init.debug.rc init.environ.rc init.rc init.recovery.sun50iw1p1.rc init.sun50iw1p1.rc init.sun50iw1p1.usb.rc init.trace.rc init.usb.rc init.zygote32.rc ueventd.rc ueventd.sun50iw1p1.rc init.rc import section

init.rc import section的解析主要在system/core/init/init_parser.c文件的parse_config()函数尾部,import解析内容会通过import结构体添加到import_list中,再次执行解析流程

static void parse_config(const char *fn, char *s) { … …. …. ….. parser_done: list_for_each(node, &import_list) { struct import *import = node_to_item(node, struct import, list); … …. …. ….. ret = init_parse_config_file(import->filename); if (ret) ERROR(“could not import file %s from %s\n”, import->filename, fn); } } 4. init.rc 解析

Android init启动分析(2)init.rc解析处理

init.rc解析流程,解析的主函数在system/core/init/init_parser.c文件中:

static void parse_config(const char *fn, char *s) { struct parse_state state; struct listnode import_list; … … … list_init(&import_list); state.priv = &import_list; for (;;) { switch (next_token(&state)) { … … … case T_NEWLINE: state.line++; if (nargs) { int kw = lookup_keyword(args[0]); if (kw_is(kw, SECTION)) { state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { state.parse_line(&state, nargs, args); } … … … parser_done: list_for_each(node, &import_list) { struct import *import = node_to_item(node, struct import, list); ret = init_parse_config_file(import->filename); … … … } }
<

parse_config主要完成以下步骤:

a.初始化state,将*.rc文件名称和文件内容分别保存在state. filename和state.ptr变量中。初始化import_list链表,链表指针保存在state.priv变量中;

b.通过next_token()函数检查每一行内容,分别返回T_EOF、T_NEWLINE和T_TEXT三种状态,分别为文件内容结束、文件内容换行和被空格隔开的参数三种类型;

c.针对T_NEWLINE类型,解析上一行脚本内容args[0]第一次参数,判断命令类型,如果是K_service、K_on和K_import类型,则调用parse_new_section进入新的section解析流程;

d.如果是K_service,调用parse_service( )动态创建struct service 类型内存区svc。初始化svc成员onrestart.name默认为”onrestart”,初始化svc->onrestart.commands链表,用于挂载服务重启时执行的命令。将服务插入service_list全局链表中。最后将svc指针返回给state->context,state->parse_line指向parse_line_service( )函数,用于后面解析service section中的options参数。

e.如果是K_on,调用parse_action()动态初始化struct action 类型内存区act,初始化commands链表和qlist链表,将act插入到action_list全局链表中。最后将act指针返回给state->context,state->parse_line指向parse_line_action() 函数,用于解析Action section中的command命令,并插入act->commands链表中;

f.如果是K_import,调用parse_import(),动态创建struct import 类型内存区import,初始化filename,将import插入到import_list全局链表中。

5. init.rc 执行

Android init启动分析(2)init.rc解析处理1

猜你喜欢