1. Linux kernel创建的/dev/下的设备节点是不对的, 其实是kernel仅负责在/sys/(基于内存的虚拟文件系统)创建一大堆下目录和文件,而真正的设备节点是在用户空间程序创建的,应该是udev实现的。
2. 对于非android系统,应该是mdev,其实到底谁来处理,关键看kernel发送uevent事件,应用层通过什么方式处理的,是侦听socket还是通过设置/proc/sys/kernel/hotplug命令文件。
3. Android的设备节点和Linux的设备节点创建方式有些不同,但是都是通过捕获设备注册的event事件来创建设备节点的,而不是在device_add()里面就注册了,因为在内核启动阶段,根文件系统还没有挂载,没有/dev/目录。
在android系统中,由init进程负责处理这种uevent事件,如果是"add" device事件, init会在/dev/下创建相应的节点,具体代码可查看 system/core/init/devices.c: handle_device_event->make_device 节点的用户、组、权限都可以在devperms中定制。
Android 使用Init 进程来创建设备节点文件,分两种情况:静态节点文件和动态节点文件,以应对已经定义好的冷插拔和系统运行起来后插入的热插拔设备。
(1)对于冷插拔设备,init 进程事先获取等待冷插拔处理的驱动程序,事先定义好个驱动的设备节点文件(在android_source_code/system/core/init/devices.c中),在struct perms_devices[ ] 列出了设备节点的名称。访问权限,用户ID,组ID,若要添加新的用户定义的新设备需要在此结构体中添加相应信息。
(2)init 对于热插拔的动态设备,使用事件处理循环来完成,使用poll()监听来自驱动程序的uevent, 然后调用handle_device_fd()创建设备节点。
/*init.c中针对cold-plug设备节点的创建:*/ int main(int argc, char **argv) int ueventd_main(int argc, char **argv) device_init(); coldboot("/sys/class"); coldboot("/sys/block"); coldboot("/sys/devices"); do_coldboot(d); //他是一个递归函数 void handle_device_fd() handle_device_event(&uevent); handle_block_device_event(uevent); handle_platform_device_event(uevent); handle_generic_device_event(uevent); //在这个文件中创建设备节点 handle_device(uevent->action, devpath, uevent->path, 0, uevent->major, uevent->minor, links); static void handle_device(const char *action, const char *devpath, const char *path, int block, int major, int minor, char **links) { int i; if(!strcmp(action, "add")) { make_device(devpath, path, block, major, minor, (const char **)links); /*创建设备节点*/ if (links) { for (i = 0; links[i]; i++) make_link_init(devpath, links[i]); } } if(!strcmp(action, "remove")) { if (links) { for (i = 0; links[i]; i++) remove_link(devpath, links[i]); /*移除软链接*/ } unlink(devpath); /*移除设备节点*/ } if (links) { for (i = 0; links[i]; i++) free(links[i]); free(links); } }
/*main.c中针对hot-plug设备的设备节点的创建*/ int main(int argc, char **argv) { . . . 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; }