美文网首页
Binder Drvier 1: 重要结构

Binder Drvier 1: 重要结构

作者: ColdWave | 来源:发表于2018-06-27 18:09 被阅读0次

<<Android系统源码情景分析>>

说明: 本文主要是参考该书籍,阅读代码.代码环境: Android 8.1 ;Kernel 4.9.

main struct

  • binder_work
  • binder_node
  • binder_ref_death
  • binder_ref
  • binder_alloc
  • binder_buffer
  • binder_proc
  • binder_thread
  • binder_transaction
  • binder_driver_command_protocol
  • binder_driver_return_protocol
  • binder_ptr_cookie
  • binder_transaction_data
  • flat_binder_object

Service——binder_node(Binder实体对象)

Client——binder_ref(Binder引用对象)

binder_work

 // proc, thread, node (async) 分别有独立的 work lists
 // 根据 type 类型,将 binder_work 插入到对应的宿主结构中.
struct binder_work {           // 描述插入到 worklist 的 work
    struct list_head entry;    // node enqueued on list

    enum {
        BINDER_WORK_TRANSACTION = 1,
        BINDER_WORK_TRANSACTION_COMPLETE,
        BINDER_WORK_RETURN_ERROR,
        BINDER_WORK_NODE,
        BINDER_WORK_DEAD_BINDER,
        BINDER_WORK_DEAD_BINDER_AND_CLEAR,
        BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
    } type; // 要执行的工作类型
};

binder_node

 /**
  * 1. binder_node 描述 Binder 实体对象。
  * 2. 每一个 Service 组件在 Binder 驱动程序中对应一个 Binder 实体对象,用来描述它在内核中的状态。
  * 3. Binder Driver 通过 强引用计数 和 弱引用计数 来维护它们的生命周期。

  * 1.  proc 指向一个 Binder 实体对象的宿主进程。在 Binder Driver 中,这些宿主进程通过 binder_proc 来描述。
  * 2. 宿主进程使用一个红黑树来维护它们内部所有的Binder实体对象,而每一个Binder实体对象的成员变量 rb_node 就正好是红黑树的一个节点。
  * 3. 如果 Binder 实体对象的宿主进程死亡了,那么这个Binder实体对象就会通过它的成员变量 dead_node 保存一个全局的 hash 链表中。
 */
 // binder_node 对应的是一个 Service 组件,并不对应 一个进程; 因为一个 进程 可以有多个 Service 组件.
struct binder_node {
    int debug_id;
    spinlock_t lock;
    struct binder_work work;
    union {
        struct rb_node rb_node;              // proc 维护的所有的 binder_node 的 红黑树 的节点
        struct hlist_node dead_node;         // proc 宿主进程已经死亡,那么 binder_node 会保存到全局的 hash list 中
    };
    struct binder_proc *proc;                // proc 指向一个 Binder 实体对象的宿主进程
    struct hlist_head refs;                  // binder_node 描述了 Service 组件,Service 可以被多个 Client 获取,
                                                 // refs 维护所有引用了该 Serivce 的 Client 对应的 binder_ref 结构
                                                 // 通过该变量就可以知道那些 Client 引用了该 binder_node
    int internal_strong_refs;                // 引用计数
    int local_weak_refs;                     // 引用计数
    int local_strong_refs;                   // 引用计数
    int tmp_refs;                            // 引用计数
    binder_uintptr_t ptr;                    // 指向 Userspace 的 Service 组件内部的一个引用计数对象(weakref_impl)的地址(用户空间地址)
    binder_uintptr_t cookie;                 // 指向 Userspace 的 Service 组件的地址(用户空间地址)
    struct {
        /*
         * bitfield elements protected by
         * proc inner_lock
         */
        u8 has_strong_ref:1;
        u8 pending_strong_ref:1;
        u8 has_weak_ref:1;
        u8 pending_weak_ref:1;
    };
    struct {
        /*
         * invariant after initialization
         */
        u8 sched_policy:2;
        u8 inherit_rt:1;
        u8 accept_fds:1;                 // 该 binder_node 是否接收含有 fds 的通信数据
        u8 min_priority;                 // Client 要求的 Server 处理线程的最小优先级
    };
    bool has_async_transaction;          // 该 binder_node 是否正在处理一个 异步事务
    struct list_head async_todo;         // 该 binder_node 的异步事务 list
    /**
     * 异步事务的说明:
     * 1. 通常情况下,Binder Driver将 一个事务 保存在一个线程的 todo list 中,表示由该线程处理该事务。
     * 2. 每一个事务关联一个 binder_node,表示该事务的目标处理对象,即要求该 binder_node 对应的 Service 组件在指定的线程中处理该事务。
     * 3. 然而,如果是异步事务,将保存在 binder_node 的 async_todo 中。
     * 
     * 什么是异步事务:
     *    单向的,不需要等待应答的进程间通信。
     *    异步事务优先级低于同步事务。在同一时刻,一个 binder_node 的所有 异步事务 只有一个会得到处理,其余的都在等待;而同步事务没有该限制。
    */
    /**
     * 引用技术的说明:
     * 1. internal_strong_refs, local_strong_refs 描述 binder_node 的强引用计数。
     * 2. local_weak_refs 描述 binder_node 的弱引用计数。
     * 3. 一个 binder_node 请求 Service 执行某一操作时,会增加该 Service 的 strong refs 或 weak refs;相应的,binder_node 会将成员变量 has_strong_ref 或 has_weak_ref 的值设置为1.
     * 4. 当一个 Service 组件完成一个 binder_node 所请求的操作后,binder_node 就会请求减少该 Service 的 strong refs 或 weak refs。
     * 5. binder_node 在请求一个 Service 增加或减少引用计数的过程中,会将成员变量 pending_strong_ref 或 pending_weak_ref 的值设置为1;当 Service 增加或减少了引用计数后,binder_node 就会将这两个成员变量的值设置为0.
     * 6. 当 binder_node 的引用计数由0->1, 或由1->0时,Binder Driver 会请求相应的 Service 增加或减少其引用计数。这时候Binder Driver会将修改引用计数的操作封装成一个类型为 binder_node 的工作项,即将 binder_node 的 work 的值设置为 BINDER_WORK_NODE,并将它添加到相应的进程的 todo list 中,等待处理。
     *
    */
};

