本文分析Android中如何解析init.rc文件

init.rc启动脚本路径:system/core/rootdir/init.rc

这里的配置文件主要指init.rc。读者可以进到Android的shell,会看到根目录有一个init.rc文件。该文件是只读的,即使有了root权限,可以修改该文件也没有。因为我们在根目录看到的文件只是内存文件的镜像。也就是说,android启动后,会将init.rc文件装载到内存。而修改init.rc文件的内容实际上只是修改内存中的init.rc文件的内容。一旦重启android,init.rc文件的内容又会恢复到最初的装载。想彻底修改init.rc文件内容的唯一方式是修改Android的ROM中的内核镜像(boot.img)。其实boot.img名曰内核镜像,不过该文件除了包含完整的Linux内核文件(zImage)外,还包括另外一个镜像文件(ramdisk.img)。ramdisk.img就包含了init.rc文件和init命令。所以只有修改ramdisk.img文件中的init.rc文件,并且重新打包boot.img文件,并刷机,才能彻底修改init.rc文件。如果读者有Android源代码,编译后,就会看到out目录中的相关子目录会生成一个root目录,该目录实际上就是ramdisk.img解压后的内容。会看到有init命令和init.rc文件。



一、解析过程

1.扫描init.rc中的token

找到其中的 文件结束EOF/文本TEXT/新行NEWLINE,其中的空格‘ ’、‘\t’、‘\r’会被忽略,#开头的行也被忽略掉;

而对于TEXT,空格‘ ’、‘\t’、‘\r’、‘\n’都是TEXT的结束标志。

2.对每一个TEXT token,都加入到args[]数组中

3. 当遇到新一行(‘\n’)的时候,用args[0]通过lookup_keyword()检索匹配关键字;

1) 对Section(on和service),调用parse_new_section() 解析:

- 对on section,调用parse_action(),并设置解析函数parse_line为parse_line_action()

- 对service section,调用parse_service(),并设置解析函数parse_line为parse_line_service()

2) 对其他关键字的行(非on或service开头的地方,也就是没有切换section)调用parse_line()

也就是,

- 对于on section内的命令行,调用parse_line_action()解析;

- 对于service section内的命令行,调用parse_line_service()解析。

二、关键数据类型原型及关键数据定义

2.1 Token的定义

[cpp] view plain copy
  1. #defineT_EOF0
  2. #defineT_TEXT1
  3. #defineT_NEWLINE2

2.2 关键字定义

[cpp] view plain copy
  1. KEYWORD(capability,OPTION,0,0)
  2. KEYWORD(chdir,COMMAND,1,do_chdir)
  3. KEYWORD(chroot,COMMAND,1,do_chroot)
  4. KEYWORD(class,OPTION,0,0)
  5. KEYWORD(class_start,COMMAND,1,do_class_start)
  6. KEYWORD(class_stop,COMMAND,1,do_class_stop)
  7. KEYWORD(console,OPTION,0,0)
  8. KEYWORD(critical,OPTION,0,0)
  9. KEYWORD(disabled,OPTION,0,0)
  10. KEYWORD(domainname,COMMAND,1,do_domainname)
  11. KEYWORD(exec,COMMAND,1,do_exec)
  12. KEYWORD(export,COMMAND,2,do_export)
  13. KEYWORD(group,OPTION,0,0)
  14. KEYWORD(hostname,COMMAND,1,do_hostname)
  15. KEYWORD(ifup,COMMAND,1,do_ifup)
  16. KEYWORD(insmod,COMMAND,1,do_insmod)
  17. KEYWORD(import,COMMAND,1,do_import)
  18. KEYWORD(keycodes,OPTION,0,0)
  19. KEYWORD(mkdir,COMMAND,1,do_mkdir)
  20. KEYWORD(mount,COMMAND,3,do_mount)
  21. KEYWORD(on,SECTION,0,0)
  22. KEYWORD(oneshot,OPTION,0,0)
  23. KEYWORD(onrestart,OPTION,0,0)
  24. KEYWORD(restart,COMMAND,1,do_restart)
  25. KEYWORD(service,SECTION,0,0)
  26. KEYWORD(setenv,OPTION,2,0)
  27. KEYWORD(setkey,COMMAND,0,do_setkey)
  28. KEYWORD(setprop,COMMAND,2,do_setprop)
  29. KEYWORD(setrlimit,COMMAND,3,do_setrlimit)
  30. KEYWORD(socket,OPTION,0,0)
  31. KEYWORD(start,COMMAND,1,do_start)
  32. KEYWORD(stop,COMMAND,1,do_stop)
  33. KEYWORD(trigger,COMMAND,1,do_trigger)
  34. KEYWORD(symlink,COMMAND,1,do_symlink)
  35. KEYWORD(sysclktz,COMMAND,1,do_sysclktz)
  36. KEYWORD(user,OPTION,0,0)
  37. KEYWORD(wait,COMMAND,1,do_wait)
  38. KEYWORD(write,COMMAND,2,do_write)
  39. KEYWORD(copy,COMMAND,2,do_copy)
  40. KEYWORD(chown,COMMAND,2,do_chown)
  41. KEYWORD(chmod,COMMAND,2,do_chmod)
  42. KEYWORD(loglevel,COMMAND,1,do_loglevel)
  43. KEYWORD(ioprio,OPTION,0,0)

