一.什么是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的服务
二.为什么要使用Binder呢?
我们都知道进程中通信的方式有好多种:比如 管道 SystemV Socket等 那么我们为什么又要重新开发Binder这个供进程间通信机制呢?
主要原因有两个方面:
1.性能方面
在移动设备上(性能受限制的设备,比如要省电),广泛地使用跨进程通信对通信机制的性能有严格的要求,Binder相对出传统的Socket方式,更加高效。Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,共享内存方式一次内存拷贝都不需要,但实现方式又比较复杂。
2.安全方面
传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易被伪造。而Binder机制从协议本身就支持对通信双方做身份效验,因而大大提升了安全性。
三 Binder 的线程管理
每个Binder的Server进程会创建很多线程来处理Binder请求,可以简单的理解为创建一个Binder的线程池 虽然实际上并不完全是这样简单的线程管理方式,但其实上真正管理只写线程并不是由这个Server端来管理的,而是由Binder驱动进行管理的
一个线程的Binder线程数默认最大是16,超过请求会被阻塞到等待空闲的Binder线程。
我们的ContentProvider(内容提供者)它的CRUD (创建,检索,更新和删除) 方法只能同时又16个线程在运行
四 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),驱动是路由器。
附一张具体的流程图:
虽然说不是很好理解 慢慢摸索肯定会有不一样的收获的
五 Binder的工作流程
1客户端首先获取服务器端的代理对象。所谓的代理对象实际上就是在客户端建立一个服务端的“引用”,该代理对象具有服务端的功能,使其在客户端访问服务端的方法就像访问本地方法一样。
2客户端通过调用服务器代理对象的方式向服务器端发送请求。
3代理对象将用户请求通过Binder驱动发送到服务器进程。
4服务器进程处理用户请求,并通过Binder驱动返回处理结果给客户端的服务器代理对象。
5客户端收到服务端的返回结果。
流程图:
六 实现一个Messenger的步骤
基于消息的进程间通信方式:
服务端进程
需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。
客户端进程
客户端进程中,首先绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息,发送消息的类型为Message对象。如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。
七 AIDL
AIDL文件的本质是系统为我们提供的一种快速实现Binder的工具而已
使用方法:
服务端
服务端首先要创建一个远程Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。
客户端
首先绑定服务端的Service,绑定成功后,将服务端返回的Binder对象转化成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。
AIDL文件支持的数据类型
基本数据类型;
String和CharSequence;
List:只支持ArrayList,里面每个元素都必须被AIDL支持;
Map:只支持HashMap,里面每个元素都必须被AIDL支持,包括key和value;
Parcelable:所有实现了Parcelable接口的对象;
AIDL:所有AIDL接口本身都可以在AIDL文件中使用。
Parcelable和AIDL对象无论是否和当前AIDL文件位于同一个包内,都要显式import进来。
服务端实现需要注意并发处理,可以借助Copy-On-Write容器
服务端实现监听时,监听存储容器使用RemoteCallbackList,系统专门提供用来删除跨进程listener的接口
AIDL的包结构在服务端和客户端要保持一致,否则出错,因为客户端要反序列化服务端中和AIDL接口相关的所有类,如果类的完整路径不一样的话,就无法成功反序列化。
AIDL调用服务端方法后,会挂起等待,如果服务端进行执行大量耗时操作,会导致客户端ANR。解决方法:客户端调用放在非UI线程即可。