binder_ref_death

struct binder_ref_death {
    /**
     * @work: worklist element for death notifications
     *        (protected by inner_lock of the proc that
     *        this ref belongs to)
     */
    struct binder_work work; // 标志死亡类型
    binder_uintptr_t cookie; // 属于 Client 的接收死亡通知的 Object address。
};
/**
 * 正常情况下,Service 被 Client 引用时,不可以销毁。然而,Client 无法控制 Service 的生命周期,因为 Service 进程可能意外奔溃。
 * Client 会在 Service 死亡时,得到通知,以便做出相应的处理。这就需要 Client 将接收死亡通知的对象注册到 Binder Driver 中。
*/
/**
 *      BINDER_WORK_DEAD_BINDER
 *      BINDER_WORK_DEAD_BINDER_AND_CLEAR
 *      BINDER_WORK_CLEAR_DEATH_NOTIFICATION
 * 
 * Binder Driver 在向 Client 发送 死亡通知 时,会将 binder_ref_death 封装成一个工作项,然后添加到 Client 进程的 todo list 中等待处理。
 * 
 * (1) Binder Drvier 探测到 Service 死亡,就会找到 binder_node, 遍历 refs 找到所有的 Client 进程,最后找到 Client 进程注册的 binder_ref_death, Binder Drvier 会将 binder_ref_death 添加到 Client 的 todo list 中等到处理。binder_ref_death 的 work 类型为 BINDER_WORK_DEAD_BINDER。
 *
 * (2) 当 Client 向 Binder Driver 注册 死亡通知 时,Service 已经死亡,那么Binder Driver会马上发送一个死亡通知给Client。这种情况下,死亡类型为:BINDER_WORK_DEAD_BINDER。
 *
 * (3) 当 Client 向 Binder Driver 注销一个 死亡通知 时,Binder Driver 也会向该 Client 进程的 todo 队列发送一个 binder_ref_death 的工作项,用来表示注销结果。这时,可能出现两种结果。
 *       ① 如果Client在注销死亡通知时,Service没有死亡,那么Binder Driver 就会找到 Client 之前注册的 binder_ref_death, 将它封装为 BINDER_WORK_CLEAR_DEATH_NOTIFICATION 的工作项加到 Client 的 todo list 中等待处理。
 *       ② 如果Client在注销死亡通知时,Service已经死亡,那么 Binder Driver 就会找到 Client 之前注册的 binder_ref_death,将它封装为 BINDER_WORK_DEAD_BINDER_AND_CLEAR 的工作项加到 Client 的 todo list 中等待处理。
*/

binder_ref

binder_ref 描述 Binder 引用对象, 对应于 Client 组件.

struct binder_ref_data {
    int debug_id;
    uint32_t desc;  // binder_ref 的描述句柄。当 Client 访问 Service 时需要指定 desc,根据 desc 找到 binder_ref, 然后找到对应的 Service 组件
    int strong;     // 强引用计数
    int weak;       // 弱引用计数
};

