8.7Binder通信机制设计
目录介绍
- 01.什么是Binder
- 02.为什么要使用Binder
- 03.Binder如何进行线程管理
- 04.Binder的工作流程
- 05.Binder通信机制原理
- 06.Binder运行机制
- 08.举例说明Binder通信
01.什么是Binder
- 1.直观来说,Binder是Android中的一个类,它继承了IBinder接口。
- 2.从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在linux中没有
- 3.从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁
- 4.从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
02.为什么要使用Binder
- 在传统的Linux上,我们还是有很多选择可以用来实现进程间通信
- 如管道、SystemV、Socket等。那么Android为什么不使用这些原有的技术,而是要使开发一种新的叫Binder的进程间通信机制呢?
- 最简单的回答:
- 性能:相比传统的Socket更高效;安全:安全性高,支持通信双方进行身份验证。
- 详细一点说,主要有两个方面的原因:
- 性能方面
- 在移动设备上(性能受限制的设备,比如要省电),广泛地使用跨进程通信对通信机制的性能有严格的要求,Binder相对出传统的Socket方式,更加高效。
- Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,共享内存方式一次内存拷贝都不需要,但实现方式又比较复杂。
- 安全方面
- 传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造。
- 而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。
- 还有一些好处,如实现面象对象的调用方式,在使用Binder时就和调用一个本地实例一样。
- 性能方面
- 为何说Binder相比传统的Socket性能更高效?
- 跨进程通讯中,只有socket支持Client-Server的通信方式,但是socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。
- 消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。
- 共享内存虽然无需拷贝,但控制复杂,难以使用。
- 为何说Binder相比传统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,安全性高。
03.Binder如何进行线程管理
- Binder中是如何进行线程管理的?
- 每个Binder的Server进程会创建很多线程来处理Binder请求,可以简单的理解为创建了一个Binder的线程池吧(虽然实际上并不完全是这样简单的线程管理方式),而真正管理这些线程并不是由这个Server端来管理的,而是由Binder驱动进行管理的。
- 一个进程的Binder线程数默认最大是16,超过的请求会被阻塞等待空闲的Binder线程。理解这一点的话,你做进程间通信时处理并发问题就会有一个底,比如使用ContentProvider时(又一个使用Binder机制的组件),你就很清楚它的CRUD(创建、检索、更新和删除)方法只能同时有16个线程在跑。
- 总结binder讲的是什么?
- 通常意义上来说,Binder就是指Android的通信机制;
- 对于服务端进程来说,Binder指的是Binder本地对象,对于客户端进程来说,Binder指的是Binder代理对象。
- 对于传输过程来说,Binder是可以进行跨进程传递的对象;
04.Binder的工作流程
- Binder的工作流程是怎样的?
- 1客户端首先获取服务器端的代理对象。所谓的代理对象实际上就是在客户端建立一个服务端的“引用”,该代理对象具有服务端的功能,使其在客户端访问服务端的方法就像访问本地方法一样。
- 2客户端通过调用服务器代理对象的方式向服务器端发送请求。
- 3代理对象将用户请求通过Binder驱动发送到服务器进程。
- 4服务器进程处理用户请求,并通过Binder驱动返回处理结果给客户端的服务器代理对象。
- 5客户端收到服务端的返回结果。
- binder工作流程图如下所示:
image
- Binder主要能提供哪些功能?
- 用驱动程序来推进进程间的通信。
- 通过共享内存来提高性能。
- 为进程请求分配每个进程的线程池。
- 针对系统中的对象引入了引用计数和跨进程的对象引用映射。
- 进程间同步调用。
05.Binder通信机制原理
image - Server进程向ServiceManager注册,告诉ServiceManager我是谁,我有什么,我能做什么。就好比徐同学(Server进程)有一台笔记本(computer对象),这台笔记本有个add方法。这时映射关系表就生成了。
- Client进程向ServiceManager查询,我要调用Server进程的computer对象的add方法,可以看到这个过程经过Binder驱动,这时候Binder驱动就开始发挥他的作用了。当向ServiceManager查询完毕,是返回一个computer对象给Client进程吗?其实不然,Binder驱动将computer对象转换成了computerProxy对象,并转发给了Client进程,因此,Client进程拿到的并不是真实的computer对象,而是一个代理对象,即computerProxy对象。很容易理解这个computerProxy对象也是有add方法,(如果连add方法都没有,岂不是欺骗了Client?),但是这个add方法只是对参数进行一些包装而已。
- 当Client进程调用add方法,这个消息发送给Binder驱动,这时驱动发现,原来是computerProxy,那么Client进程应该是需要调用computer对象的add方法的,这时驱动通知Server进程,调用你的computer对象的add方法,将结果给我。然后Server进程就将计算结果发送给驱动,驱动再转发给Client进程,这时Client进程还蒙在了鼓里,他以为自己调用的是真实的computer对象的add方法,其实他只是调用了代理而已。不过Client最终还是拿到了计算结果。
06.Binder运行机制
- Binder基于Client-Server通信模式,除了Client端和Server端,还有两角色一起合作完成进程间通信功能。
- Binder通信的四个角色:
- Client进程:使用服务的进程。
- Server进程:提供服务的进程。
- ServiceManager进程:ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
- Binder驱动:驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
- 接触这些概念可能会觉得难于理解,读者可以把四个角色和熟悉的互联网进行类比:
- Server是服务器,Client是客户终端,ServiceManager是域名服务器(DNS),驱动是路由器。
08.举例说明Binder通信
- 我们知道应用进程与SystemServer进程属于两个不同的进程,进程之间需要通讯。举例子比如说:AMS通信
- android系统采取了自身设计的Binder机制,这里的ActivityManagerProxy和ActivityManagerNative都是继承与IActivityManager的而SystemServer进程中的ActivityManagerService对象则继承与ActivityManagerNative。
- 简单的表示:Binder接口 --> ActivityManagerNative/ActivityManagerProxy --> ActivityManagerService;
- 这样ActivityManagerNative与ActivityManagerProxy相当于一个Binder的客户端
- 而ActivityManagerService相当于Binder的服务端
- 这样当ActivityManagerNative调用接口方法的时候底层通过Binder driver就会将请求数据与请求传递给server端,并在server端执行具体的接口逻辑。
- 需要注意的是Binder机制是单向的,是异步的,也就是说只能通过client端向server端传递数据与请求而不同等待服务端的返回,也无法返回,
- 那如果SystemServer进程想向应用进程传递数据怎么办?这时候就需要重新定义一个Binder请求以SystemServer为client端,以应用进程为server端,这样就是实现了两个进程之间的双向通讯。