Binder进程通信的基本原理

Binder进程通信的基本原理

基础
  • Binder是基于linux驱动设备的,所以我们可以把Binder驱动当做文件设备打开
  • mmap 系统调用用于把一个设备或者文件的内存映射到自己应用程序的内存空间中
  • A进程对Binder执行mmap调用,然后A内存空间中就有Binder的地址,即A中可以修改Binder中内存的值,当然Binder中的修改也会影响到A,于是当Binder去拷贝另一个应用程序B的一部分内存到自己的内存空间时(Bidner的内存空间),A就可以直接访问到拷贝过来的B的内存空间了,间而实现了AB的内存通信

ProcessState

ProcessState是进程单例的,会去打开/dev/binder驱动,并且mmap到当前进程的内存空间
一个进程开始的时候就会初始化一个ProcessState,然后就会去开始binder线程池循环等待指令到来

IPCThreadState

IPCThreadState是线程单例,会去和binder驱动直接交互

BpBinder

Binder的代理对象,其中主要就是持有mHandle(编号),在和Binder驱动交互的时候使用mHandle来寻找Binder服务,对应native层的Binder

Binder驱动

  • binder_proc
    在Binder驱动中,有一个binder_proc的链头的通过binder_proc队列持有了所有的binder,相当于每一次的binder_open的时候就会创建一个binder_proc表示当前的binder进程,并且把它添加到Binder驱动红黑树上。
    相当于每一次我们的进程打开的binder驱动就会获得驱动上面的所有binder服务所组成的链表,而我们发起IPC的时候,就会根据binder服务的编号进行寻找,然后就会去发起数据传递(就是修改binder驱动内存中的值)然后循环等待反馈。对应的binder服务端则会在服务注册的时候就一直循环等待客户端的连接。

  • binder_ioctl
    binder_ioctl()函数负责在两个进程间收发IPC数据和IPC reply数据。

  • binder thread pool
    Binder线程池在进程frok出来就会运行起来,即等待客户端的连接,但这个时候可能binder service并没有注册。
    binder驱动找到对应的service需要的进程service名字方法标记

思想

在一块大家都可以访问的内存中进行数据和指令的交换,而不同进程中主要靠thread的循环等待指令(事件驱动),但是这样交互很繁杂,所以又抽离出了一个manager(ServiceManager)

每一个进程开始的时候都会进行ProcessState的初始化,会去打开驱动,并提供接口去获取mHandle=0Binder,同时也会让自己的Binder线程池循环起来。

binder的调动的是阻塞的,阻塞的原理还是循环。所以客户端的binderIPC请求最好放到子线程去执行。

推荐阅读更多精彩内容