Android本身就是基于Linux,因此内核的启动方式也是差不多的。Bootloader,Kernel完成系统设置以后,首先会在系统文件中寻找init文件,然后启动系统的第一个进程:init进程

 

init进程 /system/core/init/init.c

init进程主要完成以下几件事情

创建系统目录,挂载文件系统

属性服务 SystemProperty 的初始化

解析init.rc脚本文件

服务处理,轮询property_set , keychord, 进程signal的事件


创建系统目录,挂载文件系统


/* clear the umask */
    umask(0); //清除屏蔽字(file mode creation mask),保证新建的目录的访问权限不受屏蔽字影响,相当于chmod 777

        /* 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.
         */
    //创建了3个主目录,2个dev下的子目录,挂载了4个文件系统
    mkdir("/dev", 0755);  //设备目录,所有外部设备和虚拟设备都在这个目录
    mkdir("/proc", 0755); //获取系统动态信息的目录
    mkdir("/sys", 0755);  //硬件设备在内核上的映射 

    //虚拟内存文件系统,tmpfs下的所有内容均为临时性的内容
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/socket", 0755);

    //只要pty的主复合设备/dev/ptmx被打开,就会在/dev/pts下动态的创建一个新的pty设备文件
    mount("devpts", "/dev/pts", "devpts", 0, NULL);
    //proc可以看作是内核内部数据结构的接口,通过它我们可以获得系统的信息,同时也能够在运行时修改特定的内核参数
    mount("proc", "/proc", "proc", 0, NULL);
    //与proc文件系统类似,sysfs文件系统也是一个不占有任何磁盘空间的虚拟文件系统。
    //它把连接在系统上的设备和总线组织成为一个分级的文件,使得它们可以在用户空间存取
    mount("sysfs", "/sys", "sysfs", 0, NULL);







解析init.rc脚本,把各种Action和Service加入到执行队列


INFO("reading config file\n");
    init_parse_config_file("/init.rc"); //解析init.rc

    //将early-init这个action里的Command添加到queue_list中。early-init主要目的是启动ueventd服务
    //uevent(user space event)是内核向用户空间发出的一个时间通知,使应用程序能够有机会对该event做出反应。
    action_for_each_trigger("early-init", action_add_queue_tail); //添加内建的action到action list和queue_list
    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"); //初始化组合键服务

    
    /* 初始化console终端 
     * 1.如果/proc/cmdline指定了控制台终端,那么优先使用这个控制台,如果没有指定,那么将使用默认控制台终端/dev/console。
     * 2.加载开机图片,参考load_565rle_image函数
     */
    queue_builtin_action(console_init_action, "console_init"); 

    /* execute all the boot actions to get us started */
    //导出必要的环境变量、构建根文件系统的目录结构、配置内核属性等一些和Android系统初始化化相关内容
    action_for_each_trigger("init", action_add_queue_tail);     

    /* 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");

    /* 初始化Init进程信号处理。通过socketpair创建一对已连接的socket,
     * 将生成的两个socket设置为O_NONBLOCK模式,也就是将对socket句柄的读写操作设置为非阻塞模式 
     */
    queue_builtin_action(signal_init_action, "signal_init");     

    /* Don't mount filesystems or start core system services if in charger mode. */     
    if (is_charger) {
         action_for_each_trigger("charger", action_add_queue_tail);
     } else {
         action_for_each_trigger("late-init", action_add_queue_tail); 
     }
     
    /* run all property triggers based on current state of the properties */
    /* 根据init.rc中action指定的property值与属性中的值比较,如果相等则执行对应的command。例如
     * on property:ro.secure=0																//     *  start console
     * 如果当前ro.secure的值为0,那么启动console服务 
     */
     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); 

#if BOOTCHART    
    /* Bootchart 能够对系统的性能进行分析,并生成系统启动过程的图表,以便为你提供有价值的参考信息。
     * 综合所得的信息,你就可以进行相应的改进,从而加快你的 Linux 系统启动过程。 
     */
    queue_builtin_action(bootchart_init_action, "bootchart_init"); 
#endif





