浅析Binder(二)——基础数据结构

Binder是通过AIDL来描述进程间通信的接口的,Binder作为一个特殊的字符设备,设备节点是/dev/binder。

一张从大牛那搬来的图,很形象也解释了很多东西。

浅析Binder(二)——基础数据结构_第1张图片
binder_4relationship.jpg

在驱动程序中有几个数据结构还是很有必要分析一下的
kernel/goldfish/drivers/staging/android/binder.c

1 binder_work

struct binder_work{
  struct list_head entry;
  enum{
    BINDER_WORK_TRANSACTION=1;
    BINDER_WORK_TRANSACTION_COMPLETE;
    BINDER_WORK_NODE;
    BINDER_WORK_DEAD_BINDER;
    BINDER_WORK_DEAD_BINDER_AND_CLEAR;
    BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
  }
}

该结构体用来描述待处理的工作项,这些工作项有可能属于一个进程,也可能属于某个进程的线程。成员entry 用来将这些结构体嵌入到宿主结构中,成员变量type用来描述工作项的类型。根据type的取值,binder驱动程序可以判断出一个binder_work嵌入到什么类型的宿主结构中。

2 binder_node

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 
//强引用计数和弱引用计数管理Binder对象生命周期
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实体对象。每一个Service在驱动程序中都对应一个Binder实体对象,用来描述他在内核中的状态。

  • ** proc:指向一个Binder实体对象的宿主进程*。
  • rb_node: 宿主进程是通过一个红黑二叉树来管理binder实体对象的,而这个成员变量就是这个红黑二叉树的一个节点
  • dead_node:如果Binder实体对象的宿主进程死亡,但是这个这个Binder实体对象需要暂存一下自己,这样不用再次使用原宿主进程的时候再重新创建Binder实体对象,所以它通过变量dead_node来将自己保存在一个全局的hash类表中
  • refs: Binder实体对象有可能被多个Client组件引用,所以需要使用refs来描述这些引用关系,并且将它们保存在同一个hash列表中。Binder驱动可以通过它知道那些client组件引用了同一个Binder实体对象。
  • ** cookie*:指向该Service组件的地址
  • ** ptr:指向该Service组件内部的一个引用计数对象*的地址
  • has_async_transaction:用来描述一个Binder实体对象是否正在处理一个异步事务,如果是则他的值等于1。
  • aysnc_todo:描述异步事务队列。每一个事务都关联着一个Binder实体对象,要求这个Binder实体对象对应的Service组件在指定的线程中处理该事物。但是异步事务只会有一个得到处理,所以其余等待的异步事务都保存在该队列中。
  • accept_fds:用来描述一个Binder实体对象是否可以接收包含有文件描述符的进程通信你数据,1表示可以
  • min_priority : 表示Binder实体对象在处理一个来自Client进程的请求时,他所要求的处理线程(即Server进程中的一个线程)应该具备的最小线程优先级

Binder驱动通过强应用和弱引用技术来维护他们的生命周期。internal_strong_refslocal_strong_refs均是用来描述一个Binder实体的强引用计数;local_weak_refs用来描述弱引用计数。当Binder实体对象请求一个Service组件来执行某一个操作时,会增加强引用计数或弱引用计数,相应的has_strong_refhas_weak_ref的值会至[1]。当Service组件完成操作后,就会减少强引用或者弱引用计数。Binder实体对象在请求Service组件增加或减少强引用(或弱引用)计数的过程中 pending_strong_refpending_weak_ref的值置[1],使用之后Binder实体对象会将这两个成员变量的值设置为[0]。当引用计数0变1或1变0时,work的值就变为BINDER_WORK_NODE,并将它添加到todo队列中等待处理

3 binder_ref

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哈希表中,hash列表的节点
    struct binder_proc *proc; // 该Binder引用所属的Binder进程 
    struct binder_node *node; // 该Binder引用对应的Binder实体 
    uint32_t desc; // 描述 
    int strong; //强引用计数
    int weak; //弱引用计数
    struct binder_ref_death *death; //指向一个Service组件的死亡通知
};

