init.rc簡介
init.rc文件由系統第一個啓動的init程序進行解析.它由"Android Init Language"語言編寫而成.init.rc文件可以在你android設備根目錄下找到.還記得我們上次編譯的Android源碼麼?如果你已經編譯過源碼了,那麼可以在out/target/generic/root/目錄下找到該文件.
要想讀懂init.rc文件,首先要掌握Android Init Language語言,即AIL.在/system/core/init/下有一份readme.txt文件,爲我們詳細介紹了有關AIL的知識.我們下面的學習同樣是藉助了該文檔來的.
AIL語法
AIL語言非常簡單,主要包括兩部分:結構語法及註釋語法.下面我們就這兩點進行說明
結構語法
AIL語言包含主要包含五種結構語法:
- Actions
- Services
- Options
- Commands
- Imports
需要注意,AIL採用是面向行的代碼風格,即用換行符作爲一條語句的分隔符,也就是在init.rc中以一條語句通常佔據一行.如果一行寫不下,可以在行尾添加反斜槓來鏈接到下一行,換言之,通過行尾添加反斜槓符可以將多行代碼鏈接爲一行代碼.
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將會被添加到已經存在的同名Action中.如果第二個定義的Service的名字和之前存在的Service的名字相同,第二個Service會被忽略並輸出錯誤信息.
註釋語法
AIL中的註釋語法和Shell腳本一致,以#開頭即可
結構語法詳解
Actions
Actions代表一些Action.Action代表一組命令,它包含一個觸發器,該觸發器決定了何時執行這個Action,即在什麼情況下才能執行該Action中的定義命令.當一些條件滿足觸發器的條件時,該Action中定義的命令會被添加到要執行命令隊列的尾部(如果這組命令已經在隊列中,則不會再次添加).
當一個Action從隊列移除時,該Action定義的命令會依次被執行.
Action的格式如下:
on <trgger> [&& <trigger>]*
<command>
<command>
<command>
...
不難發現Action都是以on開始,隨後會定義觸發器(trigger),接着便是爲其定義命令(Commmand).在開始講解Trigger和Command之前,我們先來看一段Action的示例代碼:
on boot
# 初始化網絡
ifup lo
hostname localhost
domainname localdomain
trigger
trigger即我們上面所說的觸發器,本質上是一個字符串,能夠匹配某種包含該字符串的事件.
trigger又被細分爲事件觸發器(event trigger)和屬性觸發器(property trigger).
事件觸發器可由"trigger"命令或初始化過程中通過QueueEventTrigger()觸發,通常是一些事先定義的簡單字符串,例如:boot
,late-init
屬性觸發器是當指定屬性的變量值變成指定值時觸發,其格式爲property:<name>=*
一個Action可以有多個屬性觸發器,但是最多有一個事件觸發器.下面我們看兩個例子:
on boot && property:a=b
該Action只有在boot事件發生時,並且屬性a和b相等的情況下才會被觸發.
on property:a=b && property:c=d
該Action會在以下三種情況被觸發:
- 在啓動時,如果屬性a的值等於b並且屬性c的值等於d
- 在屬性c的值已經是d的情況下,屬性a的值被更新爲b
- 在屬性a的值已經是b的情況下,屬性c的值被更新爲d
當前AIL中常用的有以下幾種事件觸發器:
類型 | 說明 |
---|---|
boot |
init.rc被裝載後觸發 |
device-added-<path> |
指定設備被添加時觸發 |
device-removed-<path> |
指定設備被移除時觸發 |
service-exited-<name> |
在特定服務(service)退出時觸發 |
early-init |
初始化之前觸發 |
late-init |
初始化之後觸發 |
init |
初始化時觸發 |
Commands
Commands代表一組命令,在爲Action設置了觸發器後,就需要爲其定義一組命令(command)了.AIL中內置了衆多的命令,下面我們做個簡單的說明:
命令 | 解釋 |
---|---|
bootchart_init |
如果配置了bootcharing,則啓動.包含在默認的init.rc中 |
chmod |
更改文件權限 |
chown <owner> <group> <path> |
更改文件的所有者和組 |
calss_start <serviceclass> |
啓動指定類別服務下的所有未啓動的服務 |
class_stop <serviceclass> |
停止指定類別服務類下的所有已運行的服務 |
class_reset <serviceclass> |
停止指定類別的所有服務(服務還在運行),但不會禁用這些服務.後面可以通過class_start重啓這些服務 |
copy <src> <dst> |
複製文件,對二進制/大文件非常有用 |
domainname <name> |
設置域名稱 |
enable <servicename> |
啓用已經禁用的服務 |
exec [ <seclabel> [ <user> [ <group> ]* ]] --<command> [ <argument> ]* |
fork一個進程執行指定命令,如果有參數,則帶參數執行 |
export <name> |
在全局環境中,將<name> 變量的值設置爲<value> ,即以鍵值對的方式設置全局環境變量.這些變量對之後的任何進程都有效 |
hostname |
設置主機名 |
ifup <interface> |
啓動某個網絡接口 |
insmod [-f] <path> [<options>] |
加載指定路徑下的驅動模塊。-f強制加載,即不管當前模塊是否和linux kernel匹配 |
load_all_props |
從/system,/vendor加載屬性。默認包含在init.rc |
load_persist_props |
當/data被加密時,加載固定屬性 |
loglevel <level> |
設置kernel日誌等級 |
mkdir <path> [mode] [owner] [group] |
在制定路徑下創建目錄 |
mount_all <fstab> [ <path> ]* |
在給定的fs_mgr-format上調用fs_mgr_mount和引入rc文件 |
mount <type> <device> <dir>[ <flag> ]* [<options>] |
掛載指定設備到指定目錄下. |
powerct |
用來應對sys.powerctl中系統屬性的變化,用於系統重啓 |
restart <service> |
重啓制定服務,但不會禁用該服務 |
restorecon <path> [ <path> ]* |
恢復指定文件到file_contexts配置中指定的安全上線文環境 |
restorecon_recursive <path> [ <path> ]* |
以遞歸的方式恢復指定目錄到file_contexts配置中指定的安全上下文中 |
rm <path> |
刪除指定路徑下的文件 |
rmdir <path> |
刪除制定路徑下的目錄 |
setprop <name> <value> |
將系統屬性<name> 的值設置爲<value> ,即以鍵值對的方式設置系統屬性 |
setrlimit <resource> <cur> <max> |
設置資源限制 |
start <service> |
啓動服務(如果該服務還未啓動) |
stop <service> |
關閉服務(如果該服務還未停止) |
swapon_all <fstab> |
|
symlink <target> <path> |
創建一個指向<path> 的符合鏈接<target> |
sysclktz <mins_west_of_gmt> |
設置系統時鐘的基準,比如0代表GMT,即以格林尼治時間爲準 |
trigger <event> |
觸發一個事件,將該action排在某個action之後(用於Action排隊) |
verity_load_state |
|
verity_update_state <mount_point> |
|
wait <path> [ <timeout> ] |
等待一個文件是否存在,存在時立刻返回或者超時後返回.默認超時事件是5s |
write <path> <content> |
寫內容到指定文件中 |
Services
Services代表一些Service.Service是一些在系統初始化時就啓動或者退出時需要重啓的程序.其格式如下:
service <name> <pathname> [ <argument> ]*
<option>
<option>
...
不難發現,首先需要爲服務定義名字,並指定程序路徑,然後便是通過option來修飾服務.同樣先來看一下示例:
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
Options
Options代表一些option.option用來修飾服務,決定了服務在什麼時候運行以及怎樣運行.AIL中提供了非常多的option,下面我們做個簡單說明:
選項 | 解釋 |
---|---|
console |
服務需要一個控制檯. |
critical |
表示這是一個關鍵設備服務.如果4分鐘內此服務退出4次以上,那麼這個設備將重啓進入recovery模式 |
disabled |
服務不會自動啓動,必須通過服務名顯式啓動 |
setenv <name> <value> |
在進程啓動過程中,將環境變量<name> 的值設置爲<value> ,即以鍵值對的方式設置環境變量 |
socket <name> <type> <perm> [ <user> [ <group> [seclabel]]] |
創建一個unix域下的socket,其被命名/dev/socket/<name> . 並將其文件描述符fd返回給服務進程.其中,type必須爲dgram,stream或者seqpacke,user和group默認是0.seclabel是該socket的SELLinux的安全上下文環境,默認是當前service的上下文環境,通過seclabel指定. |
user <username> |
在執行此服務之前切換用戶名,當前默認的是root.自Android M開始,即使它要求linux capabilities,也應該使用該選項.很明顯,爲了獲得該功能,進程需要以root用戶運行 |
group <groupname> |
在執行此服務之前切換組名,除了第一個必須的組名外,附加的組名用於設置進程的補充組(藉助setgroup()函數),當前默認的是root |
seclabel <seclabel> |
在執行該服務之前修改其安全上下文,默認是init程序的上下文 |
oneshot |
當服務退出時,不重啓該服務 |
class <name> |
爲當前service設定一個類別.相同類別的服務將會同時啓動或者停止,默認類名是default. |
onrestart |
當服務重啓時執行該命令 |
priority <priority> |
設置服務進程的優先級.優先級取值範圍爲-20~19,默認是0.可以通過setpriority()設置 |
Imports
用來引入一個要解析的其他配置文件,通常用於當前配置文件的擴展.
其格式如下:
import <path>
如果path是個一個目錄,則該目錄下的每個.rc文件都被引入.
在初始化過程中,共有兩次使用import來引入.rc文件:
- 在初始化引導期間,引入/init.rc文件
- 在執行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運行中,通過以下屬性能夠獲取當前程序內部信息:
類型 | 說明 |
---|---|
init.svc.<name> |
指定名稱服務的狀態,有stopped,stopping,runing,restarting這種四種狀態 |
init.action |
獲取當前正在執行的action |
init.command |
獲取當前正在執行的command |
文件示例
到現在爲止,有關AIL相關的知識基本介紹完畢,下面截取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初始化之前觸發
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#表明這是一個關鍵服務
seclabel u:r:ueventd:s0 #設置其安全上下文
總結
AIL是一種非常簡單的語言,主要用於定義啓動流程中需要做的事情.
原文鏈接:https://www.jianshu.com/p/d08e1affd5ec