这篇文章的意义在于理解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和属性服务器的相关事情
参考:
- 《深入理解Android卷I》
- Android启动流程深入理解
- 图解Android启动流程
- Android系统启动流程解析