为Android应用程序读取/dev下设备而提权(二)

原文地址:http://blog.csdn.net/yiyaaixuexi/article/details/6966800

为Android应用程序读取/dev下设备而提权(一)中,简单总结了提权的两种方法: device_initinit.rc 。在此篇文章中,我将详细总结的是稍一不留神,就容易把人弄晕乎的init.cdevice_initinit.rc 三者之间的关系,TA们到底是如何工作的。



目录结构

         ls一下system/core/init/
devices.c、devices.h、init.c、init.h、keywords.h、parser.c、property_service.c....
        另外system/core/rootdir/init.rc ,当然init.rc的位置可以另行指定。



init流程

         init过程的起点是init.c :        *注释中的序号表示执行顺序   
  1. int main(int argc, char **argv) 
  2.     … … 
  3.     mkdir("/dev", 0755); //建立基本文件系统节点 
  4.     mkdir("/proc", 0755); 
  5.     mkdir("/sys", 0755); 
  6.     mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); 
  7.     mkdir("/dev/pts", 0755); 
  8.     mkdir("/dev/socket", 0755); 
  9.     mount("devpts", "/dev/pts", "devpts", 0, NULL); 
  10.     mount("proc", "/proc", "proc", 0, NULL); 
  11.     mount("sysfs", "/sys", "sysfs", 0, NULL); 
  12. … … 
  13.     INFO("reading config file\n"); 
  14.     parse_config_file("/init.rc");   // 1、 调用parse_config 函数解析init.rc脚本  
  15.     //11、经过解析,init.rc的内容就被分为多少个段,被串在action_list链表中。on 开头的都是action类型的段,比如init段,init段用一个结构体struct action表示,    其中name是init,所有这个段内的命令,都被串在commands链表中。 
  16.     action_for_each_trigger("early-init", action_add_queue_tail);  //12、 遍历action_list链表,查找name是early-init的那个action,将这个节点放在action_queu    e的尾部。 
  17.     drain_action_queue(); // 13、将action_queue尾部的节点遍历,然后删除。就相当于遍历name是early-init的action节点内的commands链表。就是在执行init.rc脚本中    on early-init段内的所有命令。 
  18.     … … 
  19.     INFO("device init\n"); 
  20.     device_fd = device_init();  //常见必要的设备节点 
  21.     property_init(); //init 以后的任务就是proper_service 
  22.  
  23.     action_for_each_trigger("init", action_add_queue_tail);  //14、将init 段,加入action_queue 
  24.     drain_action_queue(); // 执行init段得命令 
  25.     … … 

system/core/init/parser.c:

  1. static void parse_config(const char *fn, char *s) 
  2.     struct parse_state state; 
  3.     char *args[MAXARGS]; 
  4.     int nargs; 
  5.  
  6.     nargs = 0; 
  7.     state.filename = fn; 
  8.     state.line = 1; 
  9.     state.ptr = s; 
  10.     state.nexttoken = 0; 
  11.     state.parse_line = parse_line_no_op;  //这个函数是空的,就是什么都不做 
  12.     for (;;) { 
  13.         switch (next_token(&state)) {  // 2、 和T_TEXT状态配合,先把把每一行的参数都放在args数组里 
  14.         case T_EOF: 
  15.             state.parse_line(&state, 0, 0); // 最后看这,到此文件解析完成,也是上一段的完成,需要写个NULL表示末尾。 
  16.             return
  17.         case T_NEWLINE: 
  18.             if (nargs) { 
  19.                 int kw = lookup_keyword(args[0]);  // 3、得到新的一行,开始解析,判断一下拿到的第一个参数是什么关键字,这里面有几种情,命令COMMAND,段SECTION,和选项OPTION,这个选项是针对服务的,开启,关闭等操作。 
  20.                 if (kw_is(kw, SECTION)) {   // 4、判断得到的关键字是不是段,keywords.h里定义了各种能解析的关键字分别是什么属性。 
  21.                     state.parse_line(&state, 0, 0); // 表示上一段解析结束,因为使用的是双向链表,这样就给链表最后一个元素写NULL,表示到末尾了。 
  22.                     parse_new_section(&state, kw, nargs, args);  // 5、创建一个新段的链表,比如init段,先跳到这个函数看,然后再回来。 
  23.                 } else
  24.                     state.parse_line(&state, nargs, args); //10、 得到新的一行,通过上面的操作已经知道现在是在什么段中,是on 还是service,行解析函数也做了相应变化,开始解析这一行,加入action的commands链表中。 
  25.                 } 
  26.                 nargs = 0; 
  27.             } 
  28.             break
  29.         case T_TEXT: 
  30.             if (nargs < MAXARGS) { 
  31.                 args[nargs++] = state.text; 
  32.             } 
  33.             break
  34.         } 
  35.     } 
  36.  
  37.  
  38. void parse_new_section(struct parse_state *state, int kw, 
  39.                        int nargs, char **args) 
  40.     printf("[ %s %s ]\n", args[0], 
  41.            nargs > 1 ? args[1] : ""); 
  42.     switch(kw) {  // 6、这里判断 是什么类型的段,不同类型的段使用的解析函数不同,说白了就是分命令还是服务。 
  43.     case K_service: 
  44.         state->context = parse_service(state, nargs, args); 
  45.         if (state->context) { 
  46.             state->parse_line = parse_line_service; 
  47.             return
  48.         } 
  49.         break
  50.     case K_on: 
  51.         state->context = parse_action(state, nargs, args); // 7、创建一个action 链表,把这个链表加入到action_list中 
  52.         if (state->context) { 
  53.             state->parse_line = parse_line_action; // 8、把行解析函数换掉,原来是parse_no_op 什么都不做,再在要把每行都解析成一个命令动作。把这个命令动作加入到action中的commands链表内 
  54.             return
  55.         } 
  56.         break
  57.     } 
  58.     state->parse_line = parse_line_no_op; // 9、走到这就是出错了,段的名字没写或者写多了 


本章小结


       经过上面的分析,对/dev/设备权限的修改放在不同的位置会有覆盖的效果,device.c内的修改会覆盖early-init段内的命令,init 段内的命令会覆盖device.c中的修改,如果3个位置都有对用一个设备权限的修改,那init段的修改会最终生效。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值