<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                init進程的入口函數是main,它的代碼如下所示: **init.c** ~~~ int main(int argc, char **argv) { intdevice_fd = -1; intproperty_set_fd = -1; intsignal_recv_fd = -1; intkeychord_fd = -1; int fd_count; ints[2]; intfd; structsigaction act; chartmp[PROP_VALUE_MAX]; structpollfd ufds[4]; char*tmpdev; char*debuggable; //設置子進程退出的信號處理函數,該函數為sigchld_handler。 act.sa_handler = sigchld_handler; act.sa_flags= SA_NOCLDSTOP; act.sa_mask = 0; act.sa_restorer = NULL; sigaction(SIGCHLD, &act, 0); ......//創建一些文件夾,并掛載設備,這些是和Linux相關的,不擬做過多討論。 mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0,NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); //重定向標準輸入/輸出/錯誤輸出到/dev/_null_。 open_devnull_stdio(); /* 設置init的日志輸出設備為/dev/__kmsg__,不過該文件打開后,會立即被unlink了, 這樣,其他進程就無法打開這個文件讀取日志信息了。 */ log_init(); //上面涉及很多和Linux系統相關的知識,不熟悉的讀者可自行研究,它們不影響我們的分析 //解析init.rc配置文件 parse_config_file("/init.rc"); ...... //下面這個函數通過讀取/proc/cpuinfo得到機器的Hardware名,我的HTCG7手機為bravo。 get_hardware_name(); snprintf(tmp,sizeof(tmp), "/init.%s.rc", hardware); //解析這個和機器相關的配置文件,我的G7手機對應文件為init.bravo.rc。 parse_config_file(tmp); /* 解析完上述兩個配置文件后,會得到一系列的Action(動作),下面兩句代碼將執行那些處于 early-init階段的Action。init將動作執行的時間劃分為四個階段:early-init、init、 early-boot、boot。由于有些動作必須在其他動作完成后才能執行,所以就有了先后之分。哪些 動作屬于哪個階段由配置文件決定。后面會介紹配置文件的相關知識。 */ action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); /* 創建利用Uevent和Linux內核交互的socket。關于Uevent的知識,第9章中對 Vold進行分析時會做介紹。 */ device_fd = device_init(); //初始化和屬性相關的資源 property_init(); //初始化/dev/keychord設備,這和調試有關,本書不討論它的用法。讀者可以自行研究, //內容比較簡單。 keychord_fd = open_keychord(); ...... /* INIT_IMAGE_FILE定義為”/initlogo.rle”,下面這個函數將加載這個文件作為系統的開機 畫面,注意,它不是開機動畫控制程序bootanimation加載的開機動畫文件。 */ if(load_565rle_image(INIT_IMAGE_FILE) ) { /* 如果加載initlogo.rle文件失敗(可能是沒有這個文件),則會打開/dev/ty0設備,并 輸出”ANDROID”的字樣作為開機畫面。在模擬器上看到的開機畫面就是它。 */ ...... } } if(qemu[0]) import_kernel_cmdline(1); ...... //調用property_set函數設置屬性項,一個屬性項包括屬性名和屬性值。 property_set("ro.bootloader", bootloader[0] ? bootloader :"unknown"); ......//執行位于init階段的動作 action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); //啟動屬性服務 property_set_fd = start_property_service(); /* 調用socketpair函數創建兩個已經connect好的socket。socketpair是Linux的系統調用, 不熟悉的讀者可以利用man socketpair查詢相關信息。后面就會知道它們的用處了。 */ if(socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { signal_fd = s[0]; signal_recv_fd = s[1]; ...... } ...... //執行配置文件中early-boot和boot階段的動作。 action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); drain_action_queue(); ...... //init關注來自四個方面的事情。 ufds[0].fd= device_fd;//device_fd用于監聽來自內核的Uevent事件 ufds[0].events = POLLIN; ufds[1].fd = property_set_fd;//property_set_fd用于監聽來自屬性服務器的事件 ufds[1].events= POLLIN; //signal_recv_fd由socketpair創建,它的事件來自另外一個socket。 ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN; fd_count = 3; if(keychord_fd > 0) { //如果keychord設備初始化成功,則init也會關注來自這個設備的事件。 ufds[3].fd = keychord_fd; ufds[3].events = POLLIN; fd_count++; } ...... #if BOOTCHART ......//與Boot char相關,不做討論了。 /* Boot chart是一個小工具,它能對系統的性能進行分析,并生成系統啟動過程的圖表, 以提供一些有價值的信息,而這些信息最大的用處就是幫助提升系統的啟動速度。 */ #endif for(;;) { //從此init將進入一個無限循環。 int nr, i, timeout = -1; for (i = 0; i < fd_count; i++) ufds[i].revents = 0; //在循環中執行動作 drain_action_queue(); restart_processes(); //重啟那些已經死去的進程 ...... #if BOOTCHART ...... // Boot Chart相關 #endif //調用poll等待一些事情的發生 nr= poll(ufds, fd_count, timeout); ...... //ufds[2]保存的是signal_recv_fd,用于接收來自socket的消息。 if(ufds[2].revents == POLLIN) { //有一個子進程去世,init要處理這個事情 read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; continue; } if(ufds[0].revents == POLLIN) handle_device_fd(device_fd);//處理Uevent事件 if(ufds[1].revents == POLLIN) handle_property_set_fd(property_set_fd);//處理屬性服務的事件。 if(ufds[3].revents == POLLIN) handle_keychord(keychord_fd);//處理keychord事件。 } return0; } ~~~ 從上面的代碼中可知,init的工作任務還是很重的。上面的代碼雖已省略了不少行,可結果還是很長,不過從本章要分析的兩個知識點來看,可將init的工作流程精簡為以下四點: - 解析兩個配置文件,其中,將分析對init.rc文件的解析。 - 執行各個階段的動作,創建Zygote的工作就是在其中的某個階段完成的。 - 調用property_init初始化屬性相關的資源,并且通過property_start_service啟動屬性服務。 - init進入一個無限循環,并且等待一些事情的發生。重點關注init如何處理來自socket和來自屬性服務器相關的事情。 >[info] **提示**:精簡工作流程,是以后分析代碼時常用的方法。讀者在分析代碼的過程中,也可使用這種方法。
                  <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>

                              哎呀哎呀视频在线观看