MemoryFile匿名共享内存
Android提供了一个高效的共享内存机制。如果应用中涉及到在多个进程间交换数据时使用Android提高的共享内存机制将会大大的提高效率。但是也许是出于安全考虑,在应用层使用共享内存机制将会遇到很多障碍,这篇文章旨在解决这些障碍
frameworks/base/core/java/android/os/MemoryFile.java的源码位置下面是5.0版本的网上源码
使用共享内存的流程大概是:
在一个进程中创建一个共享内存。在Android应用层中,用MemoryFile描述一块共享内存,创建共享内存其实就是创建一MemoryFile对象。这一步非常简单,MemoryFile提供了相应的构造函数
public MemoryFile(String name, int length) throws IOException
因为这块内存需要让其他进程共享,所以需要取得刚刚创建的共享内存的文件描述符FileDescriptor,并且把序列化成ParcelFileDescriptor。对于获取FileDescriptor,MemoryFile提供了相应的方法
/**
* Gets a FileDescriptor for the memory file.
*
* The returned file descriptor is not duplicated.
*
* @throws IOException If the memory file has been closed.
*
* @hide
*/
public FileDescriptor getFileDescriptor() throws IOException {
return mFD;
}
@hide可见这个方法是隐藏的,在应用层没法直接调用。所以需要用反射来完成,具体代码如下
/**
* 获取memoryFile的FileDescriptor
* @param memoryFile 描述一块共享内存
* @return 这块共享内存对应的文件描述符
*/
public static FileDescriptor getFileDescriptor(MemoryFile memoryFile){
if(memoryFile == null){
throw new IllegalArgumentException("memoryFile 不能为空");
}
FileDescriptor fd;
fd = (FileDescriptor) ReflectUtil.invoke("android.os.MemoryFile",memoryFile,"getFileDescriptor");
return fd;
}
对于把FileDescriptor序列化成ParcelFileDescriptor,ParcelFileDescriptor也提供了一隐藏的构造函数:
/** {@hide} */
public ParcelFileDescriptor(FileDescriptor fd) {
this(fd, null);
}
所以我们还是可以通过反射来实现:
/**
* 获取memoryFile的ParcelFileDescriptor
* @param memoryFile 描述一块共享内存
* @return ParcelFileDescriptor
*/
public static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile){
if(memoryFile == null){
throw new IllegalArgumentException("memoryFile 不能为空");
}
ParcelFileDescriptor pfd;
FileDescriptor fd = getFileDescriptor(memoryFile);
pfd = (ParcelFileDescriptor) ReflectUtil.getInstance("android.os.ParcelFileDescriptor",fd);
return pfd;
}
把刚刚得到的ParcelFileDescriptor传递到其他进程,这个比较简单直接用binder传就可以了
通过描述共享内存文件描述取得一个描述共享内存的MemoryFile对象,并且需要让这个MemoryFile对象指向刚刚创建的共享内存。在低版本的系统中存在一个构造函数可以直接以FileDescriptor为参数构造出一个MemoryFile对象,这样构造出来的对象刚好指向FileDescriptor描述的共享内存。但是在高版本中没有样的构造函数了。所以在这里我利用了一个取巧的方式。思路是:利用构造函数
public MemoryFile(String name, int length) throws IOException
构造一个MemoryFile对象,当然此时也创建了一块新的共享内存,但是这块共享内存不是我们需要的;调用public void close()方法关闭刚刚创建的共享内存。通过前面的操作后我们得到了一个MemoryFile对象,但是这个对象没有指向任何共享内存,所以接下来我们就需要让MemoryFile对象指向我们需要的共享内存,也就是FileDescriptor描述的那块。在MemoryFile中有一个native方法:
private static native long native_mmap(FileDescriptor fd, int length, int mode)
这个方法就是把fd描述的共享内存映射到虚拟地址空间中。所以我们可以已刚刚获得的FileDescriptor 作为参数利用反射调用这个方法:
/**
* 打开共享内存,一般是一个地方创建了一块共享内存
* 另一个地方持有描述这块共享内存的文件描述符,调用
* 此方法即可获得一个描述那块共享内存的MemoryFile
* 对象
* @param fd 文件描述
* @param length 共享内存的大小
* @param mode PROT_READ = 0x1只读方式打开,
* PROT_WRITE = 0x2可写方式打开,
* PROT_WRITE|PROT_READ可读可写方式打开
* @return MemoryFile
*/
public static MemoryFile openMemoryFile(FileDescriptor fd,int length,int mode){
MemoryFile memoryFile = null;
try {
memoryFile = new MemoryFile("tem",1);
memoryFile.close();
Class<?> c = MemoryFile.class;
Method native_mmap = null;
Method[] ms = c.getDeclaredMethods();
for(int i = 0;ms != null&&i<ms.length;i++){
if(ms[i].getName().equals("native_mmap")){
native_mmap = ms[i];
}
}
ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mFD", fd);
ReflectUtil.setField("android.os.MemoryFile",memoryFile,"mLength",length);
long address = (long) ReflectUtil.invokeMethod( null, native_mmap, fd, length, mode);
ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mAddress", address);
} catch (Exception e) {
e.printStackTrace();
}
return memoryFile;
}
这样我们就得到了一个指向一开始我们创建的那块共享内存的MemoryFile了,接下来就可以调用它的public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)和public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)从共享内存中读数据和往共享内存中写数据了
最后上完整的代码:
package wzr.com.slidefinish.util; import android.os.MemoryFile;
import android.os.ParcelFileDescriptor; import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.reflect.Method; /**
* 对memoryFile类的扩展
* 1.从memoryFile对象中获取FileDescriptor,ParcelFileDescriptor
* 2.根据一个FileDescriptor和文件length实例化memoryFile对象
*/
public class MemoryFileHelper {
/**
* 创建共享内存对象
* @param name 描述共享内存文件名称
* @param length 用于指定创建多大的共享内存对象
* @return MemoryFile 描述共享内存对象
*/
public static MemoryFile createMemoryFile(String name,int length){
try {
return new MemoryFile(name,length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
} public static MemoryFile openMemoryFile(ParcelFileDescriptor pfd,int length,int mode){
if(pfd == null){
throw new IllegalArgumentException("ParcelFileDescriptor 不能为空");
}
FileDescriptor fd = pfd.getFileDescriptor();
return openMemoryFile(fd,length,mode);
} /**
* 打开共享内存,一般是一个地方创建了一块共享内存
* 另一个地方持有描述这块共享内存的文件描述符,调用
* 此方法即可获得一个描述那块共享内存的MemoryFile
* 对象
* @param fd 文件描述
* @param length 共享内存的大小
* @param mode PROT_READ = 0x1只读方式打开,
* PROT_WRITE = 0x2可写方式打开,
* PROT_WRITE|PROT_READ可读可写方式打开
* @return MemoryFile
*/
public static MemoryFile openMemoryFile(FileDescriptor fd,int length,int mode){
MemoryFile memoryFile = null;
try {
memoryFile = new MemoryFile("tem",1);
memoryFile.close();
Class<?> c = MemoryFile.class;
Method native_mmap = null;
Method[] ms = c.getDeclaredMethods();
for(int i = 0;ms != null&&i<ms.length;i++){
if(ms[i].getName().equals("native_mmap")){
native_mmap = ms[i];
}
}
ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mFD", fd);
ReflectUtil.setField("android.os.MemoryFile",memoryFile,"mLength",length);
long address = (long) ReflectUtil.invokeMethod( null, native_mmap, fd, length, mode);
ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mAddress", address);
} catch (Exception e) {
e.printStackTrace();
}
return memoryFile;
} /**
* 获取memoryFile的ParcelFileDescriptor
* @param memoryFile 描述一块共享内存
* @return ParcelFileDescriptor
*/
public static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile){
if(memoryFile == null){
throw new IllegalArgumentException("memoryFile 不能为空");
}
ParcelFileDescriptor pfd;
FileDescriptor fd = getFileDescriptor(memoryFile);
pfd = (ParcelFileDescriptor) ReflectUtil.getInstance("android.os.ParcelFileDescriptor",fd);
return pfd;
} /**
* 获取memoryFile的FileDescriptor
* @param memoryFile 描述一块共享内存
* @return 这块共享内存对应的文件描述符
*/
public static FileDescriptor getFileDescriptor(MemoryFile memoryFile){
if(memoryFile == null){
throw new IllegalArgumentException("memoryFile 不能为空");
}
FileDescriptor fd;
fd = (FileDescriptor) ReflectUtil.invoke("android.os.MemoryFile",memoryFile,"getFileDescriptor");
return fd;
}
}
ReflectUtil.java
package wzr.com.slidefinish.util; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; /**
* 反射工具类
* Created by wuzr on 2016/6/27.
*/
public class ReflectUtil { /**
*根据类名,参数实例化对象
* @param className 类的路径全名
* @param params 构造函数需要的参数
* @return 返回T类型的一个对象
*/
public static Object getInstance(String className,Object ... params){
if(className == null || className.equals("")){
throw new IllegalArgumentException("className 不能为空");
}
try {
Class<?> c = Class.forName(className);
if(params != null){
int plength = params.length;
Class[] paramsTypes = new Class[plength];
for (int i = 0; i < plength; i++) {
paramsTypes[i] = params[i].getClass();
}
Constructor constructor = c.getDeclaredConstructor(paramsTypes);
constructor.setAccessible(true);
return constructor.newInstance(params);
}
Constructor constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 执行instance的方法
* @param className 类的全名
* @param instance 对应的对象,为null时执行类的静态方法
* @param methodName 方法名称
* @param params 参数
*/
public static Object invoke(String className,Object instance,String methodName,Object ... params){
if(className == null || className.equals("")){
throw new IllegalArgumentException("className 不能为空");
}
if(methodName == null || methodName.equals("")){
throw new IllegalArgumentException("methodName不能为空");
}
try {
Class<?> c = Class.forName(className);
if(params != null){
int plength = params.length;
Class[] paramsTypes = new Class[plength];
for(int i = 0;i < plength;i++){
paramsTypes[i] = params[i].getClass();
}
Method method = c.getDeclaredMethod(methodName, paramsTypes);
method.setAccessible(true);
return method.invoke(instance, params);
}
Method method = c.getDeclaredMethod(methodName);
method.setAccessible(true);
return method.invoke(instance);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 执行指定的对方法
* @param instance 需要执行该方法的对象,为空时,执行静态方法
* @param m 需要执行的方法对象
* @param params 方法对应的参数
* @return 方法m执行的返回值
*/
public static Object invokeMethod(Object instance,Method m,Object ... params){
if(m == null){
throw new IllegalArgumentException("method 不能为空");
}
m.setAccessible(true);
try {
return m.invoke(instance,params);
} catch (Exception e){
e.printStackTrace();
}
return null;
} /**
* 取得属性值
* @param className 类的全名
* @param fieldName 属性名
* @param instance 对应的对象,为null时取静态变量
* @return 属性对应的值
*/
public static Object getField(String className,Object instance,String fieldName){
if(className == null || className.equals("")){
throw new IllegalArgumentException("className 不能为空");
}
if(fieldName == null || fieldName.equals("")){
throw new IllegalArgumentException("fieldName 不能为空");
}
try {
Class c = Class.forName(className);
Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(instance);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} /**
* 设置属性
* @param className 类的全名
* @param fieldName 属性名
* @param instance 对应的对象,为null时改变的是静态变量
* @param value 值
*/
public static void setField(String className,Object instance,String fieldName,Object value){
if(className == null || className.equals("")){
throw new IllegalArgumentException("className 不能为空");
}
if(fieldName == null || fieldName.equals("")){
throw new IllegalArgumentException("fieldName 不能为空");
}
try {
Class<?> c = Class.forName(className);
Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, value);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 根据方法名,类名,参数获取方法
* @param className 类名,全名称
* @param methodName 方法名
* @param paramsType 参数类型列表
* @return 方法对象
*/
public static Method getMethod(String className,String methodName,Class ... paramsType){
if(className == null || className.equals("")){
throw new IllegalArgumentException("className 不能为空");
}
if(methodName == null || methodName.equals("")){
throw new IllegalArgumentException("methodName不能为空");
}
try {
Class<?> c = Class.forName(className);
return c.getDeclaredMethod(methodName,paramsType);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
源码地址: https://github.com/mingfeng002/TestMemFile
MemoryFile匿名共享内存的更多相关文章
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共 ...
- Android 匿名共享内存Java接口分析
在Android 匿名共享内存驱动源码分析中介绍了匿名共享内存的驱动实现过程,本文在Android匿名共享内存驱动基础上,介绍Android匿名共享内存对外Android系统的匿名共享内存子系统的主体 ...
- Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6939890 在Android系统中,针对移动设 ...
- Android系统匿名共享内存(Anonymous Shared Memory)Java调用接口分析
一.Ashmem驱动程序 ~/Android/kernel/goldfish ----include ----linux ----ashmem.h ----mm ----ashmem.c 驱动程序具体 ...
- Fresco内存机制(Ashmem匿名共享内存)
Fresco的内存机制 Fresco是Facebook出品的高性能图片加载库,采用了Ashmem匿名共享内存机制, 来解决图片加载中的OOM问题.这里不对Fresco做深入分析,只关注Fresco在A ...
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6666491 在前面一篇文章Android系统匿 ...
- Android 匿名共享内存C++接口分析
在上一篇Android 匿名共享内存C接口分析中介绍了Android系统的匿名共享内存C语言访问接口,本文在前文的基础上继续介绍Android系统的匿名共享内存提供的C++访问接口.在C++层通过引入 ...
- Android 匿名共享内存C接口分析
在Android 匿名共享内存驱动源码分析中详细分析了匿名共享内存在Linux内核空间的实现,虽然内核空间实现了匿名共享内存,但仍然需要在用户空间为用户使用匿名共享内存提供访问接口.Android系统 ...
- 0-Android使用Ashmem机制进行跨进程共享内存
Android使用Ashmem机制进行跨进程共享内存 来源: http://blog.csdn.net/luoshengyang/article/details/6651971 导语: 在Androi ...
随机推荐
- 20169219《linux内核原理与分析》第九周作业
网易云课堂学习 可执行程序的装载 可执行程序的产生过程:预处理-----> 编译 ----> 汇编 ----> 链接 以hello.c文件为例进行分析,编译步骤如下 vi hello ...
- const与define的区别
const与#define最大的差别,Const在堆栈分配了空间,而#define只是把具体数值 直接传递到目标变量罢了.或者说,const的常量是一个Run-Time的概念,他在程 序中确确实实的存 ...
- [转]JQ中$(window).load和$(document).ready区别与执行顺序
一.$(window).load().window.onload=function(){}和$(document).ready()方法的区别 1.$(window).load() 和window.on ...
- eclipse workspace 共享设置
总结一下,复制工作空间配置步骤如下: 1 使用eclipse新建workspace. 2 将新建的workspace下的.metadata\.plugins内容全部删除. 3 将需要拷贝的worksp ...
- framwork maven的配置及使用
maven的配置及使用 一.什么是maven: 我们在开发项目的过程中,会使用一些开源框架.第三方的工具等等,这些都是以jar包的方式被项目所引用,并且有些jar包还会依赖其他的jar包,我们同样需要 ...
- CENTOS 7 升级安装 Python 3.5
写在前面的话 本文采取源码的方式安装 Python 3.5.2,如果是其它版本会有或多或少的差异,且写这篇的时候官网最新的是 Python 3.7,个人使用 3.5 就足够了,没必要更新到最新,否则出 ...
- UWP&WP8.1 基础控件——Image
Image是UWP和WP8.1中系统自带的图片展示器. 具有较强的性能,使用也是非常的简单. 使用方式分为在XAML中,在C#代码中. XAML中: 在XAML中使用方式非常简单. 常用XAML So ...
- linux配置环境变量 - 认识
环境 ubuntu17.04 终端(就是黑框) 认识 环境变量:$PATH 在 ×××/bin 下的命令,可以不用到指定目录下, 比如:安装hbase后,hbase提供一些shell命令在habse ...
- Spring core注解
1.@Autowired Autowired是用在JavaBean中的注解,通过byType形式,用来给指定的字段或方法注入所需的外部资源 Autowired注解来指定自动装配,可以修饰setter方 ...
- 洛谷 P2447 [SDOI2010]外星千足虫
P2447 [SDOI2010]外星千足虫 题目描述 公元2089年6月4日,在经历了17年零3个月的漫长旅行后,“格纳格鲁一号”载人火箭返回舱终于安全着陆.此枚火箭由美国国家航空航天局(NASA)研 ...