前面有介绍是用来描述Binder引用对象。宿主进程使用两个红黑树来保存它内部所有的Binder引用对象。分别是句柄值(用来描述一个Binder引用对象)和Binder实体对象的地址,rb_node_desc和rb_node_node就正好是这两个红黑树的节点。

4 binder_ref_death

struct binder_ref_death{
    struct binder_work work;
    void _user *cookie; //保存负责接受死亡通知的对象的地址
}

用来描述一个Service组件的死亡通知。
因为Client无法控制他所引用的Service组件的生命周期,所以当Service意外崩溃的时候只能向Binder驱动程序中注册一个死亡通知,将其保存在cookie指正指向位置。然后根据这个通知work会取相应的值。

5 binder_buffer

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;  //异步事务置"1"
    unsigned debug_id:29; 
    struct binder_transaction *transaction; //描述该缓冲区正在交给那个缓冲区处理
    struct binder_node *target_node;  //目标Binder实体对象
    size_t data_size; 
    size_t offsets_size;
    uint8_t data[0];};

描述一个内核缓冲区,用来在进程件传递数据。

6. 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进程间通信机制的进程。可以借此查考一下如何用结构体内来描述一个进程

7. 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; // 保存一些统计信息};

该结构用来描述一个线程池中的一个线程

8. binder_transaction

struct binder_transaction{
    int debug_id;
    struct binder_work work; //当Binder驱动程序为目标进程或者目标线程创建一个事务时,就会将work的值设置为BINDER_WORK_TRANSACTION

    struct binder_thread *from; //发起事务线程,称为源线程
    sturct binder_proc *to_proc; //负责处理该事物的进程
    sturct binder_thread *to_thread; //负责处理该事物的线程

    struct binser_transaction *from_parent; //依赖事务
    struct binder_transaction *to_parent; //目标线程需要处理的下一个事务

    unsigned need_reply : 1; //区分事务是同步还是异步;1表示同步事务,需要等待对方回应。
    struct binder_buffer *buffer; //驱动程序为该事务分配的一块内核缓冲区
    unsigned int code;
    unsigned int flags;

    long priority; //源线程优先级
    long saved_priority; //线程处理一个事务时,需要先修改他的线程优先级,来满足Service组件的要求,所以需要使用这个变量来保存原先的优先级
    uid_t sender_euid; //用户ID
};
该结构提用来描述进程间通信过程,又叫事务。

9. binder_write_read

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;
};

该结构体用来描述进程间通信过程中所传输的数据。write_buffer和read_buffer都是一个数组,数组的每一个元素都是由一个通信协议代码及其通信数据组成。

10.binder_transaction_data

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;  //发起进程间通信请求的进程的PID
uid_t sender_euid;  //发起进程间通信请求的进程的UID
size_t data_size; // 数据大小 
size_t offsets_size; // 数据中包含的对象的个数 
union { 
    struct { 
      const void *buffer; 
      const void *offsets; 
    } ptr; //
    uint8_t buf[8]; 
} data; // 数据
};

该结构体用来描述进程间通信过程中所传输的数据

11.flat_binder_object

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对象)。 
};

该结构体除了可以描述一个Binder实体对象和Binder引用对象之外,还可以用来描述一个文件描述符,可以通过type来区别

通信协议代码

kerner/goldfish/drivers/staging/android/binder.h

1. BinderDriverCommandProtocol

命令协议代码,在输入缓冲区write_buffer中使用

2. BinderDriverReturnProtocol

返回协议代码,在输出缓冲区read_buffer中使用

内容有点枯燥,但是对于后面的学习很有帮助




参考:
http://wangkuiwu.github.io/2014/09/02/Binder-Datastruct/#anchor1_7
《Android系统源代码情景分析》罗升阳大神著

你可能感兴趣的:(浅析Binder(二)——基础数据结构)