Android之init启动流程(二)

来源:互联网 发布:网络大电影上线渠道 编辑:程序博客网 时间:2024/05/01 09:47

Android启动部分

本文接演init启动之Android部分

上回书说道,kernel_init线程启,run_init_process执行init。

进入init.c分析,

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;

1,if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
得到uevent.rc文件路径下的uevntd文件,ueventd会解析前者,如果由此文件,则执行uevent_main进行uevent事件主循环处理。

2,if (!strcmp(basename(argv[0]), "watchdogd"))
return watchdogd_main(argc, argv);
watchdogd伺服程序是一个看门狗程序,它的任务就是定期向看门狗设备文件执行写操作,以判断系统是否正常运行。

/* 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.
*/
3,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);
创建用户空间的目录,如/dev, /proc, /sys等。


/* indicate that booting is in progress to background fw loaders, etc */
4,close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
通过对“/dev/.bootimg”文件的创建,打开,和关闭等一系列操作来表示目前正处于启动中的状态。

/* 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.
*/
5,open_devnull_stdio();
klog_init();
创建两个设备结点:/dev/__null__以及/dev/__kmsg__,并打开标准输入流,输出流以及错误输出流,并将它们重定向到/dev/__null__,所以,此时是不能直接调用printf系列的函数直接打印Log输出,而是利用klog输出日志。

6,property_init();
初始化属性服务所需的基本空间,首先创建一个/dev/__properties__文件,然后通过对应的文件描述映射一块共享内存,大小PA_SIZE(49152),映射的地址和相应的文件描述符保存在struct workspace中。

7,get_hardware_name(hardware, &revision);
process_kernel_cmdline();
获取硬件信息,将处理传递给内核的命令行参数。

8,#ifdef HAVE_SELINUX
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);

INFO("loading selinux policy\n");
if (selinux_enabled) {
if (selinux_android_load_policy() < 0) {
selinux_enabled = 0;
INFO("SELinux: Disabled due to failed policy load\n");
} else {
selinux_init_all_handles();
}
} else {
INFO("SELinux: Disabled by command line option\n");
}
/* 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");
#endif
如果启用了SELinux机制,接下来将加载
selinux策略,并初始化文件安全上下文以及属性安全上下文。

9,is_charger = !strcmp(bootmode, "charger");

INFO("property init\n");
if (!is_charger)
property_load_boot_defaults();
判断当前的启动模式不是充电模式,将从/default.prop文件中加载默认的属性设置。

INFO("reading config file\n");
10,init_parse_config_file("/init.rc");
解析根目录下init.rc文件。

11,action_for_each_trigger("early-init", action_add_queue_tail);
将“early-init”级别的action依次加入action_queue队列。

12,queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
加入三个action到init的action_list中。

/* execute all the boot actions to get us started */
13,action_for_each_trigger("init", action_add_queue_tail);
将所有init级别的action加入action_list。


/* skip mounting filesystems in charger mode */
if (!is_charger) {
action_for_each_trigger("early-fs", action_add_queue_tail);
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);
}

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

14,execute_one_command();
之前的所有关于action的操作基本都是add进List中,此时才是真正从List取出command执行。先后次序:early-init -> init -> early-fs -> fs -> post-fs ->early-boot -> boot。

15,restart_processes();
对有SVC_RESTARTING标志的service,执行restart_service_if_needed()。

16,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;
}
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;
}
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;
}
用poll等待几个事件:property事件/子进程结束的signal事件/keychord。

if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}

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

nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;

17,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();
}
}
}

处理等到的事件,对property_set事件,调用handle_property_set_fd()处理;对keychord事件,调用handle_keychord()处理;对signal事件,调用handle_signal()处理。


return 0;
}

init.rc文件语法是Android初始化语言,涉及六个基本概念、两个基本关键字和多个指令关键字。

六个基本概念分别是Section、Action、Service、Trigger、Command、Option。

两个基本关键字是on和service。

指令关键字则定义在Trigger、Command和Option中。

每一个action和Service都包含一个隐式的section,init.rc有多个不同的section组成。

Command是最小的功能单位,代表一个Linux命令或者一个方法调用。

Trigger代表一个自定义的触发条件,用来触发Action的执行,也可以认为它是Action的名称。

一个Action便是由关键字on声明、由Trigger触发的一组Command序列。

Option是Service的修饰符,由它来指定何时、如何启动Service程序。

每一个Service都是init进程的子进程,由关键字service、服务名、服务对应的命令的路径、命令的参数和Option组成,代表一些要在初始化阶段启动的程序。


总结,本文分析了init.c文件,简单描述了android初始化语言的指令字等,后文会继续init启动过程中一些service以及系统环境的开启流程。




0 0
原创粉丝点击