Android提供了一个高效的共享内存机制。如果应用中涉及到在多个进程间交换数据时使用Android提高的共享内存机制将会大大的提高效率。但是也许是出于安全考虑,在应用层使用共享内存机制将会遇到很多障碍,这篇文章旨在解决这些障碍

frameworks/base/core/java/android/os/MemoryFile.java的源码位置下面是5.0版本的网上源码

MemoryFile.java

使用共享内存的流程大概是:

在一个进程中创建一个共享内存。在Android应用层中,用MemoryFile描述一块共享内存,创建共享内存其实就是创建一MemoryFile对象。这一步非常简单,MemoryFile提供了相应的构造函数

  1. public MemoryFile(String name, int length) throws IOException

因为这块内存需要让其他进程共享,所以需要取得刚刚创建的共享内存的文件描述符FileDescriptor,并且把序列化成ParcelFileDescriptor。对于获取FileDescriptor,MemoryFile提供了相应的方法

  1. /**
  2. * Gets a FileDescriptor for the memory file.
  3. *
  4. * The returned file descriptor is not duplicated.
  5. *
  6. * @throws IOException If the memory file has been closed.
  7. *
  8. * @hide
  9. */
  10. public FileDescriptor getFileDescriptor() throws IOException {
  11. return mFD;
  12. }
  1. @hide可见这个方法是隐藏的,在应用层没法直接调用。所以需要用反射来完成,具体代码如下
  1. /**
  2. * 获取memoryFile的FileDescriptor
  3. * @param memoryFile 描述一块共享内存
  4. * @return 这块共享内存对应的文件描述符
  5. */
  6. public static FileDescriptor getFileDescriptor(MemoryFile memoryFile){
  7. if(memoryFile == null){
  8. throw new IllegalArgumentException("memoryFile 不能为空");
  9. }
  10. FileDescriptor fd;
  11. fd = (FileDescriptor) ReflectUtil.invoke("android.os.MemoryFile",memoryFile,"getFileDescriptor");
  12. return fd;
  13. }

对于把FileDescriptor序列化成ParcelFileDescriptor,ParcelFileDescriptor也提供了一隐藏的构造函数:

  1. /** {@hide} */
  2. public ParcelFileDescriptor(FileDescriptor fd) {
  3. this(fd, null);
  4. }

所以我们还是可以通过反射来实现:

  1. /**
  2. * 获取memoryFile的ParcelFileDescriptor
  3. * @param memoryFile 描述一块共享内存
  4. * @return ParcelFileDescriptor
  5. */
  6. public static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile){
  7. if(memoryFile == null){
  8. throw new IllegalArgumentException("memoryFile 不能为空");
  9. }
  10. ParcelFileDescriptor pfd;
  11. FileDescriptor fd = getFileDescriptor(memoryFile);
  12. pfd = (ParcelFileDescriptor) ReflectUtil.getInstance("android.os.ParcelFileDescriptor",fd);
  13. return pfd;
  14. }

把刚刚得到的ParcelFileDescriptor传递到其他进程,这个比较简单直接用binder传就可以了

通过描述共享内存文件描述取得一个描述共享内存的MemoryFile对象,并且需要让这个MemoryFile对象指向刚刚创建的共享内存。在低版本的系统中存在一个构造函数可以直接以FileDescriptor为参数构造出一个MemoryFile对象,这样构造出来的对象刚好指向FileDescriptor描述的共享内存。但是在高版本中没有样的构造函数了。所以在这里我利用了一个取巧的方式。思路是:利用构造函数

  1. public MemoryFile(String name, int length) throws IOException

构造一个MemoryFile对象,当然此时也创建了一块新的共享内存,但是这块共享内存不是我们需要的;调用public void close()方法关闭刚刚创建的共享内存。通过前面的操作后我们得到了一个MemoryFile对象,但是这个对象没有指向任何共享内存,所以接下来我们就需要让MemoryFile对象指向我们需要的共享内存,也就是FileDescriptor描述的那块。在MemoryFile中有一个native方法:

  1. private static native long native_mmap(FileDescriptor fd, int length, int mode)

