Binder 原理剖析

1 Binder 概述

Binder 是一种进程间通信机制,基于开源的 OpenBinder 实现;
OpenBinder 起初由 Be Inc. 开发,后由 Plam Inc. 接手。

1.1 为什么必须理解 Binder ?

  • 作为 Android 工程师的你,是不是常常会有这样的疑问:
  • 为什么 Activity 间传递对象需要序列化?
  • Activity 的启动流程是什么样的?
  • 四大组件底层的通信机制是怎样的?
  • AIDL 内部的实现原理是什么?
  • 插件化编程技术应该从何学起?等等...
  • 这些问题的背后都与 Binder 有莫大的关系,要弄懂上面这些问题理解 Bidner 通信机制是必须的。

1.2 为什么是 Binder ?

IPC种类.png

Android 系统是基于 Linux 内核的,Linux 已经提供了管道消息队列共享内存Socket 等 IPC 机制。
那为什么 Android 还要提供 Binder 来实现 IPC 呢?主要是基于性能稳定性安全性几方面的原因。

1.2.1 性能

Socket 作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。
消息队列管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。
共享内存虽然无需拷贝,但控制复杂,难以使用。
**Binder **只需要一次数据拷贝,性能上仅次于共享内存。

IPC方式 数据拷贝次数
共享内存 0
Binder 1
Socket/管道/消息队列 2

1.2.2 稳定性

  • Binder 基于 C/S 架构,客户端(Client)有什么需求就丢给服务端(Server)去完成,架构清晰、职责明确又相互独立,自然稳定性更好。
  • 共享内存虽然无需拷贝,但是控制负责,难以使用。
  • 从稳定性的角度讲,Binder 机制是优于内存共享的。

1.2.3 安全性

  • 传统的 IPC 没有任何安全措施,完全依赖上层协议来确保。
  • 首先传统的 IPC 接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),从而无法鉴别对方身份。
  • Android 为每个安装好的 APP 分配了自己的 UID,故而进程的 UID 是鉴别进程身份的重要标志。
  • 传统的 IPC 只能由用户在数据包中填入 UID/PID,但这样不可靠,容易被恶意程序利用。
  • 可靠的身份标识只有由 IPC 机制在内核中添加。
  • 其次传统的 IPC 访问接入点是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
    同时 Binder 既支持实名 Binder,又支持匿名 Binder,安全性高。

1.2.4 Binder 的优势:

优势 描述
性能 只需要一次数据拷贝,性能上仅次于共享内存
稳定性 基于 C/S 架构,职责明确、架构清晰,因此稳定性好
安全性 为每个 APP 分配 UID,进程的 UID 是鉴别进程身份的重要标志

基于上述原因,Android 需要建立一套新的 IPC 机制来满足系统对稳定性、传输性能和安全性方面的要求,这就是 Binder。

2 Binder 跨进程通信原理

2.1 动态内核可加载模块

  • 跨进程通信是需要内核空间做支持的。
  • 传统的 IPC 机制如管道、Socket 都是内核的一部分,因此通过内核支持来实现进程间通信自然是没问题的。
  • Binder 并不是 Linux 系统内核的一部分,能够通信得益于Linux 的动态内核可加载模块(Loadable Kernel Module,LKM)的机制;
  • 模块是具有独立功能的程序,它可以被单独编译,但是不能独立运行。它在运行时被链接到内核作为内核的一部分运行。
  • Android 系统就可以通过动态添加一个内核模块运行在内核空间,用户进程之间通过这个内核模块作为桥梁来实现通信。
  • 在 Android 系统中,这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder 驱动(Binder Dirver)

2.2 内存映射

  • Binder IPC 机制中涉及到的内存映射通过 mmap() 来实现,**mmap() **是操作系统中一种内存映射的方法。
  • 内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。
  • 映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。
  • 内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。
  • 两个空间各自的修改能直接反映在映射的内存区域,从而被对方空间及时感知。也正因为如此,内存映射能够提供对进程间通信的支持

2.3 Binder IPC 实现原理

  • Binder IPC 正是基于内存映射(mmap)来实现的,但是 mmap() 通常是用在有物理介质的文件系统上的。
  • 进程中的用户区域是不能直接和物理设备打交道的,如果想要把磁盘上的数据读取到进程的用户区域,需要两次拷贝(磁盘-->内核空间-->用户空间);通常在这种场景下 mmap() 就能发挥作用,通过在物理介质和用户空间之间建立映射,减少数据的拷贝次数,用内存读写取代I/O读写,提高文件读取效率。
  • Binder 并不存在物理介质,因此 Binder 驱动使用 mmap() 并不是为了在物理介质和用户空间之间建立映射,而是用来在内核空间创建数据接收的缓存空间

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

  • 1.首先 Binder 驱动在内核空间创建一个数据接收缓存区;
  • 2.接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系
  • 3.发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
162b00a9557158d0.png

3 Binder的工作机制

3.1 binder的工作流程

