android init进程分析 ueventd
转自:http://blog.csdn.net/freshui/article/details/2132299
(懒人最近想起我还有csdn好久没打理了,这个Android init躺在我的草稿箱中快5年了,稍微改改发出来吧)
ueventd主要是负责设备节点的创建、权限设定等一些列工作。服务通过使用uevent,监控驱动发送的消息,做进一步处理。
ueventd实际和init是同一个binary,只是走了不同分支,可参看前一部分。
ueventd的整体代码比较简单,主要是三部分:
- 解析ueventd.rc
 - 初始化设备信息
 - 循环polling uevent消息
 
主函数及相关功能如下如下:
- int ueventd_main(int argc, char **argv)
 - {
 - // 和init一样,没有std输入输出
 - open_devnull_stdio();
 - // 初始化kernel log,让ueventd的log,通过kernel printk的log输出到串口中
 - klog_init();
 - //解析和处理ueventd的rc文件
 - import_kernel_cmdline(0, import_kernel_nv);
 - get_hardware_name(hardware, &revision);
 - ueventd_parse_config_file("/ueventd.rc");
 - snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
 - ueventd_parse_config_file(tmp);
 - // 设备初始化
 - device_init();
 - // polling uevent消息,对设备进行管理
 - ufd.events = POLLIN;
 - ufd.fd = get_device_fd();
 - while(1) {
 - ufd.revents = 0;
 - nr = poll(&ufd, 1, -1);
 - if (nr <= 0)
 - continue;
 - if (ufd.revents == POLLIN)
 - handle_device_fd(); // polling到消息,处理event消息
 - }
 - }
 
处理和解析ueventd.rc
这部分相比init.rc来说,巨简单,没什么特别的。主要是通过rc文件,来控制目录节点的权限。如:
- /dev/ttyUSB2 0666 radio radio
 - /dev/ts0710mux* 0640 radio radio
 - /dev/ppp 0666 radio vpn
 - # sysfs properties
 - /sys/devices/virtual/input/input* enable 0666 system system
 - /sys/devices/virtual/input/input* poll_delay 0666 system system
 
详情应该不需要展开,基本都能了解。
设备初始化
 kernel在加载设备时,会通过socket发送uevent事件给userspace, 在init里,通过接受这些uevent事件,来创建设备的节点。主要函数是device_init()
初始化函数为device_init,如下
- void device_init(void)
 - {
 - suseconds_t t0, t1;
 - struct stat info;
 - int fd;
 - sehandle = NULL;
 - if (is_selinux_enabled() > 0) {
 - sehandle = selinux_android_file_context_handle();
 - }
 - /* is 256K enough? udev uses 16MB! */
 - device_fd = uevent_open_socket(256*1024, true);
 - if(device_fd < 0)
 - return;
 - fcntl(device_fd, F_SETFD, FD_CLOEXEC);
 - fcntl(device_fd, F_SETFL, O_NONBLOCK);
 - if (stat(coldboot_done, &info) < 0) {
 - t0 = get_usecs();
 - coldboot("/sys/class");
 - coldboot("/sys/block");
 - coldboot("/sys/devices");
 - t1 = get_usecs();
 - fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);
 - close(fd);
 - log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
 - } else {
 - log_event_print("skipping coldboot, already done\n");
 - }
 - }
 
open_uevent_socket();
这是打开uevent的socket。这里的uevent是用到netlink中的内核事件向用户态通知(NETLINK_KOBJECT_UEVENT)功能,是内核和用户态进行双向数据传输的非常好的方式,除了eventd外,netd和vold也是使用uevent的。
初始化函数中,比较要注意的coldboot这个函数,字面意思是冷启动,它的作用是,对那些在uventd启动前,已经add上的驱动,再重新操作一下,让他们再发一次event消息,上层号针对性处理。
这里对 /sys/class,/sys/block和/sys/devices下的设备遍历一遍:
- static void do_coldboot(DIR *d)
 - {
 - struct dirent *de;
 - int dfd, fd;
 - dfd = dirfd(d);
 - fd = openat(dfd, "uevent", O_WRONLY);
 - if(fd >= 0) {
 - write(fd, "add\n", 4);
 - close(fd);
 - handle_device_fd();
 - }
 - while((de = readdir(d))) {
 - DIR *d2;
 - if(de->d_type != DT_DIR || de->d_name[0] == '.')
 - continue;
 - fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
 - if(fd < 0)
 - continue;
 - d2 = fdopendir(fd);
 - if(d2 == 0)
 - close(fd);
 - else {
 - do_coldboot(d2);
 - closedir(d2);
 - }
 - }
 - }
 
write(fd, "add\n", 4)激活内核,重发add事件的uevent,handle_device_fd();针对event消息,做响应的处理。
uevent消息处理
初始化好了之后,daemon程序只要polling新的event事件即可,polling到了,就调用handle_device_fd();来处理,可以看看这个函数:
- void handle_device_fd()
 - {
 - char msg[UEVENT_MSG_LEN+2];
 - int n;
 - while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
 - if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
 - continue;
 - msg[n] = '\0';
 - msg[n+1] = '\0';
 - struct uevent uevent;
 - parse_event(msg, &uevent);
 - handle_device_event(&uevent);
 - handle_firmware_event(&uevent);
 - }
 - }
 
