Android系统进程间通信采用了Binder机制,基于openBinder开发. 使用Binder进行进程间通信,只需要一次拷贝便可完成,既提升了效率,又节省了内存空间.
Binder机制的实现由三部分组成,分为运行在内核空间的驱动层,运行在用户空间的native层和Java接口层.
今天主要介绍驱动层的相关知识.
1. 设备初始化
设备初始化主要是在系统中创建相关文件,包括Binder设备文件/dev/binder,为每个进程创建一个以进程ID命令的文件,通过该文件可以读取到各进程的Binder线程池,Binder实体对象,Binder引用对象以及内核缓存区等信息.还在/prov/binder,目录下创建了state,stats,transactions,transactions_log和failed_transaction_log等文件,通过这五个文件可以读取到binder驱动程序的运行状况.
2.打开binder设备文件
一个进程在使用binder进程IPC之前,必须先调用open()函数打开设备文件/dev/binder来获得一个描述符,然后通过这个描述符和binder驱动交互,进而和其他进程IPC.
在打开/dev/binder后,驱动程序会为进程创建一个唯一的结构体binder_proc,该结构体持有进程的pid,与打开binder设备文件的进程相关联.然后将该结构体加入全局hash队列binder_procs中,该队列保存了所有正在使用binder驱动的进程的binder_proc结构体.也就是说通过遍历该队列可以知道当前有多少个进程在使用binder进程间通信.
3.binder设备文件的内核缓存区管理
基本流程是binder驱动程序在内核空间为目标进程分配一块内存空间,及内核缓存区.该内存空间同时具有内核空间的虚拟地址和目标进程用户空间的虚拟地址.发送进程通过BC_TRANSACTION命令将需要传送的数据拷贝到目标进程的内核缓冲区后,目标进程就可直接从内核缓冲区中读取数据,以达到一次拷贝就实现IPC的目的.根本原理是内核空间的内存共享,及多个进程可以共享内核空间的内存.
binder驱动最多给进程分配4M的内核缓存区来传送进程间通信的数据,如果传送的数据大于4M将被截断,控制的地方位于:
./drivers/android/binder.c的内存映射方法
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
...略...
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
...略...
}
这最大4M的内核缓存区,只能由binder驱动在内核空间写入,用户空间只可以读.
Binder机制的实现非常复杂,今天只是简单介绍其驱动的实现,后续深入研究后再做总结.