Android ioctl 第二个参数命令码以及BINDER_FREEZE示例

发布于:2025-05-01 ⋅ 阅读:(19) ⋅ 点赞:(0)

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. 关键设计思想

为何需要如此复杂的宏?

  1. ​​类型安全​​:
    _IOC_TYPECHECK(size) 确保用户空间传递的结构体大小与内核一致,避免内存越界。
  2. ​​方向明确​​:
    明确数据流向(_IOC_READ/_IOC_WRITE),驱动无需猜测用户意图。
  3. ​​幻数隔离​​:
    不同驱动的幻数不同(如 Binder 用 ‘b’,USB 用 ‘U’),避免命令码冲突。

网站公告

今日签到

点亮在社区的每一天
去签到