Binder是Android中使用最为广泛的IPC框架,从实现的角度可以分为内核层和用户空间层,本文主要分析下Binder Driver在内核层的实现。
Binder Driver初始化
|
1 2 3 |
// 驱动注册入口 device_initcall(binder_init);
|
我们看下binder_init
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
static int __init binder_init(void) { int ret; // 在目标设备上创建一个/proc/binder/proc的目录 // 每一个使用了Binder进程间通信机制的进程在该目录下都对应有一个文件,这些文件以进程ID来命名,通过它们 // 可以读取到各个进程的Binder线程池、Binder实体对象、Binder引用对象以及内核缓冲区等信息 binder_proc_dir_entry_root = proc_mkdir("binder", NULL); if (binder_proc_dir_entry_root) binder_proc_dir_entry_proc = proc_mkdir("proc", binder_proc_dir_entry_root); // 创建一个Binder设备 // 创建一个misc类型的字符设备 ret = misc_register(&binder_miscdev); // 创建/proc/binder目录下创建五个文件 // 读取这五个文件可以读取Binder驱动程序的运行状况 // 例如,BC,BR的请求次数、日志记录信息、正在执行进程间通信过程的进程信息等等 if (binder_proc_dir_entry_root) { create_proc_read_entry("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL); create_proc_read_entry("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL); create_proc_read_entry("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL); create_proc_read_entry("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log); create_proc_read_entry("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_failed); } return ret; }
|
misc_register方法向kernel注册了一个Misc设备,即虚拟设备节点,注册以后,binder driver就会成为内核驱动,我们应用层的系统调用如read, write, mmap系统调用,都会转到这个binder driver中进行。
具体的注册过程是根据binder_miscdev结构体进行的
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// 设备文件的操作方法列表 static struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, // IO控制函数 .unlocked_ioctl = binder_ioctl, // 内存映射 .mmap = binder_mmap, // 打开 .open = binder_open, .flush = binder_flush, .release = binder_release, };
static struct miscdevice binder_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = "binder", .fops = &binder_fops };
|
可以看出,主要还是提供了open,mmap,flush等系统调用。
我们接下来会逐一分析。
binder_open分析
binder_open是映射的open函数,我们看下上层是什么时候调用open()的。
Binder Service端在初始化的时候,会创键一个ProcessState对象,这个是进程内的单例。
|
1 2 |
sp<ProcessState> proc = ProcessState::self();
|
self的过程就是去获取一个进程内的单例。
|
1 2 3 4 5 6 7 8 9 10 |
sp<ProcessState> ProcessState::self() { Mutex::Autolock _l(gProcessMutex); if (gProcess != NULL) { return gProcess; } gProcess = new ProcessState("/dev/binder"); return gProcess; }
|
看下构造过程
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
ProcessState::ProcessState(const char *driver) : mDriverName(String8(driver)) , mDriverFD(open_driver(driver)) , mVMStart(MAP_FAILED) , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) , mExecutingThreadsCount(0) , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mStarvationStartTimeMs(0) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { if (mDriverFD >= 0) { // mmap the binder, providing a chunk of virtual address space to receive transactions. mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { // *sigh* ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); close(mDriverFD); mDriverFD = -1; mDriverName.clear(); } }
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating."); }
|
可以看到,在构造器中有open_driver()这个调用,作用就是打开binder_driver。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
static int open_driver(const char *driver) { // 打开 /dev/binder节点 int fd = open(driver, O_RDWR | O_CLOEXEC); if (fd >= 0) { int vers = 0; // 获取binder 版本信息 status_t result = ioctl(fd, BINDER_VERSION, &vers); if (result == -1) { ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); close(fd); fd = -1; } // 比较binder kernel层协议版本和用户层协议版本是否一致,如果不一致,直接关闭 if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) { ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d", vers, BINDER_CURRENT_PROTOCOL_VERSION, result); close(fd); fd = -1; } // 设置当前进程最多可同时进行的binder调用次数,这个值默认是15 size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } } else { ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno)); } return fd; }
|
我们看到,ProcessState使用open_driver打开了binder设备,并且执行了比较binder驱动版本,设置最大线程个数的操作。
用户空间的open()会直接调用到kernel的binder_open()上去。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc;
if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid);
// 为进程创建一个binder_proc结构体 // 进行初始化 proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; get_task_struct(current); // 任务控制块 proc->tsk = current; INIT_LIST_HEAD(&proc->todo); init_waitqueue_head(&proc->wait); // 进程优先级 proc->default_priority = task_nice(current); mutex_lock(&binder_lock); binder_stats.obj_created[BINDER_STAT_PROC]++; // 将结构体proc加入到全局hash队列binder_procs中 // 驱动将所有打开了设备文件/dev/binder的进程都加入到全局hash队列binder_procs中 // 通过这个hash队列可以知道系统当前有多少个进程在使用Binder进程间通信机制 hlist_add_head(&proc->proc_node, &binder_procs); // 进程组ID proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); // 将初始化完成之后的binder_proc结构体proc保存在参数filp成员变量的private_data中 // 参数filp指向一个打开文件结构体 // 当进程调用函数open打开设备文件/dev/binder之后,内核就会返回一个文件描述符给进程 // 这个文件描述符与参数filp所指向的打开文件结构体是关联在一起的 // 当进程后面以这个文件描述符为参数调用函数mmap或者ioctl来与binder驱动交互时 // 内核就会将与该文件描述符相关联的打开文件结构体传递给Binder驱动程序 // 这时驱动可以通过它的成员变量private_data来获得前面在函数binder_open中为进程创建的binder_proc结构体proc filp->private_data = proc; mutex_unlock(&binder_lock);
// 创建一个以进程ID为名称的只读文件 // 以函数binder_read_proc_proc作为它的文件内容读取函数 // 通过读取文件/proc/binder/proc/<PID>的内容,可以获取该进程的Binder线程池、实体对象、引用对象、内核缓冲区等信息 if (binder_proc_dir_entry_proc) { char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); remove_proc_entry(strbuf, binder_proc_dir_entry_proc); create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc); }
return 0; }
|
binder_open函数的主要逻辑是创建一个binder_proc结构体,并将binder_proc结构体放在binder driver的全局链表中和flip的private_data中。
binder_proc结构
binder_proc用来描述一个正在使用Binder的进程,如果该进程需要使用Binder进行通信,那么在开始使用前,系统会为该线程创建binder_proc实例。 定义如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
// 描述一个正在使用Binder的进程 // 当一个进程调用函数open来打开设备文件/dev/binder时,Binder驱动程序就会为它创建一个binder_proc结构体 // 并且保存在一个全局的hash列表中 // [打开了设备文件/dev/binder之后,需要调用函数mmap将它映射到进程的地址空间 // 实际上是请求Binder驱动程序为它分配一块内核缓冲区,以便可以用来在进程间传输数据] struct binder_proc { // 全局hash列表中的一个节点 struct hlist_node proc_node; // 是一个红黑树的根节点 // 它以线程ID作为关键字来组织一个进程的Binder线程池 // 进程可以调用函数ioctl将一个线程注册到Binder驱动程序中,同时,当进程没有足够的空闲 // 线程在处理进程间通信请求时,Binder驱动程序也可以主动要求进程注册更多的线程到Binder线程池中 struct rb_root threads; // 一个进程内部包含了一系列的Binder实体对象和Binder引用对象 // 进程使用三个红黑树来组织它们 // nodes变量描述的是用来组织Binder实体对象,以ptr作为关键字 struct rb_root nodes; // refs_by_desc是用来组织Binder引用对象的,以desc作为关键字 struct rb_root refs_by_desc; // refs_by_desc是用来组织Binder引用对象的,以node作为关键字 struct rb_root refs_by_node; // 进程组ID int pid; // 用户空间地址是在应用程序进程内部使用的,保存在vma struct vm_area_struct *vma; // 任务控制块 struct task_struct *tsk; // 打开文件结构体数组 struct files_struct *files; // 一个hash列表,用来保存进程可以延迟执行的工作项 // 3中类型: // enum { // BINDER_DEFERRED_PUT_FILES = 0x01, // BINDER_DEFERRED_FLUSH = 0x02, // BINDER_DEFERRED_RELEASE = 0x04, // }; struct hlist_node deferred_work_node; int deferred_work; // 内核缓冲区有两个地址 // 其中一个是内核空间地址,另一个是用户空间地址 // 内核空间地址在Binder驱动内部使用,保存在buffer // [这两个地址指的都是虚拟地址] // buffer指向的是一块大的内核缓冲区,Binder驱动程序为了方便对它进行管理,会将它划分成 // 若干个小块;这些小块的内核缓冲区就是使用binder_buffer来描述的 // 它们保存在一个列表中,按照地址值从小到大的顺序来排列 void *buffer; // vma和buffer这两个地址相差一个固定的值,保存在user_buffer_offset ptrdiff_t user_buffer_offset;
// 指向的是内核缓冲区列表的头部 struct list_head buffers; // 保存在空闲的红黑树中 struct rb_root free_buffers; // 列表中的小块内核缓冲区有的是正在使用的,即已经分配了物理页面 // 有的是空闲的,即还没有分配物理页面,分别组织在两个红黑树中 // 保存在已经分配的红黑树中 struct rb_root allocated_buffers; // 保存了当前可以用来保存异步事务数据的内核缓冲区的大小 size_t free_async_space;
// 两个内核缓冲区对应的物理页面保存在这个变量中 // [page类型是一个数组,每一个元素都指向一个物理页面 // Binder驱动一开始时只为该内核缓冲区分配一个物理页面,后面不够使用时再分配] struct page **pages; // 保存Binder驱动程序为进程分配的内核缓冲区的大小 size_t buffer_size; // 保存了空闲内核缓冲区的大小 uint32_t buffer_free; // 当进程接收到一个进程间通信请求时,Binder驱动会将请求封装成一个工作项 // 然后加入到待处理的工作项队列todo中 struct list_head todo; // 空闲的Binder线程会睡眠在由成员变量wait所描述的一个等待队列中,当它们的宿主进程的待处理工作 // 项队列增加了新得工作项之后,Binder驱动程序会唤醒这些线程,以便它们可以去处理新的工作项 wait_queue_head_t wait; // 用来统计进程数据的,例如,进程接受到的进程间通信的请求次数 struct binder_stats stats; struct list_head delivered_death; // Binder驱动最多可以主动请求进程注册的线程的数量保存在这个变量中 int max_threads; // max_threads不是指线程池中的最大线程数目 // 每一次主动请求进程注册一个线程时,都会将这个变量加1 // 而当进程响应这个请求之后,驱动会把这个变量减1 int requested_threads; // 将这个变量加1表示Bindre驱动程序已经主动请求进程注册了多少个线程到Binder线程池中 int requested_threads_started; // 表示进程当前的空闲Binder线程数目 int ready_threads; // 初始化为进程的优先级 // 这时由于线程是代表其宿主进程来处理一个工作项的 long default_priority; };
|
binder_open就分析到这里了,核心逻辑是用户空间从ProcessState中进行打开binder节点,然后内核对该进程封装一个binder_proc结构存放在自己的节点中。
binder_mmap分析
binder_mmap是binder内存管理的核心方法,我们具体看下逻辑。
先从调用点开始分析,用户空间对mmap的调用是在ProcessState构造的时候。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
ProcessState::ProcessState(const char *driver) : mDriverName(String8(driver)) , mDriverFD(open_driver(driver)) , mVMStart(MAP_FAILED) , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) , mExecutingThreadsCount(0) , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mStarvationStartTimeMs(0) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { if (mDriverFD >= 0) { // mmap the binder, providing a chunk of virtual address space to receive transactions. mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { // *sigh* ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); close(mDriverFD); mDriverFD = -1; mDriverName.clear(); } }
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating."); }
|
构造器中,调用了mmap并将返回的用户空间地址存放在mVMStart中。
我们看下kernel中binder_mmap实现。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
// 打开设备文件/dev/binder之后,还需要调用函数mmap把设备文件映射到进程的地址空间 // 然后才可以使用Binder进程间通信机制 // 设备文件对应的是一个虚拟设备,将它映射到进程的地址空间的目的不是对它的内容感兴趣 // 而是为了为进程分配内核缓冲区,以便他可以用来传输进程间的通信数据 // // filp: 指向一个打开的文件结构体,它的成员变量private_data指向一个进程结构体binder_proc // 它是在Binder驱动的binder_open中创建的 static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; // 用来描述一段虚拟地址空间 // 在Linux内核中,一个进程可以占用的虚拟地址空间是4G // 其中0-3G是用户地址空间,3G-4G是内核地址空间 // 为了区分进程的用户地址空间和内核地址空间 // Linux内核分别使用结构体vm_area_struct和vm_struct来描述它们 // 结构体vm_struct所描述的内核地址空间范围只有(3G+896M+8M)-4G // 中间空出来的3G-(3G+896M+8M)是用来做特殊用途的 // 其中,3G-(3G+896M)的896M空间是用来映射物理内存的前896M的 // 它们之间有简单的线性对应关系 // 而(3G+896M)-(3G+896M+8M)的8M空间是一个安全保护区,是用来检测非法指针的,所有指向这8M空间的指针都是非法的 struct vm_struct *area; // 将参数filp的成员变量private_data转换为一个binder_proc结构体指针,保存在proc变量中 struct binder_proc *proc = filp->private_data; const char *failure_string; struct binder_buffer *buffer;
// 参数的成员变量vm_start和vm_end指定了要映射的用户空间地址范围 // 判断是否超过了4M // 如果是,那么就将它截断为4M // Binder驱动最多为进程分配4M的内核缓冲区来传输数据 if ((vma->vm_end - vma->vm_start) > SZ_4M) vma->vm_end = vma->vm_start + SZ_4M;
if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) printk(KERN_INFO "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));
// 检查进程要映射的用户地址空间是否可写 // FORBIDDEN_MMAP_FLAGS是一个宏 // 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来映射/dev/binder // 如何proc->buffer已经指向了一块内核缓冲区就会出错返回 if (proc->buffer) { ret = -EBUSY; failure_string = "already mapped"; goto err_already_mapped; }
// 在进程的内核地址空间分配一段大小为4M的空间 // 如果分配成功就将它的起始地址以及大小保存在proc->buffer和proc->buffer_size中 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 // 接下来为进程要映射的虚拟地址空间vma和area分配物理页面 // 分配内核缓冲区 // 创建一个物理页面结构体指针数组 // 每一页虚拟地址空间都对应有一个物理页面 // PAGE_SIZE一般定义为4K 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_open和binder_vma_close vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; // 为虚拟地址空间area分配一个物理页面,对应的内核地址空间为proc->buffer~(proc->buffer + PAGE_SIZE) 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; } // 调用成功后,就使用一个binder_buffer结构体来描述它,并且将它加入到进程结构体proc中的内核缓冲区列表buffers中 buffer = proc->buffer; INIT_LIST_HEAD(&proc->buffers); list_add(&buffer->entry, &proc->buffers); buffer->free = 1; // 调用函数将它加入到进程结构体proc的空闲内核缓冲区红黑树free_buffers中 binder_insert_free_buffer(proc, buffer); // 分配线程最大用于异步事务的内核缓冲区大小为内核缓冲区的一般 // 防止异步事务消耗过多的内核缓冲区,从而影响同步事务的执行 proc->free_async_space = proc->buffer_size / 2; barrier(); proc->files = get_files_struct(current); proc->vma = vma;
/*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ 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_mmap使用get_vm_area分配了(最多)4MB的虚拟内存空间(此时并没有分配物理内存页面)。 然后使用binder_proc中的buffer字段记录该虚拟内存的地址,使用user_buffer_offset来记录用户空间地址与内核空间地址的差值。
这个user_buffer_offset是比较关键的逻辑,在IPC过程中,我们直接通过计算从用户空间读取内核中的值,免于再一次拷贝。
分配完虚拟空间地址后,会通过kzalloc分配物理内存页面,然后通过binder_update_page_range将物理页面和虚拟地址空间进行关联。
然后使用binder_buffer描述该内存结构,并将binder_buffer放入binder_proc的列表buffers中。
binder_ioctl分析
binder_ioctl是binder driver的核心机制,binder没有提供read,write之类的系统调用,而是直接使用ioctl进行操作。
进行了解binder_ioctl之前,我们先看下binder协议码,这个也是ioctl的参数之一。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
#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)
enum BinderDriverCommandProtocol { // 当一个进程请求另外一个进程执行某一个操作时,源进程就使用命令这个协议来请求Binder驱动程序 // 将通信数据传递到目标进程中 BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), // 当目标进程处理完成源代码所请求的操作之后,就使用命令这个协议来请求驱动将结果传递给源进程 BC_REPLY = _IOW('c', 1, struct binder_transaction_data), /* * binder_transaction_data: the sent command. */
BC_ACQUIRE_RESULT = _IOW('c', 2, int), /* * not currently supported * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful. * Else you have acquired a primary reference on the object. */ // 指向了在Binder驱动程序内部所分配的一块内核缓冲区 // Binder驱动使用这个缓冲区将源进程的通信数据传递到目标进程 // 当目标进程处理完成源进程的通信请求后,会使用这个协议来通知驱动释放这个内核缓冲区 BC_FREE_BUFFER = _IOW('c', 3, int), /* * void *: ptr to transaction data received on a read */ // 驱动第一次增加一个Binder实体对象的强引用计数或者弱引用计数时 // 就会使用这个协议来请求对应的Server进程增加对应的Service组件的强引用弱引用计数 BC_INCREFS = _IOW('c', 4, int), BC_ACQUIRE = _IOW('c', 5, int), BC_RELEASE = _IOW('c', 6, int), BC_DECREFS = _IOW('c', 7, int), /* * int: descriptor */ // 当Server进程处理完成这两个请求之后,就会分别使用命令协议代码将结果返回给驱动 BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie), BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie), /* * void *: ptr to binder * void *: cookie for binder */
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc), /* * not currently supported * int: priority * int: descriptor */ // 当Binder驱动程序主动请求进程注册一个新的线程到它的Binder线程池中来 // 处理进程间通信请求之后,新创建的线程就会使用这个命令协议代码 // 通知驱动已经准备就绪了 BC_REGISTER_LOOPER = _IO('c', 11), /* * No parameters. * Register a spawned looper thread with the device. */ // 当一个线程将自己注册到Binder驱动程序之后,它接着就会使用这个命令协议代码 // 通知驱动,当前线程已经准备就绪处理进程间的通信请求了 BC_ENTER_LOOPER = _IO('c', 12), // 当线程要退出时,使用这个协议代码从驱动中注销,不会再接受到进程间的通信请求了 BC_EXIT_LOOPER = _IO('c', 13), /* * No parameters. * These two commands are sent as an application-level thread * enters and exits the binder loop, respectively. They are * used so the binder can have an accurate count of the number * of looping threads it has available. */ // 如果一个进程希望获得它所引用的Service组件的死亡接受通知,那么它就使用这个敏玲向 // 驱动注册一个死亡接受通知 BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), /* * void *: ptr to binder * void *: cookie */ // 如果进程注销一个死亡通知,使用这个协议代码发送给驱动来进行请求 BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), /* * void *: ptr to binder * void *: cookie */ // 指向了死亡接受通知结构体binder_ref_death // 当一个进程获得一个Service组件的死亡通知时,它就会使用这个命令协议通知驱动 // 当前已经处理完成该Service组件的死亡通知 BC_DEAD_BINDER_DONE = _IOW('c', 16, void *), /* * void *: cookie */ };
|
在binder.h中一共定义了多个ioctl的状态码。其中Client发起的协议码以BC开头,Server或者Driver发起的协议码以BR开头。
我们看下binder_ioctl的实现。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; // 先获得为service manager创建的binder_proc结构体 struct binder_proc *proc = filp->private_data; struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg;
/*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) return ret;
mutex_lock(&binder_lock); // 获取为service manager创建的binder_thread结构体 thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; goto err; } // 根据协议码进行处理 switch (cmd) { case BINDER_WRITE_READ: { struct binder_write_read bwr; if (size != sizeof(struct binder_write_read)) { ret = -EINVAL; goto err; } // 从用户空间拷贝出binder_write_read结构体 if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto err; } if (binder_debug_mask & BINDER_DEBUG_READ_WRITE) printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx\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; } } if (binder_debug_mask & BINDER_DEBUG_READ_WRITE) printk(KERN_INFO "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; } case BINDER_SET_MAX_THREADS: if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { ret = -EINVAL; goto err; } break; case BINDER_SET_CONTEXT_MGR: // binder_context_mgr_node用来描述与Binder进程间通信机制的上下文管理者相对应的一个Binder实体对象 // 如果不为空,说明前面已经有组件将自己注册为Binder进程间通信机制的上下文管理者了 if (binder_context_mgr_node != NULL) { printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; goto err; } // binder_context_mgr_uid用来描述注册了Binder进程间通信机制的上下文管理者的进程的有效用户ID // 如果不为-1,则说明已经存在上下文管理者 // 需要检查当前进程的有效用户ID是否等于全局变量的binder_context_mgr_uid // // Binder驱动允许同一个进程重复使用IO控制命令BINDER_SET_CONTEXT_MGR // 原因是一次调用可能没有成功将注册 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_context_mgr_uid = current->cred->euid; // 为ServiceManager创建一个Binder实体对象 binder_context_mgr_node = binder_new_node(proc, NULL, NULL); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; } 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; break; case BINDER_THREAD_EXIT: if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d exit\n", proc->pid, thread->pid); binder_free_thread(proc, thread); thread = NULL; break; 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; } break; default: ret = -EINVAL; goto err; } ret = 0; err: if (thread) thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; mutex_unlock(&binder_lock); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); return ret; }
|
我们以BINDER_WRITE_READ为例进行分析。 在IPCThreadState的talkWithDriver中,使用了该协议码。
|
1 2 3 4 5 6 7 8 |
// talkWithDriver中 #if defined(__ANDROID__) if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) err = NO_ERROR; else err = -errno; #else
|
该协议会传递到内核一个binder_write_read结构体。我们看下该结构体的定义。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct binder_write_read { // 输入数据,从用户空间传输到Binder驱动程序的数据 signed long write_size; /* bytes to write */ // 用来描述Binder驱动程序从缓冲区write_buffer中处理了多少个字节的数据 signed long write_consumed; /* bytes consumed by driver */ // 大小由成员变量write_size来指定,单位是字节 unsigned long write_buffer; // 输出数据,从驱动返回给用户空间的数据,也是进程间通信的结果数据 signed long read_size; /* bytes to read */ signed long read_consumed; /* bytes consumed by driver */ // 指向一个用户空间缓冲区的地址,里面保存的内容即为Binder驱动程序返回给用户空间的进程间通信结果数据 unsigned long read_buffer; };
|
这个结构体在binder.h中,在内核和用户空间都有相同的定义。 binder_write_read里面有write_buffer和read_buffer,这两个分别是读写缓冲区的指针。
我们看下这个case的逻辑。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
case BINDER_WRITE_READ: { struct binder_write_read bwr; if (size != sizeof(struct binder_write_read)) { ret = -EINVAL; goto err; } // 从用户空间拷贝出binder_write_read结构体 if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto err; } if (binder_debug_mask & BINDER_DEBUG_READ_WRITE) printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n", proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer); // 当一个使用IO命令BINDER_WRITE_READ和Binder驱动交互时 // 传递给binder_write_read结构体的输入缓冲区长度大于0,那么会调用binder_thread_write来处理输入缓冲区的命令协议 // 传递给binder_write_read结构体的输出缓冲区长度大于0,那么会调用binder_thread_read来处理输出缓冲区的命令协议 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; } } if (binder_debug_mask & BINDER_DEBUG_READ_WRITE) printk(KERN_INFO "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; }
|
在这个case之前, driver会首先使用binder_get_thread找到当前进行binder call的线程,具体过程就不详细说了,是根据内核线程pid进行查找,没有记录的话,会重新创建一个binder_thread结构,然后放在binder_proc的threads红黑树中。
接着看,如果write_size>0那么走binder_thread_write逻辑,如果read_size>0那么走binder_thread_read逻辑,完了有会调用copy_to_user把这个结构体拷贝回用户空间。
我们先依次分析,先看binder_thread_write实现。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed) { uint32_t cmd; void __user *ptr = buffer + *consumed; void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) { if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { binder_stats.bc[_IOC_NR(cmd)]++; proc->stats.bc[_IOC_NR(cmd)]++; thread->stats.bc[_IOC_NR(cmd)]++; } // 这里的cmd是真实协议值,由talkWithDriver时写入 switch (cmd) { case BC_INCREFS: case BC_ACQUIRE: case BC_RELEASE: case BC_DECREFS: { uint32_t target; struct binder_ref *ref; const char *debug_string;
// 获取句柄值,保存在target中 if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 得到目标Binder引用对象ref // 判断句柄值是否为0 if (target == 0 && binder_context_mgr_node && (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { // 是否存在一个引用了ServiceManager的实体对象 ref = binder_get_ref_for_node(proc, binder_context_mgr_node); if (ref->desc != target) { binder_user_error("binder: %d:" "%d tried to acquire " "reference to desc 0, " "got %d instead\n", proc->pid, thread->pid, ref->desc); } } else // 查找binder_ref,binder_ref是用户空间的binder实例 ref = binder_get_ref(proc, target); if (ref == NULL) { binder_user_error("binder: %d:%d refcou" "nt change on invalid ref %d\n", proc->pid, thread->pid, target); break; } // 根据不同的协议来增加或者减少它的强引用计数或者弱引用计数 switch (cmd) { case BC_INCREFS: debug_string = "IncRefs"; binder_inc_ref(ref, 0, NULL); break; case BC_ACQUIRE: debug_string = "Acquire"; binder_inc_ref(ref, 1, NULL); break; case BC_RELEASE: debug_string = "Release"; binder_dec_ref(ref, 1); break; case BC_DECREFS: default: debug_string = "DecRefs"; binder_dec_ref(ref, 0); break; } if (binder_debug_mask & BINDER_DEBUG_USER_REFS) printk(KERN_INFO "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", proc->pid, thread->pid, debug_string, ref->debug_id, ref->desc, ref->strong, ref->weak, ref->node->debug_id); break; } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { void __user *node_ptr; void *cookie; struct binder_node *node;
if (get_user(node_ptr, (void * __user *)ptr)) return -EFAULT; ptr += sizeof(void *); if (get_user(cookie, (void * __user *)ptr)) return -EFAULT; ptr += sizeof(void *); node = binder_get_node(proc, node_ptr); if (node == NULL) { binder_user_error("binder: %d:%d " "%s u%p no match\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", node_ptr); break; } if (cookie != node->cookie) { binder_user_error("binder: %d:%d %s u%p node %d" " cookie mismatch %p != %p\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", node_ptr, node->debug_id, cookie, node->cookie); break; } if (cmd == BC_ACQUIRE_DONE) { if (node->pending_strong_ref == 0) { binder_user_error("binder: %d:%d " "BC_ACQUIRE_DONE node %d has " "no pending acquire request\n", proc->pid, thread->pid, node->debug_id); break; } node->pending_strong_ref = 0; } else { if (node->pending_weak_ref == 0) { binder_user_error("binder: %d:%d " "BC_INCREFS_DONE node %d has " "no pending increfs request\n", proc->pid, thread->pid, node->debug_id); break; } node->pending_weak_ref = 0; } binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); if (binder_debug_mask & BINDER_DEBUG_USER_REFS) printk(KERN_INFO "binder: %d:%d %s node %d ls %d lw %d\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", node->debug_id, node->local_strong_refs, node->local_weak_refs); break; } case BC_ATTEMPT_ACQUIRE: printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n"); return -EINVAL; case BC_ACQUIRE_RESULT: printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n"); return -EINVAL;
case BC_FREE_BUFFER: { void __user *data_ptr; struct binder_buffer *buffer;
// 得到要释放的内核缓冲区的用户空间地址,保存在变量data_ptr中 if (get_user(data_ptr, (void * __user *)ptr)) return -EFAULT; ptr += sizeof(void *);
// 找到与用户空间地址data_ptr对应的内核缓冲区buffer buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) { binder_user_error("binder: %d:%d " "BC_FREE_BUFFER u%p no match\n", proc->pid, thread->pid, data_ptr); break; } if (!buffer->allow_user_free) { binder_user_error("binder: %d:%d " "BC_FREE_BUFFER u%p matched " "unreturned buffer\n", proc->pid, thread->pid, data_ptr); break; } if (binder_debug_mask & BINDER_DEBUG_FREE_BUFFER) printk(KERN_INFO "binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", proc->pid, thread->pid, data_ptr, buffer->debug_id, buffer->transaction ? "active" : "finished");
if (buffer->transaction) { buffer->transaction->buffer = NULL; buffer->transaction = NULL; } // 是否分配给一个Binder实体对象用来处理异步事务 if (buffer->async_transaction && buffer->target_node) { BUG_ON(!buffer->target_node->has_async_transaction); // 检查内核缓冲区buffer的目标Binder实体对象target_node的异步事务队列async_todo是否为空 if (list_empty(&buffer->target_node->async_todo)) buffer->target_node->has_async_transaction = 0; else list_move_tail(buffer->target_node->async_todo.next, &thread->todo); } // 减少引用计数 binder_transaction_buffer_release(proc, buffer, NULL); binder_free_buf(proc, buffer); break; }
case BC_TRANSACTION: case BC_REPLY: { struct binder_transaction_data tr;
// 从用户空间拷贝binder_transaction_data对象 if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); // 处理协议 binder_transaction(proc, thread, &tr, cmd == BC_REPLY); break; }
case BC_REGISTER_LOOPER: if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d BC_REGISTER_LOOPER\n", proc->pid, thread->pid); if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("binder: %d:%d ERROR:" " BC_REGISTER_LOOPER called " "after BC_ENTER_LOOPER\n", proc->pid, thread->pid); } else if (proc->requested_threads == 0) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("binder: %d:%d ERROR:" " BC_REGISTER_LOOPER called " "without request\n", proc->pid, thread->pid); } else { proc->requested_threads--; proc->requested_threads_started++; } thread->looper |= BINDER_LOOPER_STATE_REGISTERED; break; case BC_ENTER_LOOPER: if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d BC_ENTER_LOOPER\n", proc->pid, thread->pid); if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("binder: %d:%d ERROR:" " BC_ENTER_LOOPER called after " "BC_REGISTER_LOOPER\n", proc->pid, thread->pid); } // 设置状态 thread->looper |= BINDER_LOOPER_STATE_ENTERED; break; case BC_EXIT_LOOPER: if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d BC_EXIT_LOOPER\n", proc->pid, thread->pid); thread->looper |= BINDER_LOOPER_STATE_EXITED; break;
case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; void __user *cookie; struct binder_ref *ref; struct binder_ref_death *death;
// 获取对象的句柄值和地址值并保存在target和cookie变量中 if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); if (get_user(cookie, (void __user * __user *)ptr)) return -EFAULT; ptr += sizeof(void *); // 根据target获取到Binder引用对象ref ref = binder_get_ref(proc, target); if (ref == NULL) { binder_user_error("binder: %d:%d %s " "invalid ref %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", target); break; }
if (binder_debug_mask & BINDER_DEBUG_DEATH_NOTIFICATION) printk(KERN_INFO "binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", cookie, ref->debug_id, ref->desc, ref->strong, ref->weak, ref->node->debug_id);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { // 检查是否已经注册过死亡通知 // 驱动不会重复的注册死亡接收通知 if (ref->death) { binder_user_error("binder: %d:%" "d BC_REQUEST_DEATH_NOTI" "FICATION death notific" "ation already set\n", proc->pid, thread->pid); break; } // 第一次注册的话,会创建出一个binder_ref_death的结构体 death = kzalloc(sizeof(*death), GFP_KERNEL); if (death == NULL) { thread->return_error = BR_ERROR; if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION) printk(KERN_INFO "binder: %d:%d " "BC_REQUEST_DEATH_NOTIFICATION failed\n", proc->pid, thread->pid); break; } binder_stats.obj_created[BINDER_STAT_DEATH]++; INIT_LIST_HEAD(&death->work.entry); // 将cookie保存在它的成员变量cookie中 death->cookie = cookie; ref->death = death; // 如果正在注册的Binder引用对象所引用的Binder本地对象已经死亡了 // 这时候驱动会马上向Client发送一个死亡接收通知 if (ref->node->proc == NULL) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; // 将一个类型为BINDER_WORK_DEAD_BINDER的工作项添加到当前或者当前线程所在的Client进程的todo队列中 if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { list_add_tail(&ref->death->work.entry, &thread->todo); } else { list_add_tail(&ref->death->work.entry, &proc->todo); wake_up_interruptible(&proc->wait); } } } else { if (ref->death == NULL) { binder_user_error("binder: %d:%" "d BC_CLEAR_DEATH_NOTIFI" "CATION death notificat" "ion not active\n", proc->pid, thread->pid); break; } death = ref->death; if (death->cookie != cookie) { binder_user_error("binder: %d:%" "d BC_CLEAR_DEATH_NOTIFI" "CATION death notificat" "ion cookie mismatch " "%p != %p\n", proc->pid, thread->pid, death->cookie, cookie); break; } // 清理用来描述死亡接收者的binder_ref_death结构体 ref->death = NULL; if (list_empty(&death->work.entry)) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { // 向当前线程或者线程所属的Client进程的todo队列中添加一个类型为BINDER_WORK_CLEAR_DEATH_NOTIFICATION的工作项 // 然后发送给Client进程 list_add_tail(&death->work.entry, &thread->todo); } else { list_add_tail(&death->work.entry, &proc->todo); wake_up_interruptible(&proc->wait); } } else { BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; } } } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; void __user *cookie; struct binder_ref_death *death = NULL; if (get_user(cookie, (void __user * __user *)ptr)) return -EFAULT;
ptr += sizeof(void *); list_for_each_entry(w, &proc->delivered_death, entry) { struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); if (tmp_death->cookie == cookie) { death = tmp_death; break; } } if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) printk(KERN_INFO "binder: %d:%d BC_DEAD_BINDER_DONE %p found %p\n", proc->pid, thread->pid, cookie, death); if (death == NULL) { binder_user_error("binder: %d:%d BC_DEAD" "_BINDER_DONE %p not found\n", proc->pid, thread->pid, cookie); break; }
list_del_init(&death->work.entry); if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { list_add_tail(&death->work.entry, &thread->todo); } else { list_add_tail(&death->work.entry, &proc->todo); wake_up_interruptible(&proc->wait); } } } break;
default: printk(KERN_ERR "binder: %d:%d unknown command %d\n", proc->pid, thread->pid, cmd); return -EINVAL; } *consumed = ptr - buffer; } return 0; }
|
我们先来看下这个cmd是何时写入的。 在IPCThreadState的transact中,会把BC_TRANSACTION作为cmd码进行写入。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { //... err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); //... }
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer) { binder_transaction_data tr;
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */ tr.target.handle = handle; tr.code = code; tr.flags = binderFlags; tr.cookie = 0; tr.sender_pid = 0; tr.sender_euid = 0;
const status_t err = data.errorCheck(); if (err == NO_ERROR) { tr.data_size = data.ipcDataSize(); tr.data.ptr.buffer = data.ipcData(); tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); tr.data.ptr.offsets = data.ipcObjects(); } else if (statusBuffer) { tr.flags |= TF_STATUS_CODE; *statusBuffer = err; tr.data_size = sizeof(status_t); tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer); tr.offsets_size = 0; tr.data.ptr.offsets = 0; } else { return (mLastError = err); }
mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr));
return NO_ERROR; }
|
可以看出,实际上是写入mOut中了,在binder_thread_write中通过偏移计算得出这个值。
我们看下这个BC_TRANSACTION这个case
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
case BC_TRANSACTION: case BC_REPLY: { struct binder_transaction_data tr;
// 从用户空间拷贝binder_transaction_data对象 if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); // 处理协议 binder_transaction(proc, thread, &tr, cmd == BC_REPLY); break; }
|
看来有个binder_transaction_data结构体啊,我们看下这个结构体定义,用户空间和内核空间共同使用一份定义。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
// 用来描述进程间通信过程中所传输的数据 struct binder_transaction_data { /* The first two are only used for bcTRANSACTION and brTRANSACTION, * identifying the target and contents of the transaction. */ // 用来描述一个目标Binder实体对象或者目标Binder引用对象 // 如果是实体对象,那么成员变量ptr就指向该实体对象对应的Service组件内部的弱引用计数对象的地址 // 如果是引用对象,那么成员变量handle就指向该Binder引用对象的句柄值 union { size_t handle; /* target descriptor of command transaction */ void *ptr; /* target descriptor of return transaction */ } target; // 由应用程序进程指定的额外参数 // 当Binder驱动使用返回命令协议BR_TRANSACTION向一个Server进程发出一个进程间通信请求时 // 这个变量才有意义,它指向的是目标Service组件的地址 void *cookie; /* target object cookie */ // 由执行进程间同学你的两个进程互相约定好的一个代码 // 驱动不关心含义 unsigned int code; /* transaction command */
/* General information about the transaction. */ unsigned int flags; // 发起进程间通信的请求进程的pid和uid pid_t sender_pid; uid_t sender_euid; // 用来描述一个通信数据缓冲区以及一个偏移数组的大小 size_t data_size; /* number of bytes of data */ size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately * follows here; otherwise, it ends with a pointer to * the data buffer. */ // 一个联合体 // 指向一个通信数据缓冲区 // 当通信数据较小时,使用联合体中的静态分配的数组buf来传输数据 // 当通信数据较大时,使用一块动态分配的缓冲区来传输数据 // 这块数据缓冲区通过一个包含两个指针的结构体来描述 // 结构体ptr的成员变量buffer指向一个数据缓冲区,用来保存通信数据,大小根据变量data_size来指定 // 当数据缓冲区中有Binder对象时,紧跟着这个数据缓冲区后面就会有一个偏移数组offsets // 用来描述缓冲区中每一个Binder对象的位置 // 有了偏移数组,驱动可以正确地维护其内部的Binder实体对象和Binder引用对象的引用计数 union { struct { /* transaction data */ const void *buffer; /* offsets from buffer to flat_binder_object structs */ const void *offsets; } ptr; uint8_t buf[8]; } data; };
|
这个binder_transaction_data是在IPCThreadState的transact时写入mOut中的。 里面存放了当前IPC所需要的数据。 继续我们的逻辑,内核会用copy_from_user从用户空间把binder_transaction_data结构体拷贝过来。 然后调用binder_transaction。
binder_transaction分析
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply) { struct binder_transaction *t; struct binder_work *tcomplete; size_t *offp, *off_end; struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; struct list_head *target_list; wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; uint32_t return_error;
e = binder_transaction_log_add(&binder_transaction_log); e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); e->from_proc = proc->pid; e->from_thread = thread->pid; e->target_handle = tr->target.handle; e->data_size = tr->data_size; e->offsets_size = tr->offsets_size;
if (reply) { // 找到之前请求与线程thread进行进程间通信的线程 // 取出binder_transaction结构体 in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) { binder_user_error("binder: %d:%d got reply transaction " "with no transaction stack\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_empty_call_stack; } // 恢复优先级 binder_set_nice(in_reply_to->saved_priority); if (in_reply_to->to_thread != thread) { binder_user_error("binder: %d:%d got reply transaction " "with bad transaction stack," " transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, in_reply_to->to_thread ? in_reply_to->to_thread->pid : 0); return_error = BR_FAILED_REPLY; in_reply_to = NULL; goto err_bad_call_stack; } thread->transaction_stack = in_reply_to->to_parent; // 指向了之前请求与线程thread进行进程间通信的线程 target_thread = in_reply_to->from; if (target_thread == NULL) { return_error = BR_DEAD_REPLY; goto err_dead_binder; } if (target_thread->transaction_stack != in_reply_to) { binder_user_error("binder: %d:%d got reply transaction " "with bad target transaction stack %d, " "expected %d\n", proc->pid, thread->pid, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, in_reply_to->debug_id); return_error = BR_FAILED_REPLY; in_reply_to = NULL; target_thread = NULL; goto err_dead_binder; } target_proc = target_thread->proc; // 处理binder_transaction命令协议 } else { // 这里判断handle是不是0,如果是0的话,走serviceManager的逻辑 if (tr->target.handle) { struct binder_ref *ref; // 获取server端引用对象 ref = binder_get_ref(proc, tr->target.handle); if (ref == NULL) { binder_user_error("binder: %d:%d got " "transaction to invalid handle\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_invalid_target_handle; } // 获取实体对象 target_node = ref->node; // handle为0时 } else { // 获得service manager实体对象 target_node = binder_context_mgr_node; if (target_node == NULL) { return_error = BR_DEAD_REPLY; goto err_no_context_mgr_node; } } e->to_node = target_node->debug_id; // 找到target_proc target_proc = target_node->proc; // 找到后接下来要由目标进程空闲线程处理BR_TRANSACTION // 空闲线程的类型: // 1. 无事可做而空闲 // 2. 不是真的空闲,处于某个事务过程中,需要等待其它线程来处理另外一个事务 if (target_proc == NULL) { return_error = BR_DEAD_REPLY; goto err_dead_binder; } // 对空闲线程使用做的优化 // 尝试找到第二种类型的空闲线程来处理BR_TRANSACTION,以便提高目标进程target_proc的进程间通信并发能力 // 只有当同步时才能执行该优化方案 if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; if (tmp->to_thread != thread) { binder_user_error("binder: %d:%d got new " "transaction with bad transaction stack" ", transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? tmp->to_thread->pid : 0); return_error = BR_FAILED_REPLY; goto err_bad_call_stack; } while (tmp) { if (tmp->from && tmp->from->proc == target_proc) // 找到处理的线程 target_thread = tmp->from; tmp = tmp->from_parent; } } } if (target_thread) { // 成功的找到了目标线程 e->to_thread = target_thread->pid; // 指向target_thread的todo队列和wait等待队列 target_list = &target_thread->todo; target_wait = &target_thread->wait; } else { target_list = &target_proc->todo; target_wait = &target_proc->wait; } e->to_proc = target_proc->pid;
/* TODO: reuse incoming transaction for reply */ // 分配了一个binder_transaction结构体t // 封装成一个BINDER_WORK_TRANSACTION类型的工作项加入目标todo队列target_list // 以便目标线程可以接受到BR_TRANSACTION返回协议 t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_t_failed; } binder_stats.obj_created[BINDER_STAT_TRANSACTION]++;
// 分配了一个binder_work结构体tcomplete tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_tcomplete_failed; } binder_stats.obj_created[BINDER_STAT_TRANSACTION_COMPLETE]++;
t->debug_id = ++binder_last_id; e->debug_id = t->debug_id;
if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) { if (reply) printk(KERN_INFO "binder: %d:%d BC_REPLY %d -> %d:%d, " "data %p-%p size %zd-%zd\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, tr->data.ptr.buffer, tr->data.ptr.offsets, tr->data_size, tr->offsets_size); else printk(KERN_INFO "binder: %d:%d BC_TRANSACTION %d -> " "%d - node %d, data %p-%p size %zd-%zd\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, tr->data.ptr.buffer, tr->data.ptr.offsets, tr->data_size, tr->offsets_size); }
// 初始化前面分配的binder_transaction结构体 if (!reply && !(tr->flags & TF_ONE_WAY)) // 如果函数正在处理一个BC_TRANSACTION命令协议,并且是所描述的一个同步进程间通信请求 // 将from指向源线程的thread // 以便目标进程target_proc或者目标线程target_thread处理完该进程间通信请求之后,能够找回发出该进程间通信请求的线程 // 最终返回结果给它 t->from = thread; else t->from = NULL; t->sender_euid = proc->tsk->cred->euid; t->to_proc = target_proc; t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; t->priority = task_nice(current); t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); if (t->buffer == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_alloc_buf_failed; } t->buffer->allow_user_free = 0; t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; if (target_node) // 增加目标Binder实体对象的强引用计数 binder_inc_node(target_node, 1, 0, NULL);
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
// 将数据缓冲区发送拷贝到结构体t的内核缓冲区 // 这是至关重要的一次内存拷贝 if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { binder_user_error("binder: %d:%d got transaction with invalid " "data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } // 将偏移数组的内容拷贝到分配给binder_transaction结构体t的内核缓冲区 if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("binder: %d:%d got transaction with invalid " "offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { binder_user_error("binder: %d:%d got transaction with " "invalid offsets size, %zd\n", proc->pid, thread->pid, tr->offsets_size); return_error = BR_FAILED_REPLY; goto err_bad_offset; } off_end = (void *)offp + tr->offsets_size; // 依次处理进程间通信数据中的Binder对象 // binder引用在传输过程中需要特殊对待 for (; offp < off_end; offp++) { struct flat_binder_object *fp; if (*offp > t->buffer->data_size - sizeof(*fp) || t->buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(void *))) { binder_user_error("binder: %d:%d got transaction with " "invalid offset, %zd\n", proc->pid, thread->pid, *offp); return_error = BR_FAILED_REPLY; goto err_bad_offset; } fp = (struct flat_binder_object *)(t->buffer->data + *offp); switch (fp->type) { case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { struct binder_ref *ref; struct binder_node *node = binder_get_node(proc, fp->binder); if (node == NULL) { // 创建一个Binder实体对象node node = binder_new_node(proc, fp->binder, fp->cookie); if (node == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_new_node_failed; } // 根据从用户空间传递进程的flat_binder_object结构体内容来设置它的最小线程优先级以及是否接受文件描述符标志 node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { binder_user_error("binder: %d:%d sending u%p " "node %d, cookie mismatch %p != %p\n", proc->pid, thread->pid, fp->binder, node->debug_id, fp->cookie, node->cookie); goto err_binder_get_ref_for_node_failed; } // 创建一个Binder引用对象 ref = binder_get_ref_for_node(target_proc, node); if (ref == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } if (fp->type == BINDER_TYPE_BINDER) // 修改结构体fp的类型 // 当驱动将进程间数据传递到目标进程时,进程间通信数据中的Binder实体对象就变成了Binder引用对象 fp->type = BINDER_TYPE_HANDLE; else fp->type = BINDER_TYPE_WEAK_HANDLE; fp->handle = ref->desc; // 增加引用对象ref的引用计数 binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO " node %d u%p -> ref %d desc %d\n", node->debug_id, node->ptr, ref->debug_id, ref->desc); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle); if (ref == NULL) { binder_user_error("binder: %d:%d got " "transaction with invalid " "handle, %ld\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_binder_get_ref_failed; } if (ref->node->proc == target_proc) { if (fp->type == BINDER_TYPE_HANDLE) fp->type = BINDER_TYPE_BINDER; else fp->type = BINDER_TYPE_WEAK_BINDER; fp->binder = ref->node->ptr; fp->cookie = ref->node->cookie; binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO " ref %d desc %d -> node %d u%p\n", ref->debug_id, ref->desc, ref->node->debug_id, ref->node->ptr); } else { struct binder_ref *new_ref; new_ref = binder_get_ref_for_node(target_proc, ref->node); if (new_ref == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } fp->handle = new_ref->desc; binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO " ref %d desc %d -> ref %d desc %d (node %d)\n", ref->debug_id, ref->desc, new_ref->debug_id, new_ref->desc, ref->node->debug_id); } } break;
case BINDER_TYPE_FD: { int target_fd; struct file *file;
if (reply) { if (!(in_reply_to->flags & TF_ACCEPT_FDS)) { binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; } } else if (!target_node->accept_fds) { binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; }
file = fget(fp->handle); if (file == NULL) { binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fget_failed; } target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); if (target_fd < 0) { fput(file); return_error = BR_FAILED_REPLY; goto err_get_unused_fd_failed; } task_fd_install(target_proc, target_fd, file); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd); /* TODO: fput? */ fp->handle = target_fd; } break;
default: binder_user_error("binder: %d:%d got transactio" "n with invalid object type, %lx\n", proc->pid, thread->pid, fp->type); return_error = BR_FAILED_REPLY; goto err_bad_object_type; } } if (reply) { BUG_ON(t->buffer->async_transaction != 0); // 从目标线程target_thread事务堆栈中删除binder_transaction结构体in_reply_to binder_pop_transaction(target_thread, in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { // 如果是正在处理一个同步的进程间通信请求 BUG_ON(t->buffer->async_transaction != 0); // 需要回复 t->need_reply = 1; // 压入到源线程thread的事务堆栈transaction_stack中 t->from_parent = thread->transaction_stack; thread->transaction_stack = t; } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); // 检查是否正在处理异步事务 if (target_node->has_async_transaction) { // 添加到async_todo队列中进行处理 target_list = &target_node->async_todo; target_wait = NULL; } else target_node->has_async_transaction = 1; } // 将binder_transaction结构体t封装成BINDER_WORK_TRANSACTION的工作项添加到目标进程target_proc中 t->work.type = BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry, target_list); // 将tcomplte封装成一个类型为BINDER_WORK_TRANSACTION_COMPLETE工作项添加到源线程thread的todo队列中 tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry, &thread->todo); if (target_wait) // 将target_proc或者target_thread唤醒,来处理这个重做向 wake_up_interruptible(target_wait); // 执行到这里时,源线程thread,目标进程target_proc或者目标线程target_thread就会并发的去处理各自的todo队列的工作项了 return;
err_get_unused_fd_failed: err_fget_failed: err_fd_not_allowed: err_binder_get_ref_for_node_failed: err_binder_get_ref_failed: err_binder_new_node_failed: err_bad_object_type: err_bad_offset: err_copy_data_failed: binder_transaction_buffer_release(target_proc, t->buffer, offp); t->buffer->transaction = NULL; binder_free_buf(target_proc, t->buffer); err_binder_alloc_buf_failed: kfree(tcomplete); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; err_alloc_tcomplete_failed: kfree(t); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; err_alloc_t_failed: err_bad_call_stack: err_empty_call_stack: err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION) printk(KERN_INFO "binder: %d:%d transaction failed %d, size" "%zd-%zd\n", proc->pid, thread->pid, return_error, tr->data_size, tr->offsets_size);
{ struct binder_transaction_log_entry *fe; fe = binder_transaction_log_add(&binder_transaction_log_failed); *fe = *e; }
BUG_ON(thread->return_error != BR_OK); if (in_reply_to) { thread->return_error = BR_TRANSACTION_COMPLETE; binder_send_failed_reply(in_reply_to, return_error); } else thread->return_error = return_error; }
|
这个函数非常的长,推荐装个代码折叠插件看。 我们先看下查找目标进程binder_ref的过程。binder的引用对象在内核中的描述为binder_ref结构。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// 同一个Binder实体对象可能会同时被多个Client组件引用 // 使用binder_ref来描述这些引用关系 // 将引用了同一个Binder实体对象的所有引用都保存在一个hash列表中 // // 用来描述一个Binder引用对象 // 每个Client组件在Binder驱动中度对应有一个Binder引用对象 // 用来描述它在内核的状态 // 驱动通过强引用计数与弱引用计数来维护它们在生命周期 struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ // 用来标志Binder应用对象的身份,帮助调试用 int debug_id; // 一个宿主进程使用两个红黑树来保存它内部所有的引用对象 // 分别以句柄值和对应的Binder实体对象的地址作为关键字来保存Binder引用对象 // rb_node_desc, rb_node_node 为这两个红黑树的节点 struct rb_node rb_node_desc; struct rb_node rb_node_node; // Binder实体对象hash列表的节点 struct hlist_node node_entry; // 引用对象的宿主进程 struct binder_proc *proc; // 描述一个Binder引用对象所引用的Binder实体对象 struct binder_node *node; // 句柄值描述符,用来描述一个Binder引用对象 // 句柄值在进程范围内唯一,不同进程见同一句柄值可能代表这不同Service组件 // // 在Client进程的用户空间中,访问Service组件通过以下顺序 // Client->句柄值->binder_ref->binder_node->Service uint32_t desc; // 强弱引用计数,用来维护引用对象的生命周期 int strong; int weak; // 指向死亡接收通知 // 当Client进程向驱动注册死亡通知时,会创建一个binder_ref_death结构体并保存在death变量中 struct binder_ref_death *death; };
|
获取binder_ref的过程
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
if (tr->target.handle) { struct binder_ref *ref; // 获取server端引用对象 ref = binder_get_ref(proc, tr->target.handle); if (ref == NULL) { binder_user_error("binder: %d:%d got " "transaction to invalid handle\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_invalid_target_handle; } // 获取实体对象 target_node = ref->node; // handle为0时 }
|
通过binder_get_ref根据handle值获取binder_ref,然后获取对端的binder_proc,并记录在target_node节点中。
然后获取目标线程的todo队列和wait队列,并记录在变量中。
|
1 2 3 4 5 6 7 8 9 10 11 |
if (target_thread) { // 成功的找到了目标线程 e->to_thread = target_thread->pid; // 指向target_thread的todo队列和wait等待队列 target_list = &target_thread->todo; target_wait = &target_thread->wait; } else { target_list = &target_proc->todo; target_wait = &target_proc->wait; }
|
接下来我们会看到一次内存拷贝过程,又原进程的用户空间拷贝到内核,这是binder IPC中完成的一次至关重要的拷贝,binder机制的一次内存拷贝说的就是这个地方。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
//binder_transaction代码中
// 分配了一个binder_transaction结构体t // 封装成一个BINDER_WORK_TRANSACTION类型的工作项加入目标todo队列target_list // 以便目标线程可以接受到BR_TRANSACTION返回协议 t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_t_failed; } binder_stats.obj_created[BINDER_STAT_TRANSACTION]++;
// 分配了一个binder_work结构体tcomplete tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_tcomplete_failed; } binder_stats.obj_created[BINDER_STAT_TRANSACTION_COMPLETE]++;
t->debug_id = ++binder_last_id; e->debug_id = t->debug_id;
if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) { if (reply) printk(KERN_INFO "binder: %d:%d BC_REPLY %d -> %d:%d, " "data %p-%p size %zd-%zd\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, tr->data.ptr.buffer, tr->data.ptr.offsets, tr->data_size, tr->offsets_size); else printk(KERN_INFO "binder: %d:%d BC_TRANSACTION %d -> " "%d - node %d, data %p-%p size %zd-%zd\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, tr->data.ptr.buffer, tr->data.ptr.offsets, tr->data_size, tr->offsets_size); }
// 初始化前面分配的binder_transaction结构体 if (!reply && !(tr->flags & TF_ONE_WAY)) // 如果函数正在处理一个BC_TRANSACTION命令协议,并且是所描述的一个同步进程间通信请求 // 将from指向源线程的thread // 以便目标进程target_proc或者目标线程target_thread处理完该进程间通信请求之后,能够找回发出该进程间通信请求的线程 // 最终返回结果给它 t->from = thread; else t->from = NULL; t->sender_euid = proc->tsk->cred->euid; t->to_proc = target_proc; t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; t->priority = task_nice(current); t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); if (t->buffer == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_alloc_buf_failed; } t->buffer->allow_user_free = 0; t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; if (target_node) // 增加目标Binder实体对象的强引用计数 binder_inc_node(target_node, 1, 0, NULL);
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
// 将数据缓冲区发送拷贝到结构体t的内核缓冲区 // 这是至关重要的一次内存拷贝 if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { binder_user_error("binder: %d:%d got transaction with invalid " "data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } // 将偏移数组的内容拷贝到分配给binder_transaction结构体t的内核缓冲区 if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("binder: %d:%d got transaction with invalid " "offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; }
|
然后binder内核把一个BINDER_WORK_TRANSACTION的工作添加到目标进程todo队列,把BINDER_WORK_TRANSACTION_COMPLETE添加到原线程的todo队列中。
然后唤醒目标进程,开始处理todo队列里的工作。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// binder_transaction中
// 将binder_transaction结构体t封装成BINDER_WORK_TRANSACTION的工作项添加到目标进程target_proc中 t->work.type = BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry, target_list); // 将tcomplte封装成一个类型为BINDER_WORK_TRANSACTION_COMPLETE工作项添加到源线程thread的todo队列中 tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry, &thread->todo); if (target_wait) // 将target_proc或者target_thread唤醒,来处理这个重做向 wake_up_interruptible(target_wait); // 执行到这里时,源线程thread,目标进程target_proc或者目标线程target_thread就会并发的去处理各自的todo队列的工作项了
|
BINDER_WORK_TRANSACTION_COMPLETE这个是binder内部的work type,最终还是会转成BC_XXX或者BR_XXX之类的协议。
当其他进程往todo队列中放入binder_work时,当前进程会被唤醒,执行todo队列中的工作,我们接下来看下binder_thread_read的相关逻辑。
binder_thread_read分析
Binder进程最终是在binder_thread_read中进行阻塞的,因为BnBinder会调用joinThreadPool一直询问Binder驱动是否存在Binder请求,如果没有的话,会一直阻塞住,上文分析到,其他进程会往目标进程的todo队列中放入binder_work使目标线程从binder_thread_read的逻辑中进行唤醒。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed, int non_block) { void __user *ptr = buffer + *consumed; void __user *end = buffer + size;
int ret = 0; int wait_for_proc_work;
if (*consumed == 0) { if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); }
retry: // 如果一个事务的堆栈transaction_stack不等于NULL,就表示它正在等待其他进程完成另外一个事务 // 只有在transaction_stack为空并且todo队列为空时,才可以去处理其所属进程的todo队列待处理工作项 // 否则,它就要处理其事务堆栈中的事务或者todo队列中的待处理工作项 wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
if (thread->return_error != BR_OK && ptr < end) { if (thread->return_error2 != BR_OK) { if (put_user(thread->return_error2, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); if (ptr == end) goto done; thread->return_error2 = BR_OK; } if (put_user(thread->return_error, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); thread->return_error = BR_OK; goto done; }
// 首先将当前线程状态设置为BINDER_LOOPER_STATE_WATING // 表示该线程处于空闲状态 thread->looper |= BINDER_LOOPER_STATE_WAITING; if (wait_for_proc_work) // 空闲线程加1 proc->ready_threads++; mutex_unlock(&binder_lock); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { binder_user_error("binder: %d:%d ERROR: Thread waiting " "for process work before calling BC_REGISTER_" "LOOPER or BC_ENTER_LOOPER (state %x)\n", proc->pid, thread->pid, thread->looper); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); } // 设置当前线程优先级为进程优先级 binder_set_nice(proc->default_priority); if (non_block) { // 当前线程不可以在驱动中睡眠 if (!binder_has_proc_work(proc, thread)) ret = -EAGAIN; } else // 否则,睡眠等待直到所属的进程有新的未处理工作项为止 ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread)); } else { // 是否以非阻塞模式打开设备文件/dev/binder if (non_block) { if (!binder_has_thread_work(thread)) ret = -EAGAIN; } else ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread)); } mutex_lock(&binder_lock); // 根据状态为来减少空闲线程 if (wait_for_proc_work) proc->ready_threads--; // 如果驱动发现当前线程有新的工作项时,就会将它的状态为清空 thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
if (ret) return ret;
// 当驱动和目标进程/线程通信时 // 会把一个工作项加入到它的todo队列中 // 目标进程/进程会不断的调用驱动中的函数binder_thread_read来检查它的todo队列中有没有新的工作项 // 如果有,目标进程/线程就会把它取出来,并且返回到用户空间去处理 while (1) { uint32_t cmd; struct binder_transaction_data tr; struct binder_work *w; struct binder_transaction *t = NULL;
// 检查目标进程/线程中的todo队列,并且将里面的待处理工作项保存在w中 if (!list_empty(&thread->todo)) w = list_first_entry(&thread->todo, struct binder_work, entry); else if (!list_empty(&proc->todo) && wait_for_proc_work) w = list_first_entry(&proc->todo, struct binder_work, entry); else { if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */ goto retry; break; }
if (end - ptr < sizeof(tr) + 4) break;
// 根据worktype选择工作流程 switch (w->type) { case BINDER_WORK_TRANSACTION: { // 转换成binder_transaction结构体 t = container_of(w, struct binder_transaction, work); } break; case BINDER_WORK_TRANSACTION_COMPLETE: { cmd = BR_TRANSACTION_COMPLETE; // 将一个BR_TRANSACTION_COMPLETE返回协议写入到用户空间提供的缓冲区中 // 向相应的进程发送一个BR_TRANSACTION_COMPLETE协议 if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, cmd); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION_COMPLETE) printk(KERN_INFO "binder: %d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid);
list_del(&w->entry); kfree(w); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; } break; case BINDER_WORK_NODE: { struct binder_node *node = container_of(w, struct binder_node, work); uint32_t cmd = BR_NOOP; const char *cmd_name; // 检查该Binder实体对象是否有强引用和弱引用计数 int strong = node->internal_strong_refs || node->local_strong_refs; // 是否有弱引用计数 int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; if (weak && !node->has_weak_ref) { // Binder实体对象已经引用了一个Binder本地对象 // 但是并没有增加它的弱引用计数 // 使用BC_INCREFS来增加对应的Binder本地对象的弱引用计数 cmd = BR_INCREFS; cmd_name = "BR_INCREFS"; node->has_weak_ref = 1; node->pending_weak_ref = 1; node->local_weak_refs++; } else if (strong && !node->has_strong_ref) { // Binder实体对象已经引用了一个Binder本地对象 // 但是并没有增加它的强引用计数 // 使用BC_ACQUIRE协议来请求增加对应的Binder本地对象的强引用计数 cmd = BR_ACQUIRE; cmd_name = "BR_ACQUIRE"; node->has_strong_ref = 1; node->pending_strong_ref = 1; node->local_strong_refs++; } else if (!strong && node->has_strong_ref) { // Binder实体对象已经不再引用一个Binder本地对象 // 但是没有减少它的强引用计数 // 使用BR_RELEASE协议来请求减少对应的Binder本地对象的强引用计数 cmd = BR_RELEASE; cmd_name = "BR_RELEASE"; node->has_strong_ref = 0; } else if (!weak && node->has_weak_ref) { // Binder实体对象已经不再引用Binder本地对象 // 但是没有减少它的弱引用计数 // 使用BR_DECREFS协议来请求减少对应的Binder本地对象的弱引用计数 cmd = BR_DECREFS; cmd_name = "BR_DECREFS"; node->has_weak_ref = 0; } if (cmd != BR_NOOP) { // 将前面准备好的协议以及协议内容写入到由Server进程所提供的一个用户空间缓冲区 // 然后返回到Server进程的用户空间 // Server进程通过Binder库提供的IPCThreadState接口来处理Binder驱动程序所发送的协议 if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); if (put_user(node->ptr, (void * __user *)ptr)) return -EFAULT; ptr += sizeof(void *); if (put_user(node->cookie, (void * __user *)ptr)) return -EFAULT; ptr += sizeof(void *);
binder_stat_br(proc, thread, cmd); if (binder_debug_mask & BINDER_DEBUG_USER_REFS) printk(KERN_INFO "binder: %d:%d %s %d u%p c%p\n", proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); } else { list_del_init(&w->entry); if (!weak && !strong) { if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) printk(KERN_INFO "binder: %d:%d node %d u%p c%p deleted\n", proc->pid, thread->pid, node->debug_id, node->ptr, node->cookie); rb_erase(&node->rb_node, &proc->nodes); kfree(node); binder_stats.obj_deleted[BINDER_STAT_NODE]++; } else { if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) printk(KERN_INFO "binder: %d:%d node %d u%p c%p state unchanged\n", proc->pid, thread->pid, node->debug_id, node->ptr, node->cookie); } } } break; case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { // Binder线程在空闲时,会睡眠在Binder驱动程序的函数binder_thread_read中,因此,当它们被唤醒时 // 就会执行函数binder_thread_read,并且检查自己以及宿主进程的todo队列,看看有没有工作项需要处理 // // 获得一个对应的binder_ref_death结构体 struct binder_ref_death *death = container_of(w, struct binder_ref_death, work); uint32_t cmd; if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; // 将协议代码和binder_ref_death结构体成员变量写入到Client进程提供的一个用户空间缓冲区中 if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 通知Client进程,哪一个Binder代理对象已经死亡 if (put_user(death->cookie, (void * __user *)ptr)) return -EFAULT; ptr += sizeof(void *); if (binder_debug_mask & BINDER_DEBUG_DEATH_NOTIFICATION) printk(KERN_INFO "binder: %d:%d %s %p\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", death->cookie);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { list_del(&w->entry); kfree(death); binder_stats.obj_deleted[BINDER_STAT_DEATH]++; } else // 将正在处理的工作项保存在Client进程的一个delivered_death队列中 // 当处理完成一个死亡通知之后,它就会使用协议BC_DEAD_BINDER_DONE来通知Binder驱动程序 // 如果一个进程的delivered_death队列不为空 // 那么就说明Binder驱动程序正在向他发送死亡接受通知 list_move(&w->entry, &proc->delivered_death); if (cmd == BR_DEAD_BINDER) goto done; /* DEAD_BINDER notifications can cause transactions */ } break; }
if (!t) continue;
BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { // target_node引用了service manager的实体对象binder_context_mgr_node struct binder_node *target_node = t->buffer->target_node; // 将里面的目标函数拷贝到binder_transaction_data中 // 以便目标线程thread接收到Binder驱动程序给它发送的BR_TRANSACTION返回协议之后,可以将返回协议交给指定的Binder本地对象来处理 tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; t->saved_priority = task_nice(current); // 保证目标线程的线程优先级不低于源线程的线程优先级 if (t->priority < target_node->min_priority && !(t->flags & TF_ONE_WAY)) // 设置优先级 binder_set_nice(t->priority); // 如果是异步的就不用设置优先级,因为不需要等待 else if (!(t->flags & TF_ONE_WAY) || t->saved_priority > target_node->min_priority) binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { tr.target.ptr = NULL; tr.cookie = NULL; cmd = BR_REPLY; } // 将binder_transaction结构体t中的进程间通信数据拷贝到binder_transaction_data结构体tr中 tr.code = t->code; tr.flags = t->flags; tr.sender_euid = t->sender_euid;
if (t->from) { struct task_struct *sender = t->from->proc->tsk; tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns); } else { tr.sender_pid = 0; }
// 将t中的数据缓冲区和偏移数组的内容拷贝到binder_transaction_data的结构体tr中 // // Binder驱动为进程分配的内核缓冲区是用来传输进程间的通信数据的 // 将进程间通信数据从内核地址空间传输到用户地址空间 // 为了减少一次数据拷贝操作,Binder驱动程序分配给进程的内核缓冲区同时映射到了进程的内核地址空间和用户地址空间 // // 以下并不是真正的拷贝,而是修改tr中数据缓冲区和偏移数组的地址值 // 使它们指向binder_transaction结构体t中的数据缓冲区和偏移数组 // 由于驱动为目标进程proc分配的内核缓冲区的内核空间地址和用户空间地址相差一个固定的值,并保存在user_buffer_offset中 // 因此,知道了binder_transaction结构体t中的数据缓冲区和偏移数组的内核空间地址之后,就很容易知道它们对应的用户空间地址了 tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset; tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
// 将它以及对应的返回协议拷贝到目标线程thread提供的用户空间缓冲区中 if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 拷贝tr if (copy_to_user(ptr, &tr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr);
binder_stat_br(proc, thread, cmd); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO "binder: %d:%d %s %d %d:%d, cmd %d" "size %zd-%zd ptr %p-%p\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", t->debug_id, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, tr.data.ptr.buffer, tr.data.ptr.offsets);
// 将binder_work结构体w从目标线程中或者目标进程的todo队列中删除 list_del(&t->work.entry); // 驱动为它所分配的内核缓冲区允许目标线程thread在用户空间发出BC_FREE_BUFFER命令协议来释放 t->buffer->allow_user_free = 1; // 如果是目标线程发送的BR_TRANSACTION返回协议并且是非ONE_WAY的请求 if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { // 驱动正在请求目标线程thread执行一个同步的进程间通信请求 // 将binder_transaction压入到目标线程thread的事务堆栈transaction_stack中 // 以便驱动以后可以从目标线程thread所属进程的Binder线程池中选择一个最优的空闲Binder先测会给你来处理其它的进程间通信请求 t->to_parent = thread->transaction_stack; t->to_thread = thread; thread->transaction_stack = t; } else { // 如果不是一个同步的进程间通信请求 // 那么就会释放binder_transaction的空间 t->buffer->transaction = NULL; kfree(t); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; } break; }
// 在处理完成之后,返回到函数binder_ioctl之前 // 还会检查是否需要请求当前线程所属的进程proc增加一个新的Binder线程来处理进程间通信请求 done:
*consumed = ptr - buffer; // 1. 空闲进程为0 // 2. 驱动当前没有请求进程proc增加一个新的Binder线程 // 3. 驱动请求进程proc增加Binder线程数小于预设的最大数目 // 4. 当前线程是一个已经注册了的Binder线程 if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) { proc->requested_threads++; if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid); // 返回BR_SPAWN_LOOPER到用户空间缓冲区 // 以便可以创建一个新的线程加入到Binder线程池中 if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) return -EFAULT; } return 0; }
|
我们就看下BINDER_WORK_TRANSACTION的逻辑吧,其他逻辑类似。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
... switch (w->type) { case BINDER_WORK_TRANSACTION: { // 转换成binder_transaction结构体 t = container_of(w, struct binder_transaction, work); } break; ...
if (t->buffer->target_node) { // target_node引用了service manager的实体对象binder_context_mgr_node struct binder_node *target_node = t->buffer->target_node; // 将里面的目标函数拷贝到binder_transaction_data中 // 以便目标线程thread接收到Binder驱动程序给它发送的BR_TRANSACTION返回协议之后,可以将返回协议交给指定的Binder本地对象来处理 tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; t->saved_priority = task_nice(current); // 保证目标线程的线程优先级不低于源线程的线程优先级 if (t->priority < target_node->min_priority && !(t->flags & TF_ONE_WAY)) // 设置优先级 binder_set_nice(t->priority); // 如果是异步的就不用设置优先级,因为不需要等待 else if (!(t->flags & TF_ONE_WAY) || t->saved_priority > target_node->min_priority) binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { tr.target.ptr = NULL; tr.cookie = NULL; cmd = BR_REPLY; } // 将binder_transaction结构体t中的进程间通信数据拷贝到binder_transaction_data结构体tr中 tr.code = t->code; tr.flags = t->flags; tr.sender_euid = t->sender_euid;
if (t->from) { struct task_struct *sender = t->from->proc->tsk; tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns); } else { tr.sender_pid = 0; }
tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset; tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); // 拷贝tr if (copy_to_user(ptr, &tr, sizeof(tr))) return -EFAULT;
|
这段逻辑就是把处理后的binder_transaction_data结构返回给用户空间,这个时候,用户层就会调用BnBinder的相关逻辑进行处理了。
总结下Binder协议通信流程
最后,我们从协议的角度分析下Binder Driver处理IPC的流程图。
下面根据时序编号解释下:
(1) Client向Binder Driver发送请求,此时的CMD是上层talkWithDriver之前传入的BC_TRANSACTION。
(2,3) Binder Driver在binder_transaction函数中处理此逻辑,通知Client处理BR_TRANSACTION_COMPLETE,意在告诉Client内核已收到请求,同时向目标Server发送BR_TRANSACTION,把Server端唤醒。
(4) Server执行BnBinder的逻辑后,用户层sendReply写入BC_REPLY,通知Binder Driver处理。
(5) 同样Binder Driver会回复一个BR_TRANSACTION_COMPLETE通知内核已收到请求。
(6) 收到BC_REPLY后,Binder Driver会向Client发送BR_REPLY,通知Server端已经返回,执行BpBinder端逻辑。
到此Binder Driver的核心逻辑就分析完了,接下来会分析Binder在用户空间层的实现,会用到这些知识。