(5) Android中Binder调用流程 --- 数据封装介绍

        前面几节讲解了Binder中涉及的关键类以及远程对象调用的流程步骤,其中涉及到了数据从客户端调用流向Binder内核,再由Binder内核流向宿主进程,请求数据会经过层层封装,这样请求数据到达Binder内核时,其格式是满足Binder内核要求,这样Binder才会知道怎么解析请求数据。所以,这里涉及到Binder在调用过程中各种数据结构,下面列出了调用流程中用到的主要数据结构。

客户端调用远程服务涉及到的主要数据结构

       

Binder调用涉及的数据结构
序号 数据结构名称 说明
1 flat_binder_object IBinder对象在驱动层的描述
2 binder_transaction_data 封装请求数据以及包含的IBinder对象的信息
3 binder_write_read BINDER_WRITE_READ驱动层命令对应的封装信息
4 binder_node 在Binder驱动中记录了实体服务信息
5 binder_ref 保存实体IBinder对象的引用,用来在客户端查询实体IBinder用
6 binder_proc 和Binder驱动关联的进程信息(调用binder_open就会生成)

 

 

flat_binder_object介绍

        此结构代表了在多进程传输过程中的一个IBinder对象(远程服务对象),正是因为此结构表述了一个多进程共享的服务对象,客户端在使用远程服务对象才感觉不到多进程的存在,就像在本进程中使用远程服务对象一样,下面我们先看看 flag_binder_object结构的定义。

struct flat_binder_object {        
     unsigned long           type;         //binder类型
     unsigned long           flags;        //同步或异步
     union {                         
          void           *binder;          
          signed long     handle;             
     };
     void *cookie;
};

        type:对象类型,取值:BINDER_TYPE_BINDER,BINDER_TYPE_WEAK_BINDER,BINDER_TYPE_HANDLE,BINDER_TYPE_WEAK_HANDLE。

        flags:对象处理的标志位。

        binder:如果type为BINDER_TYPE_BINDER,BINDER_TYPE_WEAK_BINDER,表示实体对象的引用;

        handle:如果type为BINDER_TYPE_HANDLE,BINDER_TYPE_WEAK_HANDLE,代表远程服务对象的handle。

        cookie:附加数值,存储实体对象的地址。

        flag_binder_object是定义在驱动层的,在Binder的通讯里,表示一个IBinder服务对象,算是比较核心的一个数据结构。

binder_transaction_data介绍

        binder_transaction_data在Binder驱动对应的处理命令为BC_TRANSACTION(用户到内核),主要用来对请求的数据进行封装,里面保存了调用的远程实体服务对应的handle,请求的数据以及请求数据里包含的对象(IBinder类型的)个数。其详细的定义如下:

struct binder_transaction_data {

     union {
          size_t   handle;     // 客户端调用,表示远程服务对应的handle      
          void  *ptr;              // 实体Binder的引用           
     } target;

     void           *cookie;      // 实体Binder的地址(真实服务对象地址)             
     unsigned int    code;    // BC_TRANSACTION                  

     unsigned int     flags;   // 上层调用过来的控制标记位
     pid_t            sender_pid;  // 调用服务接口方的进程ID
     uid_t            sender_euid; // 调用服务接口方进程的用户ID 
     size_t           data_size;        // 请求数据的大小 (就是buffer的大小)
     size_t           offsets_size;    // 请求数据包含的所有对象的字节数   

     union {
          struct {                     
               const void   *buffer;    // 请求数据(包含参数等信息)
               const void   *offsets;  // 请求数据里包含的IBinder对象在buffer中的偏移信息    
          } ptr;                             
          uint8_t     buf[8];
     } data;
};

        此结构由Binder驱动进行解析处理,一个主要的功能就是对binder_transaction_data结构中的记录的flat_binder_object类型的对象进行处理(根据flat_binder_object中的type决定是否插入binder_node到调用者进程还是插入binder_ref到远程服务所在进程),所以,从这里看出flat_binder_object结构是非常重要的。

binder_write_read介绍

        binder_write_read是在binder_transaction_data结构上进行的封装,最终通过ioctl系统调用发往Binder驱动是这个结构表示的数据,其对应的命令码为:BINDER_WRITE_READ,就是告诉Binder驱动完成一次写入、读取(是先写入再读取),其定义如下:

struct binder_write_read {
     signed long       write_size;           // 需要写入的数据大小
     signed long       write_consumed; // 已经写入多少(内核会从write_buffer+write_consumed解析)  
     unsigned long     write_buffer;      // 写入的数据(BC_TRANSACTION + binder_transaction_data)