struct binder_ref {
    /* Lookups needed: */
    /*   node + proc => ref (transaction) */
    /*   desc + proc => ref (transaction, inc/dec ref) */
    /*   node => refs + procs (proc exit) */
    struct binder_ref_data data;
    struct rb_node rb_node_desc;            // binder_proc 的 refs_by_desc 的红黑树的节点。该红黑树以 desc 来组织。
    struct rb_node rb_node_node;            // binder_proc 的 refs_by_node 的红黑树的节点。该红黑树以 binder_ref 对应的 binder_node 的 地址组织。
    struct hlist_node node_entry;           // binder_node 使用 node_entry 将所有的 binder_ref 组织为一个 hash list
    struct binder_proc *proc;               // 指向 binder_ref 的宿主进程
    struct binder_node *node;               // binder_ref 所引用的 binder_node
    struct binder_ref_death *death;         // Client 注册的死亡通知描述
};

/**
 * 注意:
 *     binder_ref 的 desc 在一个进程范围内是唯一的,在两个不同的进程中同一个 desc 可能代表两个不同的 Service。
*/

binder_alloc

binder_alloc 是 一个 binder buffer allocator,负责管理所有的 binder_buffer

struct binder_alloc {
    struct mutex mutex;
    struct task_struct *tsk;
    struct vm_area_struct *vma;        // vm_area_struct passed to mmap_handler
    struct mm_struct *vma_vm_mm;       // copy of vma->vm_mm (invarient after mmap)
    void *buffer;                      // base of per-proc address space mapped via mmap
    ptrdiff_t user_buffer_offset;      // offset between user and kernel VAs for buffer
    struct list_head buffers;          // 组织所有的 binder_buffer
    struct rb_root free_buffers;       // 组织所有的 空闲的 binder_buffer
    struct rb_root allocated_buffers;  // 组织所有的 使用的 binder_buffer
    size_t free_async_space;           // 可以用来保存异步事务数据的内核缓冲区的大小. 初始化为 mmap 时大小的 1/2
    struct page **pages;               // 每个 mmap 过的空间对应的 physical page addresses 数组
    size_t buffer_size;                // mmap 空间大小
    uint32_t buffer_free;              // 空闲内核缓冲区的大小
    int pid;
};

binder_buffer

 // 供 binder transactions 使用的 buffer
struct binder_buffer {
    struct list_head entry; /* free and allocated entries by address; entry alloc->buffers */
    struct rb_node rb_node; /* free entry by size or allocated entry; node for allocated_buffers/free_buffers rb trees */
                /* by address */
    unsigned free:1;
    unsigned allow_user_free:1;
    unsigned async_transaction:1;            // binder_buffer 所关联的是 异步事务。Binder Driver 会限制异步事务的 buffer 的大小。
    unsigned free_in_progress:1;
    unsigned debug_id:28;

    struct binder_transaction *transaction;  // 正在使用该 binder_buffer 的 事务。

    struct binder_node *target_node;         // binder_buffer 所属的 binder_node

/**
 * Binder Driver 使用 binder_transaction 描述一个事务,每个事务关联一个目标 binder_node.
 * Binder Drvier 将事务数据保存在 binder_buffer 中,然后将它交给目标 binder_node,目标 binder_node 再将该 binder_buffer 交给 Service 处理。
 * Service 处理完该事务后,如果 binder_buffer 的 allow_user_free 为 1, 那么 Service 会请求 Binder Driver 释放 该 binder_buffer。
*/

    size_t data_size;
    size_t offsets_size;
    size_t extra_buffers_size;
    void *data;
/**
 * data: 保存通信数据
 * 1. 若 data 保存的是普通数据,Binder 不需关心,只需要传递给目标对象即可。
 * 2. 若 data 保存的是 Binder 对象,Driver 需要维护 Binder 对象对应的 binder_node 或 binder_ref 的生命周期。
 *    例如:如果数据缓冲区包含一个 Binder 引用,并且该数据缓冲区是传递给另一个进程的,那么Driver需要为另一个进程创建 binder_ref,并且增加 binder_node 的引用计数。
 * 由于 普通数据 和 Binder 对象是混在一起的,他们之间没有固定的顺序,所以需要额外的数据来找到里面的Binder对象。
 * 在数据缓冲区的后面,有一个偏移数组,它记录了数据缓冲区中每一个 Binder 对象在数据缓冲区中的位置。偏移数组的大小保存在 offsets_size 中,而数据缓冲区的大小保存在 data_size 中。
*/
};
/**
 * binder_buffer 描述一个 内核缓冲区,用来在进程间传递数据。
 * 每一个使用 Binder 通信的的进程在 Binder Driver 中都有一个 内核缓冲区链表,用来保存 Binder Driver 为它所分配的内核缓冲区。
 * 
*/

