Android Binder机制(二) Binder中的数据结构

在对Binder代码展开详细介绍之前,先列举出Binder机制中涉及到的数据结构。本文是一篇参考文章,读者在阅读代码的过程中遇到相关的数据结构,就可以查阅此文中的内容。本文列举的数据结构,涵盖了内核空间和用户空间两个部分。内核空间部分就是Binder驱动中涉及到的数据结构;而用户空间的部分,包括ServiceManager守护进程,以及Android的C++层和Framework层的相关数据结构。

注意:本文是基于Android 4.4.2版本进行介绍的!

目录
1. 内核空间的Binder数据结构
1.1. binder_proc
1.2. binder_buffer
1.3. binder_thread
1.4. binder_node
1.5. binder_ref
1.6. binder_write_read
1.7. flat_binder_object
1.8. binder_transaction_data
2. 用户空间的
2.1. ServiceManager守护进程中的数据结构
2.2. C++层的数据结构

1. 内核空间的Binder数据结构

在介绍Binder驱动中的数据结构时,先回顾一下上一篇提到的"内核中的Binder设计图",有一个整体印象。

前面说过,binder_proc是描述进程上下文信息的,每一个用户空间的进程都对应一个binder_proc结构体。binder_node是Binder实体对应的结构体,它是Server在Binder驱动中的体现。binder_ref是Binder引用对应的结构体,它是Client在Binder驱动中的体现。

1.1 binder_proc

binder_proc是描述Binder进程上下文信息的结构体。Binder驱动的文件节点是"/dev/binder",每当一个程序打开该文件节点时;Binder驱动中都会新建一个binder_proc对象来保存该进程的上下文信息。

struct binder_proc {
  struct hlist_node proc_node;    // 根据proc_node,可以获取该进程在"全局哈希表binder_procs(统计了所有的binder proc进程)"中的位置
  struct rb_root threads;         // binder_proc进程内用于处理用户请求的线程组成的红黑树(关联binder_thread->rb_node)
  struct rb_root nodes;           // binder_proc进程内的binder实体组成的红黑树(关联binder_node->rb_node)
  struct rb_root refs_by_desc;    // binder_proc进程内的binder引用组成的红黑树,该引用以句柄来排序(关联binder_ref->rb_node_desc)
  struct rb_root refs_by_node;    // binder_proc进程内的binder引用组成的红黑树,该引用以它对应的binder实体的地址来排序(关联binder_ref->rb_node)
  int pid;                        // 进程id
  struct vm_area_struct *vma;     // 进程的内核虚拟内存
  struct mm_struct *vma_vm_mm;
  struct task_struct *tsk;        // 进程控制结构体(每一个进程都由task_struct 数据结构来定义)。
  struct files_struct *files;     // 保存了进程打开的所有文件表数据
  struct hlist_node deferred_work_node;
  int deferred_work;
  void *buffer;                   // 该进程映射的物理内存在内核空间中的起始位置
  ptrdiff_t user_buffer_offset;   // 内核虚拟地址与进程虚拟地址之间的差值

  // 内存管理的相关变量
  struct list_head buffers;         // 和binder_buffer->entry关联到同一链表,从而对Binder内存进行管理
  struct rb_root free_buffers;      // 空闲内存,和binder_buffer->rb_node关联。
  struct rb_root allocated_buffers; // 已分配内存,和binder_buffer->rb_node关联。
  size_t free_async_space;

  struct page **pages;            // 映射内存的page页数组,page是描述物理内存的结构体
  size_t buffer_size;             // 映射内存的大小
  uint32_t buffer_free;
  struct list_head todo;          // 该进程的待处理事件队列。
  wait_queue_head_t wait;         // 等待队列。
  struct binder_stats stats;
  struct list_head delivered_death;
  int max_threads;                // 最大线程数。定义threads中可包含的最大进程数。
  int requested_threads;
  int requested_threads_started;
  int ready_threads;
  long default_priority;          // 默认优先级。
  struct dentry *debugfs_entry;
};

