说说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)。

相关推荐
ZoeLandia2 分钟前
Qiankun 生命周期与数据通信实战
前端·微前端·qiankun
LawrenceLan3 分钟前
Flutter 零基础入门(十五):继承、多态与面向对象三大特性
开发语言·前端·flutter·dart
二川bro10 分钟前
详细解析 cesiumViewer.render() 和 requestAnimationFrame(render)
前端
前端付豪14 分钟前
必知Node应用性能提升及API test 接口测试
前端·react.js·node.js
王同学 学出来23 分钟前
vue+nodejs项目在服务器实现docker部署
服务器·前端·vue.js·docker·node.js
一道雷28 分钟前
让 Vant 弹出层适配 Uniapp Webview 返回键
前端·vue.js·前端框架
bug总结38 分钟前
uniapp+动态设置顶部导航栏使用详解
java·前端·javascript
晴殇i41 分钟前
深入理解MessageChannel:JS双向通信的高效解决方案
前端·javascript·程序员
毕设十刻43 分钟前
基于Vue的民宿管理系统st4rf(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
kkkAloha1 小时前
倒计时 | setInterval
前端·javascript·vue.js