深入理解Android-Init理解

版权声明:技术等于兴趣 https://blog.csdn.net/ItJavawfc/article/details/81517432

这篇文章的意义在于理解Android的启动流程,作为一名应用开发者理论上应该知道从native世界到Java世界是怎么一步一步来的,进而理解Android的启动流程:
先看看可参考的三张启动流程图:

这里写图片描述

这里写图片描述

这里写图片描述

其中init进程起着承上启下的作用,android本身是基于Linux而来的,init进程是Linux系统中用户空间的第一个进程,在Android中,它也是Android用户空间的第一个进程,它的进程号是1,。作为天子第一号进程,init被赋予了很多及其重要的职责。

咋们再看一看adb中的进程信息:
这里写图片描述
这里写图片描述

着重看一下PID PPID,已经用红线框圈出来了,init是第一个进程,它的子进程包括:zygote 、system/bin/* 等。
以上可以看出init在Android启动过程中的作用。
跟踪源码 system/core/init/init.c
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;

    char* args_swapon[2];
    args_swapon[0] = "swapon_all";;
    args_swapon[1] = "/fstab.sun8i";;

    char* args_write[3];
    args_write[0] = "write";
    args_write[1] = "/proc/sys/vm/page-cluster";
    args_write[2] = "0";

    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);

        /* 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.

         //创建一些Linux系统根文件系统的目录
         */
    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);

        /* indicate that booting is in progress to background fw loaders, etc */
    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));

        /* 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();
    klog_init();            //初始化log,写入init进程信息
    property_init();

    get_hardware_name(hardware, &revision);    // 取得硬件名


    process_kernel_cmdline();

    union selinux_callback cb;
    cb.func_log = klog_write;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    selinux_initialize();
    /* These directories were necessarily created before initial policy load
     * and therefore need their security context restored to the proper value.
     * This must happen before /dev is populated by ueventd.
     */
    restorecon("/dev");
    restorecon("/dev/socket");
    restorecon("/dev/__properties__");
    restorecon_recursive("/sys");

    is_charger = !strcmp(bootmode, "charger");
    usb_charge_flag = is_charger;

    INFO("property init\n");
    if (!is_charger)
        property_load_boot_defaults();
    get_kernel_cmdline_partitions();
    get_kernel_cmdline_signature();
    INFO("reading config file\n");
    init_parse_config_file("/init.rc");   //读取并且解析init.rc文件

    action_for_each_trigger("early-init", action_add_queue_tail);//触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init

    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    queue_builtin_action(keychord_init_action, "keychord_init");

    /* execute all the boot actions to get us started */
    action_for_each_trigger("init", action_add_queue_tail);     //触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init

    action_for_each_trigger("early-fs", action_add_queue_tail);
    /* skip mounting filesystems in charger mode */
    if (!is_charger) {
        queue_builtin_action(console_init_action, "console_init");
        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);

        //SWAP TO ZRAM if low mem devices
        if (!(get_dram_size() > 512)) {
            char trigger[] = {"early-fs"};
            ERROR("***************************LOW MEM DEVICE DETECT");
            add_command(trigger, 2, args_swapon);
            char trigger2[] = {"post-fs-data"};
            add_command(trigger2, 3, args_write);
        }
    }

    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     * wasn't ready immediately after wait_for_coldboot_done
     */
    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

    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) {
        queue_builtin_action(console_init_action, "console_init");
        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
         启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
        */
    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");


#if BOOTCHART
    queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif

    for(;;) {
        int nr, i, timeout = -1;

        execute_one_command();
        restart_processes();    //重启那些已经死去的进程


 -- -- --  --
//调用poll 等待一些事情的发生
        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;
}

上面解析中英文标注和对照文中首先提出来的Android启动流程图,看看Init进程究竟做了什么,主要做了一下四个方面:

  • 解析两个配置文件,其中最总要的就是init.rc文件
  • 执行各个阶段动作,这些动作是在解析完init.rc文件后产生的action【zygote就是其中一个】
  • 调用property_init初始化属性相关资源,并且通过property_start_service启动属性服务
  • init进入无限循环,并且等待一些事情的发生。重点是处理来自socket和属性服务器的相关事情

参考:

展开阅读全文

没有更多推荐了,返回首页