Binder 驱动流程:
Binder设备是基于linux的设备驱动模型,binder是一个misc设备。下面来看看具体misc设备的流程:
和binder驱动相关的文件路径:
kernel/drivers/staging/android/binder.c
kernel/drivers/staging/android/binder.h
device_initcall(binder_init);//在系统启动的时候加载,下面看看加载的时候做了哪些操作。
static int __init binder_init(void)
{
.......
binder_deferred_workqueue = create_singlethread_workqueue("binder");
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
ret = misc_register(&binder_miscdev);
binder_deferred_task=kthread_run(binder_deferred_thread,NULL,"binder_deferred_thread");
.......
}
1)创建一个单线程工作队列,binder来处理一些可以稍后执行的工作
2)创建一个bind/proc binder目录,以及其属性操作。
3)注册一个misc设备,主设备号为10,次设备号动态生成
其次就是binder_fops操作函数,主要就是对他的填充。一个个分析下这些函数是怎么实现的。
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
首先,分析binder_open函数
proc = kzalloc(sizeof(*proc), GFP_KERNEL);//分配binder proc记录空间
get_task_struct(current);//增加当前引用计数
proc->tsk = current;// 记录当前进程的地址
INIT_LIST_HEAD(&proc->todo);//初始化链表头进程全局todo任务链表
init_waitqueue_head(&proc->wait);//初始化等待队列头
proc->default_priority = task_nice(current);//获取当前进程优先级
//添加binder_proc 哈希表 将创建的binder proc 赋值给全局的binder_proc
hlist_add_head(&proc->proc_node, &binder_procs);
proc->pid = current->group_leader->pid;//保存pid和私有数据
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
mutex_unlock(&binder_lock);
分析binder_release函数
获得当前进程/线程的pid
调用remove_proc_entry()删除pid命名的只读文件。
调用binder_defer_work()释放binder_proc对象;此处使用workqueue来提高系统性能。
分析binder_mmap函数
//binder 设备最大能映射4M 内存
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
// binder 不能映射具有写权限的内存块
if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
ret = -EPERM;
failure_string = "bad vm_flags";
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
//判断是否已经mmap过了
//申请虚拟内存
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
//赋值地址和偏移量
proc->buffer = area->addr;
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
//分配page空间
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
if (proc->pages == NULL) {
ret = -ENOMEM;
failure_string = "alloc page array";
goto err_alloc_pages_failed;
}
proc->buffer_size = vma->vm_end - vma->vm_start;
//binder 内存操作函数
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
//分配物理内存
buffer = proc->buffer;
INIT_LIST_HEAD(&proc->buffers);
list_add(&buffer->entry, &proc->buffers);
buffer->free = 1;
binder_insert_free_buffer(proc, buffer);
proc->free_async_space = proc->buffer_size / 2;
proc->files = get_files_struct(current);
proc->vma = vma;
分析binder_poll函数
binder_get_thread(proc)获得当前进程信息。
如果是进程,调用proc_work();如果是线程,调用thread_work()
调用binder_has_x_work检测,来判断所要采用的等待方式
队列是否为空;
线程/进程的循环状态;
返回信息;
调用poll_wait实现poll操作。
thread = binder_get_thread(proc);//获取binder proc 中的线程信息
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo) && thread->return_error == BR_OK;//proc 状态
//判断到底是proc work 还是 thread work
if (wait_for_proc_work) {
if (binder_has_proc_work(proc, thread))
return POLLIN;
poll_wait(filp, &proc->wait, wait);
if (binder_has_proc_work(proc, thread))
return POLLIN;
} else {
if (binder_has_thread_work(thread))
return POLLIN;
poll_wait(filp, &thread->wait, wait);
if (binder_has_thread_work(thread))
return POLLIN;
}
return 0;
}
分析最主要的函数指针binder_ioctl
Ioctl是linux内核中最常用的,也是号称万能函数的一个,很多的linux子系统都用ioctl实现的功能
unsigned int size = _IOC_SIZE(cmd);//提取cmd命令
thread = binder_get_thread(proc);//获取此线程信息
总体关系图
Cmd:
BINDER_WRITE_READ
//读写函数里面有很多操作,后续再说
binder_thread_write
binder_thread_read 两个函数进行主要操作
BINDER_SET_MAX_THREADS
//设置最大线程
BINDER_SET_CONTEXT_MGR
//设置为守护进程service manage
BINDER_THREAD_EXIT
//设置线程退出
BINDER_VERSION
//设置binder版本
BinderDriverCommandProtocol:写操作命令协议
BinderDriverR eturnProtocol:读操作命令协议