26
2017
09

Android Binder 机制初步学习 笔记(一)—— 概述及数据结构介绍


NOTE

  • 源码版本:Android 7.1.2。
  • 内核版本:android-goldfish-3.4
  • 内核下载:git clone https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish.git (清华镜像站)
  • 以下分析思路均来自老罗的《Android 系统源代码情景分析(修订版)》

Binder 机制简介

  • Linux 内核提供了多种进程间通讯机制:
    • Pipe:管道。
    • Signal:信号。
    • Message:消息队列。
    • Share Memory:共享内存。
    • Socket:插口。
  • Android 虽是基于 Linux 内核而开发的,但并没有采用这些传统通讯机制,而是自己开发了一套新的机制,即 Binder
  • Binder 优势:
    • 进程间传输数据时仅执行一次拷贝操作。
    • 因此提高了效率,同时节省了空间。
  • Binder 机制中的关键词:
    1. OpenBinderBinder 机制是在它的基础上实现的。(Wiki:OpenBinder
    2. CS 通讯方式:客户端 Client / 服务端 Server
    3. Server 进程:提供服务 Service 的进程。
    4. Client 进程:访问服务的进程。
    5. Service 组件:同一个 Server 可以运行多个组件向 Client 提供服务,提供服务的组件即 Service 组件。
    6. Service 代理对象:同一个 Client 可以同时向多个 Server 请求服务,每个请求都对应有一个 Client 组件,这个组件即是 Service 代理对象。
    7. Binder 线程池:每个 ServerClient 进程都会维护一个 Binder 线程池来处理进程间通讯请求,service 的提供与访问是可并发的。
    8. Binder 驱动程序:向用户空间暴露一个设备文件 /dev/binder,使应用程序进程可以间接通过它建立通信通道。
    9. Service Manager 组件
      • Service 组件启动,就会将自己注册到一个 Service Manager 中,以便 Client 组件可以找到它。
      • 可称为 Binder 机制的上下文管理者。
      • 可看做一个特殊的 Service 组件。
    10. open:系统接口,用于打开 Binder 设备。
    11. mmap:系统接口,提供内存映射操作。
    12. ioctl:系统接口,提供内核缓冲区管理操作,可实现读、写功能。
  • ClientServiceService ManagerBinder 关系:
    1. ClientServiceService Manager 运行在用户空间。
    2. Binder 驱动程序运行在内核空间。
    3. 系统提供 Service ManagerBinder
    4. ClientService 由应用程序实现。
    5. 通过 openmmapioctlBinder 设备交互。

@图 1. 关系图


Binder 基础数据结构分析

  • NOTE
    • 结构体中经常能看到成员变量 debug_id ,它是用来标识 Binder 实体对象身份,帮助调试 Binder 驱动的,下面的分析中这个就忽略掉。
    • 数据结构介绍的部分内容比较多,我觉得在这部分,不用一开始就一一理清楚它们的详细用处,只需要大概了解每个结构体的用处就好。等到以后分析实现机制的时候,碰到不太了解的成员变量时再回头来看,这样能理解得比较深刻。

1. binder.c

  • 位置:kernel/goldfish/drivers/staging/android/binder.c
  • 该文件中的结构体都是在 Binder 驱动程序内部进行使用的。

1.1 struct 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,
        } type;
};
  • binder_work 结构用于描述待处理的工作项
  • 工作项有可能属于一个进程,也可能属于某个线程。
  • 成员变量
    1. entry:将该结构体嵌入到一个宿主结构中。
    2. type:描述工作项类型,可判断出该结构嵌入的宿主类型。

