1.Binder 的数据结构介绍

struct binder_work {
  struct list_head entry;
  enum{
    BINDER_WORK_TRANSACTION = 1;
    BINDER_WORK_TRANSACTION_COMPLETE,
    BINDER_WORK_NODE,
    BINDER_WORD_DEAD_BINDER,
    BINDER_WODK_DEAD_BINDER_AND_CLEAR,
    BINDER_WORK_CLEAR_DETAH_NOTIFICATION,
  } type
};

描述一个待处理工作项;可能属于进程,可能属于某个线程。type 描述工作类型,entry 嵌入到宿主结构。根据 type 判断判断 binder_work 锁嵌入的宿主、


struct binder_node {
  int debug_id;
  struct binder_work work;
  union {
    struct rb_node rb_node;//在 binder_proc 维护binder 实体的红黑树节点
    struct hlist_node dead_node;
  };
  struct binder_proc *proc;//描述宿主进程
  struct hlist_head resf;//维护了引用了该 Binder 实体的 binder_ref 的表
  int internal_strong_refs;
  int locak_weak_refs;
  binder_uintptr_t ptr;//指向 Service 组件内部一个引用计数对象地址
  binder_uintptr_t cookie;//指向该 Service 组件地址
  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; //该Binder 实体是否可以接受包含文件描述符的通信数据
  unsigned min_priority:8; //要求的处理线程具备的最小线程优先级
  struct list_head anync_todo; //异步事件队列
}

描述一个 Binder 实体对象。每一个 Service 组件在 Binder 驱动都对应一个 Binder 实体对象来描述在内核的状态。宿主进程 binder_proc *proc 内部有一个红黑树维护进程内的所有 Binder 实体对象,节点是 rb_node。
下面的 binder_ref 来描述 Binder 实体在 Client 中的引用关系。


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

描述 Service 组件的死亡接受通知。
binder_work work 取值为 BINDER_WORK_DEAD_BINDER、BINDER_WORK_CLEAR_DEATH_NOTIFICATION、BINDER_WORK_DEAD_BINDER_AND_CLEAR。
当 Binder 驱动向 Client 进程发送 Service 死亡通知时,将一个 binder_ref_death 封装为一个工作项,根据实际情况设置 work,然后将这个工作项添加到 Client 的 todo 队列。


struct binder_ref {
  int debug_id;
  struct rb_node rb_node_desc;
  struct rb_node rb_node_node;
  struct hlist_node node_entry;
  struct binder_proc *proc;  //binder 引用的宿主进程。
  struct binder_node *node; //该 ref 所引用的 Binder 实体对象
  uint32_t desc; //句柄值,描述一个 Binder 引用对象。
  int strong;
  int weak;
  struct binder_ref_death *death;
}

描述一个 Binder引用对象。同一个进程内的不同的 binder_ref 的 desc 不同。Binder 驱动根据 desc 找到 binder_ref,根据 binder_ref 找到 binder_node,根据 binder_node 找到 Service 服务。
binder_proc 用两个红黑树保存所有的 Binder 引用对象。key 分别为句柄值(desc)和 Binder 实体的地址(binder_node)。节点分别是 rb_node_desc 和 rb_node_node


struct binder_buffer {
  struct list_head entry;
  struct rb_node rb_node;

  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; // 内核缓冲区交由使用的 Binder 实体
  size_t data_size;  //数据缓冲区大小
  size_t offset_size; //偏移数组大小
  uint8_t data[0]; //大小可变的数据缓冲区,真正用来保存通信数据。
}

描述一个内核缓冲区,用以进程间传输数据。
Binder驱动为了方便管理,将分配给进程的一大块内核缓冲区划为若干小块。每一个小块就是 binder_buffer
每个使用 Binder 通信的进程在 Binder 驱动中都有一个内核缓冲区列表,节点是 entry。进程使用两个红黑树维护正在使用的内核缓冲区和空闲的内核缓冲区。红黑树的节点是 rb_node。
数据缓冲区(data_size)后有一个偏移数组(offset_size)记录数据缓冲区中 Binder 对象。


