Binder进程间通讯学习笔记 [C++层及驱动层]

基础知识

  1. binder_init()初始化binder设备
  2. binder_open()打开binder设备文件
    2.1 初始化binder_proc结构体
    2.2 将其加入到全局hash队列binder_procs中
    2.3 创建/proc/binder/proc/
  3. binder_mmap()进行内存映射
    3.1 分配内核缓冲区
    3.2 分配物理页面
    3.3 将分配的内核缓冲区加入到进程的空闲内核缓冲区红黑树中
    > 当Binder驱动程序需要将一块数据传输给进程时,可以先将数据保存在为该进程分配的一块内核缓冲区中
    > 然后在把这块内核缓冲区的用户空间地址告诉进程
    > 最后进程便可以访问到里面的数据了
  4. binder内核缓冲区管理
    4.1 分配内核缓冲区binder_alloc_buf()
    4.2 释放内核缓冲区binder_free_buf()

类结构(User space)

Server组件/BnInterface/Binder本地对象/Binder实体对象

                    +-------+                                   
                    |RefBase|                                   
                    ++----+-+                                   
                     ^    ^                                     
               +-----+-+  |  +------------+                     
               |IBinder|  +--+ProcessState|                     
               +-----+-+     +-----+------+                     
                     ^             ^                            
+---------+        +-+-----+       |                            
|INTERFACE|        |BBinder|       |                            
+-+-------+        +-+--+--+       |                            
  ^                  ^  |          |                            
  |   +-----------+  | use   +-----+--------+                   
  +---+BnInterface+--+  +--> |IPCThreadState|                   
      +-----------+          +--------------+                   

Client组件/BpInterface/Binder代理对象/Binder引用对象

                   +-------+                      +------------+
                   |RefBase| <---+----------------+ProcessState|
                   +---+----     |                ------+------+
                       ^         |   +-------+          ^       
                       |         +---+IBinder|          |       
+---------+          +-+-------+     +--+----+          |       
|INTERFACE|          |BpRefBase|        ^               |       
+----+----+          +---+---+-+        |               |       
     ^                   ^   |          |               |       
     |   +-----------+   |  has    +----+---+           |       
     +---+BpInterface+---+   +---> |BpBinder|           |       
         +-----------+             +-----+--+           |       
                                         |              |       
                                        use    +--------+-----+ 
                                         +---> |IPCThreadState| 
                                               +--------------+ 

每一个使用了Binder的进程都有一个Binder线程池。每一个Binder线程内部都有一个IPCThreadState对象,可以通过IPCThreadState的静态方法self获取,并调用它的transact和Binder驱动程序交互。transact内部是通过调用talkWithDriver函数与驱动进行交互。talkWithDriver函数既负责向Binder驱动程序发送通讯请求,也负责接受来自Binder驱动程序的通讯请求。

IPCThreadState有一个成员变量mProcess,指向一个ProcessState对象。ProcessState对象负责初始化Binder设备(打开设备文件/dev/binder、将/dev/binder映射到内存)。Binder线程池中的每一个线程都可以通过它来跟Binder驱动程序进行交互(ProcessState对象中保存着内核缓冲区的用户地址)。

即:
* IPCThreadState负责接受和发送进程间通讯请求
* ProcessState负责Binder线程和Binder驱动程序之间的交互

交互过程

                              +                            
              Client Process  |  Server Process            
                              |                            
                              |                            
                +--------+    |    +-------+               
             +-->BpBinder|    |    |BBinder+------+        
             |  +------+-+    |    +--^----+      |        
 User Space  |     (1) |      |    (3)|           |        
+-----------------------------+---------------------------+
 Kernel Space|         |      |       |           |        
             | +-------v--+  (2)  +---+-------+   |        
             | |binder_ref+---+--->binder_node|   |        
          (5)| +----------+   |   +-----------+   |(4)     
             |                |                   |        
             |       +--------v---------+         |        
             +-------+binder_transaction<---------+        
                     +------------------+                  

一次的从Client到Server的通讯过程如下所示:
(1) BpClient向Binder驱动程序发起请求,Binder驱动程序根据BpClient传过来的handler找到对应的binder_ref。
(2) Binder驱动程序根据binder_ref找到对应的binder_node,并且创建一个binder_transaction来描述这次通讯。
(3) Binder驱动程序根据binder_node找到Server进程中的BBinder,将数据传给它。
(4) BBinder处理完成后,将结果返回给Binder驱动程序,驱动程序找到前面建立的binder_transaction。
(5) Binder驱动程序根据binder_transaction找到Client进程,进而找到BpBinder,将结果传给它处理。