1.2 struct 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;
        void __user *ptr;
        void __user *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;
};
  • binder_node 结构描述一个 Binder 实体对象
  • 每个 Service 组件在驱动中都对应一个 Binder 实体,描述它在内核中的状态。
  • Binder 驱动通过强 (弱)引用计数技术维护实体的生命周期。
  • 成员变量
    1. work:即工作项。
    2. proc:指向一个 Binder 实体对象的宿主进程。
    3. rb_node:宿主进程用红黑树维护内部 Binder 实体,该变量则是红黑树中一个节点。
    4. dead_node:宿主进程死亡,这个 Binder 实体就通过该变量保存在全局 hash 表中。
    5. ref
      • 一个 Binder 实体可被多个 Client 组件引用,于是驱动用 binder_ref 结构描述这些引用关系。
      • 将引用同一个 Binder 实体的所有引用保存在 hash 表中。
      • 该成员变量用于描述这个 hash 表。
      • 驱动通过它可知哪些 Client 组件引用了同一 Binder 实体。
    6. internal_strong_refs && local_strong_refs:描述强引用计数。
    7. local_weak_refs:描述弱引用计数。
    8. has_strong_ref && has_weak_ref
      • 一个 Binder 实体请求一个 Service 执行某一操作,则增加该 Service 组件的强(弱)引用计数。
      • 相应地,Binder 实体将它的这两个变量置为 1
    9. pending_strong_ref && pending_weak_ref
      • 1 时,表明正处于 Binder 实体向 Service 组件请求改变引用计数的过程
      • 0 时,表明上述过程结束
    10. ptr && cookie:指向用户空间地址。
      • ptr 指向 Service 组件内部引用计数对象(weakref_impl 类型)地址。
      • cookie 指向该 Service 组件地址。
    11. has_async_transaction:描述 Binder 实体是否正在处理异步事务。(1 为是, 0 为否)
    12. async_todo
      • 异步事务队列。
      • 异步事务优先级低于同步,表现为同同一时刻,一个 Binder 实体所有异步事务至多处理一个,其余等待。而同步事务无限制。
    13. min_priority:处理来自 Client 的请求时,所要求的处理线程(Server 中的一个线程)应具备的最小线程优先级。
    14. accept_fds:表示是否可接收包含文件描述符的通讯数据(1 可以,0 不可)。

1.3 struct binder_ref_death

struct binder_ref_death {
        struct binder_work work;
        void __user *cookie;
};
  • binder_ref_death 用来描述一个 Service 组件的死亡接收通知:
    • Service 组件所在进程可能会意外崩溃。
    • Client 进程需要在引用的 Service 组件死亡时得到通知,以便做出相应处理。
  • 驱动决定向 Client 发送组件死亡通知时,将该结构体封装成一个工作项,并设置相应 work 值,再加入到 Clienttodo 队列中等待处理。
  • 成员变量
    1. work:标志一个具体的死亡通知类型。
    2. cookie:保存负责接收死亡通知的对象地址。

1.4 struct 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;
        int strong;
        int weak;
        struct binder_ref_death *death;
};
  • binder_ref 结构用来描述一个 Binder 引用对象:
    • 每个 Client 组件在 Binder 驱动中都对应一个引用对象,用于描述它在内核中状态。
    • 驱动通过强(弱)引用计数技术来维护引用对象的生命周期。
  • 成员变量
    1. node:描述引用对象所引用的 Binder 实体。
    2. node_entry:每个 Binder 实体都有一个 hash 表,该变量即是这个表的节点。
    3. desc:句柄,用于描述 Binder 引用对象。(其值在进程范围内唯一,所以在不同进程中可能有相同的句柄值存在)
    4. proc:指向引用对象的宿主进程。
    5. rb_node_desc && rb_node_node:宿主进程用两个红黑树保存所有 Binder 引用对象,分别以句柄值和对应 Binder 实体地址作为关键字,这两个成员变量即为对应的树中节点。
    6. strong && weak:强引用计数与弱引用计数。
    7. death:指向一个 Service 组件的死亡接收通知。

1.5 struct binder_buffer