binder_proc

每一个使用 Binder 通信的 进程 都会用一个 binder_proc 进行描述

struct binder_proc {
    struct hlist_node proc_node;         // 全局 hash list 的 节点
    struct rb_root threads;              // 以线程 ID 为关键字组织的进程的 Binder 线程池.            
/**
 * Binder Process 的 thread pools
 * 进程通过 ioctl 将线程注册到 Binder Driver 中,同时,如果没有足够的空闲线程来处理 IPC 请求时,Driver 会请求进程注册更多的线程到 Binder thread pools 中。
 */
    struct rb_root nodes;                   // 组织进程的所有的 binder_node
    struct rb_root refs_by_desc;            // 根据 binder_ref 的 desc 组织所有的 binder_ref
    struct rb_root refs_by_node;            // 根据 binder_ref 所引用的 binder_node 的 地址组织所有的 binder_ref
    struct list_head waiting_threads;       // 组织所有的 wait thread
    int pid;                                // Process ID
    struct task_struct *tsk;                // 进程的 task_struct
    struct hlist_node deferred_work_node;   // 组织所有可以延迟执行的工作项
    int deferred_work;                      // 延迟指向的工作项的类型
    bool is_dead;

    struct list_head todo;                  // 待处理的 IPC 请求 list
    wait_queue_head_t wait;                 
// 空闲线程会睡眠在 wait 所描述的 等待队列 中,当 宿主进程 的 待处理工作项增加新的工作后,Driver 会唤醒这些线程,以便去处理新的工作项。
    struct binder_stats stats;              // Binder IPC 通信统计
    struct list_head delivered_death;       
// 当进程所引用的 Service 组件死亡时,Driver 会向该进程发送死亡通知。将死亡通知工作加入到 delivered_death list 中。表示 Driver 正在向进程发送死亡通知。
// 当进程收到死亡通知后,会通知 Driver,Driver 会将对应的死亡通知工作项从 delivered_death 中删除。
    int max_threads;                        // Driver 可以主动请求进程注册的线程的最大数量
    int requested_threads;                  // Driver 主动请求进程注册线程时,+1, 进程响应该请求后,-1
    int requested_threads_started;          // 进程响应 主动请求进程注册线程 后,+1,表示 Driver 已经主动注册了多少个线程
    int tmp_ref;
    struct binder_priority default_priority; 
// 进程的优先级。当线程处理一个工作项时,可能设置为宿主进程的优先级,即 default_priority。因为 线程 代表其 进程 来处理 一个工作项。
    struct dentry *debugfs_entry;
    struct binder_alloc alloc;            // binder_buffer 的 管理器
    struct binder_context *context;
    spinlock_t inner_lock;
    spinlock_t outer_lock;
};

/**
 * 可以延迟执行的工作项: 
 *  close binder 时,释放 binder_proc, binder_node, binder_ref会比较耗时,可以创建一个 BINDER_DEFERRED_RELEASE 事务来延迟执行。
*/

binder_thread

binder_thread 描述 binder thread pool 中的 thread

struct binder_thread {
    struct binder_proc *proc;             // thread 所属的 process
    struct rb_node rb_node;               // binder_proc 通过 该变量 组织所有的 threads
    struct list_head waiting_thread_node; // binder_proc 通过 该变量 组织所有的 处于等待状态的 threads
    int pid;                              // 线程描述符
    int looper;              /* only modified by this thread */ // 线程状态
    bool looper_need_return; /* can be written by other thread */
    struct binder_transaction *transaction_stack;  // 由该线程处理的 事务堆栈
    struct list_head todo;                // list of work to do for this thread; 当 Client 进程的请求要指定某一线程处理时,加入到 todo list 中,并且唤醒线程
    struct binder_error return_error;     // transaction errors reported by this thread (only accessed by this thread)
    struct binder_error reply_error;      // transaction errors reported by target thread
    wait_queue_head_t wait;               // wait queue for thread work
    struct binder_stats stats;            // per-thread statistics
    atomic_t tmp_ref;                     // temporary reference to indicate thread is in use
    bool is_dead;                         // thread is dead and awaiting free
                                          // when outstanding transactions are cleaned up
    struct task_struct *task;             // struct task_struct for this thread
};

/*
 * 事务依赖:
 * 当 Binder 线程 在处理事务 T1 并需要依赖于其他 Binder 线程来处理事务 T2 时,他就会睡眠在由 wait 描述的等待队列中,直到 T2 处理完为止.
*/

