一:初识Binder Binder的用户空间为每个进程维持着一个线程池,线程池处理接收的IPC和本进程的本地消息;Binder通信是同步的。 守护进程Service Manager管理系统的各个服务。Service Manager监听是否有程序向其发送请求,有则响应,无则监听等待。 每个服务须向Service Manager注册,请求服务的客户端创建IBinder 接口用于IPC。所以Binder 机制基于C/S架构。 IPC中handle是本地进程对象,即本地进程的地址,而RPC中handle是远程对象的引用,是一个32位抽象的句柄。对发送者而言,均认为被发送Binder对象的是远端对象的句柄,而远端进程接收到Binder对象后均认为是本地对象地址。Binder驱动负责两种不同名称对象的正确映射。
二: Binder 驱动的原理及实现 Binder采用AIDL(android interface description language)来描述进程间通信的接口。Binder作为一个特殊的字符设备,其设备节点/dev/binder。主要代码实现在: kernel/drivers/staging/binder.h kernel/drivers/staging/binder.c 其中 binder_ioctl: 与用户空间进行数据交互,参数cmd区分不同的请求,BINDER_WRITE_READ表示读写数据。 binder_thread_write: 为copy_to_user服务。 get_user从用户空间获取请求并发送 或者 返回用户空间进程产生的结果. binder_thread_write函数调用binder_transaction函数转发请求并返回结果,当收到请求时,binder_transcation函数通过对象handle找到对象所在进程。将请求放到目标进程的队列中,等待目标进程读取。数据的解析工作在binder_parse()中实现。 binder_thread_read: 为copy_from_user 服务。 put_user读取结果。
1) Binder_work struct binder_work { struct list_head entry; //双链表 存储binder_work队列 enum { //binder工作状态 BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, BINDER_WORK_CLEAR_DEATH_NOTIFICATION, } type;
};2)binder类型 #define B_PACK_CHARS(c1, c2, c3, c4)
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) #define B_TYPE_LARGE 0x85enum { //binder类型 //本地对象地址 BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '', B_TYPE_LARGE), BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '', B_TYPE_LARGE), //远程对象引用 BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '', B_TYPE_LARGE), BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '', B_TYPE_LARGE), //文件,找到fd对应的文件 BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), };
3) binder对象-------进程间传递的数据 struct flat_binder_object {
unsigned long type; //binder类型 unsigned long flags; //同步或异步union { void *binder; signed long handle; }; void *cookie;
};
enum transaction_flags { //flags TF_ONE_WAY = 0x01,
TF_ROOT_OBJECT = 0x04, TF_STATUS_CODE = 0x08, TF_ACCEPT_FDS = 0x10, };4) Binder对象传递的实际内容 struct binder_transaction_data {
union { size_t handle; void *ptr; } target; void *cookie; unsigned int code; unsigned int flags; pid_t sender_pid; uid_t sender_euid; size_t data_size; size_t offsets_size; union { struct { const void *buffer; const void *offsets; } ptr; //target->ptr对应对象的数据 uint8_t buf[8]; //target->handle对应对象的数据 } data;
};
- binder_write_read
struct binder_write_read { signed long write_size;
signed long write_consumed; unsigned long write_buffer; //请求线程执行的Binder命令signed long read_size; signed long read_consumed; unsigned long read_buffer; //线程执行后的返回结果
};
//BINDER_WRITE_READ读操作命令协议 enum BinderDriverReturnProtocol {
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), //翻译解析将要被处理的数据 BR_REPLY = _IOR('r', 3, struct binder_transaction_data), //对返回结果数据的操作命令 ……
};
//BINDER_WRITE_READ写操作命令协议 enum BinderDriverCommandProtocol { BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
……
};
6) Binder_thread 存储每一个单独线程的信息 struct binder_thread { struct binder_proc *proc; //属于哪一个进程 struct rb_node rb_node; int pid; int looper; //线程状态信息 struct binder_transaction *transaction_stack; //要发送和接收进程和线程的信息 struct list_head todo; uint32_t return_error;
uint32_t return_error2;wait_queue_head_t wait; struct binder_stats stats;
};
struct binder_stats { int br[_IOC_NR(BR_FAILED_REPLY) + 1]; //存储BINDER_WRITE_READ读操作协议 int bc[_IOC_NR(BC_DEAD_BINDER_DONE) + 1]; //存储BINDER_WRITE_READ写操作协议 int obj_created[BINDER_STAT_COUNT]; //对象计数 int obj_deleted[BINDER_STAT_COUNT]; };
enum {
BINDER_LOOPER_STATE_REGISTERED = 0x01, BINDER_LOOPER_STATE_ENTERED = 0x02, BINDER_LOOPER_STATE_EXITED = 0x04, BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, BINDER_LOOPER_STATE_NEED_RETURN = 0x20 };7) binder_transcation 用来中转请求和返回结果,保持接收和发送进程的信息。 struct binder_transaction { int debug_id; struct binder_work work; struct binder_thread *from; //接收进程信息 struct binder_transaction *from_parent; //进程父节点信息 struct binder_proc *to_proc; struct binder_thread *to_thread; //要发送的进程信息 struct binder_transaction *to_parent; unsigned need_reply:1;
struct binder_buffer *buffer; unsigned int code; unsigned int flags; long priority; long saved_priority; uid_t sender_euid; //Linux中包含用户ID(UID 进程由谁创建)和有效用户ID(EUID 发送进程对资源和文件的访问)
};
struct binder_buffer { struct list_head entry; struct rb_node rb_node;
unsigned free:1; unsigned allow_user_free:1; unsigned async_transaction:1; unsigned debug_id:29; struct binder_transaction *transaction; //中转请求和返回结果 struct binder_node *target_node; size_t data_size; size_t offsets_size; uint8_t data[0]; //存储实际数据
};
三:驱动分析。 一般从初始化开始分析 1) binder_init static int __init binder_init(void) { int ret;
binder_deferred_workqueue = create_singlethread_workqueue("binder"); //创建proc节点 if (!binder_deferred_workqueue) return -ENOMEM; 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); ret = misc_register(&binder_miscdev); //注册Misc设备,使用misc来命名主要是表示该文件目前还没归类好 if (binder_debugfs_dir_entry_root) { //创建各文件 debugfs_create_file("state", //proc/binder/state S_IRUGO, binder_debugfs_dir_entry_root, NULL, &binder_state_fops); debugfs_create_file("stats", //proc/binder/stats S_IRUGO, binder_debugfs_dir_entry_root, NULL, &binder_stats_fops); debugfs_create_file("transactions", //proc/binder/transactions S_IRUGO, binder_debugfs_dir_entry_root, NULL, &binder_transactions_fops); debugfs_create_file("transaction_log", //proc/binder/transaction_log S_IRUGO, binder_debugfs_dir_entry_root, &binder_transaction_log, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", //proc/binder/failed_transcation_log S_IRUGO, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, &binder_transaction_log_fops); } return ret;
} __init和__exit标记函数,__initdata和__exitdata标记数据。 此宏定义可知标记后的函数与数据其实是放到了特定的(代码或数据)段中。标记为初始化的函数,表明该函数供在初始化期间使用。在模块装载之后,模块装载就会将初始化函数扔掉。这样可以将该函数占用的内存释放出来。 __exit修饰词标记函数只在模块卸载时使用。如果模块被直接编进内核则该函数就不会被调用。如果内核编译时没有包含该模块,则此标记的函数将被简单地丢弃。 _init不属于c的标准在内核代码里,这个表示把这个函数放在.init.text section里,在include/linux/init.h里有定义 #define __init attribute ((section (".init.text"))) 这个section的空间是会被回收的,section是和连接有关的概念
binder_init由device_initcall调用,而不是传统的module_init和module_exit。这是因为使binder驱动直接编译进内核,不支持动态编译,同时需要在Kernel中做镜像。可以修改为module_init。 misc_register在init进程中 在handle_device_fd(device_fd)函数中调用handle_device_event(&uevent)函数执行uevent_netlink事件在/dev文件下创建binder文件
static struct miscdevice binder_miscdev = { //动态获得主设备号 .minor = MISC_DYNAMIC_MINOR, .name = "binder", //设备名 .fops = &binder_fops //file_oprations };
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, };
2) binder_open static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; //保存调用Binder的各个进程和线程的信息,进程线程ID,Binder状态等 binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", current->group_leader->pid, current->pid);
proc = kzalloc(sizeof(*proc), GFP_KERNEL); //kzalloc效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0. if (proc == NULL) return -ENOMEM; get_task_struct(current); //增加引用计数 proc->tsk = current; //保持引用计数 INIT_LIST_HEAD(&proc->todo); //初始化Binder_proc队列 init_waitqueue_head(&proc->wait); proc->default_priority = task_nice(current); mutex_lock(&binder_lock); binder_stats_created(BINDER_STAT_PROC); //增加BINDER_STAT_PROC hlist_add_head(&proc->proc_node, &binder_procs); //添加到HASH表 proc->pid = current->group_leader->pid; //保持pid,private_data等数据 INIT_LIST_HEAD(&proc->delivered_death); filp->private_data = proc; mutex_unlock(&binder_lock); if (binder_debugfs_dir_entry_proc) { //创建proc/binder/proc/$pid文件 char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, binder_debugfs_dir_entry_proc, proc, &binder_proc_fops); } return 0;
} 步骤: l 创建并分配一个binder_proc空间来保持binder数据。 l 增加当前进程/线程的引用计数,并保存到binder_proc的tsk。 l 初始化binder_proc队列,包括使用INIT_LIST_HEAD初始化链表头todo,使用init_waitqueue_head初始化等待序列wait,设置默认优先级为当前进程的nice值。 l 增加BINDER_STAT_PROC的对象计数,并通过hlist_add_head把创建的binder_proc对象添加到全局的binder_proc哈希表中,这样一来,任何进程都可以访问其他进程的binder_proc对象了。 l 将当前线程组的 pid赋值给proc的pid字段,即thread_group指向线程组中的第一个线程的task_struct结构,同时把创建的binder_proc对象指针赋值给flip的private_data对象。 l 创建文件/proc/binder/proc/$pid,用来输出当前binder proc对象的状态,文件名以pid命名。Pid不是当前进程/线程的id,而是线程组的pid,即线程组中第一个线程的pid。另外,创建该文件时,也指定了操作该文件的函数接口为binder_read_proc参数即创建的binder_proc对像proc。
3) binder_release static int binder_release(struct inode *nodp, struct file *filp) { struct binder_proc *proc = filp->private_data; //获取进程,线程的pid, 然后删除/proc/binder/proc/$pid文件 debugfs_remove(proc->debugfs_entry); binder_defer_work(proc, BINDER_DEFERRED_RELEASE); //释放binder_proc对象的数据和分配的空间
return 0;
}
4) binder_flush //关闭一个设备文件描述符复制到时候被调用 static int binder_flush(struct file *filp, fl_owner_t id) { struct binder_proc *proc = filp->private_data; binder_defer_work(proc, BINDER_DEFERRED_FLUSH);
return 0;
}
5) binder_poll //非阻塞型IO操作的内核驱动实现。当用户程序read数据时,如果驱动程序没有准备好数据,则阻塞该进程,直到数据准备好。称为阻塞型IO操作
static unsigned int binder_poll(struct file *filp, struct poll_table_struct *wait) { struct binder_proc *proc = filp->private_data; struct binder_thread *thread = NULL; int wait_for_proc_work;
mutex_lock(&binder_lock); thread = binder_get_thread(proc); //获取当前进程/线程信息 wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo) && thread->return_error == BR_OK; mutex_unlock(&binder_lock); if (wait_for_proc_work) { //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 { //thread_work工作方式 线程? if (binder_has_thread_work(thread)) return POLLIN; poll_wait(filp, &thread->wait, wait); if (binder_has_thread_work(thread)) return POLLIN; } return 0;
}
static int binder_has_proc_work(struct binder_proc *proc, struct binder_thread *thread) { return !list_empty(&proc->todo) || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); }
static int binder_has_thread_work(struct binder_thread *thread) { return !list_empty(&thread->todo) || thread->return_error != BR_OK || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); } 根据检测线程队列是否为空,线程循环状态信息和返回信息确定等待方式,然后调用wait_poll实现poll操作。
static struct binder_thread *binder_get_thread(struct binder_proc *proc) { struct binder_thread *thread = NULL; struct rb_node *parent = NULL; struct rb_node **p = &proc->threads.rb_node; //取得队列中的线程
while (*p) { parent = *p; thread = rb_entry(parent, struct binder_thread, rb_node); //取得将要比较的线程 if (current->pid < thread->pid) p = &(*p)->rb_left; else if (current->pid > thread->pid) p = &(*p)->rb_right; else break; } if (*p == NULL) { //如果不存在 thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (thread == NULL) return NULL; binder_stats_created(BINDER_STAT_THREAD); thread->proc = proc; thread->pid = current->pid; init_waitqueue_head(&thread->wait); //初始化等待队列 INIT_LIST_HEAD(&thread->todo); //初始化链表表头 rb_link_node(&thread->rb_node, parent, p); rb_insert_color(&thread->rb_node, &proc->threads); thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; //设置线程循环状态 thread->return_error = BR_OK; thread->return_error2 = BR_OK; } return thread;
}
6) binder_mmap mmap把设备内存(内核空间)映射到用户空间,从而用户程序可以在用户空间操作内核空间的地址; binder_mmap能映射的最大内存空间为4M,而且不能映射具有写权限的内存区域; binder_mmap现在内核虚拟映射表上获取一块可以使用的区域,然后分配物理页,再把物理页映射到虚拟映射表上; 由于设备内存的映射在mmap中实现,因此每个进程/线程都只能执行一次映射操作。
static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; struct vm_struct *area; struct binder_proc *proc = filp->private_data; const char *failure_string; struct binder_buffer *buffer;
if ((vma->vm_end - vma->vm_start) > SZ_4M) //检测映射内存大小 vma->vm_end = vma->vm_start + SZ_4M; binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", 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) { //检测flags ret = -EPERM; failure_string = "bad vm_flags"; goto err_bad_arg; } vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; if (proc->buffer) { //判断是否已经mmap过 ret = -EBUSY; failure_string = "already mapped"; goto err_already_mapped; } area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); //申请虚拟空间 if (area == NULL) { ret = -ENOMEM; failure_string = "get_vm_area"; goto err_get_vm_area_failed; } proc->buffer = area->addr; proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
#ifdef CONFIG_CPU_CACHE_VIPT if (cache_is_vipt_aliasing()) { while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); vma->vm_start += PAGE_SIZE; } } #endif proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); //分配pages空间 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;
vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc;
//真正开始分配物理空间 if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) { ret = -ENOMEM; failure_string = "alloc small buf"; goto err_alloc_small_buf_failed; } 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; barrier(); proc->files = get_files_struct(current); proc->vma = vma;
return 0;
err_alloc_small_buf_failed: kfree(proc->pages); proc->pages = NULL; err_alloc_pages_failed: vfree(proc->buffer); proc->buffer = NULL; err_get_vm_area_failed: err_already_mapped: err_bad_arg: printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; }
binder_update_page_range函数执行步骤: 1:alloc_page 分配页面 2:map_vm_area 为分配的内存做映射关系 3:vm_insert_page 把分配的物理页插入到用户VMA区域 总结binder_mmap顺序 1:检测内存映射条件,即映射内存大小(4MB),flags,是否已经映射过; 2:获取地址空间,并把此空间的地址记录到进程信息buffer中; 3:分配物理页面并记录下来; 4:将buffer插入到进程信息的buffer列表中; 5:调用buffer_update_page_range函数将分配的物理页面和vm空间对应起来; 6:通过binder_insert_free_buffer函数把此进程的buffer插入到进程信息中。
7) binder_ioctl binder的ioctl命令主要有七个: #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) //读写操作 #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t) #define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t) #define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int) #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int) #define BINDER_THREAD_EXIT _IOW('b', 8, int) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) BINDER_SET_IDLE_PRIORITY 被service_manager用于设置自己作为context manager,所有为0的handle均被指向这个master节点。 用户程序只是将它想要做到命令传递给驱动,而驱动就是将事情完成,用户程序不需要知道如何做的这件事。 Linxu中为保证用户程序与具体设备驱动中的命令一一对应,定义了命令码的结构 这样一个命令码就转变成一个整数形式的命令码。但不直观。IOW的宏定义可以在 Ioctl.h (c:\users\lw\desktop\myandroid2.3\myandroid2.3\kernel_imx\include\asm-generic)中找到 (1) BINDER_VERSION case BINDER_VERSION: if (size != sizeof(struct binder_version)) { ret = -EINVAL; goto err; } if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) { ret = -EINVAL; goto err; } (2)BINDER_SET_MAX_THREADS case BINDER_SET_MAX_THREADS: if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { ret = -EINVAL; goto err; } (3)BINDER_THREAD_EXIT case BINDER_THREAD_EXIT: binder_debug(BINDER_DEBUG_THREADS, "binder: %d:%d exit\n", proc->pid, thread->pid); binder_free_thread(proc, thread); thread = NULL; (4)BINDER_SET_CONTEXT_MGR 若一个进程/线程能被成功设置成binder_context_mgr_node对象,称该进程/线程为Context Manager.即设置驱动中的全局变量binder_context_mgr_uid为当前进程的uid.并初始化一个Binder_node并赋值给全局变量binder_context_mgr_node。 只有创建binder_context_mgr_node对象的Binder上下文管理进程/线程才有权限重新设置这个对象。 case BINDER_SET_CONTEXT_MGR: if (binder_context_mgr_node != NULL) { printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; goto err; } if (binder_context_mgr_uid != -1) { //检测当前进程是否有操作该命令的权限 if (binder_context_mgr_uid != current->cred->euid) { printk(KERN_ERR "binder: BINDER_SET" "CONTEXT_MGR bad uid %d != %d\n", current->cred->euid, binder_context_mgr_uid); ret = -EPERM; goto err; } } else //取得进程权限 创建binder_node节点 binder_context_mgr_uid = current->cred->euid; binder_context_mgr_node = binder_new_node(proc, NULL, NULL); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; } //初始化binder_node节点数据 binder_context_mgr_node->local_weak_refs++; binder_context_mgr_node->local_strong_refs++; binder_context_mgr_node->has_strong_ref = 1; binder_context_mgr_node->has_weak_ref = 1;
static struct binder_node *binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; struct binder_node *node;
while (*p) { //查找第一个叶节点 parent = *p; node = rb_entry(parent, struct binder_node, rb_node); if (ptr < node->ptr) p = &(*p)->rb_left; else if (ptr > node->ptr) p = &(*p)->rb_right; else return NULL; }
//创建binder_node节点 node = kzalloc(sizeof(*node), GFP_KERNEL); if (node == NULL) return NULL; binder_stats_created(BINDER_STAT_NODE); rb_link_node(&node->rb_node, parent, p); //插入节点 rb_insert_color(&node->rb_node, &proc->nodes); node->debug_id = ++binder_last_id; //初始化数据 node->proc = proc; node->ptr = ptr; node->cookie = cookie; node->work.type = BINDER_WORK_NODE; INIT_LIST_HEAD(&node->work.entry); //初始化链表头 INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "binder: %d:%d node %d u%p c%p created\n", proc->pid, current->pid, node->debug_id, node->ptr, node->cookie); return node; } Binder_proc的成员node是binder_node的根节点,这是一颗红黑树,该函数首先根据规则找到第一个叶节点作为新插入的节点的父节点,然后创建binder_node节点并插入。 (5) BINDER_WRITE_READ case BINDER_WRITE_READ: { struct binder_write_read bwr; if (size != sizeof(struct binder_write_read)) { //判断数据完整性 ret = -EINVAL; goto err; } if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { //从用户空间复制数据到binder_write_read中 ret = -EFAULT; goto err; } binder_debug(BINDER_DEBUG_READ_WRITE, "binder: %d:%d write %ld at lx, read %ld at lx\n", proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);
if (bwr.write_size > 0) { //执行写操作 ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); if (ret < 0) { bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto err; } } if (bwr.read_size > 0) { //执行读操作 ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); if (ret < 0) { if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto err; } } binder_debug(BINDER_DEBUG_READ_WRITE, "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n", proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { //将数据复制到用户空间 ret = -EFAULT; goto err; } break; }
static int binder_free_thread(struct binder_proc *proc, struct binder_thread *thread) { struct binder_transaction *t; struct binder_transaction *send_reply = NULL; int active_transactions = 0;
rb_erase(&thread->rb_node, &proc->threads); //将当前线程从红杉树上删除 t = thread->transaction_stack; //取得binder_transaction数据 if (t && t->to_thread == thread) //判断要释放的是否是“回复”进程 send_reply = t; while (t) { //释放所有的binder_transaction active_transactions++; binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "binder: release %d:%d transaction %d " "%s, still active\n", proc->pid, thread->pid, t->debug_id, (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { t->to_proc = NULL; t->to_thread = NULL; if (t->buffer) { t->buffer->transaction = NULL; t->buffer = NULL; } t = t->to_parent; } else if (t->from == thread) { t->from = NULL; t = t->from_parent; } else BUG(); } if (send_reply) //需要发送失败回复 binder_send_failed_reply(send_reply, BR_DEAD_REPLY); binder_release_work(&thread->todo); //释放binder_work kfree(thread); //释放binder_thread binder_stats_deleted(BINDER_STAT_THREAD); //改变binder状态 return active_transactions;
}
static void binder_release_work(struct list_head *list) { struct binder_work *w; while (!list_empty(list)) { w = list_first_entry(list, struct binder_work, entry); list_del_init(&w->entry); switch (w->type) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t;
t = container_of(w, struct binder_transaction, work); if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) binder_send_failed_reply(t, BR_DEAD_REPLY); } break; case BINDER_WORK_TRANSACTION_COMPLETE: { kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; default: break; } }
}