Binder(一):概述

Binder开篇:

1. 开场:

Binder这个模块知识点很多,也很杂,从应用层,到native,还要深入驱动,这块涉及了java、c++、c,面很广,我也一直没敢写相关的博客,因为我也才接触Android不久,想写一篇关于Binder的博客,又害怕自己能力不够,误导了初学者。其实我是不建议初学者上来就看Binder的,毕竟基础没打好,看了也是很难理解,不过每个人的学习方式不同,也不是每个人的学习方式都和我一样。 我就是多次去看相关的博客去尝试理解Binder,但是怎么说呢,总是学了一点点就遇到难点无从下手了。最终还是关闭代码界面放弃了入门。当然这里也强烈推荐一个大佬的博客,写得十分详细,看起来也不至于很费力:Binder系列—开篇 - Gityuan博客 | 袁辉辉的技术博客

2. Binder是什么:

Binder是一种应用于进程间通信的技术。他的功能就相当于一个外卖员,而Server端就相当于是外卖商家,你就是Client端。这个时候外卖平台呢,就是一个中间商,你只需要在外卖APP上搜索想要吃什么,就能看到好多个商家,这就像Client侧想要选择通信的对象一样,Client选择通信的进程,会根据所需要的服务(Service),在ServiceManager中去搜索对应的Server端,就像你在选要点哪一家店时一样。
于是,这里就将一个抽象的概念对应到了一个实际的环境:点外卖的你->Client端;商家->Server端;外卖APP->ServiceManager;你在外面APP上订的餐和商家送过来的实物->通信的数据;外卖员->Binder驱动;

在这里插入图片描述

正如上图表述的内容,进程A就是Client,进程B就是Server,步骤3,4就是Client和Server的通信内容。可以把3,4这个流程叫做一次Binder通信的过程。不过看了这个简易的流程,就会有一个疑问,进程A为什么就跟进程B通信,不能是进程C、D呢?
这是因为进程A需要的服务a刚好只有进程B有,所以进程A只能和进程B通信。那问题又来了,进程A只知道自己要用服务a,但是为什么就知道服务a在进程B呢?
这个问题,刚好就引出了另外两个Binder通信,不过这两次通信比较容易让我们搞混,我在初学的时候,就被这多个Binder搞得晕头转向,一会这里一个Binder一会哪里一个Binder,最后哪个Binder对应哪个Binder是一团浆糊。这里就把这块用图的形式展现出来,如图三个蓝框,框出来的就分别为三次Binder通信过程。其按照时间先后关系,应该分别是:(1)进程B向ServiceManager注册自己公开的服务a;(2)进程A向ServiceManager查询,提供服务A的进程信息;(3)进程A使用进程B的服务a。
首先,在情况(1)中,进程B需要向ServiceManager注册自己公开的服务a,这个过程中,进程B反倒成了Client端了,而Server端则是ServiceManager,因为此时是B想要使用ServiceManager的平台,展示他的服务a,就像外卖商家,需要在外卖平台上注册,才能通过外卖平台向消费者们展示自己的商品一样。 在情况(2)中,ServiceManager依旧是Server端,因为这时候是进程A向他发起的请求,进程A需要通过ServiceManager查找谁能够给自己提供服务a,就像消费者在外卖平台上搜索需要的物品一样。 而情况(3)就是最容易理解的一次Binder通信了。当消费者在外卖平台上购买了商品后,这时候就到了消费者和商家直接接触的过程了,就不需要外卖平台了,消费者付钱给商家,商家送货过来。

3. Binder的原理:

那为啥进程间通信要用Binder呢?还记得之前背八股文的时候,进程间通信好多方法呢,这时候咋只用Binder了?
这个绝大部分要归功于Binder的效率了。大家都知道进程与进程之间,存储空间是相互隔离的,这就是为了防止进程A在运行过程中篡改了进程B的内容,导致进程B的异常,这个也很好理解,进程A和进程B都是由init进程fork而来,所以他们之间就是亲兄弟了,但是亲兄弟也得明算账啊,你会和你的亲兄弟共用一张银行卡吗?
所以亲兄弟也得分家,这个分家就分出来的就是用户空间,进程A和进程B都是有自己独立的家庭,但是他们说到底还是亲兄弟,所以还有一个共同的家庭,就是内核空间。所以呢过年过节的还是要回家,这时候大家都处于内核空间,交流起来就更方便了,也能面对面的传递一些物品了。
在这里插入图片描述

而对于进程来说,这不就是进程B想发个消息给进程A,得先在进程B中,把信息从用户空间拷贝到内核空间,然后进程A再将进程B放进去的信息拷贝到自己的用户空间嘛。这样就调用了一次copy_from_usr和一次copy_to_usr,虽然不知道这两函数有多耗时,但是两次拷贝操作至少不会省时间对吧。
而Binder机制就有一个好处,就是能只拷贝一次,那Binder是怎么做到的呢?
在这里插入图片描述

如上图,Binder在实现进程间通信的时候,做了一个小小的优化,他将内核空间的一块区域,映射到了进程A的用户空间,这样当进程B将信息从自己的用户空间拷贝到内核空间之后,就相当直接拷贝到进程A的用户空间,当然这时候肯定有小伙伴要问了,那为啥不直接从进程B的用户空间映射到进程A呢? 这个我也想过,不过又想起来,那不是为了进程安全,把他们隔离了嘛。只能通过内核空间向用户空间映射,所以这copy_from_usr的拷贝操作还是省不掉的。这里涉及的内存映射、虚拟地址、内核空间和用户空间的内容,都是一些基础知识,如果不了解还是得去看看的,所以说不太建议初学者上来就硬刚Binder,这些概念虽然不难,但是放在一起还是足够让大家从入门的放弃的。
当然啦,放着那么多的进程间通信方式不用,只用Binder,肯定不止这一个好处,第二个好处就是安全性。传统的IPC机制,是不考虑安全措施的,接收端是无法得到对方的身份信息的,也就是说,很可能Server侧会遭遇“电信诈骗”!而Binder机制,则是给每个进程分配一个UID,也就是电话号码实名制,没有实名制不能激活电话卡(虽然这个实名制好像只能让诈骗犯知道我们的身份呜呜呜,但是在binder通信中,这个实名制比我们的实名电话卡还是不知道高哪去了)。还有一个是我在网上查到的:传统IPC的接入点是开放的,任何程序都可以根据协议进行访问,无法阻止恶意程序的访问。这句话我也不太理解,暂时先记在这吧。

4. Binder的分层架构:

Binder的跨度很大,要想理解Binder,首先得会C++和C(Java就不说了,Java都不会还怎么看Android),这幅图就是发起一次Binder通信需要涉及的一些类和流程,我接下来就是按照这个图,分模块来讲解Binder通信的原理,心里也是比较忐忑,希望开了这个坑,能顺利的填上。
其实现在的Binder封装的都比较完善,我们在系统侧都是直接通过一个封装好的类去调用就行,基本都是封装成了Aidl接口,一般就是Server侧实现一下Aidl的stub类的方法,然后Client侧调用代理类,代理类虽然和Server侧的类的方法啥的名字都一样,但是代理侧肯定是不能真的实现函数的,代理类的主要功能就是将参数啥的统统打包,然后发送给Server侧,等Server侧调用对应的方法,再将处理完的数据返回就好了。

在这里插入图片描述

接下来的几个篇章将是代码的解读了,这里只是做了一个简单的概述,将一些概念通过比喻的形式展现出来,更方便理解,代码阶段一般不会有啥比喻了,就得硬看了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值