// 用来描述线程的状态
enum {
    BINDER_LOOPER_STATE_REGISTERED  = 0x01,
    BINDER_LOOPER_STATE_ENTERED     = 0x02,
    BINDER_LOOPER_STATE_EXITED      = 0x04,
    BINDER_LOOPER_STATE_INVALID     = 0x08,
    BINDER_LOOPER_STATE_WAITING     = 0x10,
    BINDER_LOOPER_STATE_POLL        = 0x20,
};
/*
1. 当线程是应用程序主动注册的,通过命令 BC_ENTER_LOOPER 通知 Driver,该线程可以处理通信请求了,并将线程状态设置为 BINDER_LOOPER_STATE_ENTERED
2. 当线程是 Driver 请求注册的,通过 BC_REGISTER_LOOPER 通知 Driver 该线程可以处理通信请求了,并将线程状态设置为 BINDER_LOOPER_STATE_REGISTERED
3. 当线程处于空闲状态时,为 BINDER_LOOPER_STATE_WAITING
4. 当一个线程退出时,会通过 BC_EXIT_LOOPER 通知 Driver 将线程状态设置为 BINDER_LOOPER_STATE_EXITED。
5. 当线程处于异常状态时,为 BINDER_LOOPER_STATE_INVALID。
*/

binder_transaction

描述进程间通讯过程,这个过程又称为一个 事务.

struct binder_transaction {
    int debug_id;
    struct binder_work work;
    /*
     * 当 Binder Driver 为目标进程或目标线程创建一个 事务 时,就会将该事务的成员变量 work 设置为 BINDER_WORK_TRANSACTION ,
     * 并且将它添加到目标进程或目标线程的 todo list 中等待处理.
    */
    struct binder_thread *from;               // 发起事务的线程,即源线程
    struct binder_transaction *from_parent;   // 一个事务所依赖于的另一个事务
    struct binder_proc *to_proc;              // 负责处理该事务的目标进程
    struct binder_thread *to_thread;          // 负责处理该事务的目标线程
    struct binder_transaction *to_parent;     // 目标线程锁需要处理的下一个事务.
    unsigned need_reply:1;                    // 区分同步或异步事务
    /* unsigned is_dead:1; */   /* not used at the moment */

    struct binder_buffer *buffer;  // 指向 Drvier 为该事务分配的 buffer
    unsigned int    code;          // 从 binder_transaction_data 中拷贝
    unsigned int    flags;         // 从 binder_transaction_data 中拷贝
    struct binder_priority  priority;
    struct binder_priority  saved_priority;  
// 一个线程处理事务时,需要Driver修改它的线程优先级,以满足源线程和目标Service的要求。Driver在修改之前,会将之前的 优先级 保存到 saved_priority 中。
// 目标线程处理一个事务时,线程优先级不能低于目标 Service 所要求的优先级,也不能低于源线程的优先级。这时 Driver 会将这二者中的较大值设置为目标线程的优先级
    bool    set_priority_called;
    kuid_t  sender_euid;
    /**
     * @lock:  protects @from, @to_proc, and @to_thread
     *
     * @from, @to_proc, and @to_thread can be set to NULL
     * during thread teardown
     */
    spinlock_t lock;
};

binder_write_read

通过 BINDER_WRITE_READ 命令附带结构体

struct binder_write_read {
    binder_size_t       write_size; /* bytes to write */
    binder_size_t       write_consumed; /* bytes consumed by driver */
    binder_uintptr_t    write_buffer;
    binder_size_t       read_size;  /* bytes to read */
    binder_size_t       read_consumed;  /* bytes consumed by driver */
    binder_uintptr_t    read_buffer;
};

// write_buffer: 表示从 Userspace -> KernelSpace 的数据
// read_buffer:  表示从 KernelSpace -> Userspace 的数据

write_buffer 和 read_buffer 的数据格式:

=================================================================================
|             |                          |             |                        |
|   Code-1    |    Content of Code-1     |   Code-2    |    Content of Code-2   |
|             |                          |             |                        |
=================================================================================

协议代码分为:命令协议代码和返回协议代码。

binder_driver_command_protocol

enum binder_driver_command_protocol {
    BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
    BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
    /*
     * binder_transaction_data: the sent command.
     */

    BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
    /*
     * not currently supported
     * int:  0 if the last BR_ATTEMPT_ACQUIRE was not successful.
     * Else you have acquired a primary reference on the object.
     */

    BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
    /*
     * void *: ptr to transaction data received on a read
     */

