Android系统的IPC方式通常为:文件、socket、binder、messenger、AIDL、ContentProvider,此外还有个Anonymous Shared Memory(匿名共享内存),这篇文章介绍Ashm基础使用相关知识。
demo为MainActivity和一个远程服务(指定了process的service)之间的通信,步骤如下:
1、创建aidl文件IMemoryAidlInterface
interface IMemoryAidlInterface {
ParcelFileDescriptor getParcelFileDescriptor();
}
1、创建一个服务并在manifest文件中指定process
public class MemoryFetchService extends Service {
private static final String TAG = "MemoryFetchService";
private static final String SHM_FILE_NAME = "test_memory";
@Override
public IBinder onBind(Intent intent) {
return new MemoryFetchStub();
}
static class MemoryFetchStub extends IMemoryAidlInterface.Stub {
@Override
public ParcelFileDescriptor getParcelFileDescriptor() throws RemoteException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) {
MemoryFile memoryFile = null;
try {
memoryFile = new MemoryFile(SHM_FILE_NAME, 1024);
memoryFile.getOutputStream().write(new byte[]{1, 2, 3, 4, 5});
Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
FileDescriptor des = (FileDescriptor) method.invoke(memoryFile);
return ParcelFileDescriptor.dup(des);
} catch (Exception e) {
Log.d(TAG, "getParcelFileDescriptor: exception : " + e.toString());
}
}else {
//TODO use SharedMemory to get fd
}
return null;
}
}
}
在服务MemoryFetchService中创建共享内存虚拟文件并设置size,写入内容为一个数组。
在MainActivity中绑定服务,读取共享内存文件中的内容:
private void bind() {
Intent intent = new Intent(MainActivity.this, MemoryFetchService.class);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
byte[] content = new byte[10];
IMemoryAidlInterface iMemoryAidlInterface
= IMemoryAidlInterface.Stub.asInterface(service);
try {
ParcelFileDescriptor parcelFileDescriptor = iMemoryAidlInterface.getParcelFileDescriptor();
FileDescriptor descriptor = parcelFileDescriptor.getFileDescriptor();
FileInputStream fileInputStream = new FileInputStream(descriptor);
int read = fileInputStream.read(content);
Log.d(TAG, "onServiceConnected: read == " + read);
} catch (Exception e) {
Log.d(TAG, "onServiceConnected: exception: " + e.toString());
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, Service.BIND_AUTO_CREATE);
}
package com.people.libsdk.memoryfile;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileInputStream;
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, Integer 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
*/
private 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;
}
public static byte[] readFileDescriptor(FileDescriptor fileDescriptor) {
FileInputStream input = new FileInputStream(fileDescriptor);
try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 4];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
byte[] all = output.toByteArray();
input.close();
output.close();
return all;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
package com.people.libsdk.memoryfile;
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;
}
}
01.写入数据
try {
MemoryFile pushMemoryFile = MemoryFileHelper.createMemoryFile("pushPreview", yuvData.length);
pushMemoryFile.writeBytes(yuvData, 0, 0, yuvData.length);
ParcelFileDescriptor pdf = MemoryFileHelper.getParcelFileDescriptor(pushMemoryFile);
// Log.e(TAG, "pushCameraData time: " + (System.currentTimeMillis() - startTime));
iService.pushCameraData(pdf, yuvData.length, width, height, startTime);
pushMemoryFile.close();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "pushCameraData sendByMemory Exception: " + e.toString());
}
02 获取数据
public void onCallbackPeopleDetection(ParcelFileDescriptor pfd, int length, long tag) {
try {
MemoryFile memoryFile = MemoryFileHelper.openMemoryFile(pfd, length, 1);
FileDescriptor fd = MemoryFileHelper.getFileDescriptor(memoryFile);
byte[] data = MemoryFileHelper.readFileDescriptor(fd);
Log.i(TAG, "onCallbackPeopleDetection: " + new String(data));
Log.i(TAG, "onCallbackPeopleDetection ,time: " + (System.currentTimeMillis() - tag) + ",length= " + data.length);
memoryFile.close();
} catch (Exception e) {
Log.e(TAG, "onCallbackPeopleDetection error: " + e.toString());
}
}
03 AIDL
interface IClient {
/**
* detect people
* response
*/
void onCallbackPeopleDetection(in ParcelFileDescriptor pfd,int length,long tag);
}
别人写的:
https://github.com/LovelyLittleDemon/ShareMemoryRemote