说明:binder_proc定义在drivers/staging/android/binder.c中。由于定义在.c文件中,可见binder_proc是Binder驱动的私有结构体。上面已经给出了相关成员的注释,这里只对部分比较重要的成员进行说明。
(01) proc_node, 它的作用是通过proc_node,将该binder_proc添加到"全局哈希表binder_procs(它记录了所有的binder_proc)"。不过binder_procs在Kernel驱动中暂时没有太大用处,所以不用太过关注该成员。
(02) threads,它是包含该进程内用于处理用户请求的所有线程的红黑树。threads成员和binder_thread->rb_node关联到一棵红黑树,从而将binder_proc和binder_thread关联起来。
(03) nodes,它是包行该进程内的所有Binder实体所组成的红黑树。nodes成员和binder_node->rb_node关联到一棵红黑树,从而将binder_proc和binder_node关联起来。
(04) refs_by_desc,它是包行该进程内的所有Binder引用所组成的红黑树。refs_by_desc成员和binder_ref->rb_node_desc关联到一棵红黑树,从而将binder_proc和binder_ref关联起来。
(05) refs_by_node,它是包行该进程内的所有Binder引用所组成的红黑树。refs_by_node成员和binder_ref->rb_node_node关联到一棵红黑树,从而将binder_proc和binder_ref关联起来。
(06) buffer,它是该进程内核虚拟内存的起始地址。而user_buffer_offset,则是该内核虚拟地址和进程虚拟地址之间的差值。在Binder驱动中,将进程的内核虚拟地址和进程虚拟地址映射到同一物理页面,该user_buffer_offset则是它们之间的差值;这样,已知其中一个,就可以根据差值算出另外一个。
(07) todo是该进程的待处理事务队列,而wait则是等待队列。它们的作用是实现进程的等待/唤醒。例如,当Server进程的wait等待队列为空时,Server就进入中断等待状态;当某Client向Server发送请求时,就将该请求添加到Server的todo待处理事务队列中,并尝试唤醒Server等待队列上的线程。如果,此时Server的待处理事务队列不为空,则Server被唤醒后;唤醒后,则取出待处理事务进行处理,处理完毕,则将结果返回给Client。

1.2 binder_buffer

binder_buffer是描述Binder进程所管理的每段内存的结构体。

struct binder_buffer {
    struct list_head entry;    // 和binder_proc->buffers关联到同一链表,从而使Binder进程对内存进行管理。
    struct rb_node rb_node;    // 和binder_proc->free_buffers或binder_proc->allocated_buffers关联到同一红黑树,从而对已有内存和空闲内存进行管理。

    unsigned free:1;                // 空闲与否的标记
    unsigned allow_user_free:1;
    unsigned async_transaction:1;
    unsigned debug_id:29;

    struct binder_transaction *transaction;

    struct binder_node *target_node;
    size_t data_size;
    size_t offsets_size;
    uint8_t data[0];
};

说明:binder_buffer是Binder驱动的私有结构体,它定义在drivers/staging/android/binder.c中。Binder驱动将Binder进程的内存分成一段一段进行管理,而这每一段则是使用binder_buffer来描述的。

1.3 binder_thread

binder_thread是描述Binder线程的结构体。binder_proc是描述进程的,而binder_thread是描述进程中的线程。

struct binder_thread {
    struct binder_proc *proc;   // 线程所属的Binder进程
    struct rb_node rb_node;     // 红黑树节点,关联到红黑树binder_proc->threads中。
    int pid;                    // 进程id
    int looper;                 // 线程状态。可以取BINDER_LOOPER_STATE_REGISTERED等值
    struct binder_transaction *transaction_stack;   // 正在处理的事务栈
    struct list_head todo;                          // 待处理的事务链表
    uint32_t return_error; /* Write failed, return error code in read buf */
    uint32_t return_error2; /* Write failed, return error code in read */

    wait_queue_head_t wait;                         // 等待队列
    struct binder_stats stats;                      // 保存一些统计信息
};

