Android应用层使用共享内存机制进行进程间交换数据
2018-03-01 16:42
309 查看
Android应用层使用共享内存机制进行进程间交换数据
Android提供了一个高效的共享内存机制。如果应用中涉及到在多个进程间交换数据时使用Android提高的共享内存机制将会大大的提高效率。但是也许是出于安全考虑,在应用层使用共享内存机制将会遇到很多障碍,这篇文章旨在解决这些障碍使用共享内存的流程大概是:在一个进程中创建一个共享内存。在Android应用层中,用MemoryFile描述一块共享内存,创建共享内存其实就是创建一MemoryFile对象。这一步非常简单,MemoryFile提供了相应的构造函数public MemoryFile(String name, int length) throws IOException1
因为这块内存需要让其他进程共享,所以需要取得刚刚创建的共享内存的文件描述符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; }1
2
3
4
5
6
7
8
9
10
11
12
可是这个方法是隐藏的,在应用层没法直接调用。所以需要用反射来完成,具体代码如下
/** * 获取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; }1
2
3
4
5
6
7
8
9
10
11
12
13
对于把FileDescriptor序列化成ParcelFileDescriptor,ParcelFileDescriptor也提供了一隐藏的构造函数:
/** {@hide} */ public ParcelFileDescriptor(FileDescriptor fd) { this(fd, null); }1
2
3
4
所以我们还是可以通过反射来实现:
/** * 获取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; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
把刚刚得到的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)1
这个方法就是把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; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
这样我们就得到了一个指向一开始我们创建的那块共享内存的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;1
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对象
* Created by wuzr on 2016/7/16.
*/
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; }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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; } }
相关文章推荐
- Android应用层使用共享内存机制进行进程间交换数据
- Android应用层使用共享内存机制进行进程间交换数据
- Android Binder机制实现进程间数据交换(不使用aidl实现)
- Windows CE下使用共享内存实现进程间数据交换
- Android中使用网络和服务器端程序进行数据交换
- android 使用JSON进行网络数据交换
- android使用JSON进行网络数据交换(服务端、客户端)的实现
- android使用JSON进行网络数据交换
- Android使用JSON进行网络数据交换
- 封装android 通讯使用二进制进行数据交换 2个必要的读取,写入操作
- android使用JSON进行网络数据交换(服务端、客户端)的实现
- Windows CE下使用共享内存实现进程间数据交换
- Android使用JSON进行网络数据交换
- Android 使用JSON进行网络数据交换
- android 使用JSON进行网络数据交换
- 【Android开发艺术探索】IPC机制(四)-使用AIDL进行跨进程通信
- Windows CE下使用共享内存实现进程间数据交换
- 共享内存实现进程间大数据的交换
- [转]Android上GTalk以及Push机制的XMPP数据选择使用protobuf格式而非XML格式
- android之使用文件进行数据存储