《Android的设计与实现:卷I》——第3章 3.4.2init.rc的内容

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 本节书摘来自华章出版社《Android的设计与实现:卷I》——第3章,第3.4节。作者: 杨云君著.更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.4.2 init.rc的内容

熟悉了Android初始化语言,再来阅读init.rc文件就容易多了。以下是init.rc的内容:

image
image

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

3.4.3 解析配置文件

我们已经熟悉了Android初始化语言和init.rc的内容。那init程序又是如何解析init.rc的呢?
解析init.rc的函数是init_parse_config_file("/init.rc"),位于/system/core/init/init_parser.c。代码如下:
int init_parse_config_file(const char fn)
{
char data;
/调用open、read,malloc读取init.rc到buffer;

并配合struct stat记录文件状态,主要记录的是文件大小,存入read_file的
第二个参数保存,这里传入0,即不带回文件大小。stat结构体也是Linux定义的/
data = read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data); //开始解析init.rc
/DUMP()位于/system/core/init/parser.c中,用于输出service_list和
 action_list中存储的Service和Action。调试的时候作用很大,默认是关闭的/
DUMP();
return 0;

}
从init_parse_config_file 的函数体可以看出,它主要做了读取文件、解析文件、调试文件这三部分工作。读取文件和调试文件比较简单,都是基本的C函数。这里重点分析解析文件的部分,即parse_config(fn, data),该函数定义于init_parser.c中,代码如下:
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;            //init.rc文件路径
state.line = 0;            //当前解析的行号
/ptr指向当前将要解析的内容,初始时传入的是fn的文件内容,即init_parse_config_file中
 的data指针。解析过程中,不断移动到将要解析的数据/
state.ptr = s;  
/当前解析的是什么类型的行,分为
 文件结束(T_EOF)、新的一行(T_NEWLINE)、参数(T_TEXT)/
 state.nexttoken = 0; 
/针对不同类型的行,采用不同的解析方法,初始化为
 parse_line_no_op ,这是个空函数体,不做任何操作 /
 state.parse_line = parse_line_no_op;
/在无限循环中解析init.rc,直到遇到文件结束符EOF,退出循环 /
for (;;) {
    /next_token函数以state为参数把每行的关键字存入args数组/
    switch (next_token(&state)) {
    case T_EOF: //文件结束
       state.parse_line(&state, 0, 0);//传入0,表示末尾
       goto parser_done;
    case T_NEWLINE://新的一行
       state.line++;
       if (nargs) {
/根据第一个关键字匹配Section/
 int kw = lookup_keyword(args[0]);
/如果该行是Section,即第一个关键字是on或者service/
 if (kw_is(kw, SECTION)) {
    /链表中最后一个元素写入0,即NULL,结束上一个Section /
    state.parse_line(&state, 0, 0); 
    /开始新的Section解析过程/
    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;
}
}
parser_done:
……
}

parse_config函数中主要做了两部分工作。首先提供了一个parse_state结构体存储当前解析状态,然后提供一个无限循环开始解析初始化文件。

解析过程是按行解析,并根据关键字匹配,如果遇到Section,便调用parse_new_section函数,进入Section的解析过程。parse_state定义在parser.h中,lookup_keyword和parse_new_section定义在init_parser.c中,其中lookup_keyword就是一个简单的switch语句,用来根据传入的参数匹配不同的关键字。

下面继续分析parse_new_section的内容,代码如下:
void parse_new_section(struct parse_state state, int kw, int nargs, charargs)
{

/匹配Section类型,分成Service和Action,分别对应不同的解析函数/
switch(kw) {
case K_service: //如果是关键字service,开始解析Service
     /返回初始化的Service,由state->context引用/
     state->context = parse_service(state, nargs, args);
     if (state->context) {
    /解析并填充Service,用真正的Service解析函数parse_line_service
     代替parse_line_no_op /
        state->parse_line = parse_line_service;
        return;
    }
    break;
case K_on: //如果是关键字on,即action,开始解析Action
     /返回初始化的Action,由state->context引用/
     state->context = parse_action(state, nargs, args);
     if (state->context) {
     /解析并填充Action,用真正的Action解析函数 parse_line_action
      代替parse_line_no_op /
        state->parse_line = parse_line_action;
        return;
    }
    break;
case K_import://如果是import语句,则重复解析初始化文件的过程
    parse_import(state, nargs, args);
    break;
}
/ 出错,未找到匹配项,复位解析函数为空函数体/
state->parse_line = parse_line_no_op; 

}
分析到这里,init.rc的解析过程基本明朗了。从parse_new_section函数可以看出,init.rc实际上是分成Action和Service两部分分别解析的。
解析Service调用了parse_service和parse_line_service。
解析Action调用了parse_action和parse_line_action。
接下来具体分析这4个解析函数是如何实现的。

相关文章
|
2月前
|
Shell Android开发
Android系统 init.rc文件详解
Android系统 init.rc文件详解
192 0
|
2月前
|
安全 Shell Android开发
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
Android系统 init.rc sys/class系统节点写不进解决方案和原理分析
85 0
|
2月前
|
安全 Shell Android开发
Android系统 init.rc开机执行shell脚本
Android系统 init.rc开机执行shell脚本
213 0
|
Android开发
flutter中实现仿Android端的onResume和onPause方法
flutter中实现仿Android端的onResume和onPause方法
|
10月前
|
Android开发
Android init.rc脚本详解
Android init.rc脚本详解
234 2
|
10月前
|
Shell Android开发
Android init language与init.rc初始化脚本
Android init language与init.rc初始化脚本
62 0
|
监控 安全 Linux
|
Android开发
Android Studio项目中的Gradle视图内容
Android Studio项目中的Gradle视图内容
|
缓存 JSON Java
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
372 1
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
|
XML 安全 Linux