- Binder的定义
- 从机制和模型角度来说,Binder是一种Android中实现跨进程通信的Binder机制模型。
- 从模型的结果和组成来说,Binder是一种虚拟的物理设备驱动,链接Service,Client,ServiceManager进程。
- 从Android的代码来说,Binder实现了IBinder接口 是一个类Binder类。
- Android中采用Binder实现IPC的理由分析
- 从性能角度来说,数据拷贝一次。其他的socket 管道消息队列都需要进行两次拷贝。
- 稳定行来说:Binder是c/s架构的 相对来说客户端和服务端相对独立,稳定性比较好。例如共享内存这些比较复杂一些了
-安全性角度:可靠的身份标记只有有IPC机制本身的内核中添加,从安全角度来说Binder更安全一些。像是传统的Linux IPC的接收方无法获取对方进程可靠的UID、PID从来无法鉴别对方的身份。
- IPC的原理
对于用户空间 不同进程之间彼此是无法共享的,而内核空间是可以空想的,Client进程向Server进程通信,就是利用进程间可共享的内核存储空间,Client和Server端进程采用ioctl等方法跟内核空间的驱动进行交互。
4.Binder原理
Binder通信主要包含Client,Server ServiceManager以及binder驱动,ServiceManager管理系统中的各种服务的。
无论是注册服务和获取服务,都需要ServiceManager 此处的ServiceManager是Native层的ServiceManager不是framework层的 ServiceManager是Binder通信机制中大管家,是android进程间通信机制的Binder的守护进程,
图中的三大步骤
- 注册服务(addService):service进程先注册Service到ServiceManager,这个过程中,Server是客户端,ServiceManager是服务端。
- 获取服务(getService):Client进程要使用某个服务向ServiceManager获取服务,Client是客户端,ServiceManager是服务端。
- 使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,这个过程Client是客户端,Server是服务端。
Client,Server,ServiceManger之间交互使用的虚线表示,因为他们不是接交互,而是通过,Binder驱动进行交互的ioctl
Android Binder架构
Zygote 孵化出system_server 进程后,再system_server中初始化支持整个Android framework各种各样的service,有java层的 framework层的Native层的,几乎都是基于Binder IPC机制。
- java framework:作为Server端 继承于Binder类。Client继承与BinderProxy类,例如ActivityManagerService整个服务作为Server端,进阶继承Binder类。相应的ActivityManager作为Client端间接继承了BinderProxy类,还有PackageManagerService,WindowManagerService 等很多系统服务都是C/S架构的。
- Native Framework层:C++层作为Server端继承BBinder类,Client端继承BpBinder 例如:MediaPlayService作为服务端继承BBinder类,Mediapaly作为客户端,间接继承BpBinder类。
Binder 通信模型
- Binder驱动是通信的核心,工作与内核,提供open(),mmap(),poll(),ioctl()等标准文件操作。
- Binder协议
Binder协议基本格式是:命令+数据使用ioctl 函数实现交互。
BINDER_WRITE_READ:这个命令想Binder写入或读取数据,write_size不为0就先将write_buffer里的数据写入Binder;如果read_size不为0再从Binder中读取数据存入read_buffer中.write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数
Binder内存映射和接受缓存区管理
传统的IPC方式中,数据是怎样从发送端到达接收端的呢?通常的做法是,发送方将准备好的数据存放在缓存区中,调用API通过系统调用进入内核中.内核服务程序在内核空间分配内存,将数据从发送方缓存区复制到内核缓存区中.接收方读数据时也要提供一块缓存区,内核将数据从内核缓存区拷贝到接收方提供的缓存区中并唤醒接收线程,完成一次数据发送.这种存储-转发机制有两个缺陷:首先是效率低下,需要做两次拷贝:用户空间->内核空间->用户空间.Linux使用copy-from-user()和copy-to-user()实现这两个跨空间拷贝,在此过程中如果使用了高端内存(high memory),这种拷贝需要临时建立/取消页面映射,造成性能损失.其次是接收数据的缓存要由接收方提供,可接收方不知道到底要多大的缓存才够用,只能开辟尽量大的空间或先调用API接收消息头获得消息体大小,再开辟适当的空间接收消息体.两种做法都有不足,不是浪费空间就是浪费时间.
Binder采用一种全新策略:由Binder驱动负责管理数据接收缓存.我们注意到Binder驱动实现了mmap()系统调用,这队字符设备比较特殊的,因为mmap()通常用在有物理存储介质的文件系统上,而像Binder这样没有物理介质,纯粹用来通信的字符设备没必要支持mmap().Binder驱动当然不是为了在物理介质和用户空间做映射,而是用来创建数据接收的缓存空间。
大致流程:
1.Binder驱动创建一块接受缓存区。
2.实现地址映射关系:根据需要映射的接受进程信息,实现内核缓存区和接受进程用户地址空间 同时映射到另个一个共享接受缓存区中。
3.发送进程通过系统调用copy_from_user()发送数据到虚拟内存区域(数据拷贝一次)
4.由于内核缓存区与接收进程的用户空间地址存在映射关系(同时映射Binder创建的接收缓存区中),故相当于也发送到了接收进程的用户空间地址,即实现了跨进程通信。