struct binder_buffer {
        struct list_head entry; /* free and allocated entries by address */
        struct rb_node rb_node; /* free entry by size or allocated entry */
                                /* by address */
        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 结构描述一个内核缓冲区,用于进程间数据传输
  • 成员变量
    1. entry:驱动中内核缓冲区列表的节点。
    2. free:表示是否为空闲缓冲区,1 为是。
    3. rb_node
      • 进程用两个红黑树保存内核缓冲区信息。
      • free1,则该变量表示空闲红黑树的节点。
      • free0,表示正在使用的内存缓冲区红黑树节点。
    4. transaction:内核缓冲区正在交给哪个事务。
    5. target_node:正在使用缓冲区的 Binder 实体。
    6. allow_user_free:若值为 1,当 Service 组件处理完该事务后,就会请求驱动程序释放该内存缓冲区。
    7. async_transaction:表示关联的是否是一个异步事务,是为 1,否则为 0
    8. data:指向一块大小可变的数据缓冲区,这是通讯数据真正保存的地方。
      • offset_size:偏移数组大小。用于记录 Binder 对象在缓冲区中位置。
      • data_size:数据缓冲区大小。

1.6 struct binder_proc

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;
};
  • binder_proc 结构描述一个正在使用 Binder 机制的进程。
  • 成员变量
    1. proc_node:进程调用 open 打开 Binder 设备时,驱动会将其映射到 binder_proc 结构,并保存在全局 hash 表中,这个变量即是表中的节点。
      • pid:进程的进程组 ID
      • tsk:任务控制块。
      • files:打开文件结构体数组。
    2. buffer_size:进程调用 mmapBinder 设备映射到进程的地址空间,实际上这是请求驱动为它分配一块内核缓冲区,该成员变量即是缓冲区的大小。
      • buffer:内核空间地址(驱动内部使用)。
      • vma:用户空间地址(应用程序使用)。
      • user_buffer_offset:上面两个地址的差值,用它可以通过一个地址找到另一个地址。
    3. buffers:由于 buffer 指向的是一块大的缓冲区,为方便管理将其分成若干小块,保存在一个列表中,按照地址从小到大顺序排列,而该变量则指向了列表的头部。
      • allocated_buffers:描述一个红黑树,保存了正在使用的(已分配物理页面)的内核缓冲区。
      • free_buffers:红黑树,保存了空闲的内核缓冲区。
      • buffer_free:空闲内核缓冲区的大小。
      • free_async_space:保存当前可用于保存异步事务数据的缓冲区大小。
    4. thread:一个红黑树的根节点,以线程 ID 作为关键字,组织进程的 Binder 线程池。
      • max_thread:驱动最多可主动请求注册的线程数量。
      • ready_thread:进程当前空闲 Binder 线程数。
    5. todo:待处理工作项队列。
      • wait:等待队列,对应睡眠的空闲 BInder 线程。
      • default_priority:默认优先级。
    6. nodes:描述一个红黑树,以 Binder 实体的成员变量 ptr 为关键字。
    7. refs_by_desc:描述一个红黑树,以 Binder 引用对象的成员 desc 为关键字。
    8. refs_by_node:描述一个红黑树,以 Binder 引用对象的成员 node 为关键字。
    9. delivered_death:保存死亡通知工作项的队列。
    10. stats:统计进程数据(如接收到的进程间通信请求次数)。
    11. deferred_work_node:一个 hash 表,保存进程可延迟执行的工作项。
      • deferred_work:描述该延迟工作项具体类型。
      • BINDER_DEFERRED_PUT_FILES:与文件描述符关闭相关的延迟。
      • BINDER_DEFERRED_FLUSH:与唤醒空闲 Binder 线程相关的延迟。
      • BINDER_DEFERRED_RELEASE:与资源释放相关的延迟。
enum binder_deferred_state {
        BINDER_DEFERRED_PUT_FILES    = 0x01,
        BINDER_DEFERRED_FLUSH        = 0x02,
        BINDER_DEFERRED_RELEASE      = 0x04,
};

1.7 struct binder_thread

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_NEED_RETURN = 0x20
};

struct binder_thread {
        struct binder_proc *proc;
        struct rb_node rb_node;
        int pid;
        int looper;
        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 */
                /* buffer. Used when sending a reply to a dead process that */
                /* we are also waiting on */
        wait_queue_head_t wait;
        struct binder_stats stats;
};
  • binder_thread 结构描述了 Binder 线程池中的一个线程。
  • 成员变量
    1. proc:指向宿主进程。
    2. rb_node:红黑树中的节点(进程用一个红黑树组织线程池中的线程)。
    3. pid:线程 ID
    4. looper:线程状态。
      • BINDER_LOOPER_STATE_REGISTERED:驱动程序请求注册线程的情况。
      • BINDER_LOOPER_STATE_ENTERED:应用程序主动注册线程的情况。
      • BINDER_LOOPER_STATE_EXITED:线程退出时。
      • BINDER_LOOPER_STATE_INVALID:异常情况。
      • BINDER_LOOPER_STATE_WAITING:空闲状态。
      • BINDER_LOOPER_STATE_NEED_RETURN:表示线程需要马上返回用户空间。
    5. todo:保存来自 Client 的请求(指定该线程处理)的队列。
    6. transaction_stack:描述事务的堆栈。
    7. wait:线程正在处理事务 T1,同时需要其他线程处理另一个事务 T2,此时它就会睡眠在 wait 队列中,直到 T2 处理完成。
    8. return_error && return_error2:异常情况时返回的错误信息。
    9. stats:统计线程数据,如收到的通信请求次数。

1.8 struct binder_transaction

