简介
init进程是Android系统中用户空间的第一个进程,进程ID为1,源代码位于system/core/init 目录。作为Android系统的第一个进程,Init进程承担这很多重要的初始化任务,一般Init进程的初始化可以分为两部分,前半部分挂载文件系统,初始化属性系统和Klog, selinux的初始化等,后半部分重要通过解析init.rc来初始化系统daemon服务进程,然后以epoll的监控属性文件,系统信号等。
init.rc则是init进程启动的配置脚本,这个脚本是用一种叫Android Init Language(Android初始化语言)的语言写的。在7.0以前,init进程只解析根目录下的init.rc文件,但是随着版本的迭代,init.rc越来越臃肿,在7.0以后,init.rc一些业务被拆分到
/system/etc/init
/vendor/etc/init
/odm/etc/init
三个目录下。
Android Init Language(简称 AIL)组成
AIL包括四种类型的语句:
- 动作 (Action)
- 命令 (Commands)
- 服务 (Service)
- 选项 (Option)
语法特性
- AIL是面向行的代码,也就是每一行是一条语句,回车就是分隔符,一个语句包含若干个tokens, token之间需要有空格分割符,如果token中有空格需要通过c语言风格的反斜杠(‘')来转义,或者使用双引号将整个token包裹起来。反斜杠出现在末尾表示下一行任属于当前语句。
- 以#开始的行为注释,
- AIL编写分成多个(Section), 每个部分的开头需要指定Actions或Services,也就是每个Actions和Services都是一个Section,所有的Commands和Options只能属于定义的这个Section,
- Actions和Services的名称必须唯一,如果多个一样的名字,后面声明的将被忽略为一个错误。
动作 (Action)
Actions是被命名的命令(Commands)序列,由trigger(触发器)来决定这个actions什么时候发生,当一个时间触发了一个符合的action触发器,这个action就会被添加到处理队列尾部(它已经存在在对列除外)。
在处理队列中每一个action都按照排序出列,action中的command也按照顺序执行:
on <trigger> ##触发条件
<command> ##执行命令
<command> ##可以同时执行多个命令
<command>
trigger
init.rc中常见的trigger如下:
| trigger(触发器) | 功能 |
|-|-|
| boot | 这是init启动时(加载/init.conf之后)发生的第一个触发器。|
| <name>=<value> | 当属性<name>设置为特定值<value>时,会触发此触发器 |
| device-added-<path>
device-removed-<path> | 当添加或删除设备节点时,会触发这些触发器。|
| service-exited-<name> | 当指定服务退出时,将触发这些触发器。|
两种常见的Action定义代码:
#当init被触发时执行
on init
<command>
...
#当属性sys.boot_completed被设置为1时执行
on property:sys.boot_completed=1
<command1>
命令 (Commands)
init.rc中常见的Commands有以下一些:
| Command | Description |
|—|—|
| exec <path> [ <argument> ]* | 创建和执行程序(<path>)。这将会阻塞init,直到程序执行完成。由于它不是内置命令,应尽量避免使用exec,它可能会引起init卡死|
| export <name> <value> | 在全局环境变量中设定环境变量 <name>为<value>。(这将会被所有在这命令之后运行的进程所继承)|
| ifup <interface> | 启动网络接口<interface> |
| import <filename> | 解析一个init配置文件,扩展当前配置|
| hostname <name> | 设置主机名|
| chdir <directory> | 改变工作目录|
| chmod <octal-mode> <path> | 更改文件访问权限|
| chown <owner> <group> <path> | 更改文件的所有者和组|
| chroot <directory> | 改变进程的根目录|
| class_start *
服务 (Service)
服务是初始化程序init需要启动的一些程序,初始化程序可能在这些程序退出后重启他们。Services的形式:
service <name> <pathname> [ <argument> ] *
<option>
<option>
选项 (Option)
选项属于服务,它将影响初始化程序运行服务的时机和方法。可能的选项如下: | 选项 | 说明 | |—|—| | disabled | 此服务不会自动从其类启动。它必须按名称显式启动。| | socket <name><type> <perm> [ <user> [ <group> ] ] | 创建一个名为/dev/socket/<name>的unix域套接字,并将其fd传递给启动的进程。有效的<type>值包括dgram和stream。用户和组默认为0。| | user <username> | 在执行此服务之前更改为用户名。当前默认为root | | group <groupname> [ <groupname> ]* | 在执行此服务之前更改为groupname。第一个组之外的其他组名(这是必需的)用于设置进程的其他组(使用set groups())。当前默认为root | | capability [ <capability> ]+ | 在执行此服务之前设置linux功能 | | class <name> | 指定服务的类名。命名类中的所有服务必须一起启动和停止。如果服务不是通过类选项指定的,则将其视为类“默认”。| | oneshot | 退出时不要重新启动服务。|
应用中添加使用rc例
1.在Android.mk 同目录下,新建文件haha.sh (文件名任意),执行shell 操作, 以下简单举例
#!/bin/sh
rm -rf /system/etc/xxx
2.在Android.mk 同目录下,新建文件test.rc (文件名任意)
含义:当设置系统属性persist.vendor.test.haha=2时,启动服务,执行shell 脚本
on property:persist.vendor.test.haha=2
start haha-sh
service haha-sh /vendor/bin/haha.sh
class main
user root
group root
disabled
3.在Android.mk 中添加配置
LOCAL_INIT_RC := test.rc
4.在型号添加配置模块的mk 文件中添加以下内容,将代码中的sh 文件copy 到vendor/bin 目录下
PRODUCT_COPY_FILES += \
vendor/apps/TestApp/haha.sh:$(TARGET_COPY_OUT_VENDOR)/bin/haha.sh \
参考: