對init.rc的解析是在parse_config(): [system/core/init/init_parser.c]中進行的。解析發生在init全過程中的哪個階段,參看《Android init進程啟動過程分析》。
一、解析過程
1. 掃描init.rc中的token
找到其中的 檔案結束EOF/文本TEXT/新行NEWLINE,其中的空格‘ '、‘\t'、‘\r'會被忽略,#開頭的行也被忽略掉;
而對於TEXT,空格‘ '、‘\t'、‘\r'、‘\n'都是TEXT的結束標誌。
2. 對每一個TEXT token,都加入到args[]數組中
3. 當遇到新一行(‘\n')的時候,用args[0]通過lookup_keyword()檢索匹配關鍵字;
1) 對Section(on和service),調用parse_new_section() 解析:
- 對on section,調用parse_action(),並設定解析函數parse_line為parse_line_action()
- 對service section,調用parse_service(),並設定解析函數parse_line為parse_line_service()
2) 對其他關鍵字的行(非on或service開頭的地方,也就是沒有切換section)調用parse_line()
也就是,
- 對於on section內的命令列,調用parse_line_action()解析;
- 對於service section內的命令列,調用parse_line_service()解析。
二、關鍵資料類型原型及關鍵資料定義
2.1 Token的定義
[cpp]
#defineT_EOF 0
#defineT_TEXT 1
#defineT_NEWLINE 2
#defineT_EOF 0
#defineT_TEXT 1
#defineT_NEWLINE 2
2.2 關鍵字定義
[cpp]
KEYWORD(capability, OPTION, 0, 0)
KEYWORD(chdir, COMMAND, 1, do_chdir)
KEYWORD(chroot, COMMAND, 1, do_chroot)
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1,do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
KEYWORD(console, OPTION, 0, 0)
KEYWORD(critical, OPTION, 0, 0)
KEYWORD(disabled, OPTION, 0, 0)
KEYWORD(domainname, COMMAND, 1, do_domainname)
KEYWORD(exec, COMMAND, 1, do_exec)
KEYWORD(export, COMMAND, 2, do_export)
KEYWORD(group, OPTION, 0, 0)
KEYWORD(hostname, COMMAND, 1, do_hostname)
KEYWORD(ifup, COMMAND, 1, do_ifup)
KEYWORD(insmod, COMMAND, 1, do_insmod)
KEYWORD(import, COMMAND, 1, do_import)
KEYWORD(keycodes, OPTION, 0, 0)
KEYWORD(mkdir, COMMAND, 1, do_mkdir)
KEYWORD(mount, COMMAND, 3, do_mount)
KEYWORD(on, SECTION, 0, 0)
KEYWORD(oneshot, OPTION, 0, 0)
KEYWORD(onrestart, OPTION, 0, 0)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(service, SECTION, 0, 0)
KEYWORD(setenv, OPTION, 2, 0)
KEYWORD(setkey, COMMAND, 0, do_setkey)
KEYWORD(setprop, COMMAND, 2, do_setprop)
KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
KEYWORD(socket, OPTION, 0, 0)
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(user, OPTION, 0, 0)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(copy, COMMAND, 2, do_copy)
KEYWORD(chown, COMMAND, 2, do_chown)
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(ioprio, OPTION, 0, 0)
KEYWORD(capability, OPTION, 0, 0)
KEYWORD(chdir, COMMAND, 1, do_chdir)
KEYWORD(chroot, COMMAND, 1, do_chroot)
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1,do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
KEYWORD(console, OPTION, 0, 0)
KEYWORD(critical, OPTION, 0, 0)
KEYWORD(disabled, OPTION, 0, 0)
KEYWORD(domainname, COMMAND, 1, do_domainname)
KEYWORD(exec, COMMAND, 1, do_exec)
KEYWORD(export, COMMAND, 2, do_export)
KEYWORD(group, OPTION, 0, 0)
KEYWORD(hostname, COMMAND, 1, do_hostname)
KEYWORD(ifup, COMMAND, 1, do_ifup)
KEYWORD(insmod, COMMAND, 1, do_insmod)
KEYWORD(import, COMMAND, 1, do_import)
KEYWORD(keycodes, OPTION, 0, 0)
KEYWORD(mkdir, COMMAND, 1, do_mkdir)
KEYWORD(mount, COMMAND, 3, do_mount)
KEYWORD(on, SECTION, 0, 0)
KEYWORD(oneshot, OPTION, 0, 0)
KEYWORD(onrestart, OPTION, 0, 0)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(service, SECTION, 0, 0)
KEYWORD(setenv, OPTION, 2, 0)
KEYWORD(setkey, COMMAND, 0, do_setkey)
KEYWORD(setprop, COMMAND, 2, do_setprop)
KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
KEYWORD(socket, OPTION, 0, 0)
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(user, OPTION, 0, 0)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(copy, COMMAND, 2, do_copy)
KEYWORD(chown, COMMAND, 2, do_chown)
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(ioprio, OPTION, 0, 0)
2.3 struct action 和struct command
[cpp]
複製代碼 代碼如下:struct action {
/* node in list of all actions */
struct listnode alist;
/* node in the queue of pending actions*/
struct listnode qlist;
/* node in list of actions for atrigger */
struct listnode tlist;
unsigned hash;
const char *name;
struct listnode commands;
struct command *current;
};
struct action {
/* node in list of all actions */
struct listnode alist;
/* node in the queue of pending actions*/
struct listnode qlist;
/* node in list of actions for atrigger */
struct listnode tlist;
unsigned hash;
const char *name;
struct listnode commands;
struct command *current;
};
[cpp]
view plaincopyprint?
複製代碼 代碼如下:struct command
{
/* list of commands in an action */
struct listnode clist;
int (*func)(int nargs, char **args);
int nargs;
char *args[1];
};
struct command
{
/* list of commands in an action */
struct listnode clist;
int (*func)(int nargs, char **args);
int nargs;
char *args[1];
};
2.4 list action_list和action_queue
action_list
解析init.rc時,遇到on action通過act->alist加入;
queue_builtin_action()把執行的函數組成command,建立action,掛在action_list上。
action_queue
執行action_for_each_trigger(),通過act->qlist加入;
queue_builtin_action()把執行的函數組成command,建立action,掛在action_list上,並追加到action_queue的隊尾。
三、對action的解析
結合init的啟動過程以及前面講述的init.rc的解析,總結一下對init對init.rc裡action的解析.
3.1 on section內action的解析
1.3.1中解析到新的on section調用parse_action()時,申請了struct action *act,設定:
1) act->name為on section的名字(比如boot/fs/);
2) 初始化list act->commands;
3) 把act->alist加入到action_list的列尾
這樣,action建立並加入到了action_list中。
3.2 on section內action裡的command的解析
對on section內action裡的command,調用parse_line_action()
1) 尋找關鍵字,核對是否是COMMAND,參數數目是否正確
2) 申請struct command *cmd
- cmd->func從keyword表中擷取;
- 設定參數個數給cmd->nargs,拷貝參數給cmd->args;
- 把cmd->clist加入到act->commands的列尾
這樣,command加入到了action中。
3.3 action_list裡的action加入action_queue中
action_for_each_trigger()把隊列action_list裡所匹配的action,追加到action_queue的隊尾;
queue_builtin_action()把執行的函數組成command,建立action,掛在action_list上,並追加到action_queue的隊尾。
3.4 命令的執行
Init的無限迴圈中execute_one_command():system/core/init/init.c
1) 從action_queue取下structaction *act賦給cur_action;
2) 從cur_action獲得struct command *賦給cur_command;
3) 執行cur_command->func(cur_command->nargs, cur_command->args)
上面步驟中1, 2 & 3是一次執行的,4是無限迴圈執行,從action_queue上取下action,action裡獲得command,然後執行command。
四、init.rc文法小結
system/core/init/Readme裡有init.rc文法的描述。之前筆者沒有分析init源碼時,也讀過這個Readme檔案,但是對一些概念界定都搞不太清楚。現在分析過init.rc的解析之後,下面試著對init.rc文法做一下梳理。
1. #開頭的行也被忽略掉,用於注釋;
2. ‘'、‘\t'、‘\r'都會被忽略,所以屬性中含有空格的話,後面的不會被識別;每一個Action裡command前的縮排並無文法的要求,只是便於人閱讀;
3. ‘\n'是換行的標誌,init文法裡新解析的開始都是基於新行開始才進行的,是漸進式掃描解析的;
4. 一些概念:Section / Action / Command / Trigger
- Init.rc裡,遇到on<trigger>或service <name> <pathname> [ <argument> ]*行,標誌著一個新section的開始[參看2.2裡關鍵字定義裡,類型為SECTION的也就只有on和service];
- 遇到on <trigger>,trigger是觸發條件,發生的時機。可以是early-init / init / early-fs / fs / post-fs / early-boot / boot;也可以是property:<name>=<value>,屬性<name>的值被設定為<value>時;device-added-<path>/ device-removed-<path>裝置節點被加入或移除時;service-exited-<name>服務退出時。
- on <trigger>發生時,執行action,也就是on<trigger>後面的部分,可包含多個command;
- command每條一行,支援哪些command,看2.2裡關鍵字定義裡類型為COMMAND的關鍵字。
形式如下:
[cpp]
on <trigger>
<command>
<command>
<command>
on <trigger>
<command>
<command>
<command>這整個是一個Section;所有<command>叫action。
總結
本文解析了init.rc的基本文法,重點討論on section的解析,service的解析以及property的支援在後續專題中再詳細討論。