http://blog.sina.com.cn/s/blog_5377f4930100pe01.html
最近看了android上的两种进程间通信的方式,做了个对比:
DBUS实现了一种进程间以及进程与内核间的通信的模型。Bus Daemon从源进城接收消息并且转发到目标进城;目标进城可以通过匹配机制只监听感兴趣的消息。简单调研后,目前认为DBUS是一种有中心的结构,即所有的消息都要集中到Bus Daemon转发。
Bluez采用DBUS解决了:1. 多个蓝牙服务进程间通信的问题 2. 多客户端(应用程序进程)和蓝牙通信的问题
我们蓝牙协议栈的架构区别于Bluez的架构,它采用的是单用户态进程,没有多个蓝牙服务进程间通信的问题,但同样具有多个客户端如何访问蓝牙服务的问题。
BINDER是ANDROID上内建的IPC机制,JAVA层和C++层都在使用该通信机制。
它是一种一对一的IPC机制,如上图所示,进程A和进程B之间进行通信需要通过Context得到Service B的代理对象(从BpBinder类继承)。由于之前进程B曾经向Context注册Service B服务,所以此时代理对象知道他的实现对象(从BnBinder类继承)在哪个进程。
获得代理对象后进程A就可以像完全在自己的进程一样调用Service B提供的服务接口了,执行过程是进程A通过代理对象把数据组装成两个进程约定的格式保存到内核态的一块连续的内存中(Linux共享内存机制),并通知进程B。
进程B首先会在主线程中从前面说的共享内存中提取数据并解析成服务类的成员函数和参数进行调用,如果主线程忙,则Binder会通知进程B 创建另外一个线程处理该呼叫,最大创建15个线程。
进程A发起呼叫后阻塞,等待函数的放回。所以BINDER是一种同步的IPC机制. 等待与否可以有发起呼叫的进程设定, 除非不需要返回值或者返回参数,否则发起呼叫的进程必须阻塞。
JAVA层的binder机制和C++层的binder机制一样是建立在前面所述的处理基础上,只是做了语言的转换。另外JAVA层可以用AIDL定义两个进程间通信的接口,并按照固定的规则转换出数据打包和拆包的函数。这些都是通过工具自动完成的,大大减少编程中枯燥无味的工作。
比较项 指标 | DBUS | Binder |
大数据传输 | 性能一般,因为数据要拷贝 | 性能高,因为共享内存只改变映射,无内存拷贝 |
反映速度 | 好 | 好 |
底层机制 | Socket | Share Memory |
组网方式 | 多对多 | 一对一 |
语言支持(仅限Android平台) | C | C++ 和JAVA |
第三方参与 | Dbus-Daemon全程参与 | Service Manager, 仅参与服务获取 |
通信方式 | Signal, method call, method return, error messages | Method return, Link to death |
寻址方式 | 对象路径注册,表格函数指针,如/org/cups/printer… | 在Host进程注册服务,函数解析(JAVA层有工具) |
安全 | Authentication机制,复杂 | UID检查,简单,Android采用 |
面向对象 | 否 | 是 |
应用层开发 | 不支持 | 支持 |
代码大小 | Dbus + glib(简化版) | 已内建 |
设计蓝牙架构需要讨论
1)进程模型
2)服务是否在中间层提供
3)中间层服务的实现方式
4)多客户端实现方式
5) 接口异步化处理 (主要为了防止占用SYSTEM SERVER过长时间,导致界面无响应)。
进程模型有两种:独立的蓝牙进程、融入SYSTEM SERVER进程;中间层层服务的实现方式有两种:DBUS SERVER和BINDER SERVER; 多客户端得实现方式有两种: DBUS由下而上、JAVA层BINDER服务。接口的异步化处理有三种:在应用程序起后台线程、在JAVA 蓝牙服务起后台线程、有本地蓝牙服务起后台线程。