您的位置:首页 > 移动开发 > Android开发

Android3.1 init进程启动源码分析

2014-12-23 17:36 399 查看
一、Android Init.c执行流程

Android中的内核启动后,kernel会启动第一个用户级别的进程:init,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。

PS:可以通过:ps aux | grep init命令来查看其Pid为1。

1、init负责创建系统中几个关键进程,最重要的是zygote,init是如何创建zygote??

2、Android系统中有很多,init提供了property service(属性服务)来管理他们,init属性服务是如何工作的??

init进程对应的代码在android源码目录中的:system/core/init/init.c中。(源码版本3.1)

查看Android系统源码版本号:build\core\version_defaults.mk //搜索该文件中的
PLATFORM_VERSION值

init做了什么?

1.初始化log系统

2.解析/init.rc和/init.%hardware%.rc文件

3. 执行 early-init action in the two files parsed in step 2.

4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares.

5. 初始化属性服务器,Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.

6. 执行 init action in the two files parsed in step 2.

7. 开启 属性服务。

8. 执行 early-boot and boot actions in the two files parsed in step 2.

9. 执行 Execute property action in the two files parsed in step 2.

10. 进入一个无限循环 to wait for device/property set/child process exit events.例如, 如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃 了,那么init 将会收到一个 SIGCHLD
信号,把这个信号转化为子进程退出事件, 所以在loop中,init 会操作进程退出事件并且执行 *.rc 文件中定义的命令。

例如,在init.rc中,因为有:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

socket zygote stream 666

onrestart write /sys/android_power/request_state wake

onrestart write /sys/power/state on

所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。

源码:

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;

if (!strcmp(basename(argv[0]), "ueventd"))

return ueventd_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", 0, "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);

/* 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.

*/

# init的标准输入,标准输出,标准错误文件描述符定向到__null__,意味着没有输入和输出,它的输入和输出全部写入到Log中

//需要在后面的程序中看打印信息的话,需要屏蔽open_devnull_stdio()函数

open_devnull_stdio();

# 初始化log,写入init进程信息、//初始化log系统

log_init();

INFO("reading config file\n");

init_parse_config_file("/init.rc");# 读取并且解析init.rc文件

/* pull the kernel commandline and ramdisk properties file in */

import_kernel_cmdline(0);#处理内核命令

get_hardware_name(hardware, &revision);# 取得硬件名

snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);#解析机器相关的配置文件,一般相关的放在init.rc中利用service
action调过去

init_parse_config_file(tmp);# 读取并且解析硬件相关的init脚本文件

# 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init

action_for_each_trigger("early-init", action_add_queue_tail);

queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");

queue_builtin_action(property_init_action, "property_init");

queue_builtin_action(keychord_init_action, "keychord_init");

queue_builtin_action(console_init_action, "console_init");

queue_builtin_action(set_init_properties_action, "set_init_properties");

/* execute all the boot actions to get us started */

# 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init

action_for_each_trigger("init", action_add_queue_tail);

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);

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");

/* execute all the boot actions to get us started */

# 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot

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_propety_triggers");

#if BOOTCHART

queue_builtin_action(bootchart_init_action, "bootchart_init");

#endif

# 进入死循环,并等待一些事情的到来,重点关注init如何处理来自socket和来自属性服务器的相关事情。

//建立init的子进程(init是所有进程的父进程)

for(;;) {

int nr, i, timeout = -1;

#// 执行命令(子进程对应的命令)

execute_one_command();

restart_processes();#重启那些已死去的进程

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;

}

if (process_needs_restart) {

timeout = (process_needs_restart - gettime()) * 1000;

if (timeout < 0)

timeout = 0;

}

if (!action_queue_empty() || cur_action)

timeout = 0;

// bootchart是一个性能统计工具,用于搜集硬件和系统的信息,并将其写入磁盘,以便其

// 他程序使用

#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;

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: