一、Binder是什么?
Binder是Android采用的一种实现跨进程通讯的模块。
是一种CS模型的通讯方法,利用共享内存的机制提高通讯效率。
二、使用案例
1.服务端
代码如下(示例):
int main(int argc, char **argv)
{
/* 打开binder设备节点,配置进程唯一的ProcessState */
sp<ProcessState> ps(ProcessState::self());
/* 开启一个线程,不断阻塞等待客户端发过来的Parcel消息 */
ps->startThreadPool();
/* 建立一个BnBinder的Service,并把它注册到ServiceManager中,使服务为实名Binder */
sp<SurfaceFlinger> flinger = DisplayUtils::getInstance()->getSFInstance();
sp<IServiceManager> sm(defaultServiceManager());
sm->addService("surfaceFlinger", flinger, false);
/* 主线程没有用了,也把它加入到Binder线程中,阻塞等待客户端发过来的Parcel消息 */
IPCThreadState::self()->joinThreadPool();
}
线程分析:
- joinThreadPool()函数使得线程进入内核态,并进入阻塞状态,等待客户端发送消息来唤醒
- Binder驱动采用红黑树(RB Tree),来保存binder_node的token与Process信息
- 本地的BnBinder创建强引用时,会在内核红黑树中添加自身的binder_node信息
2.客户端
代码如下(示例):
int main(int, char**)
{
/* 根据服务的名字,获取到服务的代理,也就是BpBinder */
sp<IServiceManager> sm(defaultServiceManager());
sp<IBinder> bpbinder = sm->getService("surfaceFlinger");
sp<ISurfaceComposer> flinger = interface_cast<ISurfaceComposer>(bpbinder);
/* 通过代理,调用函数,发送Parcel给服务端,服务端解析到命令后,就会执行对应的函数 */
flinger->func();
}
线程分析:
- 客户端通过BpBinder发送Parcel消息
- 内核根据Parcel中的token信息,在红黑树中查找对应的binder_node
- 根据binder_node,找到BnBinder所在的Process
- 查找Process中处于空闲状态的阻塞监听Thread,并唤醒该Thread
- 唤醒的Thread开始解析Parcel包,根据字段中的内容找到对应的BnBinder,并调用BnBinder的对应函数
三、细节
根据上述流程,我们可以得出binder的以下特性
- 服务端的BnBinder与binder监听线程数量上没有关系,服务端可以拥有多个线程监听客户端发送的消息,也可以多个服务公用一个监听线程。
- 因为binder驱动会寻找空闲的监听线程来处理客户端发送消息,因此启动多个监听线程可以提高多个客户端通讯时的吞吐量。