功能就是接受内核发的event消息,然后parser此消息,处理对应的消息事件。
这里:
- static void handle_device_event(struct uevent *uevent)
 - {
 - if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change"))
 - fixup_sys_perms(uevent->path);
 - if (!strncmp(uevent->subsystem, "block", 5)) {
 - handle_block_device_event(uevent);
 - } else if (!strncmp(uevent->subsystem, "platform", 8)) {
 - handle_platform_device_event(uevent);
 - } else {
 - handle_generic_device_event(uevent);
 - }
 - }
 
主要功能,就是根据发过来的uevent,创建/删除设备节点,同时以ueventd.rc中描述的权限设置更新一些节点权限。
- static void handle_firmware_event(struct uevent *uevent)
 - {
 - pid_t pid;
 - int ret;
 - if(strcmp(uevent->subsystem, "firmware"))
 - return;
 - if(strcmp(uevent->action, "add"))
 - return;
 - /* we fork, to avoid making large memory allocations in init proper */
 - pid = fork();
 - if (!pid) {
 - process_firmware_event(uevent);
 - exit(EXIT_SUCCESS);
 - }
 - }
 
如果有协处理器, 还要下载协处理器的firmware,这里是处理协处理器要下载firmware的指令,fork一个子进程处理。
android init进程分析 ueventd的更多相关文章
- android init进程分析 init脚本解析和处理
		
(懒人近期想起我还有csdn好久没打理了.这个android init躺在我的草稿箱中快5年了.略微改改发出来吧) RC文件格式 rc文件是linux中常见的启动载入阶段运行的文件.rc是run co ...
 - Android init进程概述
		
init进程,其程序位于根文件系统中,在kernle自行启动后,其中的 start_kernel 函数把根文件系统挂载到/目录后,在 rest_init 函数中通过 kernel_thread(ker ...
 - Android Init进程命令的执行和服务的启动
		
这里开始分析init进程中配置文件的解析,在配置文件中的命令的执行和服务的启动. 首先init是一个可执行文件,它的对应的Makfile是init/Android.mk. Android.mk定义了i ...
 - ANDROID init进程
		
init简要 init是Android上启动的第一个用户态进程. 执行序列是: start_kernel() -> rest_init() -> kernel_init() -> i ...
 - 构建根文件系统之init进程分析
		
busybox是ls.cp等命令的集合. 执行ls时,实际上是执行了busybox ls 执行cp时,实际上是执行了busybox cp 分析init程序之前,再让我们回想一下我们的目标:u-boot ...
 - Android 8.1 源码_启动篇(一) -- 深入研究 init(转 Android 9.0 分析)
		
前言 init进程,它是一个由内核启动的用户级进程,当Linux内核启动之后,运行的第一个进程是init,这个进程是一个守护进程,确切的说,它是Linux系统中用户控件的第一个进程,所以它的进程号是1 ...
 - Android 7.0 启动篇 — init原理(二)(转 Android 9.0 分析)
		
======================================================== ================================== ...
 - Android 7.0 启动篇 — init原理(一)(转 Android 9.0 分析)
		
======================================================== ================================== ...
 - 第4阶段——制作根文件系统之分析init进程(2)
		
本节目标: (1) 了解busybox(init进程和命令都放在busybox中) (2) 创建SI工程,分析busybox源码来知道init进程做了哪些事情 (3) 分析busybox中init进 ...
 
随机推荐
- 上网八个常用cmd命令你掌握了几个?
			
上网八个常用cmd命令你掌握了几个? 一.ping 它是用来检查网络是否通畅或者网络连接速度的命令.作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握 ...
 - NOIP2016呵呵记
			
经过了一年的想象和臆测,经历了学长们的几次考试,通过老师的言语莫名感受过了所谓oi式压力之后,自己的考试也终于到来了. 考前的生活也没有想象中的那么充实,无非跟着神犇刷刷题,讨论算法,学点新技巧,然后 ...
 - 创建面注记PolygonElement
			
1.根据4点创建一个面 /// <summary> /// 根据4个点创建图形,点序要顺时针 /// </summary> /// <param name="p ...
 - Oracle开机自启动
			
linux下启动oracle su - oracle #用oracle用户登陆 sqlplus /nolog conn /as sysdba startup exit lsnrctl start ex ...
 - 4Struts2标签库----青软S2SH(笔记)
			
这里弄错了,这一堆属性是<datetimepicker>标签的,不是<doubleselect>标签的 输出错误信息这个不错,挺方便的. 这个树形标签,也用了好多网络,分析如下 ...
 - cf723c Polycarp at the Radio
			
Polycarp is a music editor at the radio station. He received a playlist for tomorrow, that can be re ...
 - Mac Pro 资源管理器 Double Commander“个性化设置” 备份
			
操作系统自带的资源管理器,总是有些别扭的地方,在 Windows 系统下,我一般用 Total Commander(破解版)来作为替代品.现在换为 Mac 系统,自带的 Finer 也不怎么好用,连最 ...
 - Github.com上有哪些比较有趣的PHP项目?
			
链接就不贴了,可以在github上进行搜索.这里就不列举 symfony.laravel 这些大家都知道的项目了.只列举比较有意思的. swoole, C扩展实现的PHP异步并行网络通信框架,可以重新 ...
 - Linux学习之一--VI编辑器的基本使用
			
vi编辑器是Linux系统下标准的编辑器.而且不逊色于其他任何最新的编辑器.可是会用的有多少呢.下面介绍一下vi编辑器的简单用法和部分命令.让你在Linux系统中畅行无阻. 基本上vi可以分为三种状态 ...
 - BZOJ2007——[Noi2010]海拔
			
1.题意:一个裸的最小割 2.分析:直接转成对偶图最短路就好了,水爆了!(雾) #include <queue> #include <cstdio> #include < ...