struct binder_transaction {
        int debug_id;
        struct binder_work work;
        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;
        unsigned int    code;
        unsigned int    flags;
        long    priority;
        long    saved_priority;
        uid_t   sender_euid;
};
  • binder_transaction 结构描述了进程间的通信过程:
    • 通常称这个过程为事务
  • 成员变量
    1. need_reply:区分事务是同步(值为 1)或异步(值为 0)。
    2. from:指向发起事务的线程(源线程)。
    3. to_proc:指向负责处理该事务的进程(目标进程)。
    4. to_thread:指向负责处理该事务的线程(目标线程)。
    5. priority:源线程优先级。
    6. sender_euid:用户 ID
    7. saved_priority:修改线程优先级时的原值存档。
    8. buffer:指向驱动为该事务分配的一块内核缓冲区。
    9. code && flag:从进程间通信数据中拷贝而来,具体内容参考结构体 binder_transaction_data
    10. from_parent:描述事务所依赖的另一个事务。
    11. to_parent:描述目标线程下一个需要处理的事务。

2. binder.h

  • 位置:kernel/goldfish/drivers/staging/android/binder.h

2.1 struct binder_write_read

#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)

struct binder_write_read {
        signed long     write_size;     /* bytes to write */
        signed long     write_consumed; /* bytes consumed by driver */
        unsigned long   write_buffer;
        signed long     read_size;      /* bytes to read */
        signed long     read_consumed;  /* bytes consumed by driver */
        unsigned long   read_buffer;
};
  • BINDER_WRITE_READ 是最重要的 IO 控制命令,它控制读写操作。
  • binder_write_read 结构描述进程间通信过程中传输的数据。
  • 成员变量
    1. 输入数据
      • write_buffer:指向一个用户空间缓冲区,内容为要传输到驱动的数据。
      • write_size:相应缓冲区大小。
      • write_consumed:描述驱动从缓冲区中处理了多少字节数据。
    2. 输出数据
      • read_buffer:指向一个用户空间缓冲区,内容为驱动返回到用户空间的结果数据。
      • read_size:缓冲区大小。
      • read_consumed:应用程序从缓冲区中处理的字节数量。
  • write_buffer && read_buffer格式
    • 都是数组,数组每个元素都由一个通信协议代码及其通信数据组成。
    • 命令协议代码
      • write_buffer 中使用的协议代码。
      • 通过 BinderDriverCommandProtocol 定义。
    • 返回协议代码
      • read_buffer 中使用的协议代码。
      • 通过 BinderDriverReturnProtocol 定义。
    • 结构图如下。

@图 2. 用户空间缓冲区数据格式

2.2 enum BinderDriverCommandProtocol

enum BinderDriverCommandProtocol {
        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, int),
        /* * 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, int),
        /* * void *: ptr to transaction data received on a read */

        BC_INCREFS = _IOW('c', 4, int),
        BC_ACQUIRE = _IOW('c', 5, int),
        BC_RELEASE = _IOW('c', 6, int),
        BC_DECREFS = _IOW('c', 7, int),
        /* * 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_ptr_cookie),
        /* * void *: ptr to binder * void *: cookie */

        BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
        /* * void *: ptr to binder * void *: cookie */

        BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),
        /* * void *: cookie */
};
  • 命令协议 – 枚举成员:
    1. 进程间请求执行操作
      • BC_TRANSACTION:请求驱动将通信数据传递到目标进程。
      • BC_REPLY:请求驱动将结果传递给源进程。
    2. BC_ACQUIRE_RESULT:当前驱动程序实现中不支持。
    3. BC_FREE_BUFFER:释放相应的内核缓冲区。
    4. Binder 引用对象计数(根据句柄值获取对象):
      • BC_INCREFS && BC_DECREFS:增加/减少弱引用计数。
      • BC_ACQUIRE && BC_RELEASE:增加/减少强引用计数。
    5. 驱动第一次增加一个 Binder 实体引用计数
      • BR_ACQUIRE(返回协议):请求对应 Service 进程增加相应 Service 组件强引用计数。
      • BR_INCREFS(返回协议):请求对应 Service 进程增加相应 Service 组件弱引用计数。
      • BC_ACQUIRE_DONE && BC_INCREFS_DONE:返回操作结果给驱动。
    6. BC_ATTEMPT_ACQUIRE:当前驱动实现中不支持。
    7. 线程注册
      • BC_REGISTER_LOOPER:线程将自己注册到驱动后,给驱动的通知。
      • BC_ENTER_LOOPER:驱动主动请求进程注册新线程到线程池,线程成功注册后通知。
      • BC_EXIT_LOOPER:线程退出,通知驱动注销线程。
    8. 死亡接收通知
      • BC_REQUEST_DEATH_NOTIFICATION:向驱动注册关于它所引用的 Service 组件的死亡通知。
      • BC_CLEAR_DEATH_NOTIFICATION:注销之前注册的死亡接收通知。
      • BC_DEAD_BINDER_DONE:进程获得 Service 组件死亡通知时,告知驱动它已处理。

