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

相关推荐
前端小巷子14 分钟前
跨域问题解决方案:JSONP
前端·javascript·面试
eric*168821 分钟前
尚硅谷张天禹老师课程配套笔记
前端·vue.js·笔记·vue·尚硅谷·张天禹·尚硅谷张天禹
程序员爱钓鱼37 分钟前
Go语言中的反射机制 — 元编程技巧与注意事项
前端·后端·go
GIS之路1 小时前
GeoTools 结合 OpenLayers 实现属性查询(二)
前端·信息可视化
烛阴1 小时前
一文搞懂 Python 闭包:让你的代码瞬间“高级”起来!
前端·python
AA-代码批发V哥1 小时前
HTML之表单结构全解析
前端·html
聪聪的学习笔记1 小时前
【1】确认安装 Node.js 和 npm版本号
前端·npm·node.js
小磊哥er2 小时前
【前端工程化】你知道前端编码规范包含哪些内容吗
前端
菌菇汤2 小时前
uni-app实现单选,多选也能搜索,勾选,选择,回显
前端·javascript·vue.js·微信小程序·uni-app·app
Ramos丶2 小时前
【ABAP】 从无到有 新建一个Webdynpro程序
java·前端·javascript