Linux kernel起來後啟動並執行第一個應用程式就是init, Init屬於linux下一個應用程式,其源碼在 system/core/init中,main是應用程式的入口。從main()函數就可以知道init主要功能。 main() (1)安裝SIGCHLD訊號。(如果父進程不等待子進程結束,子進程將成為殭屍進程(zombie)從而佔用系統資源。因此需要對SIGCHLD訊號做出處理,回收殭屍進程的資源,避免造成不必要的資源浪費。 act.sa_handler = sigchld_handler; act.sa_flags = SA_NOCLDSTOP; act.sa_mask = 0; act.sa_restorer = NULL; sigaction(SIGCHLD, &act, 0); (2)為rootfs建立必要的檔案夾,並掛載適當的分區。 mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); (3)建立/dev/null和/dev/kmsg節點。 open_devnull_stdio(); log_init(); (4)解析/init.rc,將所有服務和操作資訊加入鏈表。 parse_config_file("/init.rc"); (5)從/proc/cmdline中提取資訊核心啟動參數,並儲存到全域變數。 /* pull the kernel commandline and ramdisk properties file in */ qemu_init(); import_kernel_cmdline(0); (6)先從上一步獲得的全域變數中擷取硬體資訊和版本號碼,如果沒有則從/proc/cpuinfo中提取,並儲存到全域變數。 get_hardware_name(); (7)根據硬體資訊選擇一個/init.%hardware%.rc,並解析,將服務和操作資訊加入鏈表。 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); parse_config_file(tmp); (8)執行鏈表中帶有“early-init”觸發的的命令。 action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); (9)遍曆/sys檔案夾,是核心產生裝置添加事件(為了自動產生裝置節點)。 device_init(); {int fd; fd = open_uevent_socket(); if(fd < 0) return -1; fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFL, O_NONBLOCK); coldboot(fd, "/sys/class"); coldboot(fd, "/sys/block"); coldboot(fd, "/sys/devices"); return fd; } (10)初始化屬性系統,並匯入初始化屬性檔案。 property_init(); (11)從屬性系統中得到ro.debuggable,若為1,則初始化keychord debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1")) keychord_fd = open_keychord(); (12)開啟console,如果cmdline中沒有指定console,則開啟卻省的/dev/console。 if (console[0]) { snprintf(tmp, sizeof(tmp), "/dev/%s", console); console_name = strdup(tmp); } fd = open(console_name, O_RDWR); if (fd >= 0) have_console = 1; close(fd); (14)讀取/initlogo.rle(一張565 rle 壓縮的位元影像logo),如果成功則在/dev/graphics/fb0顯示出Logo,如果失敗,則將/dev/tty0設定為TEXT模式並開啟/dev/tty0,輸出“ANDROID”字串。 if( load_565rle_image(/initlogo.rle) ) { fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) { const char *msg; msg = "/n" "/n" A N D R O I D "; write(fd, msg, strlen(msg)); close(fd); } } (15)判斷cmdline 中的參數,並設定屬性系統中的參數: if (qemu[0]) import_kernel_cmdline(1); if (!strcmp(bootmode,"factory")) property_set("ro.factorytest", "1"); else if (!strcmp(bootmode,"factory2")) property_set("ro.factorytest", "2"); else property_set("ro.factorytest", "0"); property_set("ro.serialno", serialno[0] ? serialno : ""); property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); property_set("ro.baseband", baseband[0] ? baseband : "unknown"); property_set("ro.carrier", carrier[0] ? carrier : "unknown"); property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown"); property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp); (16)執行所有觸發標識為init的action。 /* execute all the init actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); (17)開始property service /* read any property files on system or data and * fire up the property service. This must happen * after the ro.foo properties are set above so * that /data/local.prop cannot interfere with them. */ property_set_fd = start_property_service(); (18)為sigchld handler建立訊號機制。 /* create a signalling mechanism for the sigchld handler */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC); fcntl(s[1], F_SETFL, O_NONBLOCK); } (19) 執行所有觸發標識為early-boot和boot的action /* execute all the boot actions to get us started */ action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); drain_action_queue(); (20)基於當前property狀態,執行所有觸發標識為property的action /* run all property triggers based on current state of the properties */ queue_all_property_triggers(); drain_action_queue(); (21)註冊輪詢事件: - device_fd - property_set_fd -signal_recv_fd -如果有keychord,則注冊keychord_fd ufds[0].fd = device_fd; ufds[0].events = POLLIN; ufds[1].fd = property_set_fd; ufds[1].events = POLLIN; ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN; fd_count = 3; if (keychord_fd > 0) { ufds[3].fd = keychord_fd; ufds[3].events = POLLIN; fd_count++; } (22)進入無限迴圈,確保這個init進程永駐不退出 在這個迴圈體內,將通過poll模式POLLIN來監視device/property-set/chid-process-exit等事件, |