1. 动态内核可加载模块 && 内存映射

正如上一章所说, 跨进程通信是需要内核空间做支持的. 传统的 IPC 机制如 管道, Socket, 都是内核的一部分, 因此通过内核支持来实现进程间通信自然是没问题的.

但是 Binder 并不是 Linux 系统内核的一部分, 那怎么办呢, 这得益于 Linux 的动态内核可加载模块 (Loadable Kernel Module, LKM)的机制

1.1 动态内核可加载模块 (Loadable Kernel Module, LKM)

动态内核可加载模块 (Loadable Kernel Module, LKM)
 
模块是具有独立功能的程序, 它可以被单独编译, 但是不能独立运行. 它在运行时被链接到内核作为内核的一部分运行.

这样 Android 系统就可以通过动态添加一个内核模块运行在内核空间, 用户进程进程之间通过这个内核模块作为桥梁来实现通信.

在 Android 中, 这个运行在内核空间, 负责各个用户进程通过 Binder 实现通信的内核模块就叫做 Binder 驱动 (Binder Driver)

那么在 Android 系统中用户进程之间是如何通过这个内核模块 (Binder Driver)来实现通信的呢? 显然不是和上一章的传统 IPC 通信一样,进行两次 copy 了, 不然Binder 也不有在性能方面的优势了.

1.2 内存映射

Binder IPC 机制中设计到的内存映射通过 mmap() 来实现, mmap() 是操作系统中一种内存映射的方法.

内存映射
 
简单的说就是将用户空间的一块内存区域映射到内核空间.
映射关系建立后, 用户对这块内存区域的修改可以直接反应到内核空间.
反之,内核空间对这段区域的修改也能直接反应到用户空间.

内存映射能减少数据 copy 的次数, 实现用户空间和内核空间的高效互动. 两个空间各自的修改也能直接反应在映射的内存区域, 从而被对方空间及时感知. 也正因为如此, 内存映射能够提供对进程间通信的支持.


2. Binder IPC 实现原理

Binder IPC 正是基于内存映射(mmap()) 来实现的, 但是mmap() 通常是用在有物理介质的文件系统上的.

比如进程中的用户区域是不能直接和物理设备打交道的, 如果想要把磁盘上的数据读取到进程的用户区域, 需要两次 copy (磁盘 -> 内核空间 -> 用户空间). 通常在这种场景下 mmap() 就能发挥作用, 通过在物理介质和用户空间之间建立映射, 减少数据的 copy 次数, 用内存读写代替 I/O 读写, 提高文件读取效率.

而 Binder 并不存在物理介质, 因此 Binder 驱动使用 mmap() 并不是为了在物理介质和用户空间之间映射, 而是用来在内核空间创建数据接收的缓存空间.

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

  1. 首先 Binder 驱动在内核空间创建一个数据接收缓存区
  2. 接着在内核空间开辟一块内核缓存区.
  3. 建立内核缓存区 和 内核中数据接收缓存区 之间的映射关系.
  4. 建立内核中数据接收缓存区 与 数据接收进程用户空间 的地址的映射关系
  5. 发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区, 由于内核缓存区 与 内核数据接收缓存区 存在映射关系, 而内核数据接收缓存区 又与 数据接收进程用户空间 存在映射关系, 所以相当于 内核缓存区 与 数据接收进程用户空间存在映射关系. 因此也就相当于把数据发送到了数据接收进程的用户空间.

这样就完成了一次进程间通信
如下图:


3. Binder 通信模型

介绍完 Binder IPC 的底层通信原理, 接下来我们看看实现层面是如何设计的

一次完成的进程间通信必然至少包含两个进程, 通常我们称通信的双方分别为客户端进程(Client) 和服务端进程(Server), 由于进程隔离机制的存在, 通信双方必然需要借助 Binder 来实现.

3.1 Client/Server/ServiceManager/Binder驱动

BInder 是基于 C/S 架构. 是由一些列组件组成. 包括 Client, Server, ServiceManager, Binder 驱动.

  • Client, Server, ServiceManager 运行在用户空间
  • Binder 驱动运行在内核空间.
  • ServiceManager, Binder 驱动由系统提供.
  • Client, Service 由应用程序来实现

Client, Server, ServiceManager 都是通过系统调用 open, mmap,ioctl 来访问设备文件 /dev/binder, 从而实现与 Binder 驱动的交互来间接的实现跨进程通信.

3.1.1 Binder 驱动

Binder 驱动就如如同路由器一样, 是整个通信的核心. 驱动负责进程之间 Binder 通信的建立 / 传递, Binder 引用计数管理, 数据包在进程之间的传递和交互等一系列底层支持.

3.1.2 ServiceManager 与 实名 Binder

ServiceManager 作用是将字符形式的 Binder 名字转化成 Client 中对该 Binder 的引用, 使得 Client 能够通过 Binder 的名字获得对 Binder 实体的引用.

