1. Binder驱动初探

任务说明

本案例要求编写一个Linux内核模块,模拟Binder驱动的注册流程:向内核注册一个miscdevice(杂项设备),实现其open回调函数,并在模块加载后验证设备节点 /dev/binder 是否成功创建。该模块是Binder IPC机制在内核侧的入口基础,后续案例将在此基础上扩展mmap、ioctl等核心操作。

环境与依赖

  • Linux内核源码树(需已配置并编译,或至少具备编译模块所需的头文件与生成文件)
  • 内核版本建议 4.x 或 5.x(本案例代码基于通用miscdevice接口,兼容性良好)
  • 具备root权限(用于加载/卸载模块及检查设备节点)

完整代码

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>

#define BINDER_DEV_NAME "binder"

static int binder_open(struct inode *inode, struct file *filp)
{
    /* 在真实Binder驱动中,此处会为每个打开者分配binder_proc结构。
       本案例仅验证设备节点创建与open回调被正确注册。 */
    pr_info("binder: device opened\n");
    return 0;
}

static const struct file_operations binder_fops = {
    .owner = THIS_MODULE,
    .open = binder_open,
};

static struct miscdevice binder_miscdev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = BINDER_DEV_NAME,
    .fops = &binder_fops,
};

static int __init binder_init(void)
{
    int ret;

    ret = misc_register(&binder_miscdev);
    if (ret) {
        pr_err("binder: failed to register misc device, ret=%d\n", ret);
        return ret;
    }
    pr_info("binder: misc device registered, minor=%d\n", binder_miscdev.minor);
    return 0;
}

static void __exit binder_exit(void)
{
    misc_deregister(&binder_miscdev);
    pr_info("binder: misc device deregistered\n");
}

module_init(binder_init);
module_exit(binder_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Binder driver registration demo");
MODULE_AUTHOR("Kernel IPC Course");

编译与加载

  1. 将上述代码保存为 binder_demo.c,并在同目录创建 Makefile:
obj-m += binder_demo.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean
  1. 执行 make 编译模块,生成 binder_demo.ko。
  2. 加载模块:sudo insmod binder_demo.ko
  3. 卸载模块:sudo rmmod binder_demo

验证方法

按以下步骤确认模块工作正常,满足全部条件即判定通过:

  • 设备节点创建:执行 ls -l /dev/binder,应看到主设备号10(miscdevice主设备号固定为10),次设备号为动态分配值。
  • open回调生效:执行 cat /dev/binder 或 exec 3</dev/binder 打开设备,然后执行 dmesg | tail,应看到内核日志输出 binder: device opened。
  • 卸载清理:执行 sudo rmmod binder_demo 后再次执行 ls /dev/binder,应提示文件不存在,说明设备节点已正确移除。

预期输出

加载模块后,dmesg 尾部应出现类似以下日志(次设备号可能不同):

binder: misc device registered, minor=58

打开设备后,dmesg 新增一行:

binder: device opened

常见问题

  • 编译报错找不到头文件:确认内核头文件已安装(Ubuntu执行 sudo apt install linux-headers-$(uname -r))。
  • insmod失败提示Operation not permitted:确认使用root权限,且内核未禁用模块加载(如Secure Boot限制)。
  • 设备节点已存在:若系统已有其他Binder驱动占用该名称,可先卸载或改用其他设备名(如 binder_demo)测试。
Binder驱动注册与设备节点创建流程 用户空间 insmod / rmmod / cat /dev/binder 系统调用接口 (syscall) open() / close() / ioctl() 内核空间 misc_register() 动态分配次设备号 /dev/binder 主设备号10 file_operations .open = binder_open 验证:ls -l /dev/binder → 存在且主设备号=10;cat /dev/binder → dmesg出现"device opened" 模块加载时注册miscdevice → 自动创建设备节点 → open回调绑定到file_operations