Android Binder通信02 - 驱动分析 - 架构介绍

一、前言:

上一篇文章介绍了Binder通信系统Framework(用户态)的架构,并且结合代码说明了下注册ServiceManager,注册服务,注册客户端,客户端和服务端通信的业务场景,本节我们继续深入挖掘下,Framework层调用响应API之后,驱动层(内核态)如何处理的,这才是Binder系统的精髓所在!

二、架构图:

  • 在内核态驱动里,会为每一个服务创建一个binder_node,记录了进程的信息,比如:binder_node.proc=server进程
  • ServiceManager启动时候,会在驱动层创建一个全局的binder_node保存到binder_context_mgr_node当中;其他进程都有一个BpServiceManager,它的BpBinder句柄是0,表示binder_context_mgr_node,所以,其他进程都是可以直接和ServiceManager通信的。
  • ServiceManager还会再驱动中创建一个binder_ref(是个红黑树),它是binder_node的引用;
  • ServiceManager在用户态创建一个服务链表svcinfo,里面保存了namehandle
  • ClientServiceManager查询某个服务的时候,只需要传入name(因为它好记,友好);
  • ServiceManager就在链表中根据name找到这个节点,将对应的handle(因为它不好记,但是它不容易重复)传给驱动层;
  • 驱动程序在ServiceManagerbinder_ref红黑树当中,根据handle这个键找到对应的binder_ref;
  • 由于binder_ref当中保存了自己是谁的引用,也就是binder_node,因此,我们就获得了binder_node,代表服务;
  • 再给Client创建新的binder_ref,驱动就返回一个handle(这里面是desc,从1开始)client
  • 同理,Client要和Service通信,首先,client根据handle找到binder_ref,再根据binder_ref找到binder_node,最后根据binder_node找到Service进程;

三、关键数据结构:

前面一直说通过这个找到那个,又通过那个找到nie个,你肯定有点蒙圈,这里面涉及几个关键的数据结构,即:binder_nodebinder_refbinder_proc以及binder_thread,我们就重点介绍下。

1、binder_ref:

cpp 复制代码
// 在驱动代码的binder.c当中:
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;
	struct rb_node rb_node_node;
	struct hlist_node node_entry;
	struct binder_proc *proc; // 表示自己属于哪个进程
	struct binder_node *node; // binder_ref就是这个node的引用
	struct binder_ref_death *death;
};

看到着里面有个binder_node就表示自己是这个node的引用;

2、binder_node:

cpp 复制代码
struct binder_node {
	int debug_id;
	spinlock_t lock;
	struct binder_work work;
	union {
		struct rb_node rb_node;
		struct hlist_node dead_node;
	};
	struct binder_proc *proc; // 代表binder_node依附于哪个进程
	struct hlist_head refs;
	// 省略一部分乱七八糟的代码...
	struct list_head async_todo;
};

里面记录了自己依附于哪个进程;

3、binder_proc:

cpp 复制代码
struct binder_proc {
	struct hlist_node proc_node;
	struct rb_root threads; // 其实就是binder_thread
	struct rb_root nodes;
    struct list_head todo; // todo链表
	// 删除了一些乱起八糟代码...
};

这里面的threads就是binder_thread类型

4、binder_thread:

cpp 复制代码
struct binder_thread {
	struct binder_proc *proc; // 同样也记录了自己属于哪个进程
	struct list_head todo; // todo链表
	// 删除了一些乱七八糟代码...
};

注意,任何人给我发数据都放到我的todo链表中去,更要注意,进程和线程都有todo链表。

5、小结:

  • handle在服务端里面是一个数字,表示某个服务;
  • handle对应的是一个binder_ref;
  • binder_ref里面又有个成员变量node指向这个服务的binder_node;
  • binder_node这个服务又依附于某个进程,因此又有个成员变量proc表示进程binder_proc;
  • binder_proc里面又有很多线程去处理客户端的请求啊,因此有个成员变量threads(用红黑树实现),表示一个binder_thread;
  • binder_thread里面又有个todo链表,需要处理的任务都放到这个里面去;

四、数据传输:

1、数据流转图:

觉得文字比较匮乏,画了一个数据流转图,很直观:

2、数据复制次数:

对于一般应用程序,发送时候Client将数据从用户空间拷贝到内核空间一次,Server接收到之后,要从内核空间拷贝到用户空间一次。数据至少需要复制两次。

但是,对于我们binder系统,Server进程的用户空间和内核空间通过mmap做了映射,所以省去了这一次拷贝。数据只需要拷贝一次。但是注意,数据头还是需要拷贝两次的。

五、总结:

本章着重讲了一下架构,并没有涉及多少代码,后续通过实际用到的情景进行分析代码。

相关推荐
YF021131 分钟前
Frida如何稳定连接PC端跟Android手机端
android·mac·xposed
周杰伦_Jay38 分钟前
【Go 语言主流 Web】 框架详细解析
开发语言·后端·微服务·架构·golang
闲人编程1 小时前
Django微服务架构:单体应用拆分解耦实践
微服务·架构·消息队列·django·api·通信·codecapsule
颜颜yan_1 小时前
基于CANN多Stream异步执行的智能推理管道:突破传统串行瓶颈
运维·架构·stream·昇腾·cann
O***P5712 小时前
【MySQL】MySQL内置函数--日期函数字符串函数数学函数其他相关函数
android·mysql·adb
z***43842 小时前
MySQL-mysql zip安装包配置教程
android·mysql·adb
无心水2 小时前
【Python实战进阶】7、Python条件与循环实战详解:从基础语法到高级技巧
android·java·python·python列表推导式·python条件语句·python循环语句·python实战案例
吴法刚2 小时前
Gemini cli 源码分析之-Agent分析-Agent架构系统分析
架构·agent·ai编程·gemini
拾忆,想起2 小时前
Dubbo服务超时与重试策略配置指南:构建 resilient 微服务架构
服务器·网络·微服务·云原生·架构·dubbo
q***51892 小时前
【语义分割】12个主流算法架构介绍、数据集推荐、总结、挑战和未来发展
算法·架构