前言
源码版本android-11.0.0_r0.116
前言
本篇以aosp分支android-11.0.0_r25,kernel分支android-msm-wahoo-4.4-android11作为基础解析
1 binder驱动初始化
binder驱动的源码位于drivers/android目录下,我们从binder.c文件看起
1.1 binder_init
在Linux内核启动时,会调用binder_init这么一个函数,整个函数也是binder驱动初始化的入口函数
static int __init binder_init(void)
{
int ret;
char *device_name, *device_names, *device_tmp;
struct binder_device *device;
struct hlist_node *tmp;
//初始化binder内存回收
ret = binder_alloc_shrinker_init();
if (ret)
return ret;
...
//创建一个单线程工作队列,用于处理异步任务
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
//创建binder/proc目录
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
binder_debugfs_dir_entry_root);
//在binder目录下创建5个文件
if (binder_debugfs_dir_entry_root) {
debugfs_create_file("state",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_state_fops);
debugfs_create_file("stats",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_stats_fops);
debugfs_create_file("transactions",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_fops);
debugfs_create_file("transaction_log",
0444,
binder_debugfs_dir_entry_root,
&binder_transaction_log,
&binder_transaction_log_fops);
debugfs_create_file("failed_transaction_log",
0444,
binder_debugfs_dir_entry_root,
&binder_transaction_log_failed,
&binder_transaction_log_fops);
}
//"binder,hwbinder,vndbinder"
device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
if (!device_names) {
ret = -ENOMEM;
goto err_alloc_device_names_failed;
}
strcpy(device_names, binder_devices_param);
device_tmp = device_names;
//用binder,hwbinder,vndbinder分别调用init_binder_device函数
while ((device_name = strsep(&device_tmp, ","))) {
ret = init_binder_device(device_name);
if (ret)
goto err_init_binder_device_failed;
}
return ret;
err_init_binder_device_failed:
...
err_alloc_device_names_failed:
...
}
主要工作为:1,开启工作线程 2、初始化binder设备
我们将重点放在init_binder_device函数上
1.1.1 init_binder_device
static int __init init_binder_device(const char *name)
{
int ret;
struct binder_device *binder_device;
binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
if (!binder_device)
return -ENOMEM;
//binder注册虚拟字符设备所对应的file_operations
binder_device->miscdev.fops = &binder_fops;
//动态分配次设备号
binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
binder_device->miscdev.name = name;
binder_device->context.binder_context_mgr_uid = INVALID_UID;
binder_device->context.name = name;
//初始化互斥锁
mutex_init(&binder_device->context.context_mgr_node_lock);
//注册misc设备
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
kfree(binder_device);
return ret;
}
//将binder设备加入链表(头插法)
hlist_add_head(&binder_device->hlist, &binder_devices);
return ret;
}
先构造了一个结构体用来存放binder参数,然后通过misc_register函数,以misc设备进行注册binder,作为虚拟字符设备
1.1.2 misc设备的概念
我们先学习一下在Linux中如何注册一个misc设备
在Linux驱动中把无法归类的五花八门的设备定义为misc设备,Linux内核所提供的misc设备有很强的包容性,各种无法归结为标准字符设备的类型都可以定义为misc设备,譬如NVRAM,看门狗,实时时钟,字符LCD等
在Linux内核里把所有的misc设备组织在一起,构成了一个子系统(subsys),统一进行管理。在这个子系统里的所有miscdevice类型的设备共享一个主设备号MISC_MAJOR(10),但次设备号不同
在内核中用miscdevice结构体表示misc设备,具体的定义在include/linux/miscdevice.h中
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const struct attribute_group **groups;
const char *nodename;
umode_t mode;
};
我们自己注册misc设备时只需要填入前3项即可:
- minor:次设备号,如果填充MISC_DYNAMIC_MINOR,则由内核动态分配次设备号
- name:设备名
- fops:file_operations结构体,用于定义自己misc设备的文件操作函数,如果不填此项则会使用默认的misc_fops
file_operations结构体被定义在include/linux/fs.h中
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
unsigned (*mmap_capabilities)(struct file *);
#endif
};
file_operation是把系统调用和驱动程序关联起来的关键结构,这个结构的每一个成员都对应着一个系统调用,Linux系统调用通过读取file_operation中相应的函数指针,接着把控制权转交给函数,从而完成Linux设备驱动程序的工作
最后调用misc_register函数注册misc设备,函数原型如下:
//注册misc设备
//注册misc设备
extern int misc_register(struct miscdevice *misc);
//卸载misc设备
extern void misc_deregister(struct miscdevice *misc);
1.1.3 注册binder设备
了解了misc设备的注册,我们就可以看一下binder的注册过程了,代码中先构建了一个binder_device结构体,我们先观察一下这个结构体长什么样子
struct binder_device {
struct hlist_node hlist;
struct miscdevice miscdev;
struct binder_context context;
};
其中的hlist_node是链表中的一个节点,miscdevice就是上文所描述的注册misc所必要的结构体参数,binder_context用于保存binder上下文管理者的信息
回到代码中,首先给miscdevice赋了值,指定了file_operation,设置了minor动态分配次设备号,binder_context则是简单初始化了一下,然后便调用misc_register函数注册misc设备,最后将这个binder设备使用头插法加入到一个全局链表中
我们看一下它指定的file_operation
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
近期评论