struct binder_proc {
  struct hlist_node proc_node;
  struct rb_root threads; //维护 Binder 线程池。binder_thread
  struct rb_root nodes; //维护该进程的所有Binder 实体
  struct rb_root refs_by_desc; // desc 作为 key,维护Binder引用(binder_ref)
  struct rb_root refs_by_node; //binder_ref->node 作为 key,维护 Binder(引用)
  int pid; //进程组 ID
  struct vm_area_struct *vma; //物理空间在用户空间映射的虚拟内存
  struct mm_struct *vma_vm_vm;//物理空间在内核空间映射的虚拟内存
  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; //保存该进程的 binder_buffer进程,以地址排列
  struct rb_root free_buffers; //未使用的 binder_buffer(未分配物理内存),以 binder_buffer 大小排列
  struct rb_root allocated_buffers; //正在使用的 binder_buffer(已经分配物理内存)
  size_t free_async_space; // 可以用来保存异步事务数据的内核缓冲大小

  struct page **pages;  //映射的页数
  size_t buffer_size; //内核缓冲区大小
  uint32_t buffer_free; //空闲内核缓冲区大小(free_buffers)
  struct list_head todo; //工作队列
  wait_queue_head_t wait; //空闲 Binder 线程组成的队列
  struct binder_stats stats;
  struct list_head delivered_death; //死亡通知队列
  int max_threads;
  int requested_threads;
  int requested_threads_started;
  int ready_threads; //当前进程空闲 Binder线程数目
  long default_priority;
  struct dentry *debugfs_entry;
};

描述一个正在使用 Binder 进程间通信的进程。(在进程调用 open 打开/dev/binder 时由 Binder 驱动自动创建,同时保存到一个全局 hash)
进程open dev/binder 后,mmap 映射。即请求 Binder 驱动分配一块内核缓冲区。


struct binder_thread{
  struct binder_proc *proc; //宿主进程
  struct rb_node rb_node;
  int pid;
  int looper;
  struct binder_transaction *transacton_stack; //事务堆栈
  struct list_head todo; //处理队列
  uint32_t return_error;
  uint32_t return_error_2;

  wait_queue_head_t wait;
  struct binder_stats stats; //统计 Binder 线程数据
}

描述 Binder 线程池中的一个线程。是 binder_proc 的 threads 中的节点。


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; //事务是同步的还是异步

  struct binder_buffer *buffer; //Binder 驱动为该事务分配的内核缓冲区
  unsigned int code; //
  unsigned int flags;  //
  long priority;
  //saved_priority 和 sender_euid 识别事务发起方身份
  long saved_priority; //源线程优先级
  kuid_t sender_euid; //源线程用户 ID
}

描述 Binder 通信过程,即事务。


struct binder_write_read {
  //描述输入数据,从用户空间传到 Binder 驱动
  binder_size_t wirte_size; //write_buffer 的大小,单位字节
  binder_size_t write_consumed;//表示 Binder 驱动已经处理的数据大小
  binder_uintptr_t write_buffer;//指向用户空间缓冲区,保存着数据
  //描述输出数据,从 Binder 驱动返回给用户空间
  binder_size_t read_size;//read_buffer 大小
  binder_size_t read_consumed;//指用户应用已经处理的大小
  binder_uintptr_t read_buffer;//指向一个用户空间缓冲区
}

描述进程间通信所传输的数据。
write_buffer 与 read_buffer 内数据是格式固定的数组,格式是通信协议代码及通信数据。

Code-1 Content of Code-1 Code-2 Content of Code-2 ... Code-n Content of Code-n

协议分为命令协议代码(在 write_buffer 使用)[binder_driver_command_protocol]和返回协议代码(在 read_buffer 使用)[binder_driver_return_protocol]。

enum binder_driver_command_procotol {
  //Binder 请求执行操作。源进程使用BC_TRANSACTION请求 Binder驱动 转发通信数据给目标进程
  BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), 
  //目标进程处理完毕后,使用BC_REPLY请求 Binder驱动 转发结果数据给源进程
  BC_REPLY = _IOW('c', 1, struct binder_transaction_data),

  BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
  //目标进程处理完请求后,使用BC_FREE_BUFFER请求 Binder 驱动释放内核缓冲区
  BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
  //下面 4 个的通信数据是一个 Binder 引用的句柄。用来请求 Binder 驱动增加或减少 Binder 引用的引用计数
  BC_INCREFS = _IOW('c', 4, __u32),//增加弱引用
  BC_ACQUIRE = _IOW('c', 5, __u32),//增加强引用
  BC_RELEASE = IOW('c', 6, __u32),//减少强引用
  BC_DECREFS = IOW('c', 7, __u32),//减少弱引用
 
  BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
  BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),

  BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
  //Binder 驱动主动注册线程到 Binder 驱动,使用使用BC_REGISTER_LOOPER表明已经准备就绪处理通信请求了
  BC_REGISTER_LOOPER = _IO('c', 11),
  //线程将自己注册到 Binder 驱动后,使用BC_ENTER_LOOPER表明已经准备就绪处理通信请求了
  BC_ENTER_LOOPER = _IO('c', 12),
  //线程退出,表示不再接受IPC 请求
  BC_EXIT_LOOPER = _IO('c', 13),
  //注册死亡接收通知
  BC_REQUEST_DEATH_NOTIFICATION =  _IOW('c', 14, struct binder_handle_cookie),
  //注销死亡接收通知
  BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie),
  //通知 Binder 驱动已经处理好该 Service 死亡通知。
  BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
};
enum binder_driver_return_protocol {
  BR_ERROR = _IOR('r', 0, __s32),
  
