Fork me on GitHub
侧边栏

ueventd和dev节点

一、核心结论(先看结论)

  1. /dev 下的设备节点是由 用户空间进程 ueventd(Android 的简化版 udevd)创建的。
  2. 设备节点的创建是因为 内核在设备注册时(device_register)通过 kobject_uevent() 发送了 uevent 消息
  3. ueventd 监听这些来自内核的 netlink 消息(NETLINK_KOBJECT_UEVENT),解析后根据规则文件(ueventd.rc 等)创建 /dev 设备节点。
  4. 创建设备节点的本质是调用 mknod() 系统调用,并设置对应的权限、属主和 SELinux 上下文。

二、内核层(发送 uevent)

当驱动在内核中注册一个设备时,会调用:

device_register()
  └── kobject_uevent(&dev->kobj, KOBJ_ADD);

这会产生一个 uevent 消息,比如:

ACTION=add
DEVNAME=sda
DEVPATH=/devices/platform/soc/.../block/sda
SUBSYSTEM=block
MAJOR=8
MINOR=0

然后这个消息通过 netlink socket (NETLINK_KOBJECT_UEVENT) 广播到用户空间。


三、用户空间:ueventd 的作用

Android 系统启动早期,会启动 ueventd 进程(由 init 通过 init.rc 启动):

service ueventd /system/bin/ueventd
    class core
    critical

ueventd 的主要逻辑在 system/core/init/ueventd_main.cppsystem/core/init/uevent_listener.cpp
其核心行为是:

  1. 打开 NETLINK_KOBJECT_UEVENT socket;
  2. 不断 recvmsg() 等待内核发来的 uevent;
  3. 解析出关键字段(ACTIONDEVNAMEMAJORMINOR 等);
  4. 根据 ueventd.rcueventd.<hardware>.rc 的规则决定:
    • /dev/<name> 节点路径;
    • 节点权限(mode);
    • 属主、属组;
    • 是否需要符号链接(如 /dev/block/platform/soc/...)。
  5. 调用 make_device() 创建节点:
int make_device(const char* path, int block, int major, int minor, mode_t perm, uid_t uid, gid_t gid) {
    dev_t dev = makedev(major, minor);
    int flags = block ? S_IFBLK : S_IFCHR;
    mknod(path, flags | perm, dev);
    chown(path, uid, gid);
}

四、设备节点的创建路径

举例说明:
当内核注册一个 USB 串口设备 /dev/ttyUSB0 时,内核会发出 uevent:

ACTION=add
DEVNAME=ttyUSB0
DEVTYPE=tty
MAJOR=188
MINOR=0
SUBSYSTEM=tty

ueventd 收到后:

  1. 查找 ueventd.rc 是否有匹配规则:

    /dev/ttyUSB*  0660  root  uucp
    
  2. 没有匹配则使用默认权限;

  3. 执行:

    mknod /dev/ttyUSB0 c 188 0
    chmod 0660 /dev/ttyUSB0
    chown root:uucp /dev/ttyUSB0
    

最终 /dev/ttyUSB0 节点就出现在文件系统中了。


五、配置文件:ueventd.rc 与 ueventd..rc

这两个文件指定了节点的默认权限、属主和符号链接规则。示例:

/dev/null              0666   root       root
/dev/tty[0-9]*         0660   root       shell
/dev/usb/lp*           0660   root       shell
/dev/block/mmcblk[0-9]* 0660  root       disk
/dev/bus/usb/*         0660   root       usb

设备匹配规则支持通配符。


六、ueventdinit 的区别

项目 init ueventd
功能 管理系统服务、挂载、属性设置等 管理 /dev 下的设备节点
事件来源 init.rc 配置 内核 kobject_uevent
工作时机 启动整个系统 启动早期即运行
通信机制 属性系统 + socket netlink: NETLINK_KOBJECT_UEVENT

七、总结流程图

内核驱动注册设备
     ↓
kobject_uevent(KOBJ_ADD)
     ↓
通过 netlink 发送消息到用户空间
     ↓
ueventd 监听 NETLINK_KOBJECT_UEVENT
     ↓
解析消息,查找匹配规则
     ↓
调用 mknod() 创建 /dev 节点
     ↓
设置权限 / 属主 / SELinux 标签

八、扩展:Android 和传统 Linux 的区别

  • 传统 Linux 用 udevd(systemd-udevd)来处理设备节点;
  • Android 由于追求轻量化和早期可用性,用的是简化版 ueventd
  • udevd 会执行复杂的规则文件(如 /lib/udev/rules.d/*),而 ueventd 只支持简单匹配
posted @ 2025-10-09 21:27  yooooooo  阅读(47)  评论(0)    收藏  举报