简单聊聊AndroidIPC机制

前言:  

首先,我们来看一下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跨进程通信的原理

      简单理解Binder机制的原理

      Binder机制

      详细说说Binder通信原理与机制

原文地址:https://www.cnblogs.com/HelloHai/p/12417021.html

时间: 2024-10-11 07:09:32

简单聊聊AndroidIPC机制的相关文章

简单聊聊SOA和微服务

转自:https://juejin.im/post/592f87feb123db0064e5ef7c  (2017-06) 简单聊聊SOA和微服务 架构设计中的朴素主义 前两天和一个朋友聊天,他向我咨询如何从零开始构建一个健壮.强大的软件系统,聊着聊着他忽然问我,「听大家都在说微服务(下文中有的地方会使用MSA),还有人会提到SOA,那么他们的区别到底在哪里?」.我想了想,一时也列不出来一个详细的列表,只能跟他讲说其实他们在概念上是相似的. 关于软件系统的架构设计,是一个太多人喜欢讨论的问题,尤

简单聊聊消息队列的事务补偿机制

转自:https://my.oschina.net/u/1589819/blog/1503241 因为一直学习与尝试负责公司的推送相关业务,包括整个应用的实现,其中就采用了基于消息队列的异步事件驱动模型来做解耦异步处理,所以就要去做了解一些相关的知识点,这边稍作总结,并整理一下消息补偿机制的一套简单实现的代码设计图. 采用基于消息队列的异步事件驱动模型来解决问题的时候,一个计较棘手的问题就是事务的一致性. 案例:现在用户发起一个创建订单的请求,如果我们是单系统架构,那么修改订单表,修改库存表可能

直击面试,聊聊 GC 机制

前言 文章来源:https://studyidea.cn/ GC 中文直译垃圾回收,是一种回收内存空间避免内存泄漏的机制.当 JVM 内存紧张,通过执行 GC 有效回收内存,转而分配给新对象从而实现内存的再利用. JVM GC 机制虽然无需开发主动参与,减轻不少工作量,但是某些情况下,自动 GC 将会导致系统性能下降,响应变慢,所以这就需要我们提前了解掌握 GC 机制.当面对这种情况时,才能从容不迫的解决问题.另外 GC 机制也是 Java 面试高频考题,了解掌握 GC 是一项必备技能. 学习

使用redis实现简单的锁机制

在测试第三方账号注册时,授权拉取后,如果两台手册同时点击注册按钮,数据库中就会新增两天一模一样的数据,而我们的需求是一个第三方账号只能绑定一个账号,所以,由此现象可以知道,这里产生了并发访问,我们应该通过加锁的形式来杜绝该现象的产生.那么,如何操作呢? 我们先上代码: <?php /** * 加锁 * @param string $action 业务逻辑,当前框架中未方法名即可 * @param string $extra 额外参数,例如用户ID等 * @return boolen true=加

简单聊聊Linux学习经历

学习,是我们一生中都规避不了的一个话题,人的一生中都是在不断的学习,无论是功成名就的人士,还是一无是处的小混混,始终都处在一个不断学习的环境中,只是学习的内容千差万别,有的人是为了提升自己各方面的能力和素养,有的人是为了生计.而对于我一个学生来说,更是在不断地学习中成长的,从课程知识的学习,到学习做人的道理,为人处事的道理等等,都是在时刻进行中.那么,今天我就聊聊我学习过程中的一个小经历-Linux学习经历. 不知道大家对Linux了解有多少,说实话,上大学之前我对于Linux是一无所知的,因为

简单聊聊java中的BIO、NIO、AIO

BIO(blocking io,同步阻塞) 场景:客户端向服务端发送请求,服务端会为每个客户端建立一个线程来响应,问题来了,如果客户端出现了延时等异常,服务端为客户端建立的线程,就会一直出于等待状态,这个线程就会占用很长时间(因为数据的准备和处理都在这个线程上完成),更糟糕的是,如果有大量并发访问,服务器就会建立大量线程响应,引起服务器资源枯竭. BIO的网络编程模型基本是C/S模型,即两个进程间的通信. 服务端提供IP和监听端口,客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手连

简单聊聊红黑树(Red Black Tree)

? 前言 众所周知,红黑树是非常经典,也很非常重要的数据结构,自从1972年被发明以来,因为其稳定高效的特性,40多年的时间里,红黑树一直应用在许多系统组件和基础类库中,默默无闻的为我们提供服务,身边有很多同学经常问红黑树是怎么实现的,所以在这里想写一篇文章简单和大家聊聊下红黑树 小编看过很多讲红黑树的文章,都不是很容易懂,主要也是因为完整的红黑树很复杂,想通过一篇文章来说清楚实在很难,所以在这篇文章中我想尽量用通俗口语化的语言,再结合 Robert Sedgewick 在<算法>中的改进的版

简单聊聊java中如何判定一个对象可回收

背景 说到java的特性,其中一个最重要的特性便是java通过new在堆中分配给对象的内存,不需要程序员主动去释放,而是由java虚拟机自动的回收.这也是java和C++的主要区别之一:那么虚拟机是如何实现自动回收的呢?它的基本回收算法又是什么呢?  这篇随笔先不介绍这些~ ~,熟话说 饭要一口一口地吃,路要一步一步地走嘛,这篇随笔主要讲解的是回收的前提:如何判断一个对象可以回收. 对java中如何判断一个对象可以回收的一般性认识 在没有学习<深入理解java虚拟机>之前,对于java中判断一

C#简单的上位机制作之界面设计

今天开始打算正式在博客园落户了,写点有用的吧, 一个简单的C#上位机,也就是串口调试助手废话不多说,新建windows应用程序 到这人一个工程就算是新建完成了,然后就是组件的添加了,我们需要在里面添加四个下拉框分别用做 可用端口,波特率,校验位,数据位的设置,还要两个文本框用作收发数据使用,还有若干按钮,单选按钮,等等,看图吧,从工具箱里面拽一些组件出来,放到界面上边 如图中所示,右键属性就可以设置组件的属性了 下拉框属性中Items选项可以设置我们需要的项,在对应的下拉框中,单击右边的三个点的