这个方法就是把fd描述的共享内存映射到虚拟地址空间中。所以我们可以已刚刚获得的FileDescriptor 作为参数利用反射调用这个方法:

  1. /**
  2. * 打开共享内存,一般是一个地方创建了一块共享内存
  3. * 另一个地方持有描述这块共享内存的文件描述符,调用
  4. * 此方法即可获得一个描述那块共享内存的MemoryFile
  5. * 对象
  6. * @param fd 文件描述
  7. * @param length 共享内存的大小
  8. * @param mode PROT_READ = 0x1只读方式打开,
  9. * PROT_WRITE = 0x2可写方式打开,
  10. * PROT_WRITE|PROT_READ可读可写方式打开
  11. * @return MemoryFile
  12. */
  13. public static MemoryFile openMemoryFile(FileDescriptor fd,int length,int mode){
  14. MemoryFile memoryFile = null;
  15. try {
  16. memoryFile = new MemoryFile("tem",1);
  17. memoryFile.close();
  18. Class<?> c = MemoryFile.class;
  19. Method native_mmap = null;
  20. Method[] ms = c.getDeclaredMethods();
  21. for(int i = 0;ms != null&&i<ms.length;i++){
  22. if(ms[i].getName().equals("native_mmap")){
  23. native_mmap = ms[i];
  24. }
  25. }
  26. ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mFD", fd);
  27. ReflectUtil.setField("android.os.MemoryFile",memoryFile,"mLength",length);
  28. long address = (long) ReflectUtil.invokeMethod( null, native_mmap, fd, length, mode);
  29. ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mAddress", address);
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. return memoryFile;
  34. }

这样我们就得到了一个指向一开始我们创建的那块共享内存的MemoryFile了,接下来就可以调用它的public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)从共享内存中读数据和往共享内存中写数据了

最后上完整的代码:

  1. package wzr.com.slidefinish.util;
  2.  
  3. import android.os.MemoryFile;
  4. import android.os.ParcelFileDescriptor;
  5.  
  6. import java.io.FileDescriptor;
  7. import java.io.IOException;
  8. import java.lang.reflect.Method;
  9.  
  10. /**
  11. * 对memoryFile类的扩展
  12. * 1.从memoryFile对象中获取FileDescriptor,ParcelFileDescriptor
  13. * 2.根据一个FileDescriptor和文件length实例化memoryFile对象
  14. */
  15. public class MemoryFileHelper {
  16. /**
  17. * 创建共享内存对象
  18. * @param name 描述共享内存文件名称
  19. * @param length 用于指定创建多大的共享内存对象
  20. * @return MemoryFile 描述共享内存对象
  21. */
  22. public static MemoryFile createMemoryFile(String name,int length){
  23. try {
  24. return new MemoryFile(name,length);
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. return null;
  29. }
  30.  
  31. public static MemoryFile openMemoryFile(ParcelFileDescriptor pfd,int length,int mode){
  32. if(pfd == null){
  33. throw new IllegalArgumentException("ParcelFileDescriptor 不能为空");
  34. }
  35. FileDescriptor fd = pfd.getFileDescriptor();
  36. return openMemoryFile(fd,length,mode);
  37. }
  38.  
  39. /**
  40. * 打开共享内存,一般是一个地方创建了一块共享内存
  41. * 另一个地方持有描述这块共享内存的文件描述符,调用
  42. * 此方法即可获得一个描述那块共享内存的MemoryFile
  43. * 对象
  44. * @param fd 文件描述
  45. * @param length 共享内存的大小
  46. * @param mode PROT_READ = 0x1只读方式打开,
  47. * PROT_WRITE = 0x2可写方式打开,
  48. * PROT_WRITE|PROT_READ可读可写方式打开
  49. * @return MemoryFile
  50. */
  51. public static MemoryFile openMemoryFile(FileDescriptor fd,int length,int mode){
  52. MemoryFile memoryFile = null;
  53. try {
  54. memoryFile = new MemoryFile("tem",1);
  55. memoryFile.close();
  56. Class<?> c = MemoryFile.class;
  57. Method native_mmap = null;
  58. Method[] ms = c.getDeclaredMethods();
  59. for(int i = 0;ms != null&&i<ms.length;i++){
  60. if(ms[i].getName().equals("native_mmap")){
  61. native_mmap = ms[i];
  62. }
  63. }
  64. ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mFD", fd);
  65. ReflectUtil.setField("android.os.MemoryFile",memoryFile,"mLength",length);
  66. long address = (long) ReflectUtil.invokeMethod( null, native_mmap, fd, length, mode);
  67. ReflectUtil.setField("android.os.MemoryFile", memoryFile, "mAddress", address);
  68. } catch (Exception e) {
  69. e.printStackTrace();
  70. }
  71. return memoryFile;
  72. }
  73.  
  74. /**
  75. * 获取memoryFile的ParcelFileDescriptor
  76. * @param memoryFile 描述一块共享内存
  77. * @return ParcelFileDescriptor
  78. */
  79. public static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile){
  80. if(memoryFile == null){
  81. throw new IllegalArgumentException("memoryFile 不能为空");
  82. }
  83. ParcelFileDescriptor pfd;
  84. FileDescriptor fd = getFileDescriptor(memoryFile);
  85. pfd = (ParcelFileDescriptor) ReflectUtil.getInstance("android.os.ParcelFileDescriptor",fd);
  86. return pfd;
  87. }
  88.  
  89. /**
  90. * 获取memoryFile的FileDescriptor
  91. * @param memoryFile 描述一块共享内存
  92. * @return 这块共享内存对应的文件描述符
  93. */
  94. public static FileDescriptor getFileDescriptor(MemoryFile memoryFile){
  95. if(memoryFile == null){
  96. throw new IllegalArgumentException("memoryFile 不能为空");
  97. }
  98. FileDescriptor fd;
  99. fd = (FileDescriptor) ReflectUtil.invoke("android.os.MemoryFile",memoryFile,"getFileDescriptor");
  100. return fd;
  101. }
  102. }

ReflectUtil.java

  1. package wzr.com.slidefinish.util;
  2.  
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Method;
  6.  
  7. /**
  8. * 反射工具类
  9. * Created by wuzr on 2016/6/27.
  10. */
  11. public class ReflectUtil {
  12.  
  13. /**
  14. *根据类名,参数实例化对象
  15. * @param className 类的路径全名
  16. * @param params 构造函数需要的参数
  17. * @return 返回T类型的一个对象
  18. */
  19. public static Object getInstance(String className,Object ... params){
  20. if(className == null || className.equals("")){
  21. throw new IllegalArgumentException("className 不能为空");
  22. }
  23. try {
  24. Class<?> c = Class.forName(className);
  25. if(params != null){
  26. int plength = params.length;
  27. Class[] paramsTypes = new Class[plength];
  28. for (int i = 0; i < plength; i++) {
  29. paramsTypes[i] = params[i].getClass();
  30. }
  31. Constructor constructor = c.getDeclaredConstructor(paramsTypes);
  32. constructor.setAccessible(true);
  33. return constructor.newInstance(params);
  34. }
  35. Constructor constructor = c.getDeclaredConstructor();
  36. constructor.setAccessible(true);
  37. return constructor.newInstance();
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. }
  41. return null;
  42. }
  43.  
  44. /**
  45. * 执行instance的方法
  46. * @param className 类的全名
  47. * @param instance 对应的对象,为null时执行类的静态方法
  48. * @param methodName 方法名称
  49. * @param params 参数
  50. */
  51. public static Object invoke(String className,Object instance,String methodName,Object ... params){
  52. if(className == null || className.equals("")){
  53. throw new IllegalArgumentException("className 不能为空");
  54. }
  55. if(methodName == null || methodName.equals("")){
  56. throw new IllegalArgumentException("methodName不能为空");
  57. }
  58. try {
  59. Class<?> c = Class.forName(className);
  60. if(params != null){
  61. int plength = params.length;
  62. Class[] paramsTypes = new Class[plength];
  63. for(int i = 0;i < plength;i++){
  64. paramsTypes[i] = params[i].getClass();
  65. }
  66. Method method = c.getDeclaredMethod(methodName, paramsTypes);
  67. method.setAccessible(true);
  68. return method.invoke(instance, params);
  69. }
  70. Method method = c.getDeclaredMethod(methodName);
  71. method.setAccessible(true);
  72. return method.invoke(instance);
  73. } catch (Exception e) {
  74. e.printStackTrace();
  75. }
  76. return null;
  77. }
  78.  
  79. /**
  80. * 执行指定的对方法
  81. * @param instance 需要执行该方法的对象,为空时,执行静态方法
  82. * @param m 需要执行的方法对象
  83. * @param params 方法对应的参数
  84. * @return 方法m执行的返回值
  85. */
  86. public static Object invokeMethod(Object instance,Method m,Object ... params){
  87. if(m == null){
  88. throw new IllegalArgumentException("method 不能为空");
  89. }
  90. m.setAccessible(true);
  91. try {
  92. return m.invoke(instance,params);
  93. } catch (Exception e){
  94. e.printStackTrace();
  95. }
  96. return null;
  97. }
  98.  
  99. /**
  100. * 取得属性值
  101. * @param className 类的全名
  102. * @param fieldName 属性名
  103. * @param instance 对应的对象,为null时取静态变量
  104. * @return 属性对应的值
  105. */
  106. public static Object getField(String className,Object instance,String fieldName){
  107. if(className == null || className.equals("")){
  108. throw new IllegalArgumentException("className 不能为空");
  109. }
  110. if(fieldName == null || fieldName.equals("")){
  111. throw new IllegalArgumentException("fieldName 不能为空");
  112. }
  113. try {
  114. Class c = Class.forName(className);
  115. Field field = c.getDeclaredField(fieldName);
  116. field.setAccessible(true);
  117. return field.get(instance);
  118. } catch (Exception e) {
  119. e.printStackTrace();
  120. }
  121. return null;
  122. }
  123.  
  124. /**
  125. * 设置属性
  126. * @param className 类的全名
  127. * @param fieldName 属性名
  128. * @param instance 对应的对象,为null时改变的是静态变量
  129. * @param value 值
  130. */
  131. public static void setField(String className,Object instance,String fieldName,Object value){
  132. if(className == null || className.equals("")){
  133. throw new IllegalArgumentException("className 不能为空");
  134. }
  135. if(fieldName == null || fieldName.equals("")){
  136. throw new IllegalArgumentException("fieldName 不能为空");
  137. }
  138. try {
  139. Class<?> c = Class.forName(className);
  140. Field field = c.getDeclaredField(fieldName);
  141. field.setAccessible(true);
  142. field.set(instance, value);
  143. } catch (Exception e) {
  144. e.printStackTrace();
  145. }
  146. }
  147.  
  148. /**
  149. * 根据方法名,类名,参数获取方法
  150. * @param className 类名,全名称
  151. * @param methodName 方法名
  152. * @param paramsType 参数类型列表
  153. * @return 方法对象
  154. */
  155. public static Method getMethod(String className,String methodName,Class ... paramsType){
  156. if(className == null || className.equals("")){
  157. throw new IllegalArgumentException("className 不能为空");
  158. }
  159. if(methodName == null || methodName.equals("")){
  160. throw new IllegalArgumentException("methodName不能为空");
  161. }
  162. try {
  163. Class<?> c = Class.forName(className);
  164. return c.getDeclaredMethod(methodName,paramsType);
  165. } catch (Exception e) {
  166. e.printStackTrace();
  167. }
  168. return null;
  169. }
  170. }

