前言:
首先,我们来看一下IPC是个啥意思。
IPC是英文Inter-process communication的缩写,顾名思义就是进程间通信或者说跨进程通信。
没错,是进程。所以咱们今天主要说的就是有关进程之间的事儿。
在Android中,因为开发的需要我们可能需要跨应用去操作一些业务,或者项目较大的时候我们需要开启多个进程去完成。但是,Android中为了安全考虑呢,进程之间却又是不能进行数据交互的,为了解决这个问题所以就有了所谓的IPC机制。
其次,我们来说一下今天都会接触到哪些东西呢?
IPC的有哪些方式(一笔带过)
序列化(点到为止,不细说)
Binder机制(今天的主角儿)
AIDL(专为主角设计的模板)
一句话概括,在Android中实现进程间通信的方式有不少,但是最主要的就是Binder机制,同时Android为了快速实现这种功能专门设计了一种模板,叫做AIDL(Android Interface Definition Language 翻译为:Android接口定义语言)。
IPC有哪些方式:
1、通过Intent的putExtras()方法传递一个Bundle对象(如果只是简单的在进程间来回传递一些基本数据,这是一个很便捷的办法)。
2、通过共享文件来实现数据的共享(如果对该文件没有较高的数据同步要求的话,这也不失为一种很好的办法)。
3、使用四大组件之一的ContentProvider(Android专为进程间数据共享而生的,它的底层原理就是咱们今天的主角儿Binder,但它需要借助其他的数据存储方式来使用)。
4、使用信使Messenger(通过Messenger可以在进程间传递Message对象,因为它是串行的方式处理信息的,没有并发需求的话采用这个很不错,它的底层同样是今天的主角儿Binder)
5、使用Socket(它不但可以跨进程还可以跨设备,但是内存开销比较大,也不太安全)
6、Binder机制(今天的主角儿,性能高、安全)
序列化:
序列化也叫持久化。进程之间不可以传递对象,Binder也不行。我们要想传递,只能将对象做一下持久化,以便它可以写入到流。详细的咱就不说了,这里主要提一下两种序列化的方式。
1、实现Serializable接口(使用简单,但是开销较大)
2、实现Parcelable接口(使用较为复杂,一般用在内存序列化上,但是效率高)
Binder机制:
咱们先来介绍一下进程空间,以及它的特点。
一个进程空间是分为两个部分的,分别是用户空间和内核空间。其中,用户空间之间数据是不可共享的,内核空间是可以数据共享的。
这样说可能比较抽象,我来举个例子。
我们可以把进程想象成一棵棵的大树,其中树地面以上部分我们可以理解成为用户空间,地下的或者说整个大地我们可以理解为内核空间。每棵大树都是独立的存在,但是大地却是大家所共享的。
在一个进程空间中,用户空间和内核空间之间可以通过ioctl等方法来进行数据的交互的。(copy_to_user/copy_from_user)
这样来回拷贝就需要两次。如图
而Binder
则是基于C/S架构( Client - Server),并且通过内存映射来实现IPC通信的,下面咱们具体的介绍一下。
内存映射:
Binder IPC 机制中涉及到的内存映射通过 mmap() 来实现的,mmap() 是操作系统中一种内存映射的方法。内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。
Binder IPC 通信过程:
1、首先 Binder 驱动在内核空间创建一个数据接收缓存区。
2、接着在内核空间开辟一块内核缓存区。
3、建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系。(在此之前都没有数据的拷贝操作)
4、发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
Binder通讯模型:
1、Client:客户端(发送请求的进程)
2、Server:服务端(接受请求的进程)
3、Binder驱动:类似网络通信中的路由器,负责将Client的请求转发到具体的Server中执行,并将Server返回的数据传回给Client。
4、ServiceManager:管理所有的需要提供Binder服务的Server的注册与查询,将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
这里咱们着重说一下ServiceManager:
流程:
1、Server向ServiceManager注册。Server通过Binder驱动向ServiceManager注册,声明可以对外提供服务。ServiceManager中会保留一份映射表。
2、Client向ServiceManager请求Server的Binder引用。Client想要请求Server的数据时,需要先通过Binder驱动向ServiceManager请求Server的Binder引用(代理对象)。再向具体的Server发送请求。Client拿到这个Binder代理对象后,就可以通过Binder驱动和Server进行通信了。
3、Server返回结果。Server响应请求后,需要再次通过Binder驱动将结果返回给Client。
原理:
ServiceManager是一个单独的进程,那么Server与ServiceManager通讯是靠什么呢?当Android系统启动后,会创建一个名称为Servicemanager的进程,这个进程通过一个约定的命令BINDERSETCONTEXT_MGR向Binder驱动注册,申请成为为ServiceManager,Binder驱动会自动为ServiceManager创建一个Binder实体。并且这个Binder实体的引用在所有的Client中都为0,也就说各个Client通过这个0号引用就可以和ServiceManager进行通信。Server通过0号引用向ServiceManager进行注册,Client通过0号引用就可以获取到要通信的Server的Binder引用。
这里我们用一个形象的实例,来讲讲这一块过程:
1、 Server进程向ServiceManager注册,告诉ServiceManager我是谁,我有什么,我能做什么。就好比徐同学(Server进程)有一台笔记本(computer对象),这台笔记本有个add方法。这时映射关系表就生成了。
2、 Client进程向ServiceManager查询,我要调用Server进程的computer对象的add方法,可以看到这个过程经过Binder驱动,这时候Binder驱动就开始发挥他的作用了。当向ServiceManager查询完毕,是返回一个computer对象给Client进程吗?其实不然,Binder驱动将computer对象转换成了computerProxy对象,并转发给了Client进程,因此,Client进程拿到的并不是真实的computer对象,而是一个代理对象,即computerProxy对象。很容易理解这个computerProxy对象也是有add方法,(如果连add方法都没有,岂不是欺骗了Client?),但是这个add方法只是对参数进行一些包装而已。
3、当Client进程调用add方法,这个消息发送给Binder驱动,这时驱动发现,原来是computerProxy,那么Client进程应该是需要调用computer对象的add方法的,这时驱动通知Server进程,调用你的computer对象的add方法,将结果给我。然后Server进程就将计算结果发送给驱动,驱动再转发给Client进程,这时Client进程还蒙在了鼓里,他以为自己调用的是真实的computer对象的add方法,其实他只是调用了代理而已。不过Client最终还是拿到了计算结果。
AIDL:
AIDL (Android Interface Definition Language) 是一种接口定义语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数,来完成进程间通信。
咱们简单说一下AIDL使用过程
1、首先创建我们需要的实体类,并且该实体类必须要是继承Parcelable接口。
2、创建一个aidl文件。
3、创一个和实体类同名的aidl文件,并在其中声明它为Parcelable类型
4、执行一下make project操作,这时候SDK会为我们生成对应的Binder类
5、在服务端创建一个用于接收请求的service,并在内部实现Binder类中的Stub类,并在对应的接口中作出具体的实现。
6、将服务端工程中的aidl文件夹下的内容整个拷贝到客户端工程的对应位置下。
7、客户端通过Intent进行bindService绑定服务端的Service
8、实例化ServiceConnection,在内部就可以拿到我们需要的数据了。
感谢巨人的肩膀
本文也就是作者学习当中,做的一个随笔,借鉴了很多优秀的文章,算是自己IPC这块的一个笔记吧,当然啦,在这些博文里或多或少的都向我们展示代码,大家多读读代码理解的肯定会更加的深刻。(见下面的参考)
参考: 图文详解 Android Binder跨进程通信的原理
原文地址:https://www.cnblogs.com/HelloHai/p/12417021.html