若以transaction来描述一次client-server通讯,则如下图所示:

+------+                 +-------------+                     +------+
|Client|                 |Binder Driver|                     |Server|
+---+--+                 +-------+-----+                     +------+
    |                            |                               |   
    |      [BC_TRANSACTION]      |                               |   
    +--------------------------> |                               |   
    |        data(Parcel)        +---------------------+         |   
    |                            | find server process |         |   
    |                            | <-------------------+         |   
    |                            |                               |   
    | [BC_TRANSACTION_COMPLETE]  |       [BR_TRANSACTION]        |   
    | <--------------------------+-----------------------------> |   
    |                            |        data(Parcel)           |   
    |                            |                               |   
    +-----------------+          |              +----------------+   
    |wait for response|          |              |  process data  |   
    | <---------------+          |              +--------------> |   
    |                            |                               |   
    |                            |          [BC_REPLY]           |   
    |                            | <-----------------------------+   
    |        +-------------------+        result(Parcel)         |   
    |        |find client process|                               |   
    |        +-----------------> |                               |   
    |                            |                               |   
    |        [BR_REPLY]          |   [BR_TRANSACTION_COMPLETE]   |   
    | <--------------------------+-----------------------------> |   
    |      result(Parcel)        |                               |   
    |                            |              +----------------+   
    |                            |              | wait for next  |   
    |                            |              +--------------> |   
    |                            |                               |   
    +                            +                               +   

ServiceManager启动过程

ServiceManager是Binder机制的核心组件之一,扮演着Binder通讯中Context Manager的角色,通过负责管理Binder系统中的Service组件,并向Client组件提供获取Service Proxy对象的服务。

ServiceManager运行在独立进程中,与其通讯需采用Binder机制,所以ServiceManager算是一个特殊的Service组件。

ServiceManager由init进程负责启动,在系统启动的时候启动:

service servicemanager /system/bin/servicemanager
    user system
    critical
    onrestart restart zygote
    onrestart restart media
  1. servicemanager以服务方式启动
  2. critical表明当服务退出时,系统会立刻重启servicemanager。
  3. onrestart参数表明,当servicemanager重启时,zygote和media也需要重启。

进程启动后,有以下三个初始化的步骤:

  1. 调用函数binder_open打开设备文件/dev/binder,以及将其映射到本进程的内存空间。
  2. 调用binder_become_context_manager将自己注册为Binder系统的context manager。
  3. 调用binder_loop来循环等待和处理Client进程的通讯请求。

获取Binder Proxy的过程

简略过程如下图所示:

+------+                 +-------------+              +-------------+
|Client|                 |Binder Driver|              |ServerManager|
+---+--+                 +-------+-----+              +----------+--+
    |                            |                               |   
    |      [BC_TRANSACTION]      |                               |   
    +--------------------------> |                               |   
    | target service name(Parcel)+-----------------------------+ |   
    |                            | find servermanager process  | |   
    |                            | <---------------------------+ |   
    |                            |                               |   
    | [BC_TRANSACTION_COMPLETE]  |       [BR_TRANSACTION]        |   
    | <--------------------------------------------------------> |   
    |                            |                               |   
    |                            |                               |   
    +-----------------+          | +-----------------------------+   
    |wait for handler |          | |[CHECK_SERVICE_TRANSACTION]  |   
    | <---------------+          | +---------------------------> |   
    |                            |                               |   
    |                            |          [BC_REPLY]           |   
    |                            | <-----------------------------+   
    |      +---------------------+      target service info      |   
    |      | create Binder Ref   |                               |   
    |      +-------------------> |                               |   
    |                            |                               |   
    |        [BR_REPLY]          |   [BR_TRANSACTION_COMPLETE]   |   
    | <--------------------------------------------------------> |   
    |      Binder Ref Handler    |                               |   
    |                            |              +----------------+   
    |                            |              | wait for next  |   
    |                            |              +--------------> |   
    +--------------------+       |                               |   
    | create Binder Proxy|       |                               |   
    | <------------------+       |                               |   
    |                            +                               +   
    |                                                                
    |           communicate with target Service                      
    +------------------------------------------------------------>   
    +                                                                
  1. Client获取ServerManager的Proxy对象。
  2. Client向ServerManager的Proxy对象请求获取目标service的handler。
  3. ServerManager根据Client传入的service名称寻找目标service的信息,生成binder_ref,返回给client。
  4. Client根据binder_ref生成proxy对象。
  5. Client和目标Service进行进行进程间通讯。

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据