说明:binder_thread是Binder驱动的私有结构体,它定义在drivers/staging/android/binder.c中。binder_thread是描述Binder线程相关信息的结构体。
(01) proc,它是binder_proc(进程上下文信息)结构体对象。目的是保存该线程所属的Binder进程。
(02) rb_node,它是红黑树节点。通过将rb_node binder关联到红黑树proc->threads中,从而将该线程添加到进程的threads红黑树中进行管理。

1.4 binder_node

binder_node是描述Binder实体的结构体。

struct binder_node {
    int debug_id;
    struct binder_work work;
    union {
        struct rb_node rb_node;         // 如果这个Binder实体还在使用,则将该节点链接到proc->nodes中。
        struct hlist_node dead_node;    // 如果这个Binder实体所属的进程已经销毁,而这个Binder实体又被其它进程所引用,则这个Binder实体通过dead_node进入到一个哈希表中去存放
    };
    struct binder_proc *proc;           // 该binder实体所属的Binder进程
    struct hlist_head refs;             // 该Binder实体的所有Binder引用所组成的链表
    int internal_strong_refs;
    int local_weak_refs;
    int local_strong_refs;
    void __user *ptr;                   // Binder实体在用户空间的地址(为Binder实体对应的Server在用户空间的本地Binder的引用)
    void __user *cookie;                // Binder实体在用户空间的其他数据(为Binder实体对应的Server在用户空间的本地Binder自身)
    unsigned has_strong_ref:1;
    unsigned pending_strong_ref:1;
    unsigned has_weak_ref:1;
    unsigned pending_weak_ref:1;
    unsigned has_async_transaction:1;
    unsigned accept_fds:1;
    unsigned min_priority:8;
    struct list_head async_todo;
};

说明:binder_node是Binder驱动的私有结构体,它定义在drivers/staging/android/binder.c中。binder_node是描述Binder实体相关信息的结构体。
(01) rb_node和dead_node属于一个union。如果该Binder实体还在使用,则通过rb_node将该节点链接到proc->nodes红黑树中;否则,则将该Binder实体通过dead_node链接到全局哈希表binder_dead_nodes中。
(02) proc,它是binder_proc(进程上下文信息)结构体对象。目的是保存该Binder实体的进程。
(03) refs,它是该Binder实体的所有引用所组成的链表。

在Binder驱动中,会为每一个Server都创建一个Binder实体,即会为每个Server都创建一个binder_node对象。

1.5 binder_ref

binder_ref是描述Binder引用的结构体。

struct binder_ref {
    int debug_id;
    struct rb_node rb_node_desc;    // 关联到binder_proc->refs_by_desc红黑树中
    struct rb_node rb_node_node;    // 关联到binder_proc->refs_by_node红黑树中
    struct hlist_node node_entry;   // 关联到binder_node->refs哈希表中
    struct binder_proc *proc;       // 该Binder引用所属的Binder进程
    struct binder_node *node;       // 该Binder引用对应的Binder实体
    uint32_t desc;                  // 描述
    int strong;                     
    int weak;
    struct binder_ref_death *death;
};

说明:binder_ref是Binder驱动的私有结构体,它定义在drivers/staging/android/binder.c中。它是用来描述Binder引用的相关信息的。
(01) rb_node_desc和rb_node_node都是红黑树节点。通过rb_node_desc,Binder引用和binder_proc->refs_by_desc红黑树相关联;通过rb_node_node,Binder引用和binder_proc->refs_by_node红黑树相关联。
(02) node是该Binder引用所引用的Binder实体。而node_entry在是关联到该Binder实体的binder_node->refs哈希表中。
(03) proc,它是binder_proc(进程上下文信息)结构体对象。目的是保存该Binder引用所属的进程。
(04) desc是Binder引用的描述,实际上它就是Binder驱动为该Binder分配的一个唯一的int型整数。通过该desc,可以在binder_proc->refs_by_desc中找到该Binder引用,进而可以找到该Binder引用所引用的Binder实体等信息。

在Binder驱动中,会为每个Client创建对应的Binder引用,即会为每个Client创建binder_ref对象。

