理解 Binder 机制
以下文章参考 https://zhuanlan.zhihu.com/p/35519585,《Android艺术开发探索》
首先像声明,Binder 的复杂程度肯定不是一篇文章能说清楚的,之所以写这篇文章,是在博客,书上学习到后,能让自己有一个概念,希望深入理解 Binder 的可以自行参考网上文章。
什么是 Binder?
我的理解就是:是一种进程间的通讯机制
为什么是 Binder?
大家都知道,Android 是基于 Linux 内核开发的,Linux 本身就提供了多种进程间通讯的机制,如管道(Pipe)、信号(Signal)、消息队列(Message)、共享内存(Share Memory)和 Socket 等
原因:
其他通信方式存在 安全性,性能等问题
性能:
Socket 作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制复杂,难以使用。Binder 只需要一次数据拷贝,性能上仅次于共享内存。
进程间通讯方式 | 拷贝次数 |
---|---|
管道 | 2 |
消息队列 | 2 |
Socket | 2 |
Binner | 1 |
共享内存 | 0 |
安全性:
传统 IPC 接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),从而无法鉴别身份,而Binder机制为每个进程分配了UID/PID且在Binder通信时会根据UID/PID进行身份鉴别
基本的跨进程概念
-
进程隔离:
进程与进程间内存是不共享的 -
进程空间划分:用户空间(User Space)/内核空间(Kernel Space)
内核空间(Kernel)是系统内核运行的空间,用户空间(User Space)是用户程序运行的空间。为了保证安全性,它们之间是隔离的。 -
系统调用:用户态/内核态
当一个任务(进程)执行系统调用而陷入内核代码中执行时,称进程处于内核运行态(内核态)
当进程在执行用户自己的代码的时候,我们称其处于用户运行态(用户态)
系统调用主要通过如下两个函数来实现:
copy_from_user() :将数据从用户空间拷贝到内核空间
copy_to_user() :将数据从内核空间拷贝到用户空间
传统IPC原理
- 发送方将要发送数据的放在用户空间内存缓存区
- 调用 copyfromuser() 函数将数据从用户空间的内存缓存区拷贝到内核空间的内核缓存区中
- 接收方进程在接收数据时在自己的用户空间开辟一块内存缓存区
-
内核程序调用 copytouser() 函数将数据从内核缓存区拷贝到接收进程的内存缓存区
image
Binder IPC 底层通讯原理
IPC 过程
- Binder 驱动创建一块数据接收缓存区
- 在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
-
发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
image
Binder 实现层
首先我们应该知道 Binder 是 C/S 架构,他的组成主要有 Client、Server、ServiceManager, Binder 驱动 ,其中 Client、Server、ServiceManager 是运行在 用户空间层,而 Binder 驱动 自然是内核层了。
通信过程
- 首先,一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager
- Server 向 Service Manager 中注册 Binder (Server 中的 Binder 实体)表明可以对外提供服务
- Client 向 Service Manager 获取到对Binder 实体的引用
- 通过这个引用实现 Client 和 Server 的进程通信
Binder 通信中的代理模式
由上面我们知道了 跨进程通信是借住了 Binder 驱动完成的,由于 Client 和 Server 是两个不同的进程,当 Client 想要 Server 某个对象的话,是没办法直接使用的。所以既然跨进程是借住 Binder 驱动 完成的,因此在数据经过 Binder 驱动的时候驱动会对数据进行一层转换,当 A 进程想要获取 B 进程的 object 时,驱动并不会把真正的 object 返回给 A ,而是返回一个跟 object 看起来一模一样的代理对象 objectProxy ,这个 objectProxy 具有和 object 一摸一样的方法,但是这些方法并没有 B 进程中 object 对象那些方法的能力,这些方法只需要把请求参数交给驱动即可。对于 A 进程来说和直接调用 object 中的方法是一样的。
Binder 的定义
现在我们可以对 Binder 做个更加全面的定义了:
- 从进程间通信的角度看,Binder 是一种进程间通信的机制;
- 从 Server 进程的角度看,Binder 指的是 Server 中的 Binder 实体对象;
- 从 Client 进程的角度看,Binder 指的是对 Binder 代理对象,是 Binder 实体对象的一个远程代理
- 从传输过程的角度看,Binder 是一个可以跨进程传输的对象;Binder 驱动会对这个跨越进程边界的对象对一点点特殊处理,自动完成代理对象和本地对象之间的转换。