Android Init进程
来源:互联网 发布:java select数量 编辑:程序博客网 时间:2024/05/21 16:00
Android本身就是基于Linux,因此内核的启动方式也是差不多的。Bootloader,Kernel完成系统设置以后,首先会在系统文件中寻找init文件,然后启动系统的第一个进程:init进程
init进程 /system/core/init/init.c
init进程主要完成以下几件事情
创建系统目录,挂载文件系统
属性服务 SystemProperty 的初始化
解析init.rc脚本文件
服务处理,轮询property_set , keychord, 进程signal的事件
创建系统目录,挂载文件系统
/* clear the umask */ umask(0); //清除屏蔽字(file mode creation mask),保证新建的目录的访问权限不受屏蔽字影响,相当于chmod 777 /* 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个主目录,2个dev下的子目录,挂载了4个文件系统 mkdir("/dev", 0755); //设备目录,所有外部设备和虚拟设备都在这个目录 mkdir("/proc", 0755); //获取系统动态信息的目录 mkdir("/sys", 0755); //硬件设备在内核上的映射 //虚拟内存文件系统,tmpfs下的所有内容均为临时性的内容 mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/socket", 0755); //只要pty的主复合设备/dev/ptmx被打开,就会在/dev/pts下动态的创建一个新的pty设备文件 mount("devpts", "/dev/pts", "devpts", 0, NULL); //proc可以看作是内核内部数据结构的接口,通过它我们可以获得系统的信息,同时也能够在运行时修改特定的内核参数 mount("proc", "/proc", "proc", 0, NULL); //与proc文件系统类似,sysfs文件系统也是一个不占有任何磁盘空间的虚拟文件系统。 //它把连接在系统上的设备和总线组织成为一个分级的文件,使得它们可以在用户空间存取 mount("sysfs", "/sys", "sysfs", 0, NULL);
解析init.rc脚本,把各种Action和Service加入到执行队列
INFO("reading config file\n"); init_parse_config_file("/init.rc"); //解析init.rc //将early-init这个action里的Command添加到queue_list中。early-init主要目的是启动ueventd服务 //uevent(user space event)是内核向用户空间发出的一个时间通知,使应用程序能够有机会对该event做出反应。 action_for_each_trigger("early-init", action_add_queue_tail); //添加内建的action到action list和queue_list 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"); //初始化组合键服务 /* 初始化console终端 * 1.如果/proc/cmdline指定了控制台终端,那么优先使用这个控制台,如果没有指定,那么将使用默认控制台终端/dev/console。 * 2.加载开机图片,参考load_565rle_image函数 */ queue_builtin_action(console_init_action, "console_init"); /* execute all the boot actions to get us started */ //导出必要的环境变量、构建根文件系统的目录结构、配置内核属性等一些和Android系统初始化化相关内容 action_for_each_trigger("init", action_add_queue_tail); /* 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"); /* 初始化Init进程信号处理。通过socketpair创建一对已连接的socket, * 将生成的两个socket设置为O_NONBLOCK模式,也就是将对socket句柄的读写操作设置为非阻塞模式 */ queue_builtin_action(signal_init_action, "signal_init"); /* Don't mount filesystems or start core system services if in charger mode. */ if (is_charger) { action_for_each_trigger("charger", action_add_queue_tail); } else { action_for_each_trigger("late-init", action_add_queue_tail); } /* run all property triggers based on current state of the properties */ /* 根据init.rc中action指定的property值与属性中的值比较,如果相等则执行对应的command。例如 * on property:ro.secure=0// * start console * 如果当前ro.secure的值为0,那么启动console服务 */ queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); #if BOOTCHART /* Bootchart 能够对系统的性能进行分析,并生成系统启动过程的图表,以便为你提供有价值的参考信息。 * 综合所得的信息,你就可以进行相应的改进,从而加快你的 Linux 系统启动过程。 */ queue_builtin_action(bootchart_init_action, "bootchart_init"); #endif
属性服务 SystemProperty 的初始化
/* 初始化属性服务。 * 创建/dev/__properties__ ,调用mmap映射到大小为pa_size(128*1024)共享内存。 * fd和映射地址,size都存放在结构体workspace */property_init(); INFO("property init\n");property_load_boot_defaults(); //从/default.prop设置一些默认的系统属性/* 初始化属性服务 * 1.读取/system/build.prop,/system/default.prop, /data/local.prop以及/data/property/下的属性并将其设置; * 2.创建一个服务器端UNIX Domain Socket,它的socket文件路径为/dev/socket/property_service,这个socket监听来自客户端的属性修改请求. */queue_builtin_action(property_service_init_action, "property_service_init");
其他初始化工作
uevent,watchdog的入口函数
if (!strcmp(basename(argv[0]), "ueventd")) //根据main函数的参数argv[0]判断是否启动ueventd守护进程return ueventd_main(argc, argv); //ueventd_main将解析ueventd.rc文件,并创建相应的设备结点 if (!strcmp(basename(argv[0]), "watchdogd")) //watchdogd守护进程入口 return watchdogd_main(argc, argv); //设备节点/dev/watchdog,设置喂狗和超时时间,循环写入""
屏蔽标准输入输出,初始化kernel log系统
open_devnull_stdio(); //重定向stdin(0),stdout(1),stderr(2) 到 /dev/__null__ ,达到屏蔽标准输入输出的目的 klog_init(); //初始化内核log系统,内核printk的log均被写入到/dev/__kmsg__
获取硬件信息,处理kernel命令行参数,SELinux初始化
get_hardware_name(hardware, &revision); //从proc/cpuinfo读取硬件相关信息 process_kernel_cmdline(); //解析处理bl传到kernel的命令行参数,保存在系统属性中 //SELinux 初始化,恢复SELinux文件属性 union selinux_callback cb; cb.func_log = log_callback; 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");
服务处理,轮询property_set , keychord, 进程signal的事件
上述初始化工作都准备好了的话,就到了服务处理阶段了,这是一个死循环,主要工作就是:
1. 将init.rc及内建的actions命令,一条一条执行
2. 负责对service的管理。
3. 对signal及进程退出的处理
4. 响应property设置的请求(设置都在init中统一设置,读取进程可以自己读共享内存)
for(;;) { int nr, i, timeout = -1; execute_one_command(); //执行一条命令 restart_processes(); //重新启动异常退出的Service。通过遍历service_list列表,找到flags设置为 //需要重启的Service,调用restart_service_if_needed函数启动它//注册属性设置property_set_fd,监听来自属性服务property service的事件。属性服务是init提供的重要功能 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; }//注册信号signal处理signal_recv_fd,主要用于接收子进程异常退出后内核抛出的SIGCHLD信号,//然后决定回收子进程资源或者重启子进程,防止子进程成为僵尸进程。 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; }//注册keychord keychord_fd 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; }// 如果有正要处理的Action,则设置timeout=0,即poll不阻塞 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//将ufds传入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(); //收到属性设置的socket请求之后,设置相关属性。 else if (ufds[i].fd == get_keychord_fd()) handle_keychord(); else if (ufds[i].fd == get_signal_fd()) handle_signal(); //当有子进程终止时,也就是service终止时,内核会给init发送SIGCHLD,此时调用注册的handler函数 //这个handler函数是向其中的一个socket signal_fd写入数据,由于signal_init过程中初始化了一对 //已连接的socket signal_fd和signal_recv_fd,因此此时signal_recv_fd会收到向signal_fd写入的数据 //然后查询那个service终止,然后根据该service的属性来作相关的操作,是重启还是结束进行资源回收。 } } }
本文参考资料有如下:
android的init过程分析
Android的init过程详解(一)
android init进程分析 基本流程
Android系统初始化过程分析(Android 4.3)
基于android2.3.5系统:开天辟地Android启动机制[一]
3.3 init进程的执行过程(1)
0 0
- android init进程 init.rc
- Android init 进程 init.rc init.*.rc
- Android init 进程 init.rc init.*.rc
- Android init 进程 init.rc init.*.rc
- android init 进程分析
- Android init进程启动
- Android init进程分析
- Android init进程启动
- Android Init进程分析
- Android之Init进程
- Android Init进程分析
- Android init进程启动
- Android init进程解析
- Android init进程启动
- Android Init进程详解
- Android Init进程
- Android init进程
- Android init进程
- hdu1421搬寝室
- 黑马程序员——视频学习过程2
- 安装CocoaPods和使用
- WPF开发连连看系列II-图片匹配算法的实现
- poj 1426 Find The Multiple
- Android Init进程
- const
- POJ 1458-Common Subsequence(dp之最长公共子序列)
- Sudoku(POJ--2676
- 获取当前 IE 地址栏中的 URL
- [TOJ 3541] Counting Sequences
- 编程之美1.12 尼姆博弈拓展的分析与论证
- git 远程同步命令
- 归档test