init.c源码跟踪
工具:Source Insight
最好也打开源码,一步一步的跟,并仔细看后面的注释。
一、linux内核起来后,android的第一个用户进程:init
1.那么来看看init.c中的main函数,它做了什么?
Init.c system\core\Init打开source Insigt
可以看到:
...
open_devnull_stdio();
log_init();
INFO("reading config file\n");
parse_config_file("/init.rc");
...
2. 现在主要分析:parse_config_file("/init.rc");这个函数
跟进去:int parse_config_file(const char *fn)
{
char *data;
data = read_file(fn, 0);/*读取配置文件内容,这个文件就是init.c*/
if (!data) return -1;
parse_config(fn, data);/*调用parse_config做真正的解析*/
DUMP();
return 0;
}
3.看parse_config到底什么解析:
state.parse_line = parse_line_no_op; /*设置解析函数,
for (;;) { 不同的内容用不同的解析函数*/
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
return;
case T_NEWLINE:
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); /*是的话解析新的SECTION*/
} else {
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
break;
case T_TEXT:
if (nargs < SVC_MAXARGS) {
args[nargs++] = state.text;
}
break;
}
}
可见,这个函数是以一个一个Section进行解析的,而且不同的section使用不同的解析函数。
4. 那么,如何判断那些属于一个section呢?
1) 先去看看keyword.h中:
#ifndef KEYWORD
int do_class_start(int nargs, char **args); /*声明一些函数,不同的内容用不同的解析函数*/
int do_class_stop(int nargs, char **args);
...
...
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs, func) K_##symbol, /*定义KEYWORD宏,虽然有四个参数,但这里只用一个 (得到K_symbol)*/
enum { /*定义了各个关键字的枚举值*/
#endif
KEYWORD(capability, OPTION, 0, 0) /*宏展开为:K_capability*/
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1, do_class_start)
....
....
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
};
#undef __MAKE_KEYWORD_ENUM__
#undef KEYWORD /*取消宏定义*/
#endif
2) 再看看,parser.c中:
/*第一次包含*/ #include "keywords.h" /*第一次包含得到了一个枚举定义。*/
/*接下来重新定义KEYWORD宏,*/
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
struct {
const char *name; /*关键字的名称*/
int (*func)(int nargs, char **args);/*对应关键字的处理函数*/
unsigned char nargs; /*参数个数,每个关键字的参数个数是固定的*/
unsigned char flags; /*关键字的属性有三种:COMMEND,OPTION,SECTION,
其中COMMAND有对应的处理函数*/
} keyword_info[KEYWORD_COUNT] = {
[ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
/*第二次包含*/ #include "keywords.h"
};
#undef 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)
从中可以发现,包含了两次头文件,第一次包含得到了一个枚举定义。
将#include "keywords.h"替换,就可以很清楚的知道什么回事了:
第一步为:(也就是第一次#include "keywords.h"之前)
KEYWORD(capability, OPTION, 0, 0) /*宏展开为:K_capability*/
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
......
第二步:第一次替换成: (第一次#include "keywords.h"之后)
K_capability
K_class
K_class_start
K_class_stop
第三步:重新定义KEYWORD
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
第四步:第二次#include "keywords.h"
struct {
const char *name; /*关键字的名称*/
int (*func)(int nargs, char **args);/*对应关键字的处理函数*/
unsigned char nargs; /*参数个数,每个关键字的参数个数是固定的*/
unsigned char flags; /*关键字的属性有三种:COMMEND,OPTION,SECTION,
其中COMMAND有对应的处理函数*/
} keyword_info[KEYWORD_COUNT] = {
[ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
[K_capability] = "capability",func,nargs+1,flags,},
[K_class] = "class",func,nargs+1,flags,},
.....
};
回到第四点的问题:我们在keywords.h中发现只有
KEYWORD(on, SECTION, 0, 0)
KEYWORD(service, SECTION, 0, 0)
这两的中含有关键字SECTION。
5.我们进init.rc中
on init #on 关键字标志一个section,对应的名字为“init”
# 下面所有的内容都属于这个section,直到下一个section开始时
sysclktz 0
loglevel 3
# setup the global environment
export PATH /sbin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /system/lib
export ANDROID_BOOTLOGO 1 #根据keyword.h可知,export表示一个command
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
....
....
on boot
...
...
class_start default
#class_start也是一个command,对应函数为do_class_start
#keywords.h--->KEYWORD(class_start, COMMAND, 1, do_class_start)
...
...
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
6. 解析service
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666 #socket是OPTION
#下面的onrestart是OPTION,而write和restart是COMMAND。
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
解析section的入口函数是parser.c---->parse_new_section(&state, kw, nargs, args);
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) {
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;
}
state->parse_line = parse_line_no_op;
}