Android ioctl 第二个参数命令码以及BINDER_FREEZE示例
1. _IOC_NRSHIFT _IOC_TYPESHIFT _IOC_SIZESHIFT _IOC_DIRSHIFT
宏定义了命令码中各字段的二进制偏移量,用于将不同参数定位到命令码的特定位置
#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
#define _IOC_SIZEBITS 14
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
_IOC_DIRSHIFT
作用:方向(dir)字段的起始位偏移量。
值:30(大小占 14 位后,方向从第 30 位开始)。
计算逻辑:_IOC_SIZESHIFT + _IOC_SIZEBITS = 16 + 14 = 30。
_IOC_TYPESHIFT
作用:类型(type,即幻数)字段的起始位偏移量。
值:8(序号占 8 位后,类型从第 8 位开始)。
计算逻辑:_IOC_NRSHIFT + _IOC_NRBITS = 0 + 8 = 8
_IOC_NRSHIFT
作用:序号(nr)字段的起始位偏移量。
值:0(序号是命令码的第一个字段,从最低位开始)。
计算逻辑:序号占 _IOC_NRBITS(8 位),因此其偏移量为 0。
_IOC_SIZESHIFT
作用:数据大小(size)字段的起始位偏移量。
值:16(类型占 8 位后,大小从第 16 位开始)。
计算逻辑:_IOC_TYPESHIFT + _IOC_TYPEBITS = 8 + 8 = 16。
2. _IOC_TYPECHECK
此宏用于验证数据类型的大小是否合法,并生成数据大小字段的值
#define _IOC_TYPECHECK(t) (sizeof(t))
计算数据类型 t 的大小(通过 sizeof)。
确保数据大小不超过 14 位能表示的最大值(即 16383 字节)。
3. _IOC
通过 _IOC 宏将各字段组合为最终的命令码
#define _IOC(dir, type, nr, size) \(((dir) << _IOC_DIRSHIFT) | \((type) << _IOC_TYPESHIFT) | \((nr) << _IOC_NRSHIFT) | \((size) << _IOC_SIZESHIFT))
4. BINDER_FREEZE
1. 命令定义分解
#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info)
#define _IOW(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
#define _IOC(dir,type,nr,size) \(((dir) << _IOC_DIRSHIFT) | \((type) << _IOC_TYPESHIFT) | \((nr) << _IOC_NRSHIFT) | \((size) << _IOC_SIZESHIFT))
2. 命令码的二进制结构
一个 ioctl 命令码是 32位整数,按以下分段:
所谓幻数就是类型的意思。
3. 具体计算示例
假设 struct binder_freeze_info 的大小为 12 字节:
各字段二进制位置:
// 1. 方向 _IOC_WRITE (写操作)
方向位 = 1 << 30 (0x40000000)
// 2. 幻数 'b' (ASCII码 0x62)
幻数位 = 0x62 << 24 (0x62000000)
// 3. 序号 14
序号位 = 14 << 16 (0x000E0000)
// 4. 数据大小 12
大小位 = 12 << 0 (0x0000000C)
命令码 = 0x40000000 | 0x62000000 | 0x000E0000 | 0x0000000C = 0x62 00 E0 0C → 十六进制表示为 0x62E00C
4. 关键设计思想
为何需要如此复杂的宏?
- 类型安全:
_IOC_TYPECHECK(size) 确保用户空间传递的结构体大小与内核一致,避免内存越界。 - 方向明确:
明确数据流向(_IOC_READ/_IOC_WRITE),驱动无需猜测用户意图。 - 幻数隔离:
不同驱动的幻数不同(如 Binder 用 ‘b’,USB 用 ‘U’),避免命令码冲突。