一.Binder是Android系统进程间通信(IPC)方式之一。 为何选择binder呢?
1)数据拷贝次数少:肯定会有人问为何不用共享内存?虽然共享内存无需拷贝,但控制复杂,难以使用。
2)Client-Server的通信方式:c/s模式开发效率高,应用广泛。目前linux支持的IPC包括传统的管道/消息队列/共享内存/信号量,以及socket中只有socket支持Client-Server的通信方式。当然也可以在这些底层机制上架设一套协议来实现Client-Server通信,但这样增加了系统的复杂性,在手机这种条件复杂,资源稀缺的环境下可靠性也难以保证。socket传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信.
3)safe. 传统IPC完全依赖上层协议来确保安全。首先传统IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份。Android为每个安装好的应用程序分配了自己的UID(进程的UID是鉴别进程身份的重要标志)。使用传统IPC只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。其次传统IPC访问接入点是开放的,无法建立私有通道。比如命名管道的名称,消息队列/共享内存/信号量 的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,很难阻止恶意程序通过猜测接收方地址获得连接。
so. Android 选择了Binder。Binder基于Client-Server通信模式,传输过程只需一次拷贝,为发送发添加UID/PID身份,既支持实名Binder也支持匿名Binder,安全性高。
二、binder组成(也可以理解成模型)
Binder由Server,Client,ServiceManager以及Binder驱动组成。其中Server,Client,ServiceManager运行于用户空间,Binder驱动运行于内核空间。关系和互联网类似:Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),驱动是路由器。
Client 可以手动调用 Driver 的 transact 接口,也可以通过 AIDL 生成的 Proxy 调用。Server 中会启动一个线程池来处理 Client 的调用请求,处理完成后将结果返回给 Driver,Driver 再返回给 Client,Service 中通过 AIDL 提供的接口并不是线程安全的,同理 ContentProvider 底层也是使用 Binder,同样不是线程安全的,why.线程池不是线程安全的。如果业务需要。最好是做好多线程同步。
三、传送过程及其他
BpBinder是client端创建的用于消息发送的代理,而BBinder是server端用于接收消息的通道。查看各自的代码就会发现,虽然两个类型均有transact的方法,但是两者的作用不同,BpBinder的transact方法是向IPCThreadState实例发送消息,通知其有消息要发送给BD;而BBinder则是当IPCThreadState实例收到BD消息时,通过BBinder的transact的方法将其传递给它的子类BnSERVICE的onTransact函数执行server端的操作。
其中代理的过程也可以理解成一种hook,binder驱动的hook。
1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
4.代理接口将该Parcel发送给内核中的binder driver.
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。