学习 binder 我感觉得从上到下:先对 binder 架构/理论有个大概的认识、对 binder 里的数据结构有个印象,再深入代码细节

整个 binder 涉及到应用侧和驱动侧、app 侧和 framework 侧、java 层和 native 层,代码量巨大而且跨度很大,只有对整个 binder 架构有清晰的认识才不会迷失在细节里

Linux 设备

devices.jpg

linux 系统将设备分为3类:字符设备、块设备和网络设备:

  1. 字符设备 是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和 LED 设备等
  2. 块设备 是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U 盘和 SD 卡等

每个字符设备或块设备都在 /dev 目录下对应一个设备文件,linux 用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备;驱动调用的实质,就是通过设备文件找到与之对应设备号的设备,再通过设备初始化时绑定的操作函数对硬件进行控制

device_driver.jpg

字符设备、字符设备驱动与用户空间访问该设备的程序三者之间的关系如下图:

  1. 使用 cdev 结构体来描述字符设备
  2. 通过其成员 dev_t 来定义设备号(分为主、次设备号)以确定字符设备的唯一性
  3. 通过其成员 file_operations 来定义字符设备驱动提供给 VFS 的接口函数,如常见的 open()、read()、write() 等

chrdev.jpg

在 Linux 字符设备驱动中:

  1. 模块加载函数通过 register_chrdev_region 或 alloc_chrdev_region 来静态或者动态获取设备号
  2. 通过 cdev_init 建立 cdev 与 file_operations 之间的连接,通过 cdev_add 向系统添加一个 cdev 以完成注册
  3. 模块卸载函数通过 cdev_del 来注销 cdev,通过 unregister_chrdev_region 来释放设备号

杂项设备

杂项设备也是在嵌入式系统中用得比较多的一种设备驱动,使用 misc_register(struct miscdevice *misc) 注册杂项设备,misc_deregister(struct miscdevice *misc) 释放杂项设备

在 Linux 内核的 include/linux 目录下有 Miscdevice.h 文件,要把自己定义的 misc device 设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号 10 ,一起归于 misc device,其实 misc_register 就是用主标号 10 调用 register_chrdev() 的,也就是说 misc device 就是特殊的字符设备,可自动生成设备节点

misc device 是特殊字符设备,注册驱动程序时采用 misc_register 函数注册,此函数中会自动创建设备节点(即设备文件),无需 mknod 指令手动创建设备文件,杂项字符设备和一般字符设备的区别:

  1. 一般字符设备首先申请设备号,但是杂项字符设备的主设备号为 10 次设备号通过结构体 miscdevice 中的 minor 来设置
  2. 一般字符设备要创建设备文件,但是杂项字符设备在注册时会自动创建
  3. 一般字符设备要分配一个 cdev(字符设备),但是杂项字符设备只要创建 miscdevice 结构体即可
  4. 一般字符设备需要初始化 cdev,即给字符设备设置对应的操作函数集 file_operation,但是杂项字符设备在结构体 miscdevice 中定义
  5. 一般字符设备使用注册函数 cdev_add 而杂项字符设备使用 misc_register 来注册
struct miscdevice{
  int minor;                          // 杂项设备的此设备号(如果设置为 MISC_DYNAMIC_MINOR,表示系统自动分配未使用的 minor)
  const char *name;
  const stuct file_operations *fops;  // 驱动主题函数入口指针
  struct list_head list;
  struct device *parent;
  struct device *this device;
  const char *nodename;              // 在 /dev 目录下面创建的设备驱动节点
  mode_t mode;
};

常见的 Linux 设备列表

主设备号 次设备号 文件名 设备类型 说明
1 3 /dev/null char 空设备。任何写入都将被直接丢弃(但返回“成功”);任何读取都将得到 EOF (文件结束标志)
4 0 /dev/tty0 char 当前虚拟控制台
1 /dev/tty1 char 第 1 个虚拟控制台
8 0 /dev/sda block 第 1 个磁盘
16 /dev/sdb block 第 2 个磁盘
32 /dev/sdc block 第 3 个磁盘
10 1 /dev/psaux char PS/2 鼠标
156 /dev/lcd char 液晶(LCD)显示屏

Binder 也是设备

Binder 以杂项设备(misc device,是特殊的字符设备)进行注册,作为虚拟字符设备没有直接操作硬件,只是对设备内存的处理,Binder 驱动的主要方法有: