Binder机制详解

Binder 是什么

机制:Binder是一种进程间通信的机制
驱动:Binder是一个虚拟物理设备驱动
应用层:Binder是一个能发起进程间通信的JAVA类
Binder是Android提供的一套进程间相互通信框架。用来多进程间发送消息,同步和共享内存,这种跨进程的通信都是通过Binder完成。
Activity,Service等组件和AMS不是同一个进程,其实也是多进程通信。


Android系统中,涉及到多进程间的通信底层都是依赖于Binder IPC机制
例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅于此,整个Android系统架构中,大量采用了Binder机制作为IPC(进程间通信,Interprocess Communication)方案。也存在部分其他的IPC方式,如管道、SystemV、Socket等

Binder 原理

在Android系统的Binder机制中,是由Client,Service,ServiceManager,Binder驱动程序组成的。 其中Client,service,Service Manager运行在用户空间,Binder驱动程序是运行在内核空间的。而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,Service Manager提供辅助管理的功能,而Client和Service正是在Binder驱动程序和Service Manager提供的基础设施上实现C/S 之间的通信。其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,Client、Service,Service Manager通过open和ioctl文件操作相应的方法与Binder驱动程序进行通信。而Client和Service之间的进程间通信是通过Binder驱动程序间接实现的。而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。

Binder IPC 实现原理

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

IPC 通信过程

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

Binder 运行机制

  • 注册服务(addService):Server进程要先注册Service到ServiceManager。该过程:Server是客户端,ServiceManager是服务端。
  • 获取服务(getService):Client进程使用某个Service前,须先向ServiceManager中获取相应的Service。该过程:Client是客户端,ServiceManager是服务端。
  • 使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:Client是客户端,Server是服务端。

Binder 通信模型

Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及Binder驱动,其中ServiceManager用于管理系统中的各种服务。

Binder 通信过程

  1. 首先,一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;
  2. Server 通过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表;
  3. Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用,通过这个引用就能实现和 Server 进程的通信。

Binder 通信的四个角色

  • Client进程: 使用服务的进程。
  • Server进程: 提供服务的进程。
  • ServiceManager进程: ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
  • Binder驱动: 驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。

Binder驱动位于内核空间;Client,Server,Service Manager位于用户空间。

Binder 驱动

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

Binder 中使用的设计模式

  • 代理模式(Proxy Pattern ) 在Android中client不是直接去和binder打交道,client直接和Manager交互,而manager和managerProxy交互,也就是说client是通过managerProxy去和binder进行交互的。同时service也不是直接和binder交互,而是通过stub去和binder交互;
  • Bridge Pattern 应用层也就是Java层要使用MediaPlayer,就要调用native层中的MediaPlayer.cpp,但是MediaPlay.java不是直接去跟JNI打交道,而是通过与MediaPlayerSevice通信,从而经过Binder返回的。

什么是内存映射

底层原理其实就是虚拟内存
简单来说:不同的虚拟内存指向相同的物理内存,从而实现共享内存和共享文件
涉及外存和页交换,起因就是每个进程的地址空间都是0-L4的max,但是很多进程共用L4,这时候就需要拿L5来暂存L4暂时不用的数据和代码段,L4不用的换到L5,L5要用的换进L4就叫页交换。
操作系统默认是指向不同的地址,L4不够了就给你指到L5去,L5就是外存,所以有C盘空间不够了电脑卡这个说法(变量malloc不出来,阻塞了)

Binder 与 内存映射mmap

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


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

为什么使用 Binder

  • 性能方面: Binder相对于传统的Socket方式,更加高效。Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,共享内存方式一次内存拷贝都不需要,但实现方式又比较复杂。
  • 安全方面: 传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信的IP地址是客户端手动填入,很容易进行伪造Binder机制从协议本身就支持对通信双方做身份校检,从而大大提升了安全性。

为什么要用多进程

  1. 虚拟机给每一个进程分配的内存是有限制的,LMK会优先回收对系统资源占用多的进程
  2. 为了突破内存限制,防止占用内存过多被杀
  3. 功能稳定性,一个进程崩溃对另外进程不造成影响:将不稳定功能放入独立进程
  4. 规避内存泄漏,独立的WebView进程阻隔内存泄漏导致问题

进程隔离

操作系统中,进程与进程间内存是不共享的。两个进程就像两个平行的世界,A 进程没法直接访问 B 进程的数据,这就是进程隔离。
A 进程和 B 进程之间要进行数据交互就得采用特殊的通信机制:进程间通信(IPC)。

ServiceManager 与 实名Binder

ServiceManager: ServiceManager 和 DNS 类似,作用是将字符形式的 Binder 名字转化成 Client 中对该 Binder 的引用,使得 Client 能够通过 Binder 的名字获得对 Binder 实体的引用。
实名 Binder: 注册了名字的 Binder 叫实名 Binder,就像网站一样除了除了有 IP 地址意外还有自己的网址。


Server 创建了 Binder,并为它起一个字符形式将这个 Binder 实体连同名字一起以数据包的形式通过 Binder 驱动发送给 ServiceManager,通知 ServiceManager 注册一个名为 “张三” 的 Binder,驱动为这个穿越进程边界的 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager。ServiceManger 收到数据后从中取出名字和引用填入查找表。

Client 获得 实名Binder 的引用

Server 向 ServiceManager 中注册了 Binder 以后, Client 就能通过名字获得 Binder 的引用了,Client 也利用保留的 0 号引用向 ServiceManager 请求访问某个 Binder: 我申请访问名字叫张三的 Binder 引用, ServiceManager 收到这个请求后从请求数据包中取出 Binder 名称,在查找表里找到对应的条目,取出对应的 Binder 引用作为回复发送给发起请求的 Client


从面向对象的角度看,Server 中的 Binder 实体现在有两个引用:一个位于 ServiceManager 中;一个位于发起请求的 Client 中,如果接下来有更多的 Client 请求该 Binder,系统中就会有更多的引用指向该 Binder,就像 Java 中一个对象有多个引用一样。

  • 26
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是阿超

现在二师兄的肉比师父的都贵了.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值