Android中init.rc文件的解析&&Android init进程启动过程分析

本文深入解析Android中init.rc文件的处理过程,重点介绍onaction的解析,并总结init.rc语法规范。通过对init.rc文件的逐行扫描,分析其关键数据结构与解析流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/thl789/article/details/8681067

田海立@优快云

2013-3-16

 

本文分析Android中如何解析init.rc文件,重点描述了on action内的解析,并从解析的过程中总结出init.rc的语法规范。

 

对init.rc的解析是在parse_config(): [system/core/init/init_parser.c]中进行的。解析发生在init全过程中的哪个阶段,参看《Android init进程启动过程分析》。

 

一、解析过程

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的定义

  1. #defineT_EOF 0  
  2. #defineT_TEXT 1  
  3. #defineT_NEWLINE 2  
 

2.2 关键字定义

  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

  1. struct action {  
  2.         /* node in list of all actions */  
  3.     struct listnode alist;  
  4.         /* node in the queue of pending actions*/  
  5.     struct listnode qlist;  
  6.         /* node in list of actions for atrigger */  
  7.     struct listnode tlist;  
  8.    
  9.     unsigned hash;  
  10.     const char *name;  
  11.      
  12.     struct listnode commands;  
  13.     struct command *current;  
  14. };  
 
  1. struct command  
  2. {  
  3.         /* list of commands in an action */  
  4.     struct listnode clist;  
  5.    
  6.     int (*func)(int nargs, char **args);  
  7.     int nargs;  
  8.     char *args[1];  
  9. };  
 

2.4 list action_list和action_queue

action_list

    解析init.rc时,遇到on action通过act->alist加入;

    queue_builtin_action()把执行的函数组成command,创建action,挂在action_list上。

action_queue

    执行action_for_each_trigger(),通过act->qlist加入;

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

 

三、对action的解析

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

 

3.1 on section内action的解析

    1.3.1中解析到新的on section调用parse_action()时,申请了struct action *act,设置:

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

     2) 初始化list act->commands

     3) 把act->alist加入到action_list的列尾

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

 

3.2 on section内action里的command的解析

    对on section内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():system/core/init/init.c

      1) 从action_queue取下structaction *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。

 

四、init.rc语法小结

    system/core/init/Readme里有init.rc语法的描述。之前笔者没有分析init源码时,也读过这个Readme文件,但是对一些概念界定都搞不太清楚。现在分析过init.rc的解析之后,下面试着对init.rc语法做一下梳理。

1.      #开头的行也被忽略掉,用于注释;

2.      ‘’、‘\t’、‘\r’都会被忽略,所以属性中含有空格的话,后面的不会被识别;每一个Action里command前的缩进并无语法的要求,只是便于人阅读;

3.      ‘\n’是换行的标志,init语法里新解析的开始都是基于新行开始才进行的,是逐行扫描解析的;

4.      一些概念:Section / Action / Command / Trigger

-         Init.rc里,遇到on<trigger>或service <name> <pathname> [ <argument> ]*行,标志着一个新section的开始[参看2.2里关键字定义里,类型为SECTION的也就只有on和service];

-         遇到on <trigger>,trigger是触发条件,发生的时机。可以是early-init / init / early-fs / fs / post-fs / early-boot / boot;也可以是property:<name>=<value>,属性<name>的值被设置为<value>时;device-added-<path>/ device-removed-<path>设备节点被加入或移除时;service-exited-<name>服务退出时。

-         on <trigger>发生时,执行action,也就是on<trigger>后面的部分,可包含多个command;

-         command每条一行,支持哪些command,看2.2里关键字定义里类型为COMMAND的关键字。

 

形式如下:

  1. on <trigger>  
  2.     <command>  
  3.     <command>  
  4.     <command>  
这整个是一个Section;所有<command>叫action。

 

总结

本文解析了init.rc的基本语法,重点讨论on section的解析,service的解析以及property的支持在后续专题中再详细讨论。

Android init进程启动过程分析


http://blog.youkuaiyun.com/thl789/article/details/8681049

田海立@优快云

2013-3-16

 

本文分析Android中init进程的执行过程,只是分析init进程启动的流水,具体细节在今后的各个专题中再分别详细分析。本文虽是后面各个专题的基础,读者初看可能理解不深,可以在阅读后面各个专题的时候,结合本文的整体流程会有更清晰的理解。

 

Init进程从 /system/core/init/init.c里的main()函数开始

 

1.      mkdir && mount

 