2.3 enum BInderDriverReturnProtocol

enum BinderDriverReturnProtocol {
        BR_ERROR = _IOR('r', 0, int),
        /* * 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. */

        BR_ACQUIRE_RESULT = _IOR('r', 4, int),
        /* * 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),
        /* * 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),
        BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
        BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
        BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
        /* * 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),
        /* * 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),
        /* * No parameters. The driver has determined that a process has no * threads waiting to service incomming 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, void *),
        /* * void *: cookie */
        BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),
        /* * void *: cookie */

        BR_FAILED_REPLY = _IO('r', 17),
        /* * The the last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. */
};
  • 返回协议 – 枚举成员:
    1. BR_ERROR:驱动处理应用某个请求时发生异常,则需通知应用进程。
    2. BR_OK:驱动成功处理应用请求后,通知应用进程。
    3. Client 进程向 Server 进程发出通信请求
      • BR_TRANSACTION:驱动通知 Server 处理请求。
      • BR_REPLY:请求结果数据返回给 Client
    4. BR_ACQUIRE_RESULT:当前驱动实现中不支持。
    5. BR_DEAD_REPLY:驱动处理通信请求时,若目标死亡,则通知源进程。
    6. BR_TRANSACTION_COMPLETE:通知应用,对应的命令协议代码已接收,正在分发给目标进程或目标线程处理。
    7. Service 组件引用计数
      • BR_INCREFS && BR_DECREFS:增加/减少弱引用计数。
      • BR_ACQUIRE && BR_RELEASE:增加/减少强引用计数。
    8. BR_ATTEMPT_ACQUIRE:当前驱动实现中不支持。
    9. BR_NOOP:通知应用程序执行一个空操作,它的存在是为了方便之后可以替换为 BR_SPAWN_LOOPER
    10. BR_SPAWN_LOOPER:驱动发现一个进程没有足够空闲 Binder 线程处理通信请求时,通知其增加一个新线程到 Binder 线程池中。
    11. BR_FINISHED:当前驱动实现中不支持。
    12. 死亡通知
      • BR_DEAD_BINDER:驱动监测到一个 Service 组件死亡事件时,通知相应的 Client 进程。
      • BR_CLEAR_DEATH_NOTIFICATION_DONEClient 通知驱动注销它之前所注册的一个死亡接收通知,驱动执行完注销操作后,通知该 Client
    13. BR_FAILED_REPLY:驱动处理一个进程发出的 BC_TRANSACTION 命令协议时,若发生异常,则通知源进程。

2.4 struct binder_ptr_cookie

struct binder_ptr_cookie {
        void *ptr;
        void *cookie;
};
  • binder_ptr_cookie 结构描述一个 Binder 实体,或描述一个 Service 组件的死亡接收通知。
  • 成员变量
    1. ptr
      • 该结构描述 Binder 实体,则该变量与 binder_node 结构中 ptr 等同。
      • 该结构描述 Service 死亡通知,则指向一个 Binder 引用对象句柄值。
    2. cookie
      • 该结构描述 Binder 实体,则该变量与 binder_node 结构中 cookie 等同。
      • 该结构描述 Service 死亡通知,则指向一个用于接收死亡通知的对象的地址。

2.5 struct binder_transaction_data

enum transaction_flags {
        TF_ONE_WAY      = 0x01, /* this is a one-way call: async, no return */
        TF_ROOT_OBJECT  = 0x04, /* contents are the component's root object */
        TF_STATUS_CODE  = 0x08, /* contents are a 32-bit status code */
        TF_ACCEPT_FDS   = 0x10, /* allow replies with file descriptors */
};

struct binder_transaction_data {
        /* The first two are only used for bcTRANSACTION and brTRANSACTION, * identifying the target and contents of the transaction. */
        union {
                size_t  handle; /* target descriptor of command transaction */
                void    *ptr;   /* target descriptor of return transaction */
        } target;
        void            *cookie;        /* target object cookie */
        unsigned int    code;           /* transaction command */

