Binder机制原理

前言

本篇文章记录本人对Binder的学习,因为本人能力有限,若有错误,还请批评指正。
binder的使用文章推荐

1.Binder是什么?

  • 可以理解是为Android的血管。是一种进程间通信的机制。比如Activity,Service需要和AMS通信的时候,就需要Binder。
  • 除了进程间通信,也可以把Binder理解为一种虚拟物理设备驱动。虚拟表示没有实体,和键盘鼠标不一样。Binder是虚拟的。因为mmap映射时将虚拟内存映射到/dev/binder文件,在linux中这个代表一个驱动,所以说它是一种虚拟物理设备驱动。
  • 除此之外,在应用层,也可以把Binder理解为一个是一个能发起进程间通信的Java类,实现了IBinder接口。除此之外,AIDL中的Stub,Proxy也实现了IBinder,还有AMS等也实现了IBinder。另外在ServiceManager中查找服务时,所用到的Map集合的value也是IBinder类型的。

综上所述,Binder可以说是:
①进程间通信的机制
②虚拟物理设备驱动
③一个能发起进程间通信的Java类

2.为什么是Binder?

Linux也有一些很优秀的进程间通信机制,例如管道,消息队列,共享内存,socket等,但是为什么Android使用Binder而不是这些呢?
看Binder与共享内存,socket的对比

参考指标Binder共享内存socket
性能上需要拷贝1次需要拷贝0次需要拷贝2次
架构上C/S架构,很稳定,且易用难以控制,易用性差C/S架构(但是是一款通用的接口,传输效率低,开销大)
安全性上(最重要)①为每个APP分配UID②支持实名和匿名访问不分配UID,访问接入点是开放的,不安全不分配UID,访问接入点是开放的,不安全

解释下这幅图:

2.1 拷贝次数

(1)传统的IPC通信(两次拷贝)
基础知识:内存被操作系统划分成了两块:用户空间和内核空间,用户空间是用户程序代码运行的地方,内核空间是内核代码运行的地方,为了安全,它们是隔离的。即使用户的程序崩溃了,内核也不受影响。同时,内核空间映射到物理内存中是一块的,而用户空间,不同进程映射到的物理内存不一样。(所以内核空间的数据是共享的,从下面的图也可以看出来)
我们软件工程师所说的内存一般都是虚拟内存。
在这里插入图片描述
下面是我自己画的图,描述了传统IPC的过程
在这里插入图片描述
当需要进程间通信时,数据会先从进程1的用户空间,通过系统调用copy_from_user进入内核空间,然后再通过系统调用copy_to_user进入进程2的用户空间,从而完成通信。

可以看到,传统的IPC需要两次拷贝,每次拷贝都需要系统调用,上下文切换。
(2)Binder通信(一次拷贝)
在这里插入图片描述
可以看到,数据也会先从进程1的用户空间到系统的内核空间,完成一次拷贝,但是进入系统内核空间后,进程2的用户空间的数据接收区和内核空间的那部分区域,能够映射到同一块物理空间。这样就不用发生copy_to_user的系统调用了,从而不用第二次拷贝。
用到了mmap,即内存映射。即内存上的空间可以映射到磁盘上的对应区域(操作系统学过)
(3)共享内存(0次拷贝)
在这里插入图片描述
可以发现,它把copy_from_user省略掉了,直接就是进程1和进程2能够共享同一块物理内存,不需要拷贝。这样看似效率很高,但是实则易用性很差。因为程序员的水平是参差不齐的。这个技术本身没有问题,有问题的是使用这个技术的人。所以我觉得Binder的一次拷贝是故意的,目的是提高易用性。后面的mmap是谷歌工程师完成的,我们只需要让服务类继承Binder,那么它就具有了进程间通信的能力了。至于具体的细节,谷歌工程师已经帮我们封装好了。但是因为客户端太灵活了,情况很多,难以统一,所以谷歌工程师不能帮我们实现客户端这边的封装。

2.2 架构

这个其实就是C/S架构的好处,客户端有什么需求就丢给服务器,解耦,很稳定。而且很易用(Binder需要拷贝一次,而不是零次,为的就是易用性更高),程序员只需要关心业务本身代码,无需过度关注进程通信细节。
而共享内存的话,需要面临一系列复杂的问题,比如访问的安全性,同步等问题。

2.3 安全性

这个要分两方面来说
①首先Binder为每个app分配了一串UID,这串UID是app的唯一身份标识。而共享内存,socket等都是app自己生成类似的这种编码,直接交给上层,上层只管接收,没有能力去甄别对错。假如有恶意软件伪装,那么是无法跟踪这个软件的。
②其次是支持实名访问和匿名访问。实名访问的话,和共享内存,socket是一样的,这样安全性较低。匿名访问安全性高,我们自己写的AIDL一般就是匿名访问。匿名访问类似于滴滴打车,打过来的手机号是虚拟的,并不是实际的,也就是一个代理对象。

区分实名访问和匿名访问的标准是,有无在ServiceManager注册过。注册过的就是实名,反之就是匿名。
比较常见的实名如AMS,WMS等

3.mmap介绍

3.1 mmap是什么?

mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read、write 等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。

3.2 mmap实现的c++

在这里插入图片描述
同时,使用mmap一般都要创建文件,因为linux一切皆文件。

4.AIDL是什么?

关于AIDL的参考文章

(1)定义

AIDL全程是Android Interface Difination Language,即接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。目的就是实现进程间通信。
其实它就是一个模板,真正起作用的不是AIDL文件,而是编译后,根据AIDL文件生成的那个Interface类。

(2)AIDL文件编译后的组成

以这样的AIDL文件为例
在这里插入图片描述

此AIDL文件在编译后,会生成这样一个interface
在这里插入图片描述
TestAidl接口里面有两部分
一个是静态抽象内部类Stub,一个是接口待实现的方法add
其中,Stub又实现了TestAidl接口。但是又因为Stub是抽象类,所以不必实现add方法,add方法的具体实现在具体的服务类里面。也就是Stub的子类

下面来看一下Stub的组成
在这里插入图片描述
看起来有点乱,但其实可以分成以下几部分

抽象类Stub 继承Binder  实现TestAidl{
	①静态的asInterface方法{
       返回代理类(分两种情况:同进程,直接返回继承该StubBinder;不同进程,返回静态代理类)
    }
	②重写的onTransact方法
	③静态代理类Proxy  实现TestAidl{
    	实现add方法,主动调用transact方法
    }
 }

①一个是asInterface方法,如果是同一进程的,则直接返回继承该Stub的服务端对象,如果不是同一进程,则构造一个代理类,由这个代理类,来间接操作这个服务端对象。
②一个是onTransact方法,此方法在客户端调用transact方法时调用。下图是onTransact方法的代码
在这里插入图片描述
code是方法的代码,是一个int类型,因为客户端和服务端都实现同一个接口,那么他们都会实现同一批方法(在这里就是add方法),那么就可以为这一批方法进行统一编序号,方便方法的匹配调用。
③还有一个是静态代理类,它是对服务端的代理。里面的代码如下
在这里插入图片描述
会发现它和Stub的代码很像。没错,其实它代理的就是Stub的实现类,所以这是正常现象。我们再看add方法,里面有两个Parcel类型的变量,分别负责接收发送的参数,接收返回的数据。这里面就有transact方法的调用,这里调用就会调用到onTransact方法。transactonTransact方法的四个参数分别表示的含义为:
①用于区分执行哪个方法
②客户端传递的参数
③服务器返回回去的值
④标明是否有返回值,0表示有,1表示没有

(3)AIDL进行进程间通信的流程

①客户端调用bindService,在onServiceConnected的回调方法中,调用StubasInterface方法,得到mRemote值。(如果是同一进程,直接返回服务端对象。如果是不同进程,返回代理对象)。这里假设是不同进程
②客户端调用mRemoteadd方法,因为是不同进程,所以调用代理对象的add方法。
add方法里面会调用transact方法,然后客户端阻塞直到方法执行完成,拿到返回值。
④客户端调用transact方法,会调用服务端StubonTransact方法,里面会执行Stub子类即具体服务类的add方法。

  • 12
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binderAndroidbinde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个层次水平的android开发者。1、灵活使用binder跨进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码中使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值