Binder 总体架构概述(一)

627 阅读4分钟

背景

Binder是Android进程间的一种通信方式,属于C/S架构。 Android系统的底层基于Linux内核。相对与传统的IPC方式,Binder在效率上 有显著的优势。通过Binder来实现进程间通信本质上是通过Binder驱动来完成的。

Binder Driver将自己注册为一个misc device(杂项设备),并向上层提供驱动节点:dev/binder。 这种"杂项"设备不是真正的物理 硬件设备,而是虚拟驱动。它运行在内核态中,提供open()、mmap()、ioctl()等常用操作。

Binder通信涉及到四个部分:

  1. Server: 提供接口服务的具体实现;向ServiceManager(SM)注册服务。
  2. Client: 从SM获取服务,调用服务提供的接口。
  3. ServiceManager: Binder大管家。管理binder相关的服务。提供注册、查询服务等接口
  4. Binder驱动: 本质上实现跨进程通信。

架构图.png

一、Android为什么要采用Binder机制

Linux本身提供了多种多进程的通信方式: 管道、信号量、队列、socket、共享内存

  • 管道:只能单向通信。 进程A到管道一次拷贝,管道到进程B一次拷贝,总共两次拷贝(用户->内核->用户)。
  • 信号量:一般作为进程间的同步锁来使用。
  • 信号:一般是用来内核给应用发送某个信号通知,如非法访问某个内存地址、杀死进程信号。
  • 队列:进程A到队列一次拷贝,队列到进程B一次拷贝,总共两次拷贝(用户->内核->用户)。
  • socket: 通信效率较低,开销大。分为本机基于fd的socket低速通信,和基于网络的tcp/udp的socket。需要两次拷贝。
  • 共享内存:让两个进程映射到同一个内存缓冲区,实现共享,无需拷贝。但是需要自己维护同步过程,复杂且难用。
  • Binder:通过mmap映射机制,让应用进程可以直接访问内核内存,减少了一次拷贝。效率仅次于共享内存。

二、C/S 角度

Binder通信过程中涉及到了多个C/S场景:

  • 一般情况下是client作为客户端,server作为服务端。
  • 当注册服务时,Server作为client端,SM作为server端。
  • 当获取服务时,client作为客户端,SM作为服务端。

三、分层角度

3.1 java层

涉及到的类:

假设定义一个IHelloService.aidl文件,经过编译会生成IHelloService.java文件。 通信过程如下:

  • Server:
  1. HelloService继承内部抽象类Stub,实现接口sayHello()
  2. 调用ServiceManager.addService方法,注册服务到ServiceManager
  • Client:
  1. client通过ServiceManager获取到Server的本IBinder对象
  2. 通过调用IHelloService.asInterface(IBinder obj) 转换成一个IHelloService本地对象。
  3. 调用接口sayHello()完成跟服务端通信

client和server整个过程涉及到类图 :

img.png

重点:

Proxy中的mRemote其实是一个BinderProxy对象。BinderProxy的mNativeData指向的是一个c++ 层的Binder对象,实际上一个BpBinder

ServiceManager类相关的类图:

img_1.png

重点:

ServiceManagerProxy中的mRemote是一个binderProxy对象。BinderProxy的mNativeData指向的是一个c++ 层的Binder对象,实际上一个BpBinder

3.2 c++层

java层把数据封装好后,通过BinderProxy中的native指针,把数据传到了c++层。 从client客户端角度出发,会有BpBinder对象来完成接下来的操作。

总体上来讲就算没有java层,c++层完全可以实现客户端和服务端通过Binder驱动来完成通信。因此,进程通信的核心逻辑应该在c++层。里面肯定会涉及到ioctl()、open()、mmap()等系统调用的操作。

ServiceManager类图如下:

image.png

BpRefBase 类里面有一个IBinder *指针 类型的成员变量 mRemote。 mRemote指向了一个BpBinder对象, BpBinder里面含有一个mHandle成员变量。

HelloService相关类图:

image.png

3.3 内核驱动层

image.png

这个已经很清晰表明了内核中发生的事情。Binder驱动作为一个misc “杂项驱动”,它会在系统初始化阶段把binder_open()、binder_ioctl()、binder_mmap() 等函数完成注册。当用户态调用open进入到内核中,内核会直接调用之前注册好的驱动函数。

在内核态,对于每一个进程都会创建一个binder_proc与之对应。binder_proc中会有binder_buffer。这一块buffer缓冲区就是通过mmap()映射而来,因此,只要Client把数据copy_from_user()buffer,然后通知server直接读取buffer中的数据即可。

最后

Binder机制非常的复杂,以上只是简单的架构的角度来大体熟悉了binder机制分层思想,如有错误之处还请指正。后续将对每个层的细节进行解析。

参考:

gityuan.com/2015/11/02/…

blog.51cto.com/u_14344871/…