文章目录

  • 一、Binder是什么?
  • 二、使用案例
  • 1.服务端
  • 2.客户端
  • 三、细节



一、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();
}

线程分析:

  1. joinThreadPool()函数使得线程进入内核态,并进入阻塞状态,等待客户端发送消息来唤醒
  2. Binder驱动采用红黑树(RB Tree),来保存binder_node的token与Process信息
  3. 本地的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();
}

线程分析:

  1. 客户端通过BpBinder发送Parcel消息
  2. 内核根据Parcel中的token信息,在红黑树中查找对应的binder_node
  3. 根据binder_node,找到BnBinder所在的Process
  4. 查找Process中处于空闲状态的阻塞监听Thread,并唤醒该Thread
  5. 唤醒的Thread开始解析Parcel包,根据字段中的内容找到对应的BnBinder,并调用BnBinder的对应函数

三、细节

根据上述流程,我们可以得出binder的以下特性

  1. 服务端的BnBinder与binder监听线程数量上没有关系,服务端可以拥有多个线程监听客户端发送的消息,也可以多个服务公用一个监听线程。
  2. 因为binder驱动会寻找空闲的监听线程来处理客户端发送消息,因此启动多个监听线程可以提高多个客户端通讯时的吞吐量。