当前位置: 代码迷 >> Android >> android init历程分析 init脚本解析和处理
  详细解决方案

android init历程分析 init脚本解析和处理

热度:76   发布时间:2016-04-28 00:09:23.0
android init进程分析 init脚本解析和处理
 (懒人最近想起我还有csdn好久没打理了,这个android init躺在我的草稿箱中快5年了,稍微改改发出来吧)

RC文件格式

rc文件是linux中常见的启动加载阶段执行的文件,rc是run commands的缩写,基本上可以理解为在启动阶段执行的一些列命令。android init进程启动时,也会执行此启动脚本文件,init.rc。init.rc的写法稍有点复杂,详细可参考 /system/core/init下的readme文件。脚本基本组成是由四类,为:

  • commands: 命令
  • action:  动作
  • services: 服务
  • options:  选项 

该语言的语法包括下列约定:

  • 所有类型的语句都是基于行(line-oriented)的,一个语句包含若干个tokens,token之间通过空格字符分隔。如果一个token中需要包含空格字符,则需要通过C语言风格的反斜线('\')来转义,或者使用双引号把整个token引起来。反斜线还可以出现在一行的末尾,表示下一行的内容仍然属于当前语句。
  • 以'#'开始的行是注释行(注释只能是行的第一个非空字符,这个千万要注意)。
  • 动作(Actions)和服务(Services)语句隐含表示一个新的段落(section)的开始。所有的指令(commands)和选项(options)归属于上方最近的一个段落。在第一个段落之前的指令(commands)和选项(options)是无效的。
  • 动作(Actions)和服务(Services)拥有唯一性的名字。如果出现重名,那么后出现的定义将被作为错误忽略掉【目前还是忽略,不是覆盖!】。

 其实,严格来说,应该就只有两种类别Action和Service:

  •   Action是由特定trigger下的一堆command组成
  •  Service是由一堆options描述的daemon服务组成

动作(Action)

动作(Action)是一个有名字的指令(commands)序列。每个动作(Action)都定义一个触发条件(trigger),用于指示什么时候执行这个动作。在实际处理中,当与动作的触发器匹配的事件发生时,该动作下的命令,将被添加到一个即将被执行的队列的队尾(除非它已经在队列中)。
队列中的每一个命令被依次取出执行。

一个动作定义的形式如下:

on <trigger>  <command>  <command>  <command>

服务(Services)

服务是初始化程序需要启动的一些程序,初始化程序还有可能会在这些程序退出之后重启它们。Services take一个服务定义的形式如下:

service <name> <pathname> [ <argument> ]*  <option>  <option>  ...

选项(Options)

选项将影响控制初始化程序运行服务的时机和方法。可能的选项如下表(注意,options只是作为服务的附属部分的)..

说明:

disabled
服务在启动所属的class的时候,不会自动随之启动,只有明确指明要启动此服务时才会启动(通常每个服务都会属于一个class中,由class关键字描述)
 
socket <name> <type>  <perm> [ <user> [ <group> ] ]
Create a unix domain socket named/dev/socket/<name> and pass its fd to the launched process. Valid<type> values includedgram andstream.user andgroup default to 0.
 
user <username>
在exec启动此服务之前,改变进程的user,默认user是root
 
group <groupname> [ <groupname> ]*
周期exec启动服务之前,改变此服务进程的group. 默认group是root。将服务加入特定的group,可以获取一些特定的权限。
 
capability [ <capability> ]+
Set linux capability before exec'ing this service
 
oneshot
服务只执行一次。对于非daemon程序,必须要使用onshot模式。
 
class <name>
设定服务的class名字,所有的服务都必须设置一个,如果不设置,默认是属于default class的。同一个class中的服务,可以通过命令class_start统一启动。 


触发器(Triggers

触发器是一个字符串,用于匹配特定的事件,这些事件将触发触发器所属动作(Action)的执行。


指令(Commands

支持哪些指令,各个android版本不尽相同,详情可参考/system/core/init下的readme或最好看代码


属性(Properties

初始化程序(Init)可以根据需要修改一些系统的属性。readme中说的三个:
init.action
Equal to the name of the action currently being executed or "" if none.

init.command
Equal to the command being executed or "" if none.
 
init.svc.<name>
State of a named service ("stopped", "running", or "restarting").

实际init进程只看到更新 init.svc.<name>, 每个服务都会创建一个这样的property,可以通过 getprop | grep init.svc 看到每个服务的状态,状态切换的时候,会同时更新。

void notify_service_state(const char *name, const char *state){    char pname[PROP_NAME_MAX];    int len = strlen(name);    if ((len + 10) > PROP_NAME_MAX)        return;    snprintf(pname, sizeof(pname), "init.svc.%s", name);    property_set(pname, state);}

其他两个没意义,实际也没用,可能当初设计有吧,但最后也没用(comman/action都是开机时执行,且持续时间都很短,没太大用处)。

init 的parser

Init的parser是比较简单的自动机,代码也不算复杂,主要parser的是三部分:

  1. service: 每个service的描述及属性,parser好了,放在service_list中,以便以后通过actions的命令启动。
  2. actions: parser每个动作, on XXX及后继的command,就是一个action,这个parser好后,也是放在action_list中,以便在init中启动。
  3. import: init.rc 可以支持像c中的include一样,包含其他init.rc,这个支持比较简单,并不是相当于在import位置插入被import的代码,而是在主init.rc都parser好后,再依次parser被包含的rc文件。


init.rc脚本命令的执行

脚本解析好后,会将各个Actions按照时间顺序,分别推到action_queue中,再一个一个执行。
actions按照trigger的时间顺序,依次执行的是,默认trigger的顺序如下:

 action_for_each_trigger("early-init", action_add_queue_tail); action_for_each_trigger("init", action_add_queue_tail); action_for_each_trigger("early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); action_for_each_trigger("post-fs-data", action_add_queue_tail);  action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); 

 因此,各个命令需要特别注意处理好依赖。比如在init阶段,是不可能访问data分区的。另外还要注意一下, 同一个阶段中,import的rc文件,是在后面一些执行的(根据import文件的parser顺序)。
 
 service的启动时间,需要注意一下,也是通过action中的command执行的, 比如在on boot阶段:

 on boot  ...  class_start core


 这样,在boot阶段执行到这个命令时,所有属于core这一类的服务,都会被逐个启动。 







版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案