Binder跨进程通信原理(三):Binder IPC实现原理

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

  1. 首先 Binder 驱动在内核空间创建一个数据接收缓存区

  2. 接着在内核空间开辟一块内核缓存区.

  3. 建立内核缓存区 和 内核中数据接收缓存区 之间的映射关系.

  4. 建立内核中数据接收缓存区 与 数据接收进程用户空间 的地址的映射关系

  5. 发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区, 由于内核缓存区 与 内核数据接收缓存区 存在映射关系, 而内核数据接收缓存区 又与 数据接收进程用户空间 存在映射关系, 所以相当于 内核缓存区 与 数据接收进程用户空间存在映射关系. 因此也就相当于把数据发送到了数据接收进程的用户空间.

这样就完成了一次进程间通信

如下图:

image


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 驱动的交互来间接的实现跨进程通信.

image

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 端.

image


6. Binder 的完整定义

===================================================================================

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
ndroid开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门**

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值