**************************************************************************************************************************
作者:EasyWave 時間:2012.07.21
類別:Android系統源碼分析 聲明:轉載,請保留連結
注意:如有錯誤,歡迎指正。這些是我學習的日誌文章......
***************************************************************************************************************************
在android的系統中init程式是第一個啟動並執行程式,這是一個守護進程,而具體的代碼在android2.3.5的源碼中,位於system/core/init/init.c文檔中,這個是main函數的入口,也是android啟動機制的入口。代碼如下所示:
int main(int argc, char **argv){ int fd_count = 0; struct pollfd ufds[4]; char *tmpdev; char* debuggable; char tmp[32]; int property_set_fd_init = 0; int signal_fd_init = 0; int keychord_fd_init = 0; if (!strcmp(basename(argv[0]), "ueventd")) // 得到運行程式ueventd.rc的全路徑名下的ueventd return ueventd_main(argc, argv); // 如果可以找到ueventd.rc,則執行ueventd_main函數 // 解析uevent.rc以及/ueventd.%s.rc /* clear the umask */ umask(0); /* Get the basic filesystem setup we need put * together in the initramdisk on / and then we'll * let the rc file figure out the rest. */ mkdir("/dev", 0755); //建立可讀寫的/dev目錄 mkdir("/proc", 0755); //建立可讀寫的/proc目錄 mkdir("/sys", 0755); //建立可讀寫的/sys目錄,下面也是建立和掛載一些檔案系統,是不是似曾相識啊,這個就是建立一個基本的檔案系統,是不是有點像busybox. 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); /* We must have some place other than / to create the * device nodes for kmsg and null, otherwise we won't * be able to remount / read-only later on. * Now that tmpfs is mounted on /dev, we can actually * talk to the outside world. */ open_devnull_stdio(); // 建立和開啟"/dev/__null__" 虛擬設備(類似於 Linux 系統中的 /dev/null 裝置)並將 // stdin/stdout/stderr 三個檔案重新導向到 "/dev/__null__" log_init(); //建立和開啟"/dev/__kmsg__" 虛擬設備用於記錄 log INFO("reading config file\n"); init_parse_config_file("/init.rc"); //初始化解析system/etc/init.rc檔案 /* pull the kernel commandline and ramdisk properties file in */ import_kernel_cmdline(0); //匯入proc/cmdline的command line參數等。 get_hardware_name(hardware, &revision); //透過/proc/cpuinfo得到硬體模組名稱 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); //並且將其拷貝到init.xxxx.rc中。 init_parse_config_file(tmp); //初始化解析init.xxxx.rc檔案 action_for_each_trigger("early-init", action_add_queue_tail); //下面的代碼需要去瞭解android的一些檔案系統初始化的一些原理,不多說了。 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"); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); 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); queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); /* 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); /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");#if BOOTCHART queue_builtin_action(bootchart_init_action, "bootchart_init");#endif for(;;) { int nr, i, timeout = -1; execute_one_command(); //操作上面整理的 action_queue 中對應的 action restart_processes(); //當前的服務進程狀態,如果有服務進程退出,重啟對應服務進程 //property_service 的事件控制代碼填充 poll event 結構體 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;#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; // 如果當前所關注的事件控制代碼上有事件發生,進行對應的事件處理 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.rc
啟動指令碼init.rc
在 Android中使用啟動指令碼init.rc,可以在系統的初始化過程中進行一些簡單的初始化操作。這個指令碼被直接安裝到目標系統的根檔案系統中,被 init可執行程式解析。 init.rc是在init啟動後被執行的啟動指令碼,其餘發主要包含了以下內容:
- Commands:命令
- Actions:動作
- Triggers:觸發條件
- Services:服務
- Options:選項
- Propertise:屬性
Commands是一些基本的操作,例如:
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
init表示一個觸發條件,這個觸發事件發生後,進行設定環境變數和建立目錄的操作稱為一個“動作” Services(服務)通常表示啟動一個可執行程式,Options(選項)是服務的附加內容,用於配合服務使用。
service vold /system/bin/vold socket vold stream 0660 root mountservice bootsound /system/bin/playmp3 user media group audio oneshot
vold和bootsound分別是兩個服務的名稱,/system/bin /vold和/system /bin/playmp3分別是他們所對應的可執行程式。socket、user、group、oneshot就是配合服務使用的選項。 Properties(屬性)是系統中使用的一些值,可以進行設定和讀取。
setprop ro.FOREGROUND_APP_MEM 1536 setprop ro.VISIBLE_APP_MEM 2048 start adbd
setprop 用於設定屬性,on property可以用於判斷屬性,這裡的屬性在整個Android系統運行中都是一致的。
綜上如果想要修改啟動過程只需要修改init.c或者init.rc裡的內容即可.
3. 總結:
(1)核心的init_post類似介面,會去檔案系統中啟動init類似的使用者進程
(2)android實現了這樣的init,這就是android架構啟動的地方,當然linux核心也可說是android系統的一部分
(3)init進程無限分裂,啟動架構,演變成android系統
(4)android的init進程的代碼在system/core/init/init.c中,從main函數開始.
還沒有分析完,詳細的程式碼分析請見:基於android2.3.5學習之:開天闢地Android啟動機制[二]