    BC_INCREFS = _IOW('c', 4, __u32),
    BC_ACQUIRE = _IOW('c', 5, __u32),
    BC_RELEASE = _IOW('c', 6, __u32),
    BC_DECREFS = _IOW('c', 7, __u32),
    /*
     * int: descriptor
     */

    BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
    BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
    /*
     * void *: ptr to binder
     * void *: cookie for binder
     */

    BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
    /*
     * not currently supported
     * int: priority
     * int: descriptor
     */

    BC_REGISTER_LOOPER = _IO('c', 11),
    /*
     * No parameters.
     * Register a spawned looper thread with the device.
     */

    BC_ENTER_LOOPER = _IO('c', 12),
    BC_EXIT_LOOPER = _IO('c', 13),
    /*
     * No parameters.
     * These two commands are sent as an application-level thread
     * enters and exits the binder loop, respectively.  They are
     * used so the binder can have an accurate count of the number
     * of looping threads it has available.
     */

    BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14,
                        struct binder_handle_cookie),
    /*
     * int: handle
     * void *: cookie
     */

    BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15,
                        struct binder_handle_cookie),
    /*
     * int: handle
     * void *: cookie
     */

    BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
    /*
     * void *: cookie
     */

    BC_TRANSACTION_SG = _IOW('c', 17, struct binder_transaction_data_sg),
    BC_REPLY_SG = _IOW('c', 18, struct binder_transaction_data_sg),
    /*
     * binder_transaction_data_sg: the sent command.
     */
};
  1. BC_TRANSACTION 和 BC_REPLY 的通信数据用 binder_transaction_data 来描述。
    当 源进程 请求请求执行某一操作时,使用 BC_TRANSACTION 命令传递通信数据到目标进程。
    当 目标进程 处理完请求后,通过 BC_REPLY 命令 将返回数据传递到 源进程。

  2. BC_FREE_BUFFER:

    通信数据为 整数,指向了 Binder Driver 的 内核缓冲区。
    当 Driver 通过 内核缓冲区 将 源进程 的通信数据传递到 目标进程 后,当目标进程处理完通信请求后,可以通过协议命令 BC_FREE_BUFFER 请求 Driver 释放这个内核缓冲区。

  3. BC_INCREFS ,BC_ACQUIRE ,BC_RELEASE ,BC_DECREFS :

    通信数据为 整数,描述了 binder_ref 的 desc。

    BC_INCREFS, BC_DECREFS 用来请求增加和减少一个 binder_ref 的弱引用计数。

    BC_ACQUIRE, BC_RELEASE 用来请求增加和减少一个 binder_ref 的强引用计数。

  4. BC_INCREFS_DONE, BC_ACQUIRE_DONE:

    通信数据:binder_ptr_cookie

    当 Binder Driver 第一次增加 binder_node 的 强引用计数或者弱引用计数时,会使用 BR_ACQUIRE, BR_INCREFS 来请求 Server 进程 增加对应的 Service 组件的 强引用计数或者弱引用计数。当 Server 进程处理完这两个请求后,就会分别使用命令协议代码 BC_INCREFS_DONE, BC_ACQUIRE_DONE 将操作结果返回给 Binder Driver。

  5. BC_REGISTER_LOOPER, BC_ENTER_LOOPER, BC_EXIT_LOOPER:

    无通信数据。

    BC_REGISTER_LOOPER 通知 Driver , Driver 主动请求注册的 线程 处于 就绪 状态。

    BC_ENTER_LOOPER 通知 Driver , 进程自己注册的 线程 处于 就绪 状态。

    BC_EXIT_LOOPER 通知 Drvier ,该 线程 退出,不再接收请求。

  6. BC_REQUEST_DEATH_NOTIFICATION, BC_CLEAR_DEATH_NOTIFICATION

    通信数据:binder_ptr_cookie

    注册死亡通知 和 注销死亡通知

  7. BC_DEAD_BINDER_DONE:

    通信数据:void 指针

    使用该命令通知 Drvier 已处理完 Service 组件的死亡通知了。

binder_driver_return_protocol

enum binder_driver_return_protocol {
    BR_ERROR = _IOR('r', 0, __s32),
    /*
     * int: error code
     */

    BR_OK = _IO('r', 1),
    /* No parameters! */

    BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
    BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
    /*
     * binder_transaction_data: the received command.
     */
     /*
      * Client 请求 Service 时,Driver 使用 BR_TRANSACTION 通知 Server 处理该请求。
      * 当 Server 处理完该请求时, 使用 BR_REPLY 返回请求结果给 Client。
     */

    BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
    /*
     * not currently supported
     * int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
     * Else the remote object has acquired a primary reference.
     */