"Binder实体"和"Binder引用"可以很好的将Server和Client关联起来:因为Binder实体和Binder引用分别是Server和Client在Binder驱动中的体现。 Client获取到Server对象后,"Binder引用所引用的Biner实体(即binder_ref.node)" 会指向 "Server对应的Biner实体";同样的,Server被某个Client引用之后,"Server对应的Binder实体的引用列表(即,binder_node.refs)" 会包含 "Client对应的Binder引用"。

1.6 binder_write_read

binder_write_read是描述Binder读写信息的结构体。

struct binder_write_read {
    signed long write_size;
    signed long write_consumed;
    unsigned long   write_buffer;
    signed long read_size;
    signed long read_consumed;
    unsigned long   read_buffer;
};

说明:binder_write_read是内核空间和用户空间的通信结构体,它记录了Binder读写内容的相关信息。在内核中,它定义在drivers/staging/android/binder.h中;在Android中,它对应的引用在external/kernel-headers/original/linux/binder.h中。 当用户空间的应用程序和Binder驱动通信时,它会将数据打包到binder_write_read中。write开头的是记录应用程序要发送给Binder驱动的内容,而read开头的是记录Binder驱动要反馈给应用程序的内容。
(01) write_size,是写内容的总大小;write_consumed,是已写内容的大小;write_buffer,是写的内容的虚拟地址。
(02) read_size,是读内容的总大小;read_consumed,是已读内容的大小;read_buffer,是读的内容的虚拟地址。

1.7 flat_binder_object

flat_binder_object是描述Binder对象信息的结构体。

struct flat_binder_object {
    unsigned long       type;   // binder类型:可以为BINDER_TYPE_BINDER或BINDER_TYPE_HANDLE等类型
    unsigned long       flags;  // 标记

    union {
        void        *binder;    // 当type=BINDER_TYPE_BINDER时,它指向Binder对象位于C++层的本地Binder对象(即BBinder对象)的弱引用。 
        signed long handle;     // 当type=BINDER_TYPE_HANDLE时,它等于Binder对象在Binder驱动中对应的Binder实体的Binder引用的描述。
    };

    void            *cookie;    // 当type=BINDER_TYPE_BINDER时才有效,它指向Binder对象位于C++层的本地Binder对象(即BBinder对象)。 
};

说明: flat_binder_object是用来描述Binder信息的结构体。它也属于内核空间和用户空间的通信结构体。当它在用户空间被使用时(例如,Server发送添加服务请求给ServiceManager),flat_binder_object就是记录的Server位于用户空间的Binder对象的信息的结构体;此时的type的值一般都是BINDER_TYPE_BINDER类型,对应的union中的binder的值是该Binder对象在用户空间的本地Binder(即BBinder对象)的引用;同时,cookie则是本地Binder自身。 而当flat_binder_object在Binder驱动中被使用(例如,当Binder驱动收到发送服务请求时),它会将type修改为BINDER_TYPE_HANDLE,然后将联合体中的handle修改为"该Server对应的Binder实体的Binder引用"的描述;根据Binder引用的描述就能找到该Server。总体来说,在用户空间,flat_binder_object是描述该Binder实体在用户空间的存在形式;而在内核空间中,flat_binder_object则描述该Binder实体在内核中的存在形式。

1.8 binder_transaction_data

binder_transaction_data是描述Binder事务交互的数据格式的结构体。

struct binder_transaction_data {
    union {
        size_t  handle; // 当binder_transaction_data是由用户空间的进程发送给Binder驱动时,
                        // handle是该事务的发送目标在Binder驱动中的信息,即该事务会交给handle来处理;
                        // handle的值是目标在Binder驱动中的Binder引用。
        void    *ptr;   // 当binder_transaction_data是有Binder驱动反馈给用户空间进程时,
                        // ptr是该事务的发送目标在用户空间中的信息,即该事务会交给ptr对应的服务来处理;
                        // ptr是处理该事务的服务的服务在用户空间的本地Binder对象。
    } target;           // 该事务的目标对象(即,该事务数据包是给该target来处理的)
    void        *cookie;    // 只有当事务是由Binder驱动传递给用户空间时,cookie才有意思,它的值是处理该事务的Server位于C++层的本地Binder对象
    unsigned int    code;   // 事务编码。如果是请求,则以BC_开头;如果是回复,则以BR_开头。