        /* General information about the transaction. */
        unsigned int    flags;
        pid_t           sender_pid;
        uid_t           sender_euid;
        size_t          data_size;      /* number of bytes of data */
        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 */
                        const void      *buffer;
                        /* offsets from buffer to flat_binder_object structs */
                        const void      *offsets;
                } ptr;
                uint8_t buf[8];
        } data;
};
  • binder_transaction_data 描述进程间传输的数据。
  • 成员变量
    1. target
      • 描述一个目标 Binder 实体:
        • ptr:指向该实体对应的一个 Service 组件内部的一个弱引用计数对象(weakref_impl)地址。
      • 描述一个目标 Binder 引用:
        • handle:指向该引用的句柄值。
    2. cookie:由应用程序指定的额外参数。驱动使用 BR_TRANSACTION 向一个 Server 发出请求时才有意义,指向的是目标 Service 组件地址。
    3. code:通信的两个进程相互约定好的通信代码。
    4. flag:描述进程通信行为特征,取值为 enum transaction_flags
      • TF_ONE_WAY:置 1 时,表示是异步进程间通信。
      • TF_ROOT_OBJECT:未启用。
      • TF_STATUS_CODE:置 1 时,表示成员变量 data 描述的数据缓冲区内容是一个 4 字节状态码。
      • TF_ACCEPT_FDS:置 0 时,表示源进程不允许目标进程返回结果中包含文件描述符。
    5. 发起通信请求的进程:
      • sender_pid:进程 PID
      • sender_euid:进程 UID
    6. data_size && data_offset:描述通信数据缓冲区大小及偏移量。
    7. data:指向一个通信数据缓冲区
      • buf:通信数据较小时用该静态数组传输。
      • ptr:通信数据较大时用该动态分配的缓冲区传输
        • buffer:指向一个数据缓冲区,保存通信数据。
        • offsets:缓冲区中包含 Binder 对象,则用其描述每个对象的位置。
      • 数据缓冲区中每个 Binder 对象都使用一个 flat_binder_object 结构描述,布局结构图如下。

@图 3. Binder进程通信数据缓冲区内存布局

2.6 struct flat_binder_object

#define B_PACK_CHARS(c1, c2, c3, c4) \
        ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
        BINDER_TYPE_BINDER      = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
        BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
        BINDER_TYPE_HANDLE      = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
        BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
        BINDER_TYPE_FD          = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
/* * This is the flattened representation of a Binder object for transfer * between processes. The 'offsets' supplied as part of a binder transaction * contains offsets into the data where these structures occur. The Binder * driver takes care of re-writing the structure type and data as it moves * between processes. */
struct flat_binder_object {
        /* 8 bytes for large_flat_header. */
        unsigned long           type;
        unsigned long           flags;

        /* 8 bytes of data. */
        union {
                void            *binder;        /* local object */
                signed long     handle;         /* remote object */
        };

        /* extra data associated with local object */
        void                    *cookie;
};
  • flat_binder_object 结构可以描述(根据 type 区分):
    • 一个 Binder 实体对象。
    • 一个 Binder 引用对象。
    • 一个文件描述符。
  • 成员变量
    1. type:取值范围与顶部的宏定义及枚举有关
      • BINDER_TYPE_BINDER:描述强类型 Binder 实体。
      • BINDER_TYPE_WEAK_BINDER:描述弱类型 Binder 实体。
      • BINDER_TYPE_HANDLE:描述强类型 Binder 引用。
      • BINDER_TYPE_WEAK_HANDLE:描述弱类型 Binder 引用。
      • BINDER_TYPE_FD:描述文件描述符。
    2. flag:标志值,当结构描述 Binder 实体时有意义
      • 0 ~ 7 位:描述 Binder 实体处理通信请求时,它运行的线程的最小线程优先级。
      • 8 位:描述 Binder 实体是否可将一块包含文件描述符的数据传输给目标进程。
    3. 结构体描述 Binder 实体:
      • binder:指向实体对应的一个 Service 组件内部的一个弱引用计数对象的地址。
      • cookie:指向该 Service 组件地址。
    4. 结构体描述 Binder 引用:
      • handle:描述该引用对象的句柄值。

上一篇:SpringBoot发邮件-注意事项 下一篇:工作随笔---WiFi开发(5)---WIFIWpsConnect类