Binder系列1-Binder Driver

Posted xhBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Binder系列1-Binder Driver相关的知识,希望对你有一定的参考价值。

Binder系列1-Binder Driver

1. android采用Binder

  1. Linux Kernel是开源系统,所开放源代码许可协议GPL保护,Binder Driver运行在Linux Kernel是GPL协议。用户空间采用Apache-2.0协议,内核空间与用户空间(即在GPL协议与Apache-2.0协议)之间的Lib库中采用BSD证授权方法,GPL协议限定在Linux Kernel,有效隔断了GPL的传染性,仍有较大争议。开源与商业化共存的一个成功典范。

  2. Binder 是基于开源的OpenBinder实现的,而OpenBinder的作者在Google工作,直接采用 Binder 作为核心的IPC机制。

2. Binder Driver实现

Binder驱动是一个misc device,是虚拟字符设备,主设备号是10,其设备节点是/dev/binder(该节点并不对应真实的硬件设备)。misc类型驱动只需要调用misc_deregister
主要是驱动设备的初始化(binder_init),打开 (binder_open),映射(binder_mmap),数据操作(binder_ioctl)。

linux/drivers/android/binder.c
linux/include/uapi/linux/android/binder.h

  • binder_init:初始化虚拟字符设备,init_binder_device()\\init_binderfs()
  • binder_open:打开Binder驱动设备, binder_procs_lock同步锁;
  • binder_mmap:申请内存空间, binder_alloc_mmap_lock同步锁;
  • binder_ioctl:执行相应的ioctl操作, binder_procs_lock同步锁;当处于binder_thread_read过程,read_buffer无数据则释放同步锁。

2.1 binder_init 注册misc设备节点/dev/binder

  • binder_init() -> init_binder_device(device_name) -> misc_register(&binder_device->miscdev) 注册misc设备节点
  • CONFIG_ANDROID_BINDERFSbinder_devices_param = CONFIG_ANDROID_BINDER_DEVICESkernel/configs/xxx/android-base.config配置
  • binder_fops Binder驱动支持的文件操作,其中使用做多的binder_ioctl \\ binder_mmap \\ binder_open
  • init_binderfs() 注册register_filesystem(&binder_fs_type)(linux/drivers/android/binderfs.c)
const struct file_operations binder_fops = 
	.owner = THIS_MODULE,
	.poll = binder_poll,
	.unlocked_ioctl = binder_ioctl,
	.compat_ioctl = compat_ptr_ioctl,
	.mmap = binder_mmap,
	.open = binder_open,
	.flush = binder_flush,
	.release = binder_release,
;

static int __init init_binder_device(const char *name)

	// ... ...
	binder_device->miscdev.fops = &binder_fops;
	binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
	binder_device->miscdev.name = name;
	// ... ...
	ret = misc_register(&binder_device->miscdev);
	// ... ...


static int __init binder_init(void)

	// ... ...
	if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) &&
	    strcmp(binder_devices_param, "") != 0) 
		/*
		* Copy the module_parameter string, because we don't want to
		* tokenize it in-place.
		 */
		device_names = kstrdup(binder_devices_param, GFP_KERNEL);
		if (!device_names) 
			ret = -ENOMEM;
			goto err_alloc_device_names_failed;
		

		device_tmp = device_names;
		while ((device_name = strsep(&device_tmp, ","))) 
			ret = init_binder_device(device_name);
			if (ret)
				goto err_init_binder_device_failed;
		
	

	ret = init_binderfs();
	if (ret)
		goto err_init_binder_device_failed;

	return ret;

err_init_binder_device_failed:
	// ... ...
err_alloc_device_names_failed:
	// ... ...


device_initcall(binder_init);

2.2 binder_open 打开Binder驱动设备

  • binder_proc binder进程,每个进程都有独立的记录;proc->todo todo链表
  • binder_stats_created(BINDER_STAT_PROC) BINDER_PROC对象创建数加1,binder_stats是binder中统计数据载体
  • filp->private_data = proc 把binder_proc对象保存到文件指针filp
  • hlist_add_head(&proc->proc_node, &binder_procs) 把binder_proc加入到全局链表binder_procs