属性服务 SystemProperty 的初始化

/* 初始化属性服务。
 * 创建/dev/__properties__ ,调用mmap映射到大小为pa_size(128*1024)共享内存。
 * fd和映射地址,size都存放在结构体workspace */
property_init(); 
	  
INFO("property init\n");
property_load_boot_defaults(); //从/default.prop设置一些默认的系统属性


/* 初始化属性服务
 * 1.读取/system/build.prop,/system/default.prop, /data/local.prop以及/data/property/下的属性并将其设置;
 * 2.创建一个服务器端UNIX Domain Socket,它的socket文件路径为/dev/socket/property_service,这个socket监听来自客户端的属性修改请求. 
 */
queue_builtin_action(property_service_init_action, "property_service_init");



其他初始化工作

uevent,watchdog的入口函数

if (!strcmp(basename(argv[0]), "ueventd")) //根据main函数的参数argv[0]判断是否启动ueventd守护进程
	return ueventd_main(argc, argv);       //ueventd_main将解析ueventd.rc文件,并创建相应的设备结点

    if (!strcmp(basename(argv[0]), "watchdogd")) //watchdogd守护进程入口
        return watchdogd_main(argc, argv);       //设备节点/dev/watchdog,设置喂狗和超时时间,循环写入""




屏蔽标准输入输出,初始化kernel log系统

open_devnull_stdio(); //重定向stdin(0),stdout(1),stderr(2) 到 /dev/__null__ ,达到屏蔽标准输入输出的目的
    klog_init();          //初始化内核log系统,内核printk的log均被写入到/dev/__kmsg__




获取硬件信息,处理kernel命令行参数,SELinux初始化

get_hardware_name(hardware, &revision); //从proc/cpuinfo读取硬件相关信息

    process_kernel_cmdline();  //解析处理bl传到kernel的命令行参数,保存在系统属性中

    //SELinux 初始化,恢复SELinux文件属性
    union selinux_callback cb;
    cb.func_log = log_callback;
    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");



服务处理,轮询property_set , keychord, 进程signal的事件

上述初始化工作都准备好了的话,就到了服务处理阶段了,这是一个死循环,主要工作就是:

1. 将init.rc及内建的actions命令,一条一条执行

2. 负责对service的管理。

3. 对signal及进程退出的处理

4. 响应property设置的请求(设置都在init中统一设置,读取进程可以自己读共享内存)

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

        execute_one_command(); //执行一条命令
        restart_processes();   //重新启动异常退出的Service。通过遍历service_list列表,找到flags设置为  
			       //需要重启的Service,调用restart_service_if_needed函数启动它

	//注册属性设置property_set_fd,监听来自属性服务property service的事件。属性服务是init提供的重要功能
        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;
        }
	//注册信号signal处理signal_recv_fd,主要用于接收子进程异常退出后内核抛出的SIGCHLD信号,
	//然后决定回收子进程资源或者重启子进程,防止子进程成为僵尸进程。
        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;
        }
	//注册keychord keychord_fd
        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;
        }

	// 如果有正要处理的Action,则设置timeout=0,即poll不阻塞
        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

	//将ufds传入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(); //收到属性设置的socket请求之后,设置相关属性。
                else if (ufds[i].fd == get_keychord_fd())
                    handle_keychord();
                else if (ufds[i].fd == get_signal_fd())
                    handle_signal(); //当有子进程终止时,也就是service终止时,内核会给init发送SIGCHLD,此时调用注册的handler函数
				     //这个handler函数是向其中的一个socket signal_fd写入数据,由于signal_init过程中初始化了一对
				     //已连接的socket signal_fd和signal_recv_fd,因此此时signal_recv_fd会收到向signal_fd写入的数据
				     //然后查询那个service终止,然后根据该service的属性来作相关的操作,是重启还是结束进行资源回收。
            }
        }
    }





本文参考资料有如下:

android的init过程分析

Android的init过程详解(一)

android init进程分析 基本流程

Android系统初始化过程分析(Android 4.3)

基于android2.3.5系统:开天辟地Android启动机制[一]

3.3 init进程的执行过程(1)