注册了名字的 Binder 叫实名 Binder, 就像网站一样除了 IP 地址以外还有自己的网址.
Server 创建了 Binder, 并为它起一个字符形式, 可读易记的名字, 将这个 BInder 实体连同名字一起以数据包的形式通过 Binder 驱动 发送给 ServiceManager, 通知 ServiceManager 注册一个名字为 "张三"的 Binder, 它位于某个 Server 中, 驱动为这个穿越进程边界的 BInder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用, 将名字以及新建的引用打包传给 ServiceManager, ServiceManager 收到数据后从中取出名字和引用填入查找表.

ServiceManager 是一个进程, Server 又是一个另外的进程, Server 向 ServiceManager 中注册 BInder 必然涉及到进程间通信. 当实现进程间通信又要用到进程间通信, 这就好像蛋可以孵出鸡的前提确实要先找只鸡下蛋! Binder 的实现比较巧妙, 就是预先创造一只鸡来下蛋. ServiceManager 和其他进程同样采用 Binder 通信, ServiceManager 是 Server 端, 有自己的 Binder 实体, 其他进程都是 Client, 需要通过这个 Binder 的引用来实现 Binder 的注册, 查询和获取. ServiceManager 提供的 Binder 比较特殊, 它没有名字也不需要注册. 当一个进程使用 BINDERSETCONTEXT_MGR 命令将自己注册成 ServiceManager 时 Binder 驱动会自动为它创建 Binder 实体(这就是那只预先造好的那只鸡). 其实这个 Binder 实体的引用在所有 Client 中都固定为 0 , 而无需通过其他手段获得. 也就是说, 一个 Server 想要向 ServiceManager 注册自己的 Binder 就必须通过这个 0 号引用和 ServiceManager 的 Binder 通信. 这里说的 Client 是相对于 ServiceManager 而言的, 一个进程或者应用程序可能是提供服务的 Server, 但是对于 ServiceManager 来说它仍然是个 Client.

Server 向 ServiceManager 中注册了 Binder 以后, Client 就能通过名字获得 Binder 的引用. Client 也利用保留的 0 号引用向 ServiceManager 请求访问某个 Binder. 比如,Client 申请访问名字叫"张三"的 Binder 引用. ServiceManager 收到这个请求后从请求数据包中取出 Binder 名称, 在查找表里找到对应的条目, 取出对应的 Binder 引用, 作为回复发送给发起请求的 Client. 从面相对象的角度看, Server 中的 Binder 实体现在有两个引用: 一个位于 ServiceManager 中, 一个位于发起请求的 Client 中. 如果后面会有更多的 Client 请求该 Binder, 系统中就会有更多的引用指向这个 Binder, 就像 Java 中一个对象有多个引用一样.


4. Binder 通信中的代理模式

我们已经解释清楚 Client, Server 借助 Binder 驱动完成跨进程通信的实现机制了, 但是还有个问题需要弄清楚, 比如 A 进程想要 B 进程中的某个对象(object) 是如何实现的呢, 毕竟它们属于不同的进程, A 进程没办法直接使用 B 进程中的 object.

前面我们说过跨进程通信的过程都有 Binder 驱动的参与, 因此在数据流经 Binder 驱动的时候 Binder 驱动会对数据做一层转换.

我们在 Client端,向 ServiceManager 获取具体的 Server 端的 Binder 引用的时候,会首先进过 Binder 驱动,Binder 驱动它并不会把真正的 Server 的 Binder 引用返回给 Client 端,而是返回一个代理的 java 对象,该对象具有跟 Server 端的 Binder 引用相同的方法签名,这个对象为 ProxyObject,他具有跟 Server 的 Binder 实例一样的方法,只是这些方法并没有 Server 端的能力,这些方法只需要把请求参数交给 Binder 驱动即可. 对于 Client 端来说和直接调用 Server 中的方法是一样的.


5. Binder 通信过程

了解了上面之后, 我们大致可以推算出 Binder 的通信过程

1. 注册 ServiceManager

一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager.

2. 注册 Server

Server 通过 Binder 驱动向 ServiceManager 中注册 Binder (Server 中 Binder 实体), 表明可以对外提供服务.
Binder 驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用, 然后将名字及新建的引用打包传给 ServiceManager, 最后 ServiceManager 将其填入到查找表.

3. Client 获取 Server 的 Binder 引用

Client 请求获得 Server 的 Binder 引用, Binder 驱动在接收到 Client 的请求的时候, 就去 ServiceManager 中查询, 查询到后会创建一个 Server 端 Binder 对象的 ProxyObject (Binder 的代理对象), 并将该 ProxyObject 返回给 Client.

4. Client 与 Server 通信

Client 收到 Binder 驱动返回的 ProxyObject 后, 通过 ProxyObject 调用其中的方法. ProxyObject 的方法再去调用 Binder 驱动, Binder 驱动会去查询自己维护的表单, 发现这是某个 Server 端 Binder 的代理对象, 就会通知 Server 端调用具体的方法,(会把 Client 端调用 ProxyObject 中方法的参数传过去. ), 并要求 Server 把结果返回给自己. 当 Binder 驱动拿到结果后, 就会转发给 Client 端.


