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启动机制[一]