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 设备节点生命周期:从内核到用户空间
设备节点的创建不是自动发生的,它依赖于内核与用户空间守护进程的协作。下图展示了设备节点从驱动注册到用户空间可见的完整流程:
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中设备节点监听的关键路径:
- 驱动调用
device_create()→ 内核生成uevent事件 - devtmpfs在
/dev下创建设备节点(基础名称) - ueventd接收uevent → 匹配
ueventd.rc规则 → 设置权限和SELinux上下文 - AAOS HAL层通过
open()访问设备节点 → 驱动file_operations被调用 - 应用层通过
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 — 查看系统注册的所有设备驱动及其主设备号