    unsigned int    flags;
    pid_t       sender_pid;
    uid_t       sender_euid;
    size_t      data_size;    // 数据大小
    size_t      offsets_size; // 数据中包含的对象的个数

    union {
        struct {
            const void  *buffer;
            const void  *offsets;
        } ptr;
        uint8_t buf[8];
    } data;                   // 数据
};

说明: binder_transaction_data是用来描述Binder事务交互的数据结构体。它也属于内核空间和用户空间的通信结构体。

2. 用户空间的Binder数据结构

2.1 ServiceManager守护进程中的数据结构

2.1.1 binder_state

struct binder_state
{
    int fd;           // 文件节点"/dev/binder"的句柄
    void *mapped;     // 映射内存的起始地址
    unsigned mapsize; // 映射内存的大小
};  

说明:binder_state定义在frameworks/native/cmds/servicemanager/binder.c中,它是ServiceManager用来描述打开的"/dev/binder"的信息结构体。

2.1.2 binder_object

binder_object是与flat_binder_object对应的结构体。

struct binder_object
{
    uint32_t type;  // 类型
    uint32_t flags;
    void *pointer;
    void *cookie;
};

说明:binder_object定义在frameworks/native/cmds/servicemanager/binder.h中,它是ServiceManager中与flat_binder_object对应的结构体。

2.1.3 binder_txn

binder_txn与binder_transaction_data对应的结构体。

struct binder_txn
{
    void *target;
    void *cookie;
    uint32_t code;
    uint32_t flags;

    uint32_t sender_pid;
    uint32_t sender_euid;

    uint32_t data_size;
    uint32_t offs_size;
    void *data;
    void *offs;
};

说明:binder_txn定义在frameworks/native/cmds/servicemanager/binder.h中,它是ServiceManager中与binder_transaction_data对应的结构体。

2.1.4 svcinfo

struct svcinfo
{
    struct svcinfo *next;         // 下一个"服务的信息"
    void *ptr;                    // 服务在Binder驱动中的Binder引用的描述
    struct binder_death death;
    int allow_isolated;
    unsigned len;                 // 服务的名称长度
    uint16_t name[0];             // 服务的名称
};      

说明:svcinfo定义在frameworks/native/cmds/servicemanager/service_manager.c中。它是ServiceManager守护进程的私有结构体。
svcinfo是保存"注册到ServiceManager中的服务"的相关信息的结构体。它是一个单链表,在ServiceManager守护进程中的svclist是保存注册到ServiceManager中的服务的链表,它就是struct info类型。svcinfo中的next是指向下一个服务的节点,而ptr是该服务在Binder驱动中Binder引用的描述。name则是服务的名称。

2.2 C++层的数据结构

2.2.1 Parcel

Parcel是描述Binder通信信息的结构体。

class Parcel {
public:
    ...

    // 获取数据(返回mData)
    const uint8_t*      data() const;
    // 获取数据大小(返回mDataSize)
    size_t              dataSize() const;
    // 获取数据指针的当前位置(返回mDataPos)
    size_t              dataPosition() const;

private:
    ...

    status_t            mError;                                   
    uint8_t*            mData;            // 数据
    size_t              mDataSize;        // 数据大小
    size_t              mDataCapacity;    // 数据容量
    mutable size_t      mDataPos;         // 数据指针的当前位置
    size_t*             mObjects;         // 对象在mData中的偏移地址
    size_t              mObjectsSize;     // 对象个数
    size_t              mObjectsCapacity; // 对象的容量

    ...
}

说明:Parcel定义在frameworks/native/include/binder/Parcel.h中。

by skywang
Previous     Next