http://blog.csdn.net/thl789/article/details/8681067
本文分析Android中如何解析init.rc文件,重點(diǎn)描述了on action內(nèi)的解析,并從解析的過(guò)程中總結(jié)出init.rc的語(yǔ)法規(guī)范。
對(duì)init.rc的解析是在parse_config(): [system/core/init/init_parser.c]中進(jìn)行的。解析發(fā)生在init全過(guò)程中的哪個(gè)階段,參看《Android init進(jìn)程啟動(dòng)過(guò)程分析》。
一、解析過(guò)程
1. 掃描init.rc中的token
找到其中的 文件結(jié)束EOF/文本TEXT/新行NEWLINE,其中的空格' ’、'\t’、'\r’會(huì)被忽略,#開頭的行也被忽略掉;
而對(duì)于TEXT,空格' ’、'\t’、'\r’、'\n’都是TEXT的結(jié)束標(biāo)志。
2. 對(duì)每一個(gè)TEXT token,都加入到args[]數(shù)組中
3. 當(dāng)遇到新一行('\n’)的時(shí)候,用args[0]通過(guò)lookup_keyword()檢索匹配關(guān)鍵字;
1) 對(duì)Section(on和service),調(diào)用parse_new_section() 解析:
- 對(duì)on section,調(diào)用parse_action(),并設(shè)置解析函數(shù)parse_line為parse_line_action()
- 對(duì)service section,調(diào)用parse_service(),并設(shè)置解析函數(shù)parse_line為parse_line_service()
2) 對(duì)其他關(guān)鍵字的行(非on或service開頭的地方,也就是沒(méi)有切換section)調(diào)用parse_line()
也就是,
- 對(duì)于on section內(nèi)的命令行,調(diào)用parse_line_action()解析;
- 對(duì)于service section內(nèi)的命令行,調(diào)用parse_line_service()解析。
二、關(guān)鍵數(shù)據(jù)類型原型及關(guān)鍵數(shù)據(jù)定義
2.1 Token的定義
2.2 關(guān)鍵字定義
2.3 struct action 和struct command
2.4 list action_list和action_queue
action_list
解析init.rc時(shí),遇到on action通過(guò)act->alist加入;
queue_builtin_action()把執(zhí)行的函數(shù)組成command,創(chuàng)建action,掛在action_list上。
action_queue
執(zhí)行action_for_each_trigger(),通過(guò)act->qlist加入;
queue_builtin_action()把執(zhí)行的函數(shù)組成command,創(chuàng)建action,掛在action_list上,并追加到action_queue的隊(duì)尾。
三、對(duì)action的解析
結(jié)合init的啟動(dòng)過(guò)程以及前面講述的init.rc的解析,總結(jié)一下對(duì)init對(duì)init.rc里action的解析.
3.1 on section內(nèi)action的解析
1.3.1中解析到新的on section調(diào)用parse_action()時(shí),申請(qǐng)了struct action *act,設(shè)置:
1) act->name為on section的名字(比如boot/fs/);
2) 初始化list act->commands;
3) 把a(bǔ)ct->alist加入到action_list的列尾
這樣,action創(chuàng)建并加入到了action_list中。
3.2 on section內(nèi)action里的command的解析
對(duì)on section內(nèi)action里的command,調(diào)用parse_line_action()
1) 查找關(guān)鍵字,核對(duì)是否是COMMAND,參數(shù)數(shù)目是否正確
2) 申請(qǐng)struct command *cmd
- cmd->func從keyword表中獲??;
- 設(shè)置參數(shù)個(gè)數(shù)給cmd->nargs,拷貝參數(shù)給cmd->args;
- 把cmd->clist加入到act->commands的列尾
這樣,command加入到了action中。
3.3 action_list里的action加入action_queue中
action_for_each_trigger()把隊(duì)列action_list里所匹配的action,追加到action_queue的隊(duì)尾;
queue_builtin_action()把執(zhí)行的函數(shù)組成command,創(chuàng)建action,掛在action_list上,并追加到action_queue的隊(duì)尾。
3.4 命令的執(zhí)行
Init的無(wú)限循環(huán)中execute_one_command():system/core/init/init.c
1) 從action_queue取下structaction *act賦給cur_action;
2) 從cur_action獲得struct command *賦給cur_command;
3) 執(zhí)行cur_command->func(cur_command->nargs, cur_command->args)
上面步驟中1, 2 & 3是一次執(zhí)行的,4是無(wú)限循環(huán)執(zhí)行,從action_queue上取下action,action里獲得command,然后執(zhí)行command。
四、init.rc語(yǔ)法小結(jié)
system/core/init/Readme里有init.rc語(yǔ)法的描述。之前筆者沒(méi)有分析init源碼時(shí),也讀過(guò)這個(gè)Readme文件,但是對(duì)一些概念界定都搞不太清楚?,F(xiàn)在分析過(guò)init.rc的解析之后,下面試著對(duì)init.rc語(yǔ)法做一下梳理。
1. #開頭的行也被忽略掉,用于注釋;
2. '’、'\t’、'\r’都會(huì)被忽略,所以屬性中含有空格的話,后面的不會(huì)被識(shí)別;每一個(gè)Action里command前的縮進(jìn)并無(wú)語(yǔ)法的要求,只是便于人閱讀;
3. '\n’是換行的標(biāo)志,init語(yǔ)法里新解析的開始都是基于新行開始才進(jìn)行的,是逐行掃描解析的;
4. 一些概念:Section / Action / Command / Trigger
- Init.rc里,遇到on<trigger>或service <name> <pathname> [ <argument> ]*行,標(biāo)志著一個(gè)新section的開始[參看2.2里關(guān)鍵字定義里,類型為SECTION的也就只有on和service];
- 遇到on <trigger>,trigger是觸發(fā)條件,發(fā)生的時(shí)機(jī)??梢允莈arly-init / init / early-fs / fs / post-fs / early-boot / boot;也可以是property:<name>=<value>,屬性<name>的值被設(shè)置為<value>時(shí);device-added-<path>/ device-removed-<path>設(shè)備節(jié)點(diǎn)被加入或移除時(shí);service-exited-<name>服務(wù)退出時(shí)。
- on <trigger>發(fā)生時(shí),執(zhí)行action,也就是on<trigger>后面的部分,可包含多個(gè)command;
- command每條一行,支持哪些command,看2.2里關(guān)鍵字定義里類型為COMMAND的關(guān)鍵字。
形式如下:
總結(jié)
本文解析了init.rc的基本語(yǔ)法,重點(diǎn)討論on section的解析,service的解析以及property的支持在后續(xù)專題中再詳細(xì)討論。
========================
Android啟動(dòng)腳本init.rc
Init.rc的基本規(guī)則
1,init.rc是一個(gè)可配置的初始化文件,通常定制廠商可以配置額外的初始化配置,init.%PRODUCT%.rc
2,init.rc是在$GINGERBREAD/system/core/init/init.c中讀取的,它基于“行”,包含一些用空格隔開的關(guān)鍵字(它屬于特殊字符)
4,#開頭的表示注釋
5,init.rc包含4種狀態(tài)類別:Actions/Commands/Services/Options
6,當(dāng)聲明一個(gè)service或者action的時(shí)候,它將隱式聲明一個(gè)section,它之后跟隨的command或者option都將屬于這個(gè)section
7,action和service不能重名,否則忽略為error
在Android中使用啟動(dòng)腳本init.rc,可以在系統(tǒng)的初始化過(guò)程中進(jìn)行一些簡(jiǎn)單的初始化操作。這個(gè)腳本被直接安裝到目標(biāo)系統(tǒng)的根文件系統(tǒng)中,被init可執(zhí)行程序解析。init.rc是在init啟動(dòng)后被執(zhí)行的啟動(dòng)腳本,其語(yǔ)法主要包含了以下內(nèi)容:
Commands:命令
Actions: 動(dòng)作
Triggers:觸發(fā)條件
Services:服務(wù)
Options: 選項(xiàng)
Propertise:屬性
Commands是一些基本的操作,
exec <path> [<argument> ]*
Fork并執(zhí)行一個(gè)程序(<path>).這將被block直到程序執(zhí)行完畢。最好避免執(zhí)行例如內(nèi)建命令以外的程序,它可能會(huì)導(dǎo)致init被阻塞不動(dòng)。
export <name><value>
設(shè)定全局環(huán)境變量<name>的值<value>,當(dāng)這個(gè)命令執(zhí)行后所有的進(jìn)程都可以取得。
ifup <interface>
使網(wǎng)絡(luò)接口<interface>聯(lián)機(jī)。
import <filename>
解析一個(gè)init配置文件,擴(kuò)展當(dāng)前配置文件。
hostname <name>
設(shè)置主機(jī)名
chmod <octal-mode><path>
改變文件訪問(wèn)權(quán)限
chown <owner><group> <path>
改變文件所屬和組
class_start <serviceclass>
當(dāng)指定類別的服務(wù)沒(méi)有運(yùn)行,啟動(dòng)該類別所有的服務(wù)。
class_stop <serviceclass>
當(dāng)指定類別的服務(wù)正在運(yùn)行,停止該類別所有的服務(wù)。
domainname <name>
設(shè)置域名。
insmod <path>
加載該路徑<path>的模塊
mkdir <path> [mode][owner] [group]
在<path>創(chuàng)建一個(gè)目錄,可選選項(xiàng):mod,owner,group.如果沒(méi)有指定,目錄以755權(quán)限,owner為root,group為root創(chuàng)建.
mount <type><device> <dir> [ <mountoption> ]*
嘗試mount <device>到目錄<dir>.<device>可以用mtd@name格式以命名指定一個(gè)mtd塊設(shè)備。<mountoption>包含"ro","rw","remount","noatime".
setkey
暫時(shí)沒(méi)有
setprop <name><value>
設(shè)置系統(tǒng)property <name>的值<value>.
setrlimit <resource><cur> <max>
設(shè)置resource的rlimit.
start <service>
啟動(dòng)一個(gè)沒(méi)有運(yùn)行的服務(wù)。
stop <service>
停止一個(gè)正在運(yùn)行的服務(wù)。
symlink <target><path>
創(chuàng)建一個(gè)<path>的符號(hào)鏈接到<target>
sysclktz<mins_west_of_gmt>
設(shè)置系統(tǒng)時(shí)區(qū)(GMT為0)
trigger <event>
觸發(fā)一個(gè)事件。用于調(diào)用其它action。
write <path><string> [ <string> ]*
打開<path>的文件并寫入一個(gè)或多個(gè)字符串。
例如:
mkdir /sdcard 0000 system system
mkdir /system
mkdir /data 0771 system system
mkdir /cache 0770 system cache
mkdir /config 0500 root root
mkdir /sqlite_stmt_journals 01777 root root
mount tmpfs tmpfs /sqlite_stmt_journals size=4m
這些命令在init可執(zhí)行程序中被解析,然后調(diào)用相關(guān)的函數(shù)來(lái)實(shí)現(xiàn)。
(2) Actions(動(dòng)作)表示一系列的命令,通常在Triggers(觸發(fā)條件)中調(diào)用,動(dòng)作和觸發(fā)條件的形式為:
on <trigger>
<command>
<command>
<command>
動(dòng)作的使用示例如下:
on init
export PATH /sbin:/system/sbin:/system/bin:/system/xbin
mkdir /system
init表示一個(gè)觸發(fā)條件,這個(gè)觸發(fā)事件發(fā)生后,進(jìn)行設(shè)置環(huán)境變量和建立目錄的操作稱為一個(gè)“動(dòng)作”
Triggers
--------
Triggers(觸發(fā)器)是一個(gè)字符串,可以用來(lái)匹配某種類型的事件并執(zhí)行一個(gè)action。
boot
這是當(dāng)init開始后執(zhí)行的第一個(gè)觸發(fā)器(當(dāng)/init.conf被加載)
<name>=<value>
當(dāng)property<name>被設(shè)為指定的值<value>時(shí)觸發(fā)。
device-added-<path>
device-removed-<path>
當(dāng)設(shè)備節(jié)點(diǎn)被添加或移除時(shí)觸發(fā)。
service-exited-<name>
當(dāng)指定的服務(wù)存在時(shí)觸發(fā)聯(lián)系客服