源码地址: https://github.com/mingfeng002/TestMemFile

MemoryFile匿名共享内存的更多相关文章

  1. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共 ...

  2. Android 匿名共享内存Java接口分析

    在Android 匿名共享内存驱动源码分析中介绍了匿名共享内存的驱动实现过程,本文在Android匿名共享内存驱动基础上,介绍Android匿名共享内存对外Android系统的匿名共享内存子系统的主体 ...

  3. Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6939890 在Android系统中,针对移动设 ...

  4. Android系统匿名共享内存(Anonymous Shared Memory)Java调用接口分析

    一.Ashmem驱动程序 ~/Android/kernel/goldfish ----include ----linux ----ashmem.h ----mm ----ashmem.c 驱动程序具体 ...

  5. Fresco内存机制(Ashmem匿名共享内存)

    Fresco的内存机制 Fresco是Facebook出品的高性能图片加载库,采用了Ashmem匿名共享内存机制, 来解决图片加载中的OOM问题.这里不对Fresco做深入分析,只关注Fresco在A ...

  6. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6666491 在前面一篇文章Android系统匿 ...

  7. Android 匿名共享内存C++接口分析

    在上一篇Android 匿名共享内存C接口分析中介绍了Android系统的匿名共享内存C语言访问接口,本文在前文的基础上继续介绍Android系统的匿名共享内存提供的C++访问接口.在C++层通过引入 ...

  8. Android 匿名共享内存C接口分析

    在Android 匿名共享内存驱动源码分析中详细分析了匿名共享内存在Linux内核空间的实现,虽然内核空间实现了匿名共享内存,但仍然需要在用户空间为用户使用匿名共享内存提供访问接口.Android系统 ...

  9. 0-Android使用Ashmem机制进行跨进程共享内存

    Android使用Ashmem机制进行跨进程共享内存 来源: http://blog.csdn.net/luoshengyang/article/details/6651971 导语: 在Androi ...