  BR_OK = _IO('r', 1),
  //当 Client 当 Service 发出请求,Binder 驱动会使用BR_TRANSACTION通知 Server 进程处理请求。
  //Server 请求返回给 Binder 驱动时,驱动使用BR_REPLY将请求结果返回给 Client 进程
  BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
  BR_REPLY = _IOR('r', 3, struct binder_transaction_data),

  BR_ACQUIRE_RESULT = _IOR('r', 4, __32),
  
  BR_DEAD_REPLY = _IO('r', 5),

  BR_TRANSACTION_COMPLETE = _IO('r', 6),

  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_cooike),

  BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cooike),
  
  BR_NOOP = _IO('r', 12),

  BR_SPAWN_LOOPER = _IO('r', 13),
   
  BR_FINISHED = _IO('r', 14),
  
  BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
  BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
  BR_FAILED_REPLY = _IO('r', 17),
};
Binder 驱动转发请求

struct binder_ptr_cookie {
  binder_uintptr_t ptr;
  binder_uintptr_t cookie;
}

描述一个 Binder 实体对象或者一个 Service 组件的死亡接收通知。
当描述 Binder 实体,ptr 和 cookie 即 binder_node 的 ptr 和 cookie;
当描述 Service 组件时,ptr 指向 Binder 引用对象的句柄值,cookie 指向用来接收死亡通知的对象地址。


struct binder_transaction_data {
  union {
    __u32 handle;  //若是目标 Binder 引用对象,指向 Binder 引用句柄
    binder_uintptr_t ptr;//如果是 Binder 实体,指向 Service 内部一个弱引用计数对象地址。
  } target; //描述一个目标 Binder 对象或者目标 Binder 引用对象
  binder_uintptr_t cookie; //当 Binder 驱动使用 BR_TRANSACTION 向 Service 进程请求,才有意义,指向目标 Serveice 组件地址。
  __u32 code; //Client 与 Service 约定好的通信代码

  __u32 flags; //描述通信行为特征
  pid_t sender_pid; //发起 IPC 的进程 PID
  uid_t sender_euid;  //发起 IPC 的进程 UID
  binder_size_t data_size;  
  binder_size_t offsets_size; // 偏移数据大小

  union{
    struct {
      binder_uintptr_t buffer; //指向数据缓冲区,前面的 data_size 说明数据大小
      binder_uintptr_t offsets;  //如果数据内有 Binder对象,则数据后有偏移数组描述 Binder 对象位置。
    }  ptr;  //数据大使用 ptr
    __u8 buf[8];  //数据比较小使用 buf[8]。
  } data; //指向通信数据缓冲区。
};

描述进程间通信过程中所传输的数据。数据每个 Binder 对象对应一个 flat_binder_object 结构来描述


struct flat_binder_object {
  __u32 type; // 区别描述的是 Binder 实体还是 Binder 引用还是文件描述符
  __u32 flags; //当描述的是 Binder 实体时,有意义。低 7 位代表处理请求时的线程的最小线程优先级。第八位代表是否允许传递含文件描述符的数据(1允许)

  union {
    binder_uintptr_t binder;  //描述的是 Binder 实体时,指向 Binder 实体对应的 Service 组件内的弱引用计数对象地址。cookie 指向 Serivice 组件地址
    __u32 handle;  //  当描述的是Binder 引用时,描述 Binder 引用对象句柄
  }

  binder_uintptr_t cookie; //大概描述的是 Binder 实体时,指向 Service 组件地址
}

描述一个 Binder 实体对象,或 Binder 引用对象,或一个文件描述符。通过 type 区别。
type 类型

#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 实体对象
  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),    //描述一个文件描述符
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容