Android init.rc文件解析过程详解(三)
Android init.rc文件解析過程詳解(三)
?
三、相關結構體
?
?????1、listnode
listnode結構體用于建立雙向鏈表,這種結構廣泛用于kernel代碼中, android源代碼中定義了listnode結構體以及相關操作雙向鏈表的方法,與kernel中的定義類似。
?
這個實現的核心思想是:在用戶自定義的結構體xx中定義一個listnode類型的成員,
這個listnode類型成員的作用就是能將xx類型的變量組成一個雙向鏈表。下面我們來看一下是listnode是怎么做到的。
?
//listnode類型里面只有兩個指針prev,next
struct listnode
{
????struct listnode *next;
????struct listnode *prev;
};
?
//將鏈表中的一個node轉換成自定義結構體中的一個對象
#define node_to_item(node, container, member) \
????(container *) (((char*) (node)) - offsetof(container, member))
?
//初始化一個鏈表
void list_init(struct listnode *node)
{
????node->next = node;
????node->prev = node;
}
?
//將一個節點到鏈表
void list_add_tail(struct listnode *head, struct listnode *item)
{
????item->next = head;
????item->prev = head->prev;
????head->prev->next = item;
????head->prev = item;
}
?
//刪除一個節點
void list_remove(struct listnode *item)
{
????item->next->prev = item->prev;
????item->prev->next = item->next;
}
?
理解node_to_item宏是理解listnode用法的關鍵,這個宏的作用是將一個listnode指針轉換成了一個指定類型(自定義)的指針,這個宏先使用offsetof函數獲取到指定結構體中指定成員變量的地址偏移量,然后通過指針運算獲得listnode指針變量所在結構體變量的指針。
這種實現與我們課堂上所學的鏈表實現方法不太一樣,教科書上的實現是在listnode中存儲了自定義的數據,而這個實現是在自定義的數據當中存儲listnode指針。
?
?
?
2、action結構體
?????前面已經講過on類型的section解析之后會生成一個雙向鏈表action_list,?這個action_list每個node表示就是action結構體的對象,也就是說一個on類型的section都會生成一個action結構體的對象。
????
action結構體定義如下:
?
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 a trigger */
????struct listnode tlist;
?
????unsigned hash;
????const char *name;
???
????struct listnode commands;????????//節點為command結構體的雙向鏈表
????struct command *current;
};
?
?????action結構體除了用在on類型的section,?也用在service類型的section,下面介紹service結構體時會說明。
?
3、command結構體
?
Command結構體定義如下:
struct command
{
????????/* list of commands in an action */
????struct listnode clist;
?
????int (*func)(int nargs, char **args);
????int nargs;
????char *args[1];
};
?
command結構體比較簡單,?用于標識一個命令,包含雙向鏈表指針、對應的執行函數、參數個數以及命令關鍵字。
?
4、service結構體
?
?
struct service {
????????/* list of all services */
????struct listnode slist;??????????????????//將結構體鏈接成service_list用
?
????const char *name;
????const char *classname;
?
????unsigned flags;
????pid_t pid;
????time_t time_started;????/* time of last start */
????time_t time_crashed;????/* first crash within inspection window */
????int nr_crashed;?????????/* number of times crashed within window */
???
????uid_t uid;
????gid_t gid;
????gid_t supp_gids[NR_SVC_SUPP_GIDS];
????size_t nr_supp_gids;
?
#ifdef HAVE_SELINUX
????char *seclabel;
#endif
?
????struct socketinfo *sockets;
????struct svcenvinfo *envvars;
?
????struct action onrestart;??/* Actions to execute on restart. */
???
????/* keycodes for triggering this service via /dev/keychord */
????int *keycodes;
????int nkeycodes;
????int keychord_id;
?
????int ioprio_class;
????int ioprio_pri;
?
????int nargs;
????/* "MUST BE AT THE END OF THE STRUCT" */
????char *args[1];
};
?
service結構體存儲了service的相關信息,?包括進程號、啟動時間、名字等,?字段onrestart
就用到了action結構體,?onrestart這個option后面通常跟著一個命令,所以也用action結構體來表示。
?
?
注:本文基于android4.2的源代碼分析
最后我們分析一下init.c中的main()函數
| 01 | int?main(int?argc,?char?**argv) |
| 02 | { |
| 03 | ????... ... |
| 04 | ????????/* Get the basic filesystem setup we need put |
| 05 | ?????????* together in the initramdisk on / and then we'll |
| 06 | ?????????* let the rc file figure out the rest. |
| 07 | ?????????*/ |
| 08 | ????// 創建一些linux根文件系統中的目錄 |
| 09 | ????mkdir("/dev", 0755); |
| 10 | ????mkdir("/proc", 0755); |
| 11 | ????mkdir("/sys", 0755); |
| 12 | ? |
| 13 | ????mount("tmpfs",?"/dev",?"tmpfs", MS_NOSUID,?"mode=0755"); |
| 14 | ????mkdir("/dev/pts", 0755); |
| 15 | ????mkdir("/dev/socket", 0755); |
| 16 | ????mount("devpts",?"/dev/pts",?"devpts", 0, NULL); |
| 17 | ????mount("proc",?"/proc",?"proc", 0, NULL); |
| 18 | ????mount("sysfs",?"/sys",?"sysfs", 0, NULL); |
| 19 | ? |
| 20 | ????//open_devnull_stdio(); |
| 21 | ????klog_init(); |
| 22 | ? |
| 23 | ????... ... |
| 24 | ? |
| 25 | ????printf("Parsing init.rc ...\n");? |
| 26 | ????// 讀取并且解析init.rc文件 |
| 27 | ????init_parse_config_file("/init.rc"); |
| 28 | ? |
| 29 | ????... ... |
| 30 | ? |
| 31 | ????// 取得硬件名 |
| 32 | ????get_hardware_name(); |
| 33 | ????snprintf(tmp,?sizeof(tmp),?"/init.%s.rc", hardware); |
| 34 | ? |
| 35 | ????// 讀取并且解析硬件相關的init腳本文件 |
| 36 | ????parse_config_file(tmp); |
| 37 | ? |
| 38 | ????... ... |
| 39 | ? |
| 40 | ????# 觸發在init腳本文件中名字為early-init的action,并且執行其commands,其實是: on early-init |
| 41 | ????action_for_each_trigger("early-init", action_add_queue_tail); |
| 42 | ? |
| 43 | ????queue_builtin_action(wait_for_coldboot_done_action,?"wait_for_coldboot_done"); |
| 44 | ????queue_builtin_action(property_init_action,?"property_init"); |
| 45 | ????queue_builtin_action(keychord_init_action,?"keychord_init"); |
| 46 | ????# 控制臺相關初始化,在這里會加載啟動動畫,如果動畫打開失敗,則在屏幕上打印: A N D R O I D字樣。 |
| 47 | ????queue_builtin_action(console_init_action,?"console_init"); |
| 48 | ????queue_builtin_action(set_init_properties_action,?"set_init_properties"); |
| 49 | ? |
| 50 | ????/* execute all the boot actions to get us started */ |
| 51 | ????# 觸發在init腳本文件中名字為init的action,并且執行其commands,其實是:on init |
| 52 | ????action_for_each_trigger("init", action_add_queue_tail); |
| 53 | ? |
| 54 | ????/* skip mounting filesystems in charger mode */ |
| 55 | ????if?(strcmp(bootmode,?"charger") != 0) { |
| 56 | ????????action_for_each_trigger("early-fs", action_add_queue_tail); |
| 57 | ????????action_for_each_trigger("fs", action_add_queue_tail); |
| 58 | ????????action_for_each_trigger("post-fs", action_add_queue_tail); |
| 59 | ????????action_for_each_trigger("post-fs-data", action_add_queue_tail); |
| 60 | ????} |
| 61 | ? |
| 62 | ????// 啟動系統屬性服務: system property service |
| 63 | ????queue_builtin_action(property_service_init_action,?"property_service_init"); |
| 64 | ????queue_builtin_action(signal_init_action,?"signal_init"); |
| 65 | ????queue_builtin_action(check_startup_action,?"check_startup"); |
| 66 | ? |
| 67 | ????queue_builtin_action(queue_early_property_triggers_action,?"queue_early_propety_triggers"); |
| 68 | ? |
| 69 | ????if?(!strcmp(bootmode,?"charger")) { |
| 70 | ????????action_for_each_trigger("charger", action_add_queue_tail); |
| 71 | ????}?else?{ |
| 72 | ????????// 觸發在init腳本文件中名字為early-boot和boot的action,并且執行其commands,其實是:on early-boot和on boot |
| 73 | ????????action_for_each_trigger("early-boot", action_add_queue_tail); |
| 74 | ????????action_for_each_trigger("boot", action_add_queue_tail); |
| 75 | ????} |
| 76 | ? |
| 77 | ????????/* run all property triggers based on current state of the properties */ |
| 78 | ????// 啟動所有屬性變化觸發命令,其實是: on property:ro.xx.xx=xx |
| 79 | ????queue_builtin_action(queue_property_triggers_action,?"queue_propety_triggers"); |
| 80 | ? |
| 81 | ????// 進入死循環 |
| 82 | ????for(;;) { |
| 83 | ????????int?nr, i, timeout = -1; |
| 84 | ? |
| 85 | ????????execute_one_command(); |
| 86 | ????????// 啟動所有init腳本中聲明的service |
| 87 | ????????restart_processes(); |
| 88 | ????????... ... |
| 89 | ????????// 多路監聽設備管理,子進程運行狀態,屬性服務 |
| 90 | ????????nr = poll(ufds, fd_count, timeout); |
| 91 | ????????... ... |
| 92 | ????} |
| 93 | ? |
| 94 | ????return?0; |
| 95 | } |
轉載:http://blog.itpub.net/7232789/viewspace-758168/
http://blog.csdn.net/mk1111/article/details/16357327
總結
以上是生活随笔為你收集整理的Android init.rc文件解析过程详解(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android init.rc文件解析过
- 下一篇: Android关于Theme.AppCo