Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动。架构图如下所示:
图中的Client,Server,Service Manager之间交互都是虚线表示,是由于它们彼此之间不是直接交互的,而是都通过与Binder驱动进行交互的,从而实现IPC通信方式。
关于Binder驱动设备
这部分涉及到Linux设备驱动的开发,如有兴趣可参考Binder系列1—Binder Driver初探。这里仅简单阐述Binder驱动的原理。
binder作为虚拟设备,没有直接操作硬件,只是对设备内存的处理。主要完成以下几件事
- 初始化(binder_init):创建/dev/binder设备节点
- 打开 (binder_open):获取Binder Driver的文件描述
- 映射(binder_mmap):内核中分配内存,用于存放数据
- 数据操作(binder_ioctl):将IPC数据作为参数传给Binder Driver
binder_open创建了一个对象保存当前进程信息,并将这个对象加入一个全局链表。
binder_mmap首先在内核虚拟地址空间,申请一块与用户虚拟内存相同大小的内存;然后再申请1个page大小的物理内存,再将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,从而实现了用户空间的Buffer和内核空间的Buffer同步操作的功能。
经常听说Binder进程间通信的高效率,正是源于binder_mmap。通过Binder进行进程间通信时,只会发生一次内存拷贝。因为,当Client端与Server端发送数据时,Client先从自己的进程空间把IPC通信数据拷贝到内核空间,而Server与内核共享数据,不再需要拷贝数据,而是通过内存地址空间的偏移量,即可获悉内存地址,整个过程只发生一次内存拷贝。
binder_ioctl负责在两个进程间收发IPC数据和IPC reply数据。
关于ServiceManager
- 本身也是一个的Server
- 主要职责是管理其他Server
- 是Binder机制的守护进程
ServiceManager启动流程:
- 打开binder驱动,并调用mmap()方法分配128k的内存映射空间
- 通知binder驱动使其成为守护进程
- 进入循环状态,等待Client端的请求
ServiceManager可以做什么:
- 注册服务(addService)
- 验证selinux权限,判断进程是否有权注册或查看指定服务
- 如果服务已注册,则不再添加
- 注册服务时,普通服务时作为Client,ServiceManager作为Server
- 获取服务(getService)
- Client首先获取ServiceManager
- 再通过字符串名称来查找对应的Service
-
defaultServiceManager()
是一个单例模式,用于获取ServiceMananger
总结
到此为止,已经基本讲明了ServiceManager和Binder。如果对于一个普通的Server怎么注册和被获取感兴趣,还可继续阅读Binder系列5—注册服务(addService)
和Binder系列6—获取服务(getService)