2.3 struct action (动作的结构体)和struct command(命令的结构体)

[cpp] view plain copy
  1. structaction{
  2. /*nodeinlistofallactions*/
  3. structlistnodealist; //所有Action组成的动作列表
  4. /*nodeinthequeueofpendingactions*/
  5. structlistnodeqlist;
  6. /*nodeinlistofactionsforatrigger*/
  7. structlistnodetlist;
  8. unsignedhash;
  9. constchar*name; //动作名字
  10. structlistnodecommands; //命令列表
  11. structcommand*current; //当前命令指针
  12. };

[cpp] view plain copy
  1. structcommand
  2. {
  3. /*listofcommandsinanaction*/
  4. structlistnodeclist; //一个动作的命令列表
  5. int(*func)(intnargs,char**args); //函数()
  6. intnargs;
  7. char*args[1];
  8. };


三、对action的解析

结合init的启动过程以及前面讲述的init.rc的解析,总结一下对init对init.rc里action的解析.

3.1action的解析

调用parse_action()解析Action,并申请了struct action *act(动作的结构体对象),设置:

1) act->name为动作的名字(比如boot/fs/);

2) 初始化list ,act->commands(一个动作的命令列表)

3) 通过act->alist所有Action组成的动作列表)把该动作加入到action_list的列尾(也就是加入到act->alist列表)

这样,action创建并加入到了action_list中。

3.2 action里的command的解析

action里的command,调用parse_line_action()来解析

1) 查找关键字,核对是否是COMMAND,参数数目是否正确

2) 申请struct command *cmd

- cmd->func从keyword表中获取;

- 设置参数个数给cmd->nargs,拷贝参数给cmd->args;

- 通过cmd->clist把该命令加入到act->commands的列尾

这样,command加入到了action中。

3.3 action_list里的action加入action_queue中

action_for_each_trigger()把队列action_list里所匹配的action,追加到action_queue的队尾;

queue_builtin_action()把执行的函数组成command,创建action,挂在action_list上,并追加到action_queue的队尾。

3.4 命令的执行

Init的无限循环中execute_one_command():执行action_queue队列中的Action(system/core/init/init.c)

1) 从action_queue取下struct action *act 赋给cur_action;

2) 从cur_action获得struct command *赋给cur_command;

3) 执行cur_command->func(cur_command->nargs, cur_command->args)

上面步骤中1, 2 & 3是一次执行的,4是无限循环执行,从action_queue上取下action,action里获得command,然后执行command。




更多相关文章

  1. android中下载文件到sdcard和进度条小结
  2. Android(安卓)中webview与原生Java的 交互以及网页JS 与原生的交
  3. Webview实现Android和JS通信
  4. 【转】Android(安卓)技术-- 图形系统详解
  5. Android(安卓)Jni代码示例讲解
  6. AndroidManifest.xml文件详解
  7. Android布局文件中命名空间的解析
  8. Android入门
  9. Android事件分发机制完全解析(终极版二)

随机推荐

  1. Android高仿微信之mvp实现(二)
  2. 【Xamarin.Android】探索android的底部导
  3. 简单轻松!通过USB数据线,让Android(安卓)St
  4. Android(安卓)自定义View实现炮弹射击小
  5. 牛逼的Android(安卓)UI--第18章 与用户交
  6. Android(安卓)超级轻量的版本更新库AppUp
  7. 【评论】阿里云os,到底是不是android OS
  8. android,内存优化详解 .
  9. Android为App签名(为apk签名)
  10. Android用AsyncTask来下载图片及用AsyncT