Android-init進程(1)
init進程是android啟動的第一個進程 進程pid為1.其主要做了如下幾件事:
*解析設定檔
*根據設定檔執行操作early_init init early_boot boot
*設定屬性服務
本節主要內容講解如何解析init.rc檔案和運行zygote.
1.解析init.rc設定檔
/**init.c*/
在main函數中,執行如下函數:
init_parse_config_file("/init.rc");/**init_parse.c*/
int init_parse_config_file(const char *fn){ char *data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); DUMP(); return 0;}static void parse_config(const char *fn, char *s);
parse_config函數主要找到一個SECTION的節點開始解析if (kw_is(kw, SECTION)) { state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args);}
kw_is函數執行了keywords檔案 並找處指定標示 k_##symbol
/**keywords.h*/
1>定義枚舉.枚舉值為k_class k_mkdir等
2>定義結構體數組keyword_info,把KEYOWRD宏改變成結構體,通過宏定義找出symbol與func解析init.rc檔案
如關鍵字section的symbol為chdir 則找到如int do_chdir(int nargs, char **args)的聲明查看對應定義
>>>關鍵字有:OPTION,COMMAND,SECTION
/**init.rc*/
on init #表示on的SECTION名稱為init 基本步驟為early-init init early-boot boot
#從一個section開始 到下一個section開始標籤前結束
export ANDROID_ROOT /system #表示export為一個COMMAND
*如
2.分析zygote
/**init.rc設定檔*/
在該檔案中 zygote被定義為需要執行4個操作並且擁有一個socket為660的服務,他是init的一個子進程.<喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjxicj4KPC9wPgo8cHJlIGNsYXNzPQ=="brush:java;">service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd
---------------Service定義資訊------------------
-維護所有產生Service的一個雙向鏈表listnode
-service的name zygote的name為init.svc.zygote
-className 預設"default"
-屬性flag pid uid gid io優先順序 參數(個數)
-time_started time_crashed nr_crashed 上次啟動死亡時 總死亡次數
-socketinfo(socket環境變數資訊) svcenvinfo(進程所需環境變數資訊)
-struct action onrestart; 儲存OPTION後面的COMMAND資訊
------------------------------------------------
---------------onrestart定義資訊------------------
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; struct command *current;//儲存restart裡面的COMMOND動作};
------------------------------------------------
/**init_parse.c*/
#主要執行parse_service 和parse_line_service
//建立service結構體主要架構,並添加到service_list雙向鏈表中
//socketinfo是一個單向鏈表 zygote只有一個660 的TCP scoket
//onrestart通過commond指向一個commonds鏈表 zygote如上在init.rc中可以看出有4個commond
static void *parse_service(struct parse_state *state, int nargs, char **args){struct service *svc;svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); if (!svc) { parse_error(state, "out of memory\n"); return 0; } svc->name = args[1]; svc->classname = "default"; memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs; svc->onrestart.name = "onrestart"; list_init(&svc->onrestart.commands); list_add_tail(&service_list, &svc->slist); return svc;}
static void parse_line_service(struct parse_state *state, int nargs, char **args){struct service *svc = state->context; nargs--; args++; kw = lookup_keyword(args[0]);//建立Commond結構體 cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs);//添加到雙向列表中 list_add_tail(&svc->onrestart.commands, &cmd->clist);}
**********init 啟動zygote**********
1)init.c::main>
// 將boot的commond加入到執行隊列中 因為zygote 包含在boot動作中
action_for_each_trigger("boot", action_add_queue_tail);
//執行隊列中的commond 並統一執行所有section的commond
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
2)Bultins.c::do_class_start>
//因為class_start是一個COMMOND所以他會被執行 在這裡zygote是一個 "default"的className
//所以執行service_start_if_not_disabled函數
//如果service的flag被明確規定為disable 那麼執行該service必須單獨再執行
service_for_each_class(args[1],service_start_if_not_disabled);
3)Bultins.c::service_start_if_not_disabled>
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);//之前設定沒有建立flags 表示該service還未啟用 執行service_start
}
4)init.c::service_start>
>>判斷檔案進程/system/bin/process檔案是否存在 一般service有自己的進程
rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
>>啟動init子進程
pid = fork();
>>添加進程環境變數資訊
>>添加socket環境變數資訊並建立socket
>>設定uid gid並啟動/system/bin/app_process檔案的main函數
>>設定service的啟動時間 pid等等
**********init 重啟zygote**********
>>綁定操作 響應事件
1)init.c::main>>
queue_builtin_action(signal_init_action, "signal_init");
2)init.c::signal_init_action>>
signal_init();
3)signal_handler::signal_init>>
struct sigaction act;//綁定2個方法 sigchld_handler handle_signal 其結構體還包括了一個sa_flags標示
>>zygote死後父進程init調用sigchld_handler
1)signal_handler::sigchld_handler>>
write(signal_fd, &s, 1);//往signal_fd中寫資料 signal_fd是socketpair中兩條socket中的一條
2)init.c::main>>
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
3)signal_handler::handle_signal>>
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0)) ;
4)signal_handler::wait_for_one_process>>
//殺掉zygote的所有子進程
//清除我們將要重建的scoket
//將所有onrestart的commond(zygote中有4個)添加到svc中的action結構體列表中
//改變svc狀態為restarting
5)init.c::main>>
//poll後進入下一輪迴圈 又執行main
execute_one_command();//執行所有COMMOND
restart_processes();//改變flag標識