随机推荐

  1. Luogu 3402 可持久化并查集

    点开这题纯属无聊……不过既然写掉了,那就丢一个模板好了 不得不说,可持久化并查集实现真的很暴力,就是把并查集的数组弄一个主席树可持久化. 有一点要注意的是不能写路径压缩,这样跳版本的时候会错,所以弄一 ...

  2. 形式化验证工具(PAT)Perterson Algorithm学习

    今天学习一下Perterson Algorithm. 这个算法是使用三个变量来实现并发程序的互斥性算法. 具体看一下代码: Peterson算法是一个实现互斥锁的并发程序设计算法,核心就是三个标志位是 ...

  3. 查看vim配置文件并编辑

    查看vim配置文件并编辑 1 $vim 进入vim命令行 2 进入底行模式,输入 echo $VIM,能够看到vim的路径为/usr/share/vim 3 查看配置文件vimrc 4 编辑vim配置 ...

  4. 算法导论 寻找第i小元素 9.2

    PS1:如果单纯为做出这道题那么这个代价是O(nlgn),通过排序就可以了. 这里讨论的是O(n)的算法.那么来分析一下这个算法是如何做到O(n)的,算了不分析了,这个推到看起来太麻烦了.其实我想知道 ...

  5. 【转】深入理解java的String

    要理解 java中String的运作方式,必须明确一点:String是一个非可变类(immutable).什么是非可变类呢?简单说来,非可变类的实例是不能被修改的,每个实例中包含的信息都必须在该实例创 ...

  6. SQLServer数据库,表内存,实例名分析SQL语句

    --数据库内存分析 USE master go DECLARE @insSize TABLE(dbName sysname,checkTime VARCHAR(19),dbSize VARCHAR(5 ...

  7. c++标准库介绍

    C++标准库的所有头文件都没有扩展名.C++标准库的内容总共在50个标准头文件中定义,其中18个提供了C库的功能.<cname>形式的标准头文件[<complex>例外]其内容 ...

  8. loj #2024. 「JLOI / SHOI2016」侦查守卫

    #2024. 「JLOI / SHOI2016」侦查守卫   题目描述 小 R 和 B 神正在玩一款游戏.这款游戏的地图由 nnn 个点和 n−1n - 1n−1 条无向边组成,每条无向边连接两个点, ...

  9. java读取 500M 以上文件,java读取大文件

    java 读取txt,java读取大文件 设置缓存大小BUFFER_SIZE ,Config.tempdatafile是文件地址 来源博客http://yijianfengvip.blog.163.c ...

  10. Java foreach remove问题分析

    原文链接:http://www.cnblogs.com/chrischennx/p/9610853.html 都说ArrayList在用foreach循环的时候,不能add元素,也不能remove元素 ...