     signed long       read_size;             // 读取数据缓冲区大小
     signed long       read_consumed;   // 已经读取的数据大小   
     unsigned long     read_buffer;        // 数据读取的缓冲区
};

binder_node介绍

        binder_node是在驱动层使用的数据结构,其表示一个实体IBinder,这个节点首先是插入IBinder所在的宿主进程里的,然后远程客户端调用进程会持有其引用,就是后面将要介绍的binder_ref结构信息,binder_node的定义如下:

struct binder_node {
    int debug_id;
    struct binder_work work;
    union {
        struct rb_node rb_node;
        struct hlist_node dead_node;
    };
    struct binder_proc *proc;
    struct hlist_head refs;
    int internal_strong_refs;
    int local_weak_refs;
    int local_strong_refs;
    binder_uintptr_t ptr;
    binder_uintptr_t cookie;
    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;
};

        这里面我们主要讲解几个变量:proc、ptr、cookie、async_todo。

        proc:IBinder实体所在的进程对象地址(实现IBinder服务的进程);

        ptr:IBinder实体服务的引用(内核通过引用来管理对象的生命周期);

        cookie:实体服务的对象地址,在调用服务的时候会直接转为BBinder;

        async_todo:执行的任务队列;

        binder_node结构信息插入是通过flat_binder_object的type值为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER会插入到宿主进程的binder_proc的node里。

binder_ref介绍

        binder_ref结构记录了实体Binder(binder_node)的引用信息,由服务端进程插入到客户端进程binder_proc。这个结构是作为客户端用来查询远程服务对象的binder_node用,因为这个结构有个成员变量desc,这个desc就是服务端对象在客户端的引用handle,下面是binder_ref定义。

struct binder_ref {
    /* Lookups needed: */
    /*   node + proc => ref (transaction) */
    /*   desc + proc => ref (transaction, inc/dec ref) */
    /*   node => refs + procs (proc exit) */
    int debug_id;
    struct rb_node rb_node_desc;
    struct rb_node rb_node_node;
    struct hlist_node node_entry;
    struct binder_proc *proc;          // 进程地址信息(客户端的进程)
    struct binder_node *node;        // 远程服务对象的节点信息
    uint32_t desc;                           // 远程服务引用对应的索引值(客户会通过引用其来找到binder_node)
    int strong;
    int weak;
    struct binder_ref_death *death;
};

binder_proc介绍

        binder_proc结构描述和Binder驱动关联的进程信息,这个结构在驱动层的binder_open函数里生成,同时保存在返回的文件句柄中,这个结构非常重要,其保存真实进程的全部信息、本进程实现的服务实体信息以及远程服务的引用信息(本进程调用的远程服务),下面看看这个结构的定义。

struct binder_proc {
    struct hlist_node proc_node;
    struct rb_root threads;
    struct rb_root nodes;
    struct rb_root refs_by_desc;
    struct rb_root refs_by_node;
    int pid;
    struct vm_area_struct *vma;
    struct mm_struct *vma_vm_mm;
    struct task_struct *tsk;
    struct files_struct *files;
    struct hlist_node deferred_work_node;
    int deferred_work;
    void *buffer;
    ptrdiff_t user_buffer_offset;

    struct list_head buffers;
    struct rb_root free_buffers;
    struct rb_root allocated_buffers;
    size_t free_async_space;

    struct page **pages;
    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;
    int requested_threads;
    int requested_threads_started;
    int ready_threads;
    long default_priority;
    struct dentry *debugfs_entry;
    struct binder_context *context;
};

        binder_proc结构定义的字段比较多,这里说下比较重要的几个。

        threads:和本进程关联的线程信息;

        nodes:本进程实现的服务信息;

        refs_by_desc:使用handle索引的远程服务的引用信息(主要用查询用);

        refs_by_node:使用node索引的远程服务的引用信息(主要用查询用);

        从上面可以看出refs_by_desc和refs_by_node其实是复用的,只是索引的不一样,一个以handle索引,一个以node索引,这个节点在应用层其实对应的是BpBinder对象(相关知识大家可以看看我前面的文章)。

        这里我们简单介绍了Binder调用过程中用到的主要数据结构,当然还有很多其他的数据结构,以后有时间再整理下,文中如有理解不当之处,欢迎大家指正,谢谢!

        本系列文章均为原创,主要总结作者多年在软件行业的一些经验,和大家共同学习、进步,转载请注明出处,谢谢!

猜你喜欢

转载自blog.csdn.net/china0851/article/details/87854271