Android init.rc on property
来源:互联网 发布:手机微信无法连接网络 编辑:程序博客网 时间:2024/06/02 06:06
在 init.rc 中,可以见到下面类似的用法,当一个属性值等于XX时,触发下面的事件,比如启动一个进程,或者设置打印级别
on property:sys.init_log_level=*
loglevel ${sys.init_log_level}
那么它是如何实现的,启动时触发一次?还是任何时刻只要属性值满足条件就触发?
实验验证结果:
1、启动时,如果属性满足设定条件会触发一次
2、系统运行中如果属性发生变化,且新值等于设定值,则触发一次
代码分析:
init.c (system\core\init)
int main(int argc, char **argv)
{
...
//分配存放属性的共享内存
property_init();
...
INFO("property init\n");
property_load_boot_defaults(); //加载默认的属性
INFO("reading config file\n");
init_parse_config_file("/init.rc");//解析init.rc文件
...
//处理 on early-init\init section部分,本文暂不关心
action_for_each_trigger("early-init", action_add_queue_tail);
action_for_each_trigger("init", action_add_queue_tail);
//这个是重点
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
//陷入死循环,等待接收别的进程设置属性
for (;;)
{
int nr, i, timeout = -1;
//重点稍后分析
execute_one_command();
restart_processes();
//使用poll轮训是否有进程设置属性
...
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;
}
.rc 文件中关于类似 on property:sys.init_log_level=* 的解析过程:
int init_parse_config_file(const char *fn)
parse_config(fn, data);
return 0;
}
static void parse_config(const char *fn, char *s)
{
...
for (;;) {
switch (next_token(&state)) {
...
case T_NEWLINE: //如果是新的一行
state.line++;
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);
} else { //不是section,那就是command
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
break;
...
}
parser_done:
...
}
static 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;
case K_import:
parse_import(state, nargs, args);
break;
}
state->parse_line = parse_line_no_op;
}
.rc 文件中有三种 section
1:on 开头的
on property:sys.init_log_level=*
loglevel ${sys.init_log_level}
2:service 开头的
service netd /system/bin/netd
3:import开头的
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc
这里,我们只关心 on property:sys.init_log_level=* 这种
static void *parse_action(struct parse_state *state, int nargs, char **args)
{
struct action *act;
//解析 section 构造一个 action 挂入 action_list
act = calloc(1, sizeof(*act));
act->name = args[1];
list_init(&act->commands);
list_init(&act->qlist);
list_add_tail(&action_list, &act->alist);
/* XXX add to hash */
return act;
}
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
struct command *cmd;
struct action *act = state->context;
int (*func)(int nargs, char **args);
int kw, n;
//解析这个 section 对应的 commond 挂入 action 的 commands 链表
cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
cmd->func = kw_func(kw);
cmd->line = state->line;
cmd->filename = state->filename;
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char*) * nargs);
list_add_tail(&act->commands, &cmd->clist);
}
也就是说,在解析完 .rc 文件以后,action_list 链表中填充了大量的 action ,名字类似于property:sys.init_log_level=*,并且可以找到它们对应的 command .
queue_builtin_action(property_service_init_action, "property_service_init");
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;
//和解析 .rc 文件一样,构造 action command 放入 action_list
act = calloc(1, sizeof(*act));
act->name = name;
list_init(&act->commands);
list_init(&act->qlist);
cmd = calloc(1, sizeof(*cmd));
cmd->func = func;
cmd->args[0] = name;
cmd->nargs = 1;
list_add_tail(&act->commands, &cmd->clist);
list_add_tail(&action_list, &act->alist);
action_add_queue_tail(act);
}
值得注意的是,这里还调用了 action_add_queue_tail(act) 将该 action 挂入了 action_queue 链表,在main函数最后的for循环中,将取出 action_queue 链表中的 action ,调用它们的 command ,后面在分析
这里构造了名字为property_service_init、queue_property_triggers的两个 action ,分别都放入action_list\action_queue链表
来看陷入for循环之后的工作:
for (;;)
{
int nr, i, timeout = -1;
//重点稍后分析
execute_one_command();
restart_processes();
//使用poll轮训是否有进程设置属性
...
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(); }
}
}
}
1 execute_one_command();
void execute_one_command(void)
{
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
cur_action = action_remove_queue_head(); //从 action_queue 链表中取出 action
cur_command = NULL;
}
ret = cur_command->func(cur_command->nargs, cur_command->args);//执行 action 的 command
}
现在来分析一下前面的:
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
这里就会调用 property_service_init_action 、queue_property_triggers_action
static int property_service_init_action(int nargs, char **args)
{
start_property_service(); //创建用于获取属性的 socket,不是关心的重点
return 0;
}
static int queue_property_triggers_action(int nargs, char **args)
{
queue_all_property_triggers();
property_triggers_enabled = 1;
return 0;
}
void queue_all_property_triggers()
{
struct listnode *node;
struct action *act;
list_for_each(node, &action_list) {
act = node_to_item(node, struct action, alist);
if (!strncmp(act->name, "property:", strlen("property:"))) {
/* parse property name and value
syntax is property:<name>=<value> */
const char* name = act->name + strlen("property:");
const char* equals = strchr(name, '=');
if (equals) {
char prop_name[PROP_NAME_MAX + 1];
char value[PROP_VALUE_MAX];
int length = equals - name;
if (length > PROP_NAME_MAX) {
ERROR("property name too long in trigger %s", act->name);
} else {
int ret;
memcpy(prop_name, name, length);
prop_name[length] = 0;
/* 如果对应的属性存在,判断是否等于设置的值,或者是* */
ret = property_get(prop_name, value);
if (ret > 0 && (!strcmp(equals + 1, value) ||
!strcmp(equals + 1, "*"))) {
//如果判断成功,挂入 action_queue
action_add_queue_tail(act);
}
}
}
}
}
}
举例分析:property:sys.init_log_level=*
name sys.init_log_level
value *
如果系统中存在 sys.init_log_level 这个属性,就将这个 action 挂入 action_queue
那么,在下次调用 execute_one_command 的时候,就会调用 sys.init_log_level 对应的 command loglevel ${sys.init_log_level} 设置打印级别
也就验证了实验结论,在系统启动过程中,如果存在满足条件的属性,则触发一次!
下次 execute_one_command 什么时候调用?很简单,poll超时返回时,就回到for的起点,调用了!
handle_property_set_fd
property_set((char*) msg.name, (char*) msg.value);
//设置属性
property_changed(name, value);
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled) //前面 queue_property_triggers_action 函数中已经设置为1
queue_property_triggers(name, value);
}
void queue_property_triggers(const char *name, const char *value)
{
struct listnode *node;
struct action *act;
list_for_each(node, &action_list) {
act = node_to_item(node, struct action, alist);
if (!strncmp(act->name, "property:", strlen("property:"))) {
const char *test = act->name + strlen("property:");
int name_length = strlen(name);
if (!strncmp(name, test, name_length) &&
test[name_length] == '=' &&
(!strcmp(test + name_length + 1, value) ||
!strcmp(test + name_length + 1, "*"))) {
action_add_queue_tail(act);
}
}
}
}
在execute_one_command 中就会调用 commmand 了
验证了实验结论中的:系统运行中如果属性发生变化,且新值等于设定值,则触发一次
阅读全文
1 0
- Android init.rc on property
- android—init.rc中on property的触发
- init.rc on property:vold.decrypt=trigger_reset_main 过程
- Android init 进程 init.rc init.*.rc
- Android init 进程 init.rc init.*.rc
- Android init 进程 init.rc init.*.rc
- Android init.rc init.vendor.rc 介绍
- [init.rc] android init.rc 总结
- android init.c init.rc
- android init进程 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
- Advanced System Call Return Values
- ubuntu14.0.4 zhongwen shurufa
- 启动 MacOS10.12.5 上的apache2.4还有php56
- C语言-----如何面向对象编程
- 设计模式-7-装饰器模式
- Android init.rc on property
- 顺序栈的基本用法
- mysql(三)操作数据库
- 2017.7.26 电源设计经验 基础总结
- STL 成员函数
- Redis连接池理解
- STM32 ADC 多通道16路电压采集
- CodeForces 520 B.Two Buttons(bfs)
- json-server模拟接口获取mock数据