6. Binder 的完整定义

  • 从进程间通信的角度看, Binder 是一种进程间通信的机制
  • 从 Server 进程的角度看, Binder 指的是 Server 中的 Binder 实体对象.
  • 从 Client 进程的角度看, Binder 指的是对 Binder 代理对象, 是 Binder 实体对象的一个远程代理.
  • 从传输过程的角度看, Binder 是一个可以跨进程通信的对象. Binder 驱动会对这个跨越进程边界的对象

Binder跨进程通信原理(三):Binder IPC实现原理相关推荐

  1. Binder跨进程通信原理(一):动态内核加载模块

    先上一张Binder 的工作流程图.(如果不清晰,可以 复制图片链接到浏览器 或 保存到本地 查看,我经常都是这样看图的哈) 一开始上手,陌生的东西比较多,But,其实并不复杂.喔,流程图是用 Pro ...

  2. 再谈Android Binder跨进程通信原理

    在谈Android的跨进程通信问题上时,总会问到Android的IPC机制,是指两个进程之间进行数据交换的过程.按操作系统的中的描述,线程是CPU调度最小的单元,同时线程是一种有限的系统资源,而进程是 ...

  3. Binder跨进程通信原理(二):内存映射mmap原理分析

    一直都对内存映射文件这个概念很模糊,不知道它和虚拟内存有什么区别,而且映射这个词也很让人迷茫,今天终于搞清楚了...下面,我先解释一下我对映射这个词的理解,再区分一下几个容易混淆的概念,之后,什么是内 ...

  4. Android跨进程通信Binder机制与AIDL实例

    文章目录 进程通信 1.1 进程空间划分 1.2 跨进程通信IPC 1.3 Linux跨进程通信 1.4 Android进程通信 Binder跨进程通信 2.1 Binder简介 2.2 Binder ...

  5. 【Binder】Android 跨进程通信原理解析

    前言 在Android开发的过程中,用到跨进程通信的地方非常非常多,我们所使用的Activity.Service等组件都需要和AMS进行跨进程通信,而这种跨进程的通信都是由Binder完成的. 甚至一 ...

  6. Android进阶——Android跨进程通讯机制之Binder、IBinder、Parcel、AIDL

    前言 Binder机制是Android系统提供的跨进程通讯机制,这篇文章开始会从Linux相关的基础概念知识开始介绍,从基础概念知识中引出Binder机制,归纳Binder机制与Linux系统的跨进程 ...

  7. Android跨进程通讯机制之Binder、IBinder、Parcel、AIDL

    https://blog.csdn.net/qq_30379689/article/details/79451596 前言 Binder机制是Android系统提供的跨进程通讯机制,这篇文章开始会从L ...

  8. Android IPC 进程进程间通信或跨进程通信

    Android IPC 机制 老话长谈,趁现在有时间对IPC做一个具体的总结. IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间 ...

  9. Android - 跨进程通信(IPC) 另一种便捷实现 详解

    文章目录 1. 写在前面 2. 跨进程通信的实现 3. 扩展思考 4. 参考资料 1. 写在前面 看到此图有何感想,这是另一种便捷的实现方式,我们先来看看其它的几种方式. Android 进程间通信 ...

最新文章

  1. HelloWorld 和相关设置
  2. 操作系统(2) -- 进程管理
  3. ABAP下载的病毒扫描Virus Scan
  4. php有lambda表达式吗,Python中lambda表达式的简单介绍(附示例)
  5. oracle rac启动关闭,Oracle RAC启动及关闭步骤
  6. HDU-神、上帝以及老天爷
  7. 哪个相机可以拍gif动图_入门级微单相机哪家强?索尼微单A6400评测来了!
  8. python测开课程_2020年第五期《python接口自动化+测试开发》课程,10月11号开学(火热报名中!)...
  9. 单阶段人体姿态估计解决方案
  10. 电动汽车动力系统整车仿真模型,具有双向DCDC变换器实现能量反馈,带异步电机仿真,应用最大转矩电流比控制加独特的弱磁控制策略
  11. idm bt种子下载如何提升速度?
  12. 使用nvs管理node版本
  13. python中------decode解码出现的0xca问题解决方法
  14. get(obj, “a.b[0].c“, 0)
  15. 什么是最好的UML在线免费软件
  16. 如何修改oa服务器地址,oa服务器地址设置
  17. 定位服务器的功能是提供用户位置信息和什么,LBS是什么意思 LBS的现有模式和功能介绍...
  18. 在cmd下import cv2报错——OpenCV实现BRISK
  19. Android 高质量开发之崩溃优化
  20. MySQL存emoji表情

热门文章

  1. Java运行作业控制语言_Java安全——语言本身的设计
  2. 推荐两款快速查找/替换电脑中文件的软件
  3. python 自定义模块_Python 自定义模块路径
  4. C++编程进阶1(对于单纯的常量,用const替换#define、operator[]与const)
  5. opencv标定函数解说
  6. java c s 与b s架构结合使用_Java技术学习笔记:C/S 与B/S 区别
  7. java继承和多态的实验报告_JAVA,继承和多态实验报告
  8. springframework引入不进来_啥?你不知道JWT
  9. ethereumjs/ethereumjs-vm-4-tests
  10. EF 查看生成的SQL语句