init進程是Android啓動後系統執行的第一個名稱爲init的可執行程序。這個程序以一個守護進程的方式運行,它提供了以下功能:
1、init可執行程序
init 可執行文件是系統運行的第一個用戶空間程序,它以守護進程的方式運行。因此這個程序的init.c文件包含main函數的入口,基本分析如下:int main(int argc, char **argv) { (省略若干。。。) umask(0); /*對umask進行清零。*/ mkdir("/dev", 0755);/*爲rootfs建立必要的文件夾,並掛載適當的分區。 */ 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); /*創建/dev/null和/dev/kmsg節點*/ open_devnull_stdio(); log_init(); /*解析/init.rc,將所有服務和操作信息加入鏈表。*/ INFO("reading config file/n"); parse_config_file("/init.rc"); /*獲取內核命令行參數*/ qemu_init(); import_kernel_cmdline(0); /*先從上一步獲得的全局變量中獲取信息硬件信息和版本號,如果沒有則從/proc/cpuinfo中提取, *並保存到全局變量。根據硬件信息選擇一個/init.(硬件).rc,並解析,將服務和操作信息加入鏈表。 */ get_hardware_name(); snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); parse_config_file(tmp); /*執行鏈表中帶有“early-init”觸發的的命令。*/ action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); /*遍歷/sys文件夾,是內核產生設備添加事件(爲了自動產生設備節點)。 *初始化屬性系統,並導入初始化屬性文件。用於在系統運行過程中動態創建設備節點、刪除設備節點等操作 */ INFO("device init/n"); device_fd = device_init(); property_init(); // 從屬性系統中得到ro.debuggable,若爲1,則初始化keychord監聽。 debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1")) { keychord_fd = open_keychord(); } /*打開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); /*讀取/initlogo.rle(一張位圖),如果成功則在/dev/graphics/fb0 顯示Logo,如果失敗則將/dev/tty0 *設爲TEXT模式並打開/dev/tty0,輸出文本ANDROID(本人修改爲Zhao Rui Jia做爲啓動項目的修改)。 */ if( load_565rle_image(INIT_IMAGE_FILE) ) { fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) { const char *msg; msg = "/n" "/n" "/n" "/n" "/n" "/n" "/n" // console is 40 cols x 30 lines "/n" "/n" "/n" "/n" "/n" "/n" "/n" /*" A N D R O I D ";*/ " z h a o R u i J i a"; write(fd, msg, strlen(msg)); close(fd); } } /* 判斷cmdline 中的參數,並設置屬性系統中的參數: * 1、 如果 bootmode爲 * - factory,設置ro.factorytest值爲1 * - factory2,設置ro.factorytest值爲2 * - 其他的設ro.factorytest值為0 * 2、如果有serialno參數,則設置ro.serialno,否則爲"" * 3、如果有bootmod參數,則設置ro.bootmod,否則爲"unknown" * 4、如果有baseband參數,則設置ro.baseband,否則爲"unknown" * 5、如果有carrier參數,則設置ro.carrier,否則爲"unknown" * 6、如果有bootloader參數,則設置ro.bootloader,否則爲"unknown" * 7、通過全局變量(前面從/proc/cpuinfo中提取的)設置ro.hardware和ro.version。 */ 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); /*執行所有觸發標識爲init的action。*/ action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); property_set_fd = start_property_service(); /* 爲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); } /* 確認所有初始化工作完成 * device_fd(device init 完成) * property_set_fd(property server start 完成) * signal_recv_fd (信號機制建立) */ if ((device_fd < 0) || (property_set_fd < 0) || (signal_recv_fd < 0)) { ERROR("init startup failure/n"); return 1; } /* 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(); /* run all property triggers based on current state of the properties */ queue_all_property_triggers(); drain_action_queue(); /* enable property triggers */ property_triggers_enabled = 1; /* * 註冊輪詢事件: * - 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++; } else { ufds[3].events = 0; ufds[3].revents = 0; } /*如果支持BOOTCHART,則初始化BOOTCHART*/ #if BOOTCHART bootchart_count = bootchart_init(); if (bootchart_count < 0) { ERROR("bootcharting init failure/n"); } else if (bootchart_count > 0) { NOTICE("bootcharting started (period=%d ms)/n", bootchart_count*BOOTCHART_POLLING_MS); } else { NOTICE("bootcharting ignored/n"); } #endif /* *進入主進程循環: * - 重置輪詢事件的接受狀態,revents爲0 * - 查詢action隊列並執行。 * - 重啓需要重啓的服務 * - 輪詢註冊的事件 * - 如果signal_recv_fd的revents爲POLLIN,則得到一個信號,獲取並處理 * - 如果device_fd的revents爲POLLIN,調用handle_device_fd * - 如果property_fd的revents爲POLLIN,調用handle_property_set_fd * - 如果keychord_fd的revents爲POLLIN,調用handle_keychord */ for(;;) { int nr, i, timeout = -1; for (i = 0; i < fd_count; i++) ufds[i].revents = 0; drain_action_queue(); restart_processes(); if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } #if BOOTCHART if (bootchart_count > 0) { if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) timeout = BOOTCHART_POLLING_MS; if (bootchart_step() < 0 || --bootchart_count == 0) { bootchart_finish(); bootchart_count = 0; } } #endif nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; if (ufds[2].revents == POLLIN) { /* we got a SIGCHLD - reap and restart as needed */ read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; continue; } if (ufds[0].revents == POLLIN) handle_device_fd(device_fd); if (ufds[1].revents == POLLIN) handle_property_set_fd(property_set_fd); if (ufds[3].revents == POLLIN) handle_keychord(keychord_fd); } return 0; }
2、啓動腳本init.rc
mkdir /sdcard 0000 system system mkdir /system mkdir /data 0771 system system mkdir /cache 0770 system cache mkdir /config 0500 root root mkdir /sqlite_stmt_journals 01777 root root mount tmpfs tmpfs /sqlite_stmt_journals size=4m
這些命令在init可執行程序中被解析,然後調用相關的函數來實現。 Actions(動作)表示一系列的命令,通常在Triggers(觸發條件)中調用,動作和觸發條件例如:
on init export PATH /sbin:/system/sbin:/system/bin:/system/xbin
service vold /system/bin/vold socket vold stream 0660 root mount service bootsound /system/bin/playmp3 user media group audio oneshot
setprop ro.FOREGROUND_APP_MEM 1536 setprop ro.VISIBLE_APP_MEM 2048 start adbd
setprop 用於設置屬性,on property可以用於判斷屬性,這裏的屬性在整個Android系統運行中都是一致的。
綜上如果想要修改啓動過程只需要修改init.c或者init.rc裏的內容即可.