android啟動init流程分析

來源:互聯網
上載者:User

 

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等事件,

比如,SD卡插入時,init中device_fd將能收到卡插入事件,以便可以建立節點。

 另外,所有其他的重要進程都是init的子進程,一旦這些子進程出現意外,init的signal_recv_fd將收到SIGCHLD,系統將可以做後續處理。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.