binder的工作流程.png
  • 通过上图,我们可以看出binder的工作流程是这样实现的:
  • (1)Client发送请求给Server,在Server未返回结果前,Client处于阻塞状态。请求的数据和相应操作交给Client的Proxy处理。
  • (2)Proxy代理将数据封装后,交给Binder驱动程序进行数据的传输调度。(transact()
  • (3)Binder驱动程序将数据发送个Server,Server对数据进行解析,并根据相应的操作标识进行相应的操作处理。
  • (4)Server操作完成之后,将执行之后结果数据封装。然后将数据交给Binder驱动程序调度。(onTransact()
  • (5)Binder驱动程序将结果数据交给Client的Proxy代理,Proxy代理将数据解析后将最终结果返回给Client。
  • (6)Client接收到数据之后,结束阻塞状态。

3.2 Server向ServiceManager注册服务

  • 在Binder的工作机制中,我们是依赖binder驱动程序去执行数据的调度,发送方依赖binder打包数据,接收方依赖binder回传数据
Server向ServiceManager注册服务.png
  • 注册流程是这样的:
  • (1)Server在自己的进程中向Binder驱动程序申请创建一个作为自己Service的Binder实体。
  • (2)Binder驱动程序为这个Service创建位于内核中binder实体节点binder引用,然后将Service的名称和binder的引用传给ServiceManager,通知ServiceManager注册相应的Service服务。
  • (3)ServiceManager接收到数据之后,根据Service的名称和binder引用填写入一张表中。

3.3 Client从SericeManager获取Service的远程接口

Client从SericeManager获取Service的远程接口.png
  • 如果这时Client向Server发送申请该Service服务请求时,ServiceManager就会通过该服务的名称,查找表获取相应服务的binder引用,返回给Client。

3.4 总结

总结:作为数据发送方,它持有Binder的实体;作为数据接收方,它持有Binder的引用。

4 Binder 通信模型

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

4.1Client/Server/ServiceManager/BinderDriver驱动

  • Binder 是基于 C/S 架构的。由一系列的组件组成,包括Client、Server、ServiceManager、Binder 驱动
  • Client、Server、Service Manager 运行在用户空间,Binder 驱动运行在内核空间
  • 其中 Service Manager 和 Binder 驱动由系统提供,而 Client、Server 由应用程序来实现。
  • Client、Server 和 ServiceManager 均是通过系统调用 open、mmap 和 ioctl 来访问设备文件 /dev/binder,从而实现与 Binder 驱动的交互来间接的实现跨进程通信。
162b00a955f25e1c.png

4.2 网页请求模型

  • Client、Server、ServiceManager、Binder 驱动这几个组件在通信过程中扮演的角色就如同互联网中服务器(Server)、客户端(Client)、DNS域名服务器(ServiceManager)以及路由器(Binder 驱动)之前的关系。
  • 通常我们访问一个网页的步骤是这样的:首先在浏览器输入一个地址,如 www.google.com 然后按下回车键。但是并没有办法通过域名地址直接找到我们要访问的服务器,因此需要首先访问 DNS 域名服务器,域名服务器中保存了 www.google.com 对应的 ip 地址 10.249.23.13,然后通过这个 ip 地址才能放到到 www.google.com 对应的服务器。
162b00a979646aee.png

4.3 流程

  • Binder Driver位于内核空间中,其以字符设备中的misc类型注册
  • 用户可以从/dev/binder设备文件节点上,通过open和ioctl文件操作函数与Binder Driver进行通信,其主要负责Binder通信的建立,以及其在进程间的传递和Binder引用计数管理/数据包的传输等。
  • 1.当手机启动后,ServiceManager会先向Binder Driver进行注册,它在Binder Driver中是最先被注册的,其注册ID为0
  • 2.当其他的服务想要注册到Binder Driver时,会先通过这个0号ID获取到ServiceManager所对应的IBinder接口,该接口实质上的实现逻辑是由BpBinder实现的。
  • 3.获取到对应的接口后就回调用其中的transact方法,此后就会在Binder Driver中新注册一个ID 1来对应这个服务。
  • 4.如果有客户端想要使用这个服务,那么,它先会像 Binder Driver 一样获取到ID为0的接口,也就是ServiceManager所对应的接口,并调用其transact方法要求连接到刚才的服务,这时候Binder Driver就会将ID为1的服务回传给客户端并将相关消息反馈给 ServiceManager 完成。

5 Binder架构

Binder架构.png
  • Java应用层: 对于上层应用通过调用AMP.startService, 完全可以不用关心底层,经过层层调用,最终必然会调用到AMS.startService.
  • Java IPC层: Binder通信是采用C/S架构, Android系统的基础架构便已设计好Binder在Java framework层的Binder客户类BinderProxy和服务类Binder;
  • Native IPC层: 对于Native层,如果需要直接使用Binder(比如media相关), 则可以直接使用BpBinder和BBinder(当然这里还有JavaBBinder)即可, 对于上一层Java IPC的通信也是基于这个层面.
  • Kernel物理层: 这里是Binder Driver, 前面3层都跑在用户空间,对于用户空间的内存资源是不共享的,每个Android的进程只能运行在自己进程所拥有的虚拟地址空间, 而内核空间却是可共享的. 真正通信的核心环节还是在Binder Driver.

参考

https://blog.csdn.net/universus/article/details/6211589
https://juejin.im/post/5acccf845188255c3201100f?utm_medium=an&utm_source=weixinqun
https://www.jianshu.com/p/82cdb9d53ca3
https://juejin.im/post/5a181ed151882512a86100e5

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容