欢迎光临
专注android技术,聚焦行业精粹,我们一直在努力

插件化基础之Binder和AIDL

1、Binder

1.1、概念

Binder是Android中为了解决跨进程通信而设计的,我们知道Android系统是基于linux内核的。然而 linux 已经提供了管道、消息队列、共享内存和 Socket 等 IPC 机制。那为什么 Android 还要提供 Binder 来实现 IPC 呢?主要是基于性能稳定性安全性几方面的原因。

1.2、Binder介绍

1.2.1、性能

binder的性能相对还是挺高的,一组对比数据如下:

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

1.2.2、安全

传统IPC没有任何安全措施,完全依赖上层协议来确保。首先传统IPC的接收方无法获得对方进程可靠的UID/PID(用户ID/进程ID),从而无法鉴别对方身份。Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志。使用传统IPC只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。其次传统IPC访问接入点是开放的,无法建立私有通道。比如命名管道的名称,system V的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
基于以上原因,Android需要建立一套新的IPC机制来满足系统对通信方式,传输性能和安全性的要求,这就是Binder。

1.2.3、Binder的表现形式

面向对象思想的引入将进程间通信转化为通过对某个Binder对象的引用调用该对象的方法,而其独特之处在于Binder对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各个进程之中。最诱人的是,这个引用和java里引用一样既可以是强类型,也可以是弱类型,而且可以从一个进程传给其它进程,让大家都能访问同一Server,就象将一个对象或引用赋值给另一个引用一样。Binder模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中。形形色色的Binder对象以及星罗棋布的引用仿佛粘接各个应用程序的胶水,这也是Binder在英文里的原意。

举个例子,我们通过ServiceConnection获取远端的IBinder引用后,转换成本地的proxy对象,然后调用远程的方法就是操作本地的proxy对象的方法

1.3、Binder机制

通过上面的介绍我们知道 Binder对象是一个可以跨进程引用的对象,我们使用ServiceConnection通过bindService从另一个进程拿到了一个binder对象的引用,这种常见的跨进程获取得到的Binder,我们称之为匿名Binder。它们的进程间数据流如下图所示,使用linux内核的mmap内存映射实现,我们看到这个数据流交互中只有一次数据拷贝:

与之对应的还有一种获取方式会得到实名Binder,也就是我们常见的通过ServiceManager找到在系统注册的服务并调用的方式:

1.3.1、实名Binder

举一个获取实名Binder的例子,常见的用法是我们调用系统服务的方法:

对于android的实名Binder,它包含四个角色:Server,Client,ServiceManager(以后简称SMgr)以及Binder驱动。其中Server,Client,SMgr运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似:Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),驱动是路由器。

关系图如下:

1.3.2、Binder整体机制

图片来源:https://blog.csdn.net/universus/article/details/6211589

这张图描述了Binder在系统中的表现形式,包含前面提到的匿名Binder和实名Binder,以及数据在Client和Server之间是如何通信的。

从图中我们发现Binder起到了路由的作用,让Client端通过Binder引用与Server端的Binder实体通信。从使用角度上看,Binder的设计是面向对象的,对于客户端而言跨进程调用如同调用本地对象方法一样,使用上没有什么不同。从安全角度上看Binder机制不同于Linux自带的跨进程通信机制,Binder为通信双方建立了一条私密通道,别的进程无法通过穷举或猜测的方式获得该Binder引用,保证了通信的安全性。

2、AIDL

2.1、什么是AIDL

官方描述如下,原文地址

AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似。 您可以利用它定义客户端与服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。 在 Android 上,一个进程通常无法访问另一个进程的内存。 尽管如此,进程需要将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。 编写执行这一编组操作的代码是一项繁琐的工作,因此 Android 会使用 AIDL 来处理。

我对这段话的理解是Android为了使用面向对象的方式来实现跨进程通信而使用了AIDL

官方对AIDL的使用有以下的建议

:只有允许不同应用的客户端用 IPC 方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。 如果您不需要执行跨越不同应用的并发 IPC,就应该通过实现一个 Binder 创建接口;或者,如果您想执行 IPC,但根本不需要处理多线程,则使用 Messenger 类来实现接口。无论如何,在实现 AIDL 之前,请您务必理解绑定服务

换言之,归结为下面3点:

  • 进程内调用,无需AIDL,直接用Binder: 如果不需要跨进程进行IPC通信,而是同应用同一个进程内通信,服务端直接继承Binder,并将Binder对象通过ServiceConnection返回给Client端,此时Client端无需使用AIDL的Proxy代理,而直接调用Binder对象的引用访问服务端对象的方法
  • Server端无需处理多线程并发调用,建议使用Messenger:当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现它更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
    对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。
  • 需要跨进程IPC通信,且Server端需要处理多线程并发调用:该场景可以使用AIDL来处理

2.2、AIDL的交互流程

我们定义一个aidl文件,并包含一个自定义方法myInterface:

  1. 从Client看,做为对AIDL的使用者,我们会调用Stub的asInterface获得IBinder对象,然后调用对应的myInterface方法实现调用远程服务。asInterface方法的作用是判断参数,也就是IBinder对象,和自己是否在同一个进程,如果是,则直接转换,直接使用,接下来则与Binder跨进程通信无关;如果否,则把这个IBinder对象参数包装成一个Proxy对象,这时调用Stub的myInterface接口方法,间接调用Proxy的myInterface方法
  2. Proxy在自己的myInterface方法中,会使用Parcelable来准备数据,把函数名称、函数参数都写入_data,让_reply接收函数返回值。最后使用IBinder的transact方法,就可以把数据传给Binder的Server端了。
  3. Server则是通过onTransact方法接收Client进程传过来的数据,包含函数名称、函数参数,找到对应的函数(这里是myInterface方法),把参数传进去,得到结果,返回。所以onTransact函数经历了读数据->执行要调用的函数->把执行结果再写数据的过程。

赞(2) 打赏
未经允许不得转载:花花鞋 » 插件化基础之Binder和AIDL
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

国内精品Android技术社区

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