2.      import_kernel_cmdline

    从内核中通过/proc/cmdline导入下列命令行参数,这些参数会分别被设置到各个属性值中:

[plain] view plain copy
  1. androidboot.console      // 设置console  
  2. androidboot.mode         // 设置属性ro.factorytest  
  3. androidboot.serialno     // 设置属性ro.serialno  
  4. androidboot.baseband     // 设置属性ro.baseband  
  5. androidboot.carrier      // 设置属性ro.carrier  
  6. androidboot.bootloader   // 设置属性ro.bootloader  
  7. androidboot.hardware     // 设置属性ro.hardware  
  8. androidboot.bsp          // 根据这个设置与否,选择不同的init.rc版本  
注意:以上说的设置属性还未真正设置,property机制还未工作。

 

3.      init_parse_config_file()

    解析init.rc或者init_bsp.rc(看步骤2导入的参数“androidboot.bsp”是否设置)

    Init.rc的解析,参见《Android中init.rc文件的解析

 

4.      get_hardware_name()

    从/proc/cpuinfo中获取“Hardware”字段信息写入<hw>;“Reversion” 字段信息写入<reversion>

 

5.      init_parse_config_file()

    解析init.<hw>.rc或者init_bsp.<hw>.rc(看步骤2导入的参数“androidboot.bsp”是否设置)

    Init.rc的解析,参见《Android中init.rc文件的解析

 

6.      action_for_each_trigger("early-init",action_add_queue_tail);

    对init???.rc中解析出的early-initsection里action,执行action_add_queue_tail操作,也就是把act->qlist加入到action_queue的列尾

:此时并未真正执行,只是挂在队列尾。

 

7.      把一些初始化操作加入到action_queue列表中

  1. queue_builtin_action(wait_for_coldboot_done_action,"wait_for_coldboot_done");  
  2. queue_builtin_action(property_init_action,"property_init");  
  3. queue_builtin_action(keychord_init_action,"keychord_init");  
  4. queue_builtin_action(console_init_action,"console_init");  
  5. queue_builtin_action(set_init_properties_action,"set_init_properties");  
queue_builtin_action(int (*func)(int nargs,char **args), char *name)是以name形成action,挂在 action_list上;以func和name组成command,挂在action的commands上。然后加入到 action_queue的队尾。

 

8.      对其他section内的action,加入到action_queue列表中

    另外一些初始操作也加入到action_queue列表中

  1.     /* execute all the boot actions to getus started */  
  2. action_for_each_trigger("init",action_add_queue_tail);  
  3. action_for_each_trigger("early-fs", action_add_queue_tail);  
  4. action_for_each_trigger("fs",action_add_queue_tail);  
  5. action_for_each_trigger("post-fs",action_add_queue_tail);  
  6.   
  7. queue_builtin_action(property_service_init_action,"property_service_init");  
  8. queue_builtin_action(signal_init_action,"signal_init");  
  9. queue_builtin_action(check_startup_action,"check_startup");  
  10.   
  11. /* execute all the boot actions to get usstarted */  
  12. action_for_each_trigger("early-boot", action_add_queue_tail);  
  13. action_for_each_trigger("boot",action_add_queue_tail);  
  14.   
  15.     /* run all property triggers based oncurrent state of the properties */  
  16. queue_builtin_action(queue_property_triggers_action,"queue_propety_triggers");  
 

9.      进入无限循环中for(;;)

   9.1 execute_one_command():[system/core/init/init.c]

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

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

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

     注1:以上是第一次执行时,如果action中还有command,就不需要1,而2中就是直接再在action上取下一条command即可。

     注2:这里才是真正地命令的执行,前面的action_for_each_trigger()和queue_builtin_action()只是加入到action_queue队列中,而这里是从队列中顺序取出,并执行。

     所以,加入队列action_queue的顺序也就决定了执行的顺序。Init???.rc中action所在的section决定了它们执行的先后次序:early-init -> init -> early-fs -> fs -> post-fs ->early-boot -> boot。

 

   9.2 restart_processes():system/core/init/init.c

      对有SVC_RESTARTING标志的service,执行restart_service_if_needed()

 

  9.3 用poll等待几个事件:property事件/子进程结束的signal事件/keychord

 

   9.4 处理等到的事件

      对property_set事件,调用handle_property_set_fd()处理;

      对keychord事件,调用handle_keychord()处理;

      对signal事件,调用handle_signal()处理;  

 

总结

本文分析了Android里的init进程的启动过程,从中可以知道init做的主要工作包括对init.rc的解析property机制的实现service支撑的实现。详细细节在后面的专题中讨论。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值