说说binder

推荐选择方式

场景 推荐通信方式
两个组件属于同一 App Handler、Messenger、AIDL(同包)
两个 App 通信 AIDL、ContentProvider、BroadcastReceiver
进程通信大量数据 Binder 或 mmap + Socket
简单消息通知 BroadcastReceiver、Messenger
数据存储共享 ContentProvider、共享文件
先说Binder ipc通信的底层原理
再说Binder模型。

一次完整的 Binder IPC 通信过程通常是这样:

binder通信原理是一次数据拷贝+内存映射完成的

只有一块数据接收缓存区

  1. 服务端启动的时候调用mmap和binder建立内存映射通道,在服务端的用户空间开辟一块虚拟的地址空间,内核将服务端的这个虚拟空间地址记录,此时没有进行真正的内存映射
  2. 客户端发起数据传输的时候,内核才为服务端这个虚拟空间开辟物理地址空间,才真正进行了内存映射,
  3. 客户端通过系统 copyfromuser() 将数据发送给内核时,内核将客户端数据拷贝到这个地址空间,由于这个地址空间和服务端的地址空间存在内存映射,数据相当于直接发送到了服务端的地址空间。

服务端一开始就会轮训这个地址空间是否有数据,没有的话就会阻塞,有数据了,内核会唤醒服务端读数据。

服务端调用 mmap() 时:

  • 不会立刻分配 binder buffer
  • 只是在服务端进程地址空间里创建了一块虚拟内存区域(mmap 区域);
  • 这块区域的实际物理内存是由内核 binder 驱动 在"真正需要时"才分配的 ------ 即客户端发起事务时

换句话说:

服务端 mmap() 是**"预先建立通道" ,但真正的数据 buffer 是在事务发送时分配的**。

Binder 通信模型

  1. 首先,一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;
  2. Server 通过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表。
  3. Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用,通过这个引用就能实现和 Server 进程的通信。

注意:

1,ServiceManager进程是使用BINDER_SET_CONTEXT_MGR将自己注册成ServiceManager,并会创建一个Binder 实体

2,这个 Binder 实体的引用在所有 Client 中Binder 引用编号(int)中都固定为 0 ,无需通过其它手段获得。也就是说,一个 Server 想要向 ServiceManager 注册自己的 Binder 就必须通过这个 0 号引用和 ServiceManager 的 Binder 通信。

当 Binder 驱动接收到 A 进程的消息后,发现这是个 objectProxy 就去查询自己维护的表单,一查发现这是 B 进程 object 的代理对象。于是就会去通知 B 进程调用 object 的方法,并要求 B 进程把返回结果发给自己。当驱动拿到 B 进程的返回结果后就会转发给 A 进程,一次通信就完成了。

性能

  1. 性能低下,一次数据传递需要经历:内存缓存区 --> 内核缓存区 --> 内存缓存区,需要 2 次数据拷贝;
  2. 接收数据的缓存区由数据接收进程提供,但是接收进程并不知道需要多大的空间来存放将要传递过来的数据,因此只能开辟尽可能大的内存空间或者先调用 API 接收消息头来获取消息体的大小,这两种做法不是浪费空间就是浪费时间。

再说说稳定性,Binder 基于 C/S 架构,客户端(Client)有什么需求就丢给服务端(Server)去完成,架构清晰、职责明确又相互独立,自然稳定性更好。

安全性, 服务端通过pid验证客户端,进行权限控制

内存映射

内存映射(mmap)本质上是将 「用户进程的虚拟地址空间」映射到 「一块内核控制的物理内存页」 ,从而实现内核与用户空间对同一块物理内存的共享访问


📌 更准确地说:

内存映射 并不是直接映射"虚拟地址 ↔ 虚拟地址" ,而是:

✅ 将:

  • 内核中管理的一块物理页

  • 映射到:

    • 服务端进程的用户空间虚拟地址(mmap区域)
    • 同时这块物理页也是内核中 binder buffer 的一部分

这样,内核和服务端进程就能访问同一块实际物理内存,实现高效的零拷贝通信(read/write 不需要额外 copy)。

相关推荐
tiandyoin1 小时前
调教 DeepSeek - 输出精致的 HTML MARKDOWN
前端·html
Electrolux3 小时前
【使用教程】一个前端写的自动化rpa工具
前端·javascript·程序员
赵大仁4 小时前
深入理解 Pinia:Vue 状态管理的革新与实践
前端·javascript·vue.js
小小小小宇4 小时前
业务项目中使用自定义Webpack 插件
前端
小小小小宇4 小时前
前端AST 节点类型
前端
小小小小宇5 小时前
业务项目中使用自定义eslint插件
前端
babicu1235 小时前
CSS Day07
java·前端·css
小小小小宇5 小时前
业务项目使用自定义babel插件
前端
前端码虫5 小时前
JS分支和循环
开发语言·前端·javascript
GISer_Jing5 小时前
MonitorSDK_性能监控(从Web Vital性能指标、PerformanceObserver API和具体代码实现)
开发语言·前端·javascript