2024年5月25日发(作者:)

android共享内存(ShareMemory)的实现

Android 几种进程通信方式

跨进程通信要求把方法调用及其数据分解至操作系统可以识别的程度,并将其从本

地进程和地址空间传输至远程进程和地址空间,然后在远程进程中重新组装并执行

该调用。

然后,返回值将沿相反方向传输回来。

Android 为我们提供了以下几种进程通信机制(供开发者使用的进程通信 API)对

应的文章链接如下:

文件

AIDL (基于 Binder)

Binder

Messenger (基于 Binder)

ContentProvider (基于 Binder)

Socket

在上述通信机制的基础上,我们只需集中精力定义和实现 RPC 编程接口即可。

如何选择这几种通信方式

这里再对比总结一下:

只有允许不同应用的客户端用 IPC 方式调用远程方法,并且想要在服务中处

理多线程时,才有必要使用 AIDL

如果需要调用远程方法,但不需要处理并发 IPC,就应该通过实现一个

Binder 创建接口

如果您想执行 IPC,但只是传递数据,不涉及方法调用,也不需要高并发,

就使用 Messenger 来实现接口

如果需要处理一对多的进程间数据共享(主要是数据的 CRUD),就使用

ContentProvider

如果要实现一对多的并发实时通信,就使用 Socket

IPC分析:

android IPC的核心方式是binder,但是android binder的传输限制1M(被很多进

程共享),在较大数据交换一般通过文件,但是效率很低,因此介绍下新的内存共

享方式: ShareMemory

具体实现:

通过binder把MemoryFile的ParcelFileDescriptor 传到Service; 在服务

端通过ParcelFileDescriptor 读取共享内存数据;

客户端 通过MemoryFile获取ParcelFileDescriptor,通过

Binder把ParcelFileDescriptor(int类型)传递到服务端

服务端 RemoteService 获取到ParcelFileDescriptor 之后,有两种方式 第一

种:通过FileInputStream 读取ParcelFileDescriptor 的FD,此种方式的问

题在于,每次读取之后FD的游标都在文件最后(也就是说第二次读取结果

是不低的,必须重置FD的游标) 第二种:就是通过反射,直接

ParcelFileDescriptor构建MemoryFile,然后读取,此种方式问题在于26

和27实现的不同,代码如下:

Android P(9.0)反射限制: 上述反射的方式在android P上被限制(android 9.0禁

止通过放射调用系统的的非公开方法),此路不同(If they cut off one head, two

more shall take it' Hail Hydra.),还有千万条路

ShareMemory android O(8.0)之后增加新的共享内存方式,

此类继承Parcelable,可以作为IPC通讯传输的数据;

ClassLoader 多态:此方式并非真正的多态,而是根据ClassLoader类的加

载顺序,在应用中构建一个和系统类同样包名的类(方法也同名,可以不做

实现),编译时使用的应用中的类,运行时加载的是系统中的类,从而实现

伪多态;

GitHub:

ShareMemory优点:

binder 限制(binder的android上的限制1M,而且是被多个进程共享

的); binder 在android进程中经过一次内存copy,内存共享通过mmap,

0次copy效率更高;