3. 设备节点基础:Linux设备节点概念、设备号(主/次)、udev与devtmpfs

在AAOS(Android Automotive OS)系统中,车载硬件(如GPS、CAN总线、摄像头、传感器)通过设备节点暴露给用户空间。理解设备节点的本质、设备号的分配机制以及设备节点的管理方式,是编写稳定可靠的设备监听与uevent驱动的基础。

3.1 设备节点概念

在Linux中,设备节点是位于/dev目录下的特殊文件,是用户空间程序与内核驱动程序交互的接口。应用程序通过标准的文件操作API(open()、read()、write()、ioctl())访问设备节点,内核VFS层将操作路由到对应的驱动程序。

特性 说明
文件类型 字符设备(c)或块设备(b),通过ls -l首字符识别
存储位置 通常位于/dev目录,AAOS中也可能出现在/devices或/sys下的符号链接
生命周期 由内核模块加载/卸载或设备热插拔事件驱动,动态创建和销毁
权限控制 通过udev规则设置用户、组和访问权限,AAOS中由android.hardware.*权限组管控
AAOS实践提示: 在AAOS中,车载传感器(如加速度计、陀螺仪)通常注册为输入子系统设备,对应的设备节点为/dev/input/eventX。监听这些节点时,必须确保AAOS的SELinux策略允许应用进程访问对应的设备节点。

3.2 设备号:主设备号与次设备号

每个设备节点在内核中由唯一的设备号标识,设备号是一个dev_t类型(32位无符号整数),分为两部分:

  • 主设备号(Major Number):标识设备对应的驱动程序。内核通过主设备号在全局设备表(chrdevs[])中查找对应的file_operations结构体。
  • 次设备号(Minor Number):标识由同一驱动管理的具体设备实例。驱动内部通过次设备号区分不同的硬件或逻辑单元。

设备号分配策略:

  • 静态分配:驱动调用register_chrdev_region(),指定起始主/次设备号。适用于已知且固定的设备(如/dev/ttyS0主设备号4)。
  • 动态分配:驱动调用alloc_chrdev_region(),由内核自动分配未使用的主设备号。推荐用于AAOS中的可热插拔设备(如USB外设)。

查看系统中已分配的设备号:

# 查看所有字符设备的主次设备号
cat /proc/devices

# 查看具体设备节点的设备号
ls -l /dev/input/event0
# 输出示例:crw-rw---- 1 root input 13, 64 Jan 15 10:30 /dev/input/event0
# 主设备号=13,次设备号=64

3.3 设备节点生命周期:从内核到用户空间

设备节点的创建不是自动发生的,它依赖于内核与用户空间守护进程的协作。下图展示了设备节点从驱动注册到用户空间可见的完整流程:

设备节点创建与生命周期流程 内核驱动注册 alloc_chrdev_region() 设备类创建 class_create() 设备注册 device_create() 内核空间(Kernel Space) 系统调用 / uevent 事件 用户空间(User Space) uevent 内核事件 kobject_uevent() udev 守护进程 udevd devtmpfs 自动创建 /dev/xxx udev 规则匹配 /etc/udev/rules.d/*.rules 设备节点就绪 权限设置 / 符号链接 / 自定义命名 AAOS 应用 / HAL 层访问设备节点 open() / read() / write() / ioctl()

3.4 udev 与 devtmpfs 的协同机制

现代Linux系统(包括AAOS)使用两种机制协同管理设备节点:

机制 角色 工作原理 AAOS中的特点
devtmpfs 内核级自动创建设备节点 内核在注册设备时,直接在devtmpfs文件系统中创建设备节点文件,无需用户空间干预 保证核心设备节点(如/dev/input/*)在驱动加载后立即可见,减少启动延迟
udev 用户空间设备管理器 监听内核uevent事件,根据规则文件设置权限、创建符号链接、加载固件或触发自定义操作 AAOS中通过ueventd(Android定制版udev)管理设备节点权限和SELinux标签
AAOS关键差异: Android(包括AAOS)使用ueventd替代标准udev。ueventd读取/ueventd.rc和/vendor/etc/ueventd.rc配置文件,为设备节点设置固定的用户、组和权限模式。在AAOS中,车载专用设备(如/dev/can*、/dev/gps*)必须在ueventd.rc中显式声明,否则应用层无法访问。

3.5 udev 规则与设备节点自定义

udev规则文件允许开发者根据设备属性(如厂商ID、产品ID、序列号)自定义设备节点的名称、权限和符号链接。规则文件通常位于/etc/udev/rules.d/目录,以.rules结尾。

典型udev规则示例:

# 根据USB设备的VID/PID创建符号链接
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="my_usb_serial"

# 设置设备节点权限和所属组
SUBSYSTEM=="input", KERNEL=="event[0-9]*", GROUP="input", MODE="0660"

# 根据设备序列号创建固定名称
SUBSYSTEM=="block", ATTRS{serial}=="1234567890", NAME="my_disk"

AAOS中设备节点监听的关键路径:

  1. 驱动调用device_create() → 内核生成uevent事件
  2. devtmpfs在/dev下创建设备节点(基础名称)
  3. ueventd接收uevent → 匹配ueventd.rc规则 → 设置权限和SELinux上下文
  4. AAOS HAL层通过open()访问设备节点 → 驱动file_operations被调用
  5. 应用层通过inotify或poll()监听设备节点事件

3.6 设备节点在AAOS中的特殊考量

AAOS作为车载操作系统,对设备节点的管理有额外的安全与稳定性要求:

  • SELinux强制访问控制:每个设备节点都有对应的SELinux上下文(如u:object_r:input_device:s0),只有拥有对应权限的域(domain)才能访问。监听设备节点前必须确认SELinux策略允许。
  • 设备节点持久化:AAOS使用devtmpfs挂载/dev,设备节点在重启后不持久化。需要持久化的设备配置(如CAN接口名称)应通过udev规则或AAOS的persist属性实现。
  • 热插拔场景:车载USB外设(如诊断工具、存储设备)的热插拔会触发uevent事件。监听程序需要处理设备节点的动态创建和销毁,避免使用已失效的文件描述符。
调试命令速查:
udevadm monitor --property — 实时监控uevent事件
udevadm info --attribute-walk --name=/dev/input/event0 — 查看设备节点的所有属性
ls -l /dev/input/ — 查看所有输入设备节点及其主次设备号
cat /proc/devices — 查看系统注册的所有设备驱动及其主设备号