    BR_DEAD_REPLY = _IO('r', 5),  // 发送死亡通知到源进程
    /*
     * The target of the last transaction (either a bcTRANSACTION or
     * a bcATTEMPT_ACQUIRE) is no longer with us.  No parameters.
     */

    BR_TRANSACTION_COMPLETE = _IO('r', 6),  // BC_TRANSACTION, BC_REPLY的返回命令,通知源进程命令已接收,正在处理
    /*
     * No parameters... always refers to the last transaction requested
     * (including replies).  Note that this will be sent even for
     * asynchronous transactions.
     */

    BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),  // 增加 Service 组件的 弱引用计数
    BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),  // 增加 Service 组件的 强引用计数
    BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),  // 减少 Service 组件的 弱引用计数
    BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie), // 减少 Service 组件的 强引用计数
    /*
     * void *:  ptr to binder
     * void *: cookie for binder
     */

    BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
    /*
     * not currently supported
     * int: priority
     * void *: ptr to binder
     * void *: cookie for binder
     */

    BR_NOOP = _IO('r', 12),    // 通知 进程 执行一个 空操作,目的是方便以后可以接收返回协议代码 BR_SPAWN_LOOPER
    /*
     * No parameters.  Do nothing and examine the next command.  It exists
     * primarily so that we can replace it with a BR_SPAWN_LOOPER command.
     */

    BR_SPAWN_LOOPER = _IO('r', 13),  // Drvier 主动请求 进程 增加新的线程来处理通信请求
    /*
     * No parameters.  The driver has determined that a process has no
     * threads waiting to service incoming transactions.  When a process
     * receives this command, it must spawn a new service thread and
     * register it via bcENTER_LOOPER.
     */

    BR_FINISHED = _IO('r', 14),
    /*
     * not currently supported
     * stop threadpool thread
     */

    BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),   // 死亡通知 Client 
    /*
     * void *: cookie
     */
    BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),  // Client 请求注销 死亡通知后,使用该命令通知 Client 进程
    /*
     * void *: cookie
     */

    BR_FAILED_REPLY = _IO('r', 17), // 当 BC_TRANSACTION 异常时,使用该命令通知 源进程
    /*
     * The the last transaction (either a bcTRANSACTION or
     * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory).  No parameters.
     */
};
  1. BR_ERROR
    通信数据: 整数(错误代码)
    Binder Driver 处理请求时异常,使用 BR_ERROR 通知应用程序.

  2. BR_OK
    通信数据: 无
    Binder Driver 成功处理了请求,使用 BR_OK 通知应用程序.

  3. BR_TRANSACTION, BR_REPLAY
    通信数据: binder_transaction_data
    Client 请求 Service , Driver 使用 BR_TRANSACTION 通知 Service 进程处理该请求.
    Service 处理完了请求, Drvier 使用 BR_REPLY 给 Client 进程返回结果.

  4. BR_DEAD_REPLY:
    通信数据: 无
    Drvier 处理请求时,发现目标进程或目标线程已经死亡,使用 BR_DEAD_REPLY 通知源进程.

  5. BR_TRANSACTION_COMPLETE:
    通信数据: 无
    Driver 接收到 BC_TRANSACION 或这 BC_REPLY 时,使用 该命令 通知应用程序,命令代码已被接收,正在发给目标进程或目标线程.

  6. BR_INCREFS, BR_ACQUIRE, BR_RELEASE, BR_DECREFS:
    通信数据: binder_ptr_cookie
    BR_INCREFS, BR_DECREFS 增加/减少 Service 组件的 弱引用计数.
    BR_ACQUIRE, BR_RELEASE 增加/较少 Service 组件的 强引用计数.

  7. BR_NOOP:
    空操作
    为了方便以后可以替换为 BR_SPAWN_LOOPER

  8. BR_SPAWN_LOOPER:
    通信数据: 无
    Drvier 发现没有进程没有足够的线程处理请求时,使用该命令来通知进程增加一个新的线程到 Binder 线程池 中.

  9. BR_DEAD_BINDER, BR_CLEAR_DEATH_NOTIFICATION_DONE:
    通信数据: void 指针, 指向 Service 组件死亡通知的对象地址.
    当 Drvier 监测到 Service 死亡时,使用 BR_DEAD_BINDER 通知 Client 进程.
    当 Client 进程通知 Driver 注销之前注册的死亡通知时, Drvier 指向完这个注销操作后,使用 BR_CLEAR_DEATH_NOTIFICATION_DONE 通知 Client 进程.

binder_ptr_cookie