static int binder_open(struct inode *nodp, struct file *filp)

	struct binder_proc *proc, *itr;
	struct binder_device *binder_dev;
	struct binderfs_info *info;
	struct dentry *binder_binderfs_dir_entry_proc = NULL;
	// ... ...
	proc = kzalloc(sizeof(*proc), GFP_KERNEL);
	// ... ...
	INIT_LIST_HEAD(&proc->todo);
	init_waitqueue_head(&proc->freeze_wait);
	proc->default_priority = task_nice(current);
	// ... ...
	binder_stats_created(BINDER_STAT_PROC);
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	INIT_LIST_HEAD(&proc->waiting_threads);
	filp->private_data = proc;

	mutex_lock(&binder_procs_lock);
	hlist_for_each_entry(itr, &binder_procs, proc_node) 
		if (itr->pid == proc->pid) 
			existing_pid = true;
			break;
		
	
	hlist_add_head(&proc->proc_node, &binder_procs);
	mutex_unlock(&binder_procs_lock);
	// ... ...

2.3 binder_mmap 申请内存空间

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)

	struct binder_proc *proc = filp->private_data;

	if (proc->tsk != current->group_leader)
		return -EINVAL;

	binder_debug(BINDER_DEBUG_OPEN_CLOSE,
		     "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\\n",
		     __func__, proc->pid, vma->vm_start, vma->vm_end,
		     (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
		     (unsigned long)pgprot_val(vma->vm_page_prot));

	if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) 
		pr_err("%s: %d %lx-%lx %s failed %d\\n", __func__,
		       proc->pid, vma->vm_start, vma->vm_end, "bad vm_flags", -EPERM);
		return -EPERM;
	
	vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
	vma->vm_flags &= ~VM_MAYWRITE;

	vma->vm_ops = &binder_vm_ops;
	vma->vm_private_data = proc;

	return binder_alloc_mmap_handler(&proc->alloc, vma);

2.4 binder_ioctl 执行相应的ioctl操作

  • binder_ioctl 函数负责在两个进程间收发IPC数据和IPC reply数据处理
  • 核心方法binder_ioctl_write_read() -> binder_thread_write()\\binder_thread_read()
    1. binder_thread_write() :get_user(cmd, (uint32_t __user *)ptr) 获取IPC数据BC请求码
    2. binder_thread_read():根据w->type(即binder_work->type)响应相应处理。
ioctl命令cmd说明
BINDER_WRITE_READ收发Binder IPC数据
BINDER_SET_MAX_THREADS设置Binder线程最大个数
BINDER_SET_CONTEXT_MGR设置Service Manager节点
BINDER_SET_CONTEXT_MGR_EXT
BINDER_THREAD_EXIT释放Binder线程
BINDER_VERSION获取Binder版本信息
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

	int ret;
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	// ... ...
	trace_binder_ioctl(cmd, arg);
	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
	// ... ...
	thread = binder_get_thread(proc);
	// ... ...
	switch (cmd) 
	case BINDER_WRITE_READ:
		ret = binder_ioctl_write_read(filp, cmd, arg, thread);
		if (ret)
			goto err;
		break;
	case BINDER_SET_MAX_THREADS://......
	case BINDER_SET_CONTEXT_MGR_EXT://......
	case BINDER_SET_CONTEXT_MGR://......
	case BINDER_THREAD_EXIT://......
	case BINDER_VERSION://......
	case BINDER_GET_NODE_INFO_FOR_REF://......
	case BINDER_GET_NODE_DEBUG_INFO://......
	case BINDER_FREEZE://......
	case BINDER_GET_FROZEN_INFO://......
	case BINDER_ENABLE_ONEWAY_SPAM_DETECTION://......
	case BINDER_GET_EXTENDED_ERROR://......
	default:
		ret = -EINVAL;
		goto err;
	
	// ... ...
	if (thread)
		thread->looper_need_return = false;
	wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
	// ... ...

3. Binder通信模型

Binder是基于C/S架构的,简单解释下C/S架构,是指客户端(Client)和服务端(Server)组成的架构,Client端有什么需求,直接发送给Server端去完成。Android系统中对外只暴露Client端,Client端将任务发送给Server端。

以上是关于Binder系列1-Binder Driver的主要内容,如果未能解决你的问题,请参考以下文章

Binder 域

Binder 系列总结

Binder系列2—Binder Driver再探 - Gityuan博客

Android 跨进程通信-Binder机制传输数据限制—罪魁祸首Binder线程池

[Android5.1]Binder机制学习---Binder框架

Android面试Android跨进程通信之Binder