Android面试Android跨进程通信IPC

Posted Rose J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android面试Android跨进程通信IPC相关的知识,希望对你有一定的参考价值。

他是谁?

IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信

windows IPC机制

剪贴板,管道,邮槽

Linux IPC机制

命名管道,共享内容,信号量

哪里需要用到多进程?

系统为每个进程分配的内存是有限的,比如在以前的低端手机上常见是 16M,现在的机器内存更大一些,32M、48M,甚至更高。但是,总是有限的,毕竟一个手机出厂之后 RAM 的大小就定了,总是无法满足所有应用的需求。

一个明智的选择就是使用多进程,将一些看不见的服务、比较独立而又相当占用内存的功能运行在另外一个进程当中,主动分担主进程的内存消耗。常见如,应用中的推送服务,音乐类 App 的后台播放器等等,单独运行在一个进程中。

还有互相拉起,一个应用去调用其他应用的数据

service的保活,可以给服务创建一个独立的进程。

可以把一些存在oom的操作,比如下载一张很大的图片,放到一个新的进程,这样就算出现了内存溢出,也不会影响主线程

调用闹钟,拨打电话,推送

1.序列化

serializable和parcelable接口可以完成对象的序列化过程,当我们需要通过Intent和Binder传输数据时就需要使用parcelable或者serializable,还有的时候我们需要把对象持久化到存储设备(硬盘)或者通过网络传输给其他客户端,这个时候也需要使用serializable来完成对象的持久化。

1.serializable和parcelable区别

1.serializable是java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量的I/O操作。

2.parcelable是android中的序列化方式,因此更适合在Android平台上,它的缺点就是使用起来稍微麻烦一点,但是它的效率很高,这是Android推荐的序列化方式,因此我们首选parcelable

3.parcelable主要用在内存序列化上,通过parcelable将对象序列化到存储设备中 或者 将对象序列化后 通过网络传输也都是可以的,但是这个过程稍显复杂,因此在这两者情况下选serializable。

2.Binder

1.定义

Binder是Android中的一个类,他实现了IBinder接口,

1.从IPC角度来说

Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是dev/binder,该通信方式Linux中没有

2.从Android Framework角度来说

Binder是ServiceManager连接各Manager(ActivityManager,WindowManager,等等)和相应的ManagerService的桥梁;

3.从Android应用层来说

Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务

img

2.架构

Linux内存被分为用户空间内核空间,用户空间需要经过系统调用才能访问到内核空间。

img

Binder整体基于C/S架构。运行在内核空间的Binder驱动程序,会为用户空间暴露出一个设备文件/dev/binder,进程间通过该文件来建立通信通道。 img

3.优点

  • 好用:易用的C/S架构(借助AIDL后只需编写业务逻辑)
  • 性能:用mmap进行内存映射,只需一次拷贝
  • 安全:内核态管理身份标记,每个App有UID来校验权限,同时支持实名(系统服务)和匿名(自己创建的服务)

3.Android 中的IPC方式

1.Bundle

2.文件共享

3.Messenger

4.AIDL

5.ContentProvider

6.Socket

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kzm3EXg7-1620121064622)(C:\\Users\\Lenovo\\AppData\\Roaming\\Typora\\typora-user-images\\1619779969983.png)]

Buudle

Bundle实现了Parcelable接口,所以它可以很方便的在不同进程间传输 。 Bundle在Activity之间传递数据,传递的数据可以是boolean、byte、int、long、float、double、string等基本类型或它们对应的数组,也可以是对象或对象数组。当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口。

所以Bundle其实是一种数据“容器”。通过Intent来传递。

这里除了数据传递,在Android的艺术探索中有提到另外一种场景

:比如A进程正在进行一个计算,计算完成后它要启动B进程的一个组件并把计算结果传输给B进程,但是这个计算结果不支持放进Bundle中,因此无法用Intent来传输,但是用其他IPC方式会略显复杂。

所以我们通过Intent启动进程B的一个service组件(比如IntentService)让service在后台计算,计算完毕以后再启动B进程中真正想要启动目标组件,由于Service也运行在B进程中,所以目标组件就可以直接获取计算结果。这样也就是实现了跨进程的效果。

文件共享

共享文件也是一种进程间通信方式,两个进程通过读/写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取这个文件来获取数据。存在并发问题

Messenger

Messenger翻译为信使,通过它可以在不同进程中传递Message对象,Message中放入我们需要传递的数据,就可以轻松的实现数据的进程间传递了。Messenger是一种轻量级IPC方案,他的底层实现原理AIDL。

它对AIDL做了封装,使得我们可以更简便的进行进程间通信,同时,由于他一次处理一个请求,因此在服务端中我们不用考虑线程同步的问题,这是因为服务端中不存在并发执行的情形。

实现一个Messenger:分为服务端和客户端

1.服务端进程

首先,我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可

2.客户端进程

客户端进程中,首先要绑定服务端的service,绑定成功后服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象,如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。

Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端仍然只能一个一个处理,所以Messenger不太合适了。而且Messenger的作用主要是为了传递消息,但很多时候我们需要跨进程调用服务端的方法,这种情形用Messenger就无法做到了,但是我们可以用AIDL来实现跨进程的方法调用。

AIDL

AIDL是Messenger底层的实现,因此Messenger本质上也是AIDL,只不过系统为我们做了封装从而方便上层的调用而已。

AIDL的使用

1.服务端

服务端首先要创建一个service来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口

2.客户端

首先需要绑定服务端的Service,绑定成功以后,将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。(实际的实现没有这么简单,这只是大致描述)

ContentProvider

系统预置了许多ContentProvider,比如通讯录信息,日程表信息,要跨进程访问这些信息,只需要通过ContentProvider的query,updata,insert,delete方法即可。也可以实现自定义ContentProvider,然后在其他应用中获得ContentProvider中的数据从而实现进程间通信。

Socket

socket也称套接字,是网络通信中的概念,它分为流失套接字和用户数据报套接字两种,分别对应于网络的传输控制层中的tcp和udp协议。

Binder连接池


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUAx76Ez-1621656437052)(G:\\桌面\\image\\图像\\1621653380608.png)]

在这种模式下,整个工作机制是这样的,每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后想服务端提供自己的唯一标识和其对应的Binder对象,对于服务端来说,只需要一个service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给他们,不停的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。

由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程

以上是关于Android面试Android跨进程通信IPC的主要内容,如果未能解决你的问题,请参考以下文章

Android IPC通信系列篇

Android IPC机制用Socket实现跨进程聊天程序

Android里的多进程和跨进程通讯方式

IPC进程间通信/跨进程通信

IPC进程间通信/跨进程通信

Android跨进程通信Binder机制与AIDL实例