Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android系統教程 >> Android開發教程 >> Android的init過程詳解(一)init的初始化

Android的init過程詳解(一)init的初始化

編輯:Android開發教程

本文使用的軟件版本

Android:4.2.2

Linux內核:3.1.10

本文及後續幾篇文章將對Android的初始化(init)過程進行詳細地、剝絲抽繭式地分析,並且在其中穿插了大量的知識,希望對讀者了解Android的啟動過程又所幫助。本章主要介紹了與硬件相關初始化文件名的確定以及屬性服務的原理和實現。

Android本質上就是一個基於Linux內核的操作系統。與Ubuntu Linux、Fedora Linux類似。只是Android在應用層專門為移動設備添加了一些特有的支持。既然Android是Linux內核的系統,那麼基本的啟動過程也應符 合Linux的規則。如果研究過其他Linux系統應該了解,一個完整的Linux系統首先會將一個Linux內核裝載到內存,也就是編譯Linux內核 源代碼生成的bzImage文件,對於為Android優化的Linux內核源代碼會生成zImage文件。該文件就是Linux內核的二進制版本。由於 zImage在內核空間運行,而我們平常使用的軟件都是在應用空間運行(關於內核空間和應用空間的詳細描述,可以參考《Android深度探索(卷1):HAL與驅動開發》一書的內容,在後續的各卷中將會對Android的整體體系進行全方位的剖析)。內核空間和應用空間是不能直接通過內存地址級別訪問的,所以就需要建立某種通訊機制。

目前Linux有很多通訊機制可以在用戶空間和內核空間之間交互,例如設備驅動文件(位於/dev目錄中)、內存文件(/proc、/sys目錄等)。了 解Linux的同學都應該知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一個設備通常與一個或多個設備文件對應。這些與內核空間交 互的文件都在用戶空間,所以在Linux內核裝載完,需要首先建立這些文件所在的目錄。而完成這些工作的程序就是本文要介紹的init。Init是一個命 令行程序。其主要工作之一就是建立這些與內核空間交互的文件所在的目錄。當Linux內核加載完後,要做的第一件事就是調用init程序,也就是 說,init是用戶空間執行的第一個程序。

在分析init的核心代碼之前,還需要初步了解init除了建立一些目錄外,還做了如下的工作

1. 初始化屬性

2. 處理配置文件的命令(主要是init.rc文件),包括處理各種Action。

3. 性能分析(使用bootchart工具)。

4. 無限循環執行command(啟動其他的進程)。

盡管init完成的工作不算很多,不過代碼還是非常復雜的。Init程序並不是由一個源代碼文件組成的,而是由一組源代碼文件的目標文件鏈接而成的。這些文件位於如下的目錄。

<Android源代碼本目錄>/system/core/init

其中init.c是init的主文件,現在打開該文件,看看其中的內容。由於init是命令行程序,所以分析init.c首先應從main函數開始,現在好到main函數,代碼如下:

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; 
    bool is_charger = false; 
      
    if (!strcmp(basename(argv[0]), "ueventd")) 
        return ueventd_main(argc, argv); 
      
    if (!strcmp(basename(argv[0]), "watchdogd")) 
        return watchdogd_main(argc, argv); 
      
    /* clear the umask */ 
    umask(0); 
    //  下面的代碼開始建立各種用戶空間的目錄,如/dev、/proc、/sys等 
    mkdir("/dev", 0755); 
    mkdir("/proc", 0755); 
    mkdir("/sys", 0755); 
      
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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/.booting文件是否可讀寫和創建*/ 
    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000)); 
      
    open_devnull_stdio(); 
    klog_init(); 
    //  初始化屬性 
    property_init(); 
      
    get_hardware_name(hardware, &revision); 
    //  處理內核命令行 
    process_kernel_cmdline(); 
    … … 
      
    is_charger = !strcmp(bootmode, "charger"); 
      
    INFO("property init\n"); 
    if (!is_charger) 
        property_load_boot_defaults(); 
      
    INFO("reading config file\n"); 
    //  分析/init.rc文件的內容 
    init_parse_config_file("/init.rc"); 
    … …//  執行初始化文件中的動作 
    action_for_each_trigger("init", action_add_queue_tail); 
    //  在charger模式下略過mount文件系統的工作 
    if (!is_charger) { 
        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"); 
    queue_builtin_action(signal_init_action, "signal_init"); 
    queue_builtin_action(check_startup_action, "check_startup"); 
      
    if (is_charger) { 
        action_for_each_trigger("charger", action_add_queue_tail); 
    } else { 
        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_property_triggers"); 
      

      
#if BOOTCHART 
    queue_builtin_action(bootchart_init_action, "bootchart_init"); 
#endif 
    //  進入無限循環,建立init的子進程(init是所有進程的父進程) 
    for(;;) { 
        int nr, i, timeout = -1; 
        //  執行命令(子進程對應的命令) 
        execute_one_command(); 
        restart_processes(); 
      
        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; 
//  bootchart是一個性能統計工具,用於搜集硬件和系統的信息,並將其寫入磁盤,以便其 
//  他程序使用 
#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. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved