init.rc簡介
init.rc文件由系統(tǒng)第一個啟動的init程序進行解析.它由"Android Init Language"語言編寫而成.init.rc文件可以在你android設備根目錄下找到.還記得我們上次編譯的Android源碼么?如果你已經(jīng)編譯過源碼了,那么可以在out/target/generic/root/目錄下找到該文件.
要想讀懂init.rc文件,首先要掌握Android Init Language語言,即AIL.在/system/core/init/下有一份readme.txt文件,為我們詳細介紹了有關(guān)AIL的知識.我們下面的學習同樣是借助了該文檔來的.
AIL語法
AIL語言非常簡單,主要包括兩部分:結(jié)構(gòu)語法及注釋語法.下面我們就這兩點進行說明
結(jié)構(gòu)語法
AIL語言包含主要包含五種結(jié)構(gòu)語法:
- Actions
- Services
- Options
- Commands
- Imports
需要注意,AIL采用是面向行的代碼風格,即用換行符作為一條語句的分隔符,也就是在init.rc中以一條語句通常占據(jù)一行.如果一行寫不下,可以在行尾添加反斜杠來鏈接到下一行,換言之,通過行尾添加反斜杠符可以將多行代碼鏈接為一行代碼.
init.rc有許多Service和Action組成.那么什么是Service和Action呢?
Action和Service顯式聲明了一個語句塊,而Commands和Options則分別用來定義Actions和Service(你可以理解為這是Action或者Service的屬性).
另外,我們聲明的Commands和Options屬于最近聲明的語句塊,即就近原則.需要注意,在第一個語句塊之前的commands和options會被忽略.
每個Actions或者Services應該有唯一的名字.對于名字重復的情況,Action和Service有自己不同的處理方式:
如果第二個定義的Action的名字和之前存在Action的名字相同,第二個Action中定義的Commands將會被添加到已經(jīng)存在的同名Action中.如果第二個定義的Service的名字和之前存在的Service的名字相同,第二個Service會被忽略并輸出錯誤信息.
注釋語法
AIL中的注釋語法和Shell腳本一致,以#開頭即可
結(jié)構(gòu)語法詳解
Actions
Actions代表一些Action.Action代表一組命令,它包含一個觸發(fā)器,該觸發(fā)器決定了何時執(zhí)行這個Action,即在什么情況下才能執(zhí)行該Action中的定義命令.當一些條件滿足觸發(fā)器的條件時,該Action中定義的命令會被添加到要執(zhí)行命令隊列的尾部(如果這組命令已經(jīng)在隊列中,則不會再次添加).
當一個Action從隊列移除時,該Action定義的命令會依次被執(zhí)行.
Action的格式如下:
on <trgger> [&& <trigger>]*
<command>
<command>
<command>
...
不難發(fā)現(xiàn)Action都是以on開始,隨后會定義觸發(fā)器(trigger),接著便是為其定義命令(Commmand).在開始講解Trigger和Command之前,我們先來看一段Action的示例代碼:
on boot
# 初始化網(wǎng)絡
ifup lo
hostname localhost
domainname localdomain
trigger
trigger即我們上面所說的觸發(fā)器,本質(zhì)上是一個字符串,能夠匹配某種包含該字符串的事件.
trigger又被細分為事件觸發(fā)器(event trigger)和屬性觸發(fā)器(property trigger).
事件觸發(fā)器可由"trigger"命令或初始化過程中通過QueueEventTrigger()觸發(fā),通常是一些事先定義的簡單字符串,例如:boot
,late-init
屬性觸發(fā)器是當指定屬性的變量值變成指定值時觸發(fā),其格式為property:<name>=*
一個Action可以有多個屬性觸發(fā)器,但是最多有一個事件觸發(fā)器.下面我們看兩個例子:
on boot && property:a=b
該Action只有在boot事件發(fā)生時,并且屬性a和b相等的情況下才會被觸發(fā).
on property:a=b && property:c=d
該Action會在以下三種情況被觸發(fā):
- 在啟動時,如果屬性a的值等于b并且屬性c的值等于d
- 在屬性c的值已經(jīng)是d的情況下,屬性a的值被更新為b
- 在屬性a的值已經(jīng)是b的情況下,屬性c的值被更新為d
當前AIL中常用的有以下幾種事件觸發(fā)器:
類型 | 說明 |
---|---|
boot |
init.rc被裝載后觸發(fā) |
device-added-<path> |
指定設備被添加時觸發(fā) |
device-removed-<path> |
指定設備被移除時觸發(fā) |
service-exited-<name> |
在特定服務(service)退出時觸發(fā) |
early-init |
初始化之前觸發(fā) |
late-init |
初始化之后觸發(fā) |
init |
初始化時觸發(fā) |
Commands
Commands代表一組命令,在為Action設置了觸發(fā)器后,就需要為其定義一組命令(command)了.AIL中內(nèi)置了眾多的命令,下面我們做個簡單的說明:
命令 | 解釋 |
---|---|
bootchart_init |
如果配置了bootcharing,則啟動.包含在默認的init.rc中 |
chmod |
更改文件權(quán)限 |
chown <owner> <group> <path> |
更改文件的所有者和組 |
calss_start <serviceclass> |
啟動指定類別服務下的所有未啟動的服務 |
class_stop <serviceclass> |
停止指定類別服務類下的所有已運行的服務 |
class_reset <serviceclass> |
停止指定類別的所有服務(服務還在運行),但不會禁用這些服務.后面可以通過class_start重啟這些服務 |
copy <src> <dst> |
復制文件,對二進制/大文件非常有用 |
domainname <name> |
設置域名稱 |
enable <servicename> |
啟用已經(jīng)禁用的服務 |
exec [ <seclabel> [ <user> [ <group> ]* ]] --<command> [ <argument> ]*
|
fork一個進程執(zhí)行指定命令,如果有參數(shù),則帶參數(shù)執(zhí)行 |
export <name> |
在全局環(huán)境中,將<name> 變量的值設置為<value> ,即以鍵值對的方式設置全局環(huán)境變量.這些變量對之后的任何進程都有效 |
hostname |
設置主機名 |
ifup <interface> |
啟動某個網(wǎng)絡接口 |
insmod [-f] <path> [<options>] |
加載指定路徑下的驅(qū)動模塊。-f強制加載檬果,即不管當前模塊是否和linux kernel匹配 |
load_all_props |
從/system抄邀,/vendor加載屬性饵史。默認包含在init.rc |
load_persist_props |
當/data被加密時,加載固定屬性 |
loglevel <level> |
設置kernel日志等級 |
mkdir <path> [mode] [owner] [group] |
在制定路徑下創(chuàng)建目錄 |
mount_all <fstab> [ <path> ]* |
在給定的fs_mgr-format上調(diào)用fs_mgr_mount和引入rc文件 |
mount <type> <device> <dir>[ <flag> ]* [<options>] |
掛載指定設備到指定目錄下. |
powerct |
用來應對sys.powerctl中系統(tǒng)屬性的變化,用于系統(tǒng)重啟 |
restart <service> |
重啟制定服務非洲,但不會禁用該服務 |
restorecon <path> [ <path> ]* |
恢復指定文件到file_contexts配置中指定的安全上線文環(huán)境 |
restorecon_recursive <path> [ <path> ]* |
以遞歸的方式恢復指定目錄到file_contexts配置中指定的安全上下文中 |
rm <path> |
刪除指定路徑下的文件 |
rmdir <path> |
刪除制定路徑下的目錄 |
setprop <name> <value> |
將系統(tǒng)屬性<name> 的值設置為<value> ,即以鍵值對的方式設置系統(tǒng)屬性 |
setrlimit <resource> <cur> <max> |
設置資源限制 |
start <service> |
啟動服務(如果該服務還未啟動) |
stop <service> |
關(guān)閉服務(如果該服務還未停止) |
swapon_all <fstab> |
|
symlink <target> <path> |
創(chuàng)建一個指向<path> 的符合鏈接<target>
|
sysclktz <mins_west_of_gmt> |
設置系統(tǒng)時鐘的基準,比如0代表GMT,即以格林尼治時間為準 |
trigger <event> |
觸發(fā)一個事件,將該action排在某個action之后(用于Action排隊) |
verity_load_state |
|
verity_update_state <mount_point> |
|
wait <path> [ <timeout> ] |
等待一個文件是否存在,存在時立刻返回或者超時后返回.默認超時事件是5s |
write <path> <content> |
寫內(nèi)容到指定文件中 |
Services
Services代表一些Service.Service是一些在系統(tǒng)初始化時就啟動或者退出時需要重啟的程序.其格式如下:
service <name> <pathname> [ <argument> ]*
<option>
<option>
...
不難發(fā)現(xiàn),首先需要為服務定義名字,并指定程序路徑,然后便是通過option來修飾服務.同樣先來看一下示例:
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
Options
Options代表一些option.option用來修飾服務,決定了服務在什么時候運行以及怎樣運行.AIL中提供了非常多的option,下面我們做個簡單說明:
選項 | 解釋 |
---|---|
console |
服務需要一個控制臺. |
critical |
表示這是一個關(guān)鍵設備服務.如果4分鐘內(nèi)此服務退出4次以上,那么這個設備將重啟進入recovery模式 |
disabled |
服務不會自動啟動,必須通過服務名顯式啟動 |
setenv <name> <value> |
在進程啟動過程中,將環(huán)境變量<name> 的值設置為<value> ,即以鍵值對的方式設置環(huán)境變量 |
socket <name> <type> <perm> [ <user> [ <group> [seclabel]]] |
創(chuàng)建一個unix域下的socket,其被命名/dev/socket/<name> . 并將其文件描述符fd返回給服務進程.其中,type必須為dgram,stream或者seqpacke,user和group默認是0.seclabel是該socket的SELLinux的安全上下文環(huán)境,默認是當前service的上下文環(huán)境,通過seclabel指定. |
user <username> |
在執(zhí)行此服務之前切換用戶名,當前默認的是root.自Android M開始,即使它要求linux capabilities,也應該使用該選項.很明顯,為了獲得該功能,進程需要以root用戶運行 |
group <groupname> |
在執(zhí)行此服務之前切換組名,除了第一個必須的組名外,附加的組名用于設置進程的補充組(借助setgroup()函數(shù)),當前默認的是root |
seclabel <seclabel> |
在執(zhí)行該服務之前修改其安全上下文,默認是init程序的上下文 |
oneshot |
當服務退出時,不重啟該服務 |
class <name> |
為當前service設定一個類別.相同類別的服務將會同時啟動或者停止,默認類名是default. |
onrestart |
當服務重啟時執(zhí)行該命令 |
priority <priority> |
設置服務進程的優(yōu)先級.優(yōu)先級取值范圍為-20~19,默認是0.可以通過setpriority()設置 |
Imports
用來引入一個要解析的其他配置文件,通常用于當前配置文件的擴展.
其格式如下:
import <path>
如果path是個一個目錄,則該目錄下的每個.rc文件都被引入.
在初始化過程中,共有兩次使用import來引入.rc文件:
- 在初始化引導期間,引入/init.rc文件
- 在執(zhí)行mount_all命令時,引入/{system,vendor,odm}/etc/init/或者指定路徑下的.rc文件
我們來看看init.rc文件引入的.rc文件:
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
Properties
Properties代表Init進程運行中的一些屬性信息.在Init運行中,通過以下屬性能夠獲取當前程序內(nèi)部信息:
類型 | 說明 |
---|---|
init.svc.<name> |
指定名稱服務的狀態(tài),有stopped,stopping,runing,restarting這種四種狀態(tài) |
init.action |
獲取當前正在執(zhí)行的action |
init.command |
獲取當前正在執(zhí)行的command |
文件示例
到現(xiàn)在為止,有關(guān)AIL相關(guān)的知識基本介紹完畢,下面截取init.rc文件中的一段來做個簡單的說明:
//引入其他要解析的rc文件
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
#定義了一個action,在init初始化之前觸發(fā)
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
# Set the security context of /adb_keys if present.
restorecon /adb_keys
# Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
mkdir /mnt 0775 root system
# Set the security context of /postinstall if present.
restorecon /postinstall
#啟動ueventd服務
start ueventd
#...省略多行...
#定義ueventd服務,設置服務為/sbin/ueventd
service ueventd /sbin/ueventd
class core#為其設置類名為core
critical#表明這是一個關(guān)鍵服務
seclabel u:r:ueventd:s0 #設置其安全上下文
總結(jié)
AIL是一種非常簡單的語言,主要用于定義啟動流程中需要做的事情.