进入用户空间
在kernel中通过run_init_process来执行init进程,之后就会进入system/core/init/init.cpp的main函数,这才真正的进入用户空间。
进入main函数后,会进行判断是否是系统启动的第一阶段,只有启动参数中有--second-stage才为第二阶段
bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 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.
if (is_first_stage) {
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
}
对klog进行初始化,设置klog level为NOTICE,所以可以将NOTICE级别的log输出,而INFO级别的log就打印不出来
具体原因,请阅读Android7.0 klog机制
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
系统启动流程的关键log来了,可以通过该行log知道init进程启动起来了,也表示kernel启动结束。大家注意klog level为NOTICE所以可以打印出来。
NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
//示例log , 我们可以通过时间戳2.042999s, 获得从开始启动kernel到进入init花费多长时间,也就是开机过程中kernel耗时情况。
[01-01 08:26:55.194] <13>[ 2.042999] c3 init: init first stage started!
如果为第一阶段的话会对selinux进行初始化
// Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
selinux_initialize(is_first_stage);
selinux初始化函数,我们可以修改该函数,本地手动开关selinux来调试问题。
static void selinux_initialize(bool in_kernel_domain) {
Timer t; //使用Timer计时,计算selinux初始化耗时
selinux_callback cb;
cb.func_log = selinux_klog_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
if (in_kernel_domain) { //第一阶段in_kernel_domain为true
INFO("Loading SELinux policy...\n"); //该行log打印不出,INFO级别
if (selinux_android_load_policy() < 0) {
ERROR("failed to load policy: %s\n", strerror(errno));
security_failure();
}
bool kernel_enforcing = (security_getenforce() == 1);
bool is_enforcing = selinux_is_enforcing();
if (kernel_enforcing != is_enforcing) {
if (security_setenforce(is_enforcing)) { //设置selinux的模式,是开还是关
ERROR("security_setenforce(%s) failed: %s\n",
is_enforcing ? "true" : "false", strerror(errno));
security_failure();