<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                源碼位置:/syste/core/init/init.c文件 ~~~ int main(int argc, char **argv) { int fd_count = 0; struct pollfd ufds[4]; int property_set_fd_init = 0; int signal_fd_init = 0; int keychord_fd_init = 0; if (!strcmp(basename(argv[0]), "ueventd")) return ueventd_main(argc, argv); init_parse_config_file("/init.rc"); // 解析/init.rc文件 /* pull the kernel commandline and ramdisk properties file in */ import_kernel_cmdline(0, import_kernel_nv); // 從/proc/cmdline獲取參數 chmod("/proc/cmdline", 0440); get_hardware_name(hardware, &revision); snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); // 根據硬件名字,獲取對應的rc文件 init_parse_config_file(tmp); // 對于service,這里會為每個服務建立一個struct service結構體,全部加入service_list鏈表之后,在init的最后循環中按照順序啟動 // 檢查解析出的命令行當中是否有early-init階段的動作,加入到action_queue中,馬上執行 // init動作執行分為4個階段:early-init、init、early-boot、boot action_for_each_trigger("early-init", action_add_queue_tail); // 屬性初始化等等 queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); queue_builtin_action(property_init_action, "property_init"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); queue_builtin_action(set_init_properties_action, "set_init_properties"); // 觸發init階段的動作 action_for_each_trigger("init", action_add_queue_tail); // 如果是充電啟動,則跳過下面這些動作 if (strcmp(bootmode, "charger") != 0) { action_for_each_trigger("early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); action_for_each_trigger("post-fs-data", action_add_queue_tail); } // 啟動屬性服務,加載屬性文件 queue_builtin_action(property_service_init_action, "property_service_init"); // 信號處理這里會通過socketpair創建兩個socket套接字,一個用于接收,一個用于發送 queue_builtin_action(signal_init_action, "signal_init"); // 檢查開機狀況 queue_builtin_action(check_startup_action, "check_startup"); if (!strcmp(bootmode, "charger")) { action_for_each_trigger("charger", action_add_queue_tail); } else { // 觸發early-boot和boot階段的動作 action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); } // 啟動所有依賴于當前時間屬性的操作,即:啟動那些根據屬性值來判斷是否執行的動作 queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers"); for(;;) { int nr, i, timeout = -1; // 循環中執行動作,并重啟那些死去的進程 execute_one_command(); restart_processes(); // init 處理來自三個方面的消息 if (!property_set_fd_init && get_property_set_fd() > 0) { ufds[fd_count].fd = get_property_set_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; property_set_fd_init = 1; } if (!signal_fd_init && get_signal_fd() > 0) { ufds[fd_count].fd = get_signal_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; signal_fd_init = 1; } if (!keychord_fd_init && get_keychord_fd() > 0) { ufds[fd_count].fd = get_keychord_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; keychord_fd_init = 1; } if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } if (!action_queue_empty() || cur_action) timeout = 0; nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; // 處理這三個方面的消息 for (i = 0; i < fd_count; i++) { if (ufds[i].revents == POLLIN) { if (ufds[i].fd == get_property_set_fd()) handle_property_set_fd(); else if (ufds[i].fd == get_keychord_fd()) handle_keychord(); else if (ufds[i].fd == get_signal_fd()) handle_signal(); } } } return 0; } ~~~ **1)解析配置文件:** ????? 根據前面所知,在init中系統會解析兩個配置文件,一個是/init.rc系統配置文件,另外一個是與硬件平臺相關的配置文件。調用的都是同一個函數: ~~~ int init_parse_config_file(const char*fn) { char*data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); return 0; } struct parse_state { char* ptr; // 讀指針 char* text; // 文本 int line; // 第幾行 int nexttoken; // 下一個標示符 void* context; void (*parse_line)(struct parse_state* state, int nargs, char**args); // 解析函數 const char* filename; }; static void parse_config(const char *fn, char *s) { struct parse_state state; char *args[INIT_PARSER_MAXARGS]; // 最多64個參數 int nargs; nargs = 0; state.filename = fn; state.line = 0; state.ptr = s; state.nexttoken = 0; state.parse_line = parse_line_no_op; // 設置解析函數,不同內容對應不同的解析函數 for (;;) { switch (next_token(&state)) // 獲取配置文件中特殊標識,如文件結尾:T_EOF, 換行符:T_NEWLINE, 文本:T_TEXT { case T_EOF: state.parse_line(&state, 0, 0); return; case T_NEWLINE: state.line++; if (nargs) { int kw = lookup_keyword(args[0]); if (kw_is(kw, SECTION)) { // 判斷關鍵字類型是不是為SECTION state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { state.parse_line(&state, nargs, args); } nargs = 0; } break; case T_TEXT: if (nargs < INIT_PARSER_MAXARGS) { args[nargs++] = state.text; } break; } } } 這里parse_config,首先會找到配置文件的一個section,然后針對不同的section使用不同的解析函數來解析。 下面我們看看關鍵字的定義:keywords.h文件中 #ifndef KEYWORD // 如果沒有定義KEYWORD這個宏 int do_class_start(int nargs, char**args); int do_class_stop(int nargs, char**args); int do_class_reset(int nargs, char**args); ... #define __MAKE_KEYWORD_ENUM__ // 定義一個宏 #define KEYWORD(symbol, flags, nargs, func) K_##symbol, enum { K_UNKNOWN, #endif KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start) KEYWORD(on, SECTION, 0, 0) .... #ifdef __MAKE_KEYWORD_ENUM__ KEYWORD_COUNT, }; #undef __MAKE_KEYWORD_ENUM__ #undef KEYWORD #endif 在parser.c文件中: #define SECTION 0x01 #define COMMAND 0x02 #define OPTION 0x04 #include "keywords.h" // 第一次包含ketwords.h文件,由于沒有定義宏KEYWORD所以,相當于: /* int do_class_start(int nargs, char**args); int do_class_stop(int nargs, char**args); int do_class_reset(int nargs, char**args); ... enum { K_UNKNOWN, // 0 K_class, K_class_start, K_on, .... KEYWORD_COUNT, }; 得到了一個枚舉的定義 */ // 自己定義了一個宏 #define KEYWORD(symbok, flags, nargs, func) [ K_##symbol ] = {#symbol, func, nargs+1, flags,}, struct { const char* name; // 關鍵字名字 int (*func)(int args, char**args); // 對應關鍵字的處理函數 unsigned char nargs; unsigned char flags; // 關鍵字屬性:COMMAND、OPTION、SECTION } keyword_info[KEYWORD_COUNT] = { [ K_UNKNOWN] = {"unknown", 0, 0, 0}, // #include "keyword.h" //第二次包含keywords.h文件,由于已經定義了KEYWORD所以相當于: // KEYWORD(class, OPTION, 0, 0) // KEYWORD(class_start, COMMAND, 1, do_class_start) // KEYWORD(service, SECTION, 0, 0) /***宏替換之后為 ***/ [ K_class ] = {"class", 0, 1, OPTION,}, [ k_class_start ] = {"class_start", do_class_start, 2, COMMAND,}, [ k_service ] = {"service", 0, 1, SECTION}, ..... }; #indef KEYWORD 同時我們還定義了一些輔助的宏: #define kw_is(kw, type) (keyword_info[kw].flags & (type)) #define kw_name(kw) (keyword_info[kw].name) #define kw_func(kw) (keyword_info[kw].func) #define kw_nargs(kw) (keyword_info[kw].nargs) 這樣我們就得到了一個全局的數組keyword_info,以前面枚舉值為索引,存儲對應的關鍵字信息,包括關鍵字名稱、處理函數、參數個數、屬性等等。 下面我們根據上面定義的數組ketword_info來看看init.rc文件,如 Zygote: // service是一個section 的標志,名字為zygote 參數個數為5 service zygote /system/bin/app_process -Xzygote /system/bin -zygote --start-system-server // 下面socket 和 onrestart 都是表示OPTION // write 和 restart都是COMMAND socket zygote stream 666 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media 找到section之后我們的入口函數時parse_new_section: void parse_new_section(struct parse_state *state, int kw, int nargs, char **args) { switch(kw) { case K_service: state->context = parse_service(state, nargs, args); if (state->context) { state->parse_line = parse_line_service; return; } break; case K_on: state->context = parse_action(state, nargs, args); if (state->context) { state->parse_line = parse_line_action; return; } break; case K_import: if (nargs != 2) { ERROR("single argument needed for import\n"); } else { int ret = init_parse_config_file(args[1]); if (ret) ERROR("could not import file %s\n", args[1]); } } state->parse_line = parse_line_no_op; } 對于service這里我們看到主要就是調用兩個函數:parse_service 和 parse_line_service,在這之前我們首先看看init是怎么組織這些service的。 struct service { struct listnode slist; // 用于將結構體連接成一個雙向鏈表,Init 中有一個全局鏈表service_list 專門用來保存service const char* name; // service 名字 const char* classname; // 默認 default unsigned char flags; pid_t pid; ... struct socketinfo *sockets; // 保存service用到的socket,也是一個鏈表 struct svcenvinfo *envvars; // 描述創建這個進程時需要的環境變量信息 struct action onrestart; // 存儲command信息 int nargs; // 參數個數 char *nargs[1]; // 存儲參數 }; struct action { // 一個action 存放在三個雙向鏈表中,alist 存儲所有的action // qlist 存儲那些等待執行的action // tlist 存儲那些等待某些條件滿足后需要執行的action struct listnode alist; struct listnode qlist; struct listnode tlist; unsigned hash; const char* name; struct listnode commands; struct command* current; }; struct command { struct listnode clist; // command 鏈表 int (*func)(int nargs, char**args); int nargs; char *args[1]; }; //parse_service:創建service對象,解析定義的service行,設置默認class為default static void* parse_service(struct parse_state* state, int nargs, char**args) { struct service *svc; svc = service_find_by_name(argv[1]); // 如果這個服務已經存在 if (svc) return 0; nargs -= 2; svc = calloc(1, sizeof(*svc) + sizeof(char*)*nargs); 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); // 將這個service加到全局鏈表service_list的尾部 return svc; } // 根據服務名字查找鏈表 struct service* service_find_by_name(const char*name) { struct listnode* node; struct service* svc; list_for_each(node, &service_list) { svc = node_to_item(node, struct service, slist); if (!strcmp(svc->name, name)) return svc; } /* 宏替換相當于: for(node = service_list->next; node != service_list; node = node->next) { svc = (struct srevice*)(((char*)node) - offsetof(struct service, slist)); // svc = (strcut service*)( ((char*)node) - (size_t)&((struct service)0)->slist) // 就是根據鏈表中的node找到對應的service結構體 if (!strcmp(svc->name, name)) return svc; } */ return 0; } /* 這里的service_list是一個全局的雙向循環鏈表,static list_declare(service_list);宏替換后為: struct listnode service_list = { .next = &service_lsit, .prev = &service_list,}; */ // 雙向鏈表添加程序 void list_add_tail(struct listnode *head, struct listnode *item) { item->next = head; item->prev = head->prev; head->prev->next = item; head->prev = item; } /* 當添加了3個節點a,b,c到鏈表之后相當于: service_list->next = a; a->next = b; b->next= c; c->next = service_list; */ //parse_line_service: 解析service中的option static void parse_line_service(struct parse_state* state, int nargs, char**args) { struct service *svc = state->context; struct command* cmd; int i, kw, kw_nargs; svc->ioptro_class = IoSchedClass_NONE; kw = lookup_keyword(args[0]); switch(kw) { case K_capability: break; case K_class: ... case K_onrestart:{ // onrestart write /sys/android_power/request_state wake nargs--; args++; kw = lookup_keyword(args[0]); // 返回K_write 作為索引 if(!kw_id(kw, COMMAND)) break; // 根據前面的keyword_info數組判斷write是不是command kw_nargs = kw_nargs(kw); // 判斷write需要幾個參數 cmd = malloc(sizeof(*cmd) + sizeof(char*)*nargs); cmd->func = kw_func(kw); // 這里應該是do_write函數 cmd->nargs = nargs; // 3 memcpy(cmd->args, args, sizeof(char*)*nargs); // onrestart write /sys/android_power/request_state wake list_add_tail(&svc->onrestart.commands, &cmd->clist); break; } case K_socket: { // socket zygote stream 666 struct socketinfo* si; si = calloc(1, sizeof(*st)); si->name = args[1]; // zygote si->type = args[2]; // stream si->perm = strtoul(args[3], 0, 8); // 666 if(nargs > 4) .... si->next = svc->sockets; // 前向插入到svc->sockets這個鏈表中 svc->sockets = si; break; } default: psrse_error(""); } } ~~~ 這樣通過解析init.rc和init.hardware.rc之后我們將所有的service通過一個全局鏈表service_list連接起來了,同理將所有action通過一個全局鏈表action_list連接起來。 **2)判斷各個階段工作開始執行** ~~~ action_for_each_trigger("early-init", action_add_queue_tail); action_for_each_trigger("init", action_add_queue_tail); action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); // 這里我們通過分析early-init為例: void action_for_each_trigger(const char* trigger, void (*func)(struct action* act)) { struct listnode *node; struct action *act; list_for_each(node, &action_list){ act = node_to_item(node, struct action, alist); if(!strcmp(act->name, trigger)) func(act); } } //同前面的service分析,這里通過全局鏈表action_list,找到對應節點的action,如果節點的名字屬性為early-init,執行func這個回調函數。 void action_add_queue_tail(struct action* act) { list_add_tail(&action_queue, &act->qlist); } //我在網上看到很多說上面的action_for_each_trigger函數是執行early-init階段的action,但是我分析發現:這里也是將這些那些等待執行鏈表qlist中的action加入到action_queue這個全局鏈表中,action_queue也是通過宏聲明的list_declare(action_queue)。并沒有立即執行!!! 同理后面的action_for_each_trigger("init",...)等都是將不同階段的action加入到action_queue這個鏈表中。 ~~~ **3)屬性服務初始化和信號處理初始化** ~~~ queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); queue_builtin_action(property_init_action, "property_init"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); queue_builtin_action(set_init_properties_action, "set_init_properties"); queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signale_init_action, "signale_init"); queue_builtin_action(check_startup_action, "check_startup"); queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); void queue_builtin_action(int (*func)(int nargs, char**args), char *name) { struct action* act; struct command *cmd; act = calloc(1, sizeof(*act)); act->name = name; list_init(&act->commands); // 將這個命令加到action的commands里面 cmd = calloc(1, sizeof(*cmd)); cmd->func = func; cmd->args[0] = name; list_add_tail(&act->commands, &cmd->clist); // 將這個action加到全局鏈表action_list中去 list_add_tail(&action_list, &act->alist); // 將這個action的等待執行的鏈表qlist加入到action_queue中 action_add_queue_tail(act); } ~~~ **4)進入死循環執行** ~~~ for(;;) { execute_command(); restart_processes(); for(i = 0; i < fd_count; i++) { if(ufds[i].revents == POLLIN) { if (ufds[i].fd == get_property_set_fd()) handle_property_set_fd(); else if(ufds[i].fd == get_keychord_fd()) handle_keychord(); else if(ufds[i].fd == get_signale_fd()) handle_signale(); } } } // 這里主要關心屬性設置、組合按鍵輸入、信號三個事件。 handle_property_set_fd(); handle_keychord(); handle_signale(); ~~~ 下面我們主要來看看execute_command() 函數 和 restart_processes()函數 ~~~ static struct action *cur_action = NULL; static struct command *cur_command = NULL; execute_one_command() { // 第一次進來肯定為NULL if(!cur_action || !cur_command || is_last_command(cur_action, cur_command)) { cur_action = action_remove_queue_head(); // 獲得action cur_command = NULL; if (!cur_action) return; cur_command = get_first_command(cur_action); // 根據action獲得command } else {// 如果一個action包含多個command的情況就需要多次調用才能執行完成 cur_command = get_next_command(cur_action, cur_command); } if (!cur_command) return; cur_command->func(cur_command->nargs, cur_command->args); // 調用當前command的func函數 } // 從鏈表action_queue頭部開始獲取action void action_remove_queue_head() { if(list_empty(&action_queue)) return 0; else { struct listnode* node = list_head(&action_queue); struct action *act = node_to_item(node, struct action, qlist); list_remove(node); return act; } } // 根據action獲得包含的第一個command static struct command* get_first_command(struct action* act) { struct listnode* node; node = list_head(&act->commands); if (!node || list_empty(&act->commands)) return NULL; return node_to_item(node, struct command, clist); } // 重新啟動那些死去的進程 restart_processes() { process_needs_restart = 0; service_for_each_flags(SVC_RESTARTING, restart_servce_if_needed); } // 這里根據init.rc里面服務service的標志位flag判斷如果死亡是否需要重啟,最后調用的service_start函數 ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看