一 Init
init进程,它是内核启动的第一个用户级进程。
代码路径system/core/init/
1.0 main
init程序的入口函数是init.cpp中的main函数
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) { // ln -sf ../init /sbin/ueventd
return ueventd_main(argc, argv); // ueventd软链接到了init,当运行ueventd时,执行ueventd_main函数
}
if (!strcmp(basename(argv[0]), "watchdogd")) { // ln -sf ../init /sbin/watchdogd
return watchdogd_main(argc, argv); // watchdogd软链接到了init,当运行watchdogd时,执行watchdogd_main函数
}
// Clear the umask.
umask(0); // 清除umask值
add_environment("PATH", _PATH_DEFPATH); // 设置环境变量PATH=/usr/local/bin:/bin:/usr/bin
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) { // 第一次启动init,创建或挂载一些linux根文件系统中的目录
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);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
}
// 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(); // init的标准输入,标准输出,标准错误文件描述符定向到/dev/__null__
klog_init(); // 打开/dev/kmsg,init进程的log,打印到内核printk的log buffer
klog_set_level(KLOG_NOTICE_LEVEL); // 设置log级别为5
NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
property_init(); // 创建/dev/__properties__文件,大小128KB,并映射进内存
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
process_kernel_dt();
process_kernel_cmdline(); // 解析cmdline中以androidboot.开头的参数,并设置相应的property属性
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props(); 设置"ro.serialno", "ro.bootmode", "ro.baseband", "ro.bootloader","ro.hardware", "ro.revision"的property属性
}
// Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
selinux_initialize(is_first_stage); // 初始化SEAndroid
// If we're in the kernel domain, re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (is_first_stage) {
if (restorecon("/init") == -1) { // 恢复/init的SELinux文件属性
ERROR("restorecon failed: %s\n", strerror(errno));
security_failure();
}
char* path = argv[0];
char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
if (execv(path, args) == -1) { // execv会停止执行当前的进程,并且以progname应用进程替换被停止执行的进程,进程ID没有改变,这里是运行init,将其从kernel域变成用户域
ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
security_failure();
}
}
// 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.
NOTICE("Running restorecon...\n");
restorecon("/dev"); // 我的看版本restorecon是个空函数?
restorecon("/dev/socket");
restorecon("/dev/__properties__");
restorecon("/property_contexts");
restorecon_recursive("/sys");
epoll_fd = epoll_create1(EPOLL_CLOEXEC); // 表示生成的epoll fd具有“执行后关闭”特性
if (epoll_fd == -1) {
ERROR("epoll_create1 failed: %s\n", strerror(errno));
exit(1);
}
signal_handler_init(); // 子进程退出处理
property_load_boot_defaults(); // 加载/default.prop文件
export_oem_lock_status(); // 设置ro.boot.flash.locked的property属性
start_property_service(); // 启动property属性服务