// 描述 Binder 实体对象 或 死亡通知
struct binder_ptr_cookie {
    binder_uintptr_t ptr;
    binder_uintptr_t cookie;
};

/*
 当 描述 binder_node 时,ptr 和 cookie 等同于 binder_node 的 ptr 和 cookie
*/
/*
当 描述 Service 组件的死亡通知时, ptr 指向 binder_ref 的 desc,cookie 指向 接收死亡通知的 对象地址
*/

binder_transaction_data

用来描述进程间通信所传输的数据

struct binder_transaction_data {
    /* The first two are only used for bcTRANSACTION and brTRANSACTION,
     * identifying the target and contents of the transaction.
     */
    union {
        /* target descriptor of command transaction */
        __u32   handle;       // 如果目标是 binder_ref, handle 表示 binder_ref 的 desc
        /* target descriptor of return transaction */
        binder_uintptr_t ptr; // 如果目标是 binder_node ,ptr 指向 binder_node 对应的 Service 组件的 弱引用计数对象(weakref_impl) 的地址
    } target;
    binder_uintptr_t    cookie; /* target object cookie */
    // 当 执行 BR_TRANSACTION 时有意义,指向目标 Service 组件的地址

    __u32       code;       /* transaction command */
    // code 是 用户命令,Drvier 并不关心

    /* General information about the transaction. */
    __u32           flags;
    // flags 描述通信特征
    /*
    
    enum transaction_flags {
    TF_ONE_WAY  = 0x01, /* 单向,异步,无返回值 */
    TF_ROOT_OBJECT  = 0x04, /* contents are the component's root object */
    TF_STATUS_CODE  = 0x08, /* 表示 data 成员变量描述的数据缓冲区是一个 4字节的状态码 */
    TF_ACCEPT_FDS   = 0x10, /* 源进程不允许目标进程返回的结果数据中包含文件描述符 */
    };
    */

    pid_t       sender_pid;
    uid_t       sender_euid;
    binder_size_t   data_size;  /* number of bytes of data */
    binder_size_t   offsets_size;   /* number of bytes of offsets */

    /* If this transaction is inline, the data immediately
     * follows here; otherwise, it ends with a pointer to
     * the data buffer.
     */
    union {
        struct {
            /* transaction data */
            binder_uintptr_t    buffer;
            /* offsets from buffer to flat_binder_object structs */
            binder_uintptr_t    offsets;
        } ptr;           // 数据较大时,需要动态分配内存,由 ptr 描述
        __u8    buf[8];  // 数据较小时,使用 buf 来传递数据
    } data;
};

/*
 * ptr 说明:
 * 当 buffer 指向的数据中包含 Binder 对象时,那么 offsets 数组 用来描述 Binder 对象的位置。
 * 有了这个偏移数组后,Drvier 维护 binder_node 和 binder_ref 的引用计数
*/
|                                                                              |                                 |
|------------------------------------data_size---------------------------------|-----------offset_size-----------|
|---------------------------n2----------------------|                          |                                 |
|-------n1--------|                                 |                          |                                 |
|================================================================================================================|
|                 |                         |       |                          |                   |             |
|    ......       |  flat_binder_object     |  ...  |    flat_binder_obejct    |        n1         |      n2     |
|                 |                         |       |                          |                   |             |
|================================================================================================================|
|                                                                              |
|                                                                              |
data.ptr.buffer                                                                |
                                                                        data.ptr.offsets

falt_binder_object

// 描述 binder 实体对象
// 描述 binder 引用对象
// 描述 文件描述符

struct flat_binder_object {
    struct binder_object_header hdr;
    __u32               flags;

    /* 8 bytes of data. */
    union {
        binder_uintptr_t    binder; /* local object */  // 描述 binder 实体对象,指向 Service 组件内部弱引用计数对象(weakref_impl) 的地址
        __u32           handle; /* remote object */     // 描述 Binder 引用对象,binder 引用对象的 句柄
    };

    /* extra data associated with local object */
    binder_uintptr_t    cookie;  // 指向 Service 组件的地址
};

enum {
    BINDER_TYPE_BINDER  = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),         // Binder 实体对象
    BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),     // Binder 实体对象
    BINDER_TYPE_HANDLE  = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),         // Binder 引用对象
    BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),     // Binder 引用对象
    BINDER_TYPE_FD      = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),         // 文件描述符
    BINDER_TYPE_FDA     = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE),         //
    BINDER_TYPE_PTR     = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE),         // 
};
``

相关文章

网友评论

      本文标题:Binder Drvier 1: 重要结构

      本文链接:https://www.haomeiwen.com/subject/tijiyftx.html