1 为什么需要跨进程通信
首先同一个程序中之所以两个函数之间能够直接调用,其根本原因是它们处于相同的内存空间中,虚拟地址的映射规则完全一致。反之不同进程之间它们没办法通过内存地址来直接访问到对方内部的函数或者变量。
2 为什么采用Binder
常用的IPC机制有管道、Socket、共享内存等,那么Android中为什么要建立一套新的IPC机制?
1 开销问题
socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制复杂,难以使用。
2 安全问题
传统IPC没有任何安全措施,完全依赖上层协议来确保。首先传统IPC的接收方无法获得对方进程可靠的UID和PID(用户ID进程ID),从而无法鉴别对方身份。Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志。使用传统IPC只能由用户在数据包里填入UID和PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。其次传统IPC访问接入点是开放的,无法建立私有通道。比如命名管道的名称,systemV的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
基于以上原因,Android需要建立一套新的IPC机制来满足系统对通信方式,传输性能和安全性的要求,这就是Binder。Binder基于Client-Server通信模式,传输过程只需一次拷贝,为发送发添加UID/PID身份,既支持实名Binder也支持匿名Binder,安全性高。
3 Binder跨进程通信原理
mmap()的返回值是内存映射在用户空间的地址,不过这段空间是由驱动管理,用户不必也不能直接访问(映射类型为PROT_READ,只读映射)。进程A通过copy_from_user()将数据拷贝到binder_proc->buffer所指向的内存空间中,而因为binder_proc->buffer在物理内存中的位置和进程B是共享的,因此进程B可以直接访问到这段数据,从而实现了进程间的数据共享。