MemoryFile一个可以帮助开发者"偷"内存的地方

Android系统的IPC方式通常为:文件、socket、binder、messenger、AIDL、ContentProvider,此外还有个Anonymous Shared Memory(匿名共享内存),这篇文章介绍Ashm基础使用相关知识。

  • ShareMemory android O(8.0)之后增加新的共享内存方式,SharedMemory.java 此类继承Parcelable,可以作为IPC通讯传输的数据;
  • ClassLoader 多态:此方式并非真正的多态,而是根据ClassLoader类的加载顺序,在应用中构建一个和系统类同样包名的类(方法也同名,可以不做实现),编译时使用的应用中的类,运行时加载的是系统中的类,从而实现伪多态;
  • AIDL 通过 传输 ParcelFileDescriptor,它继承Parcelable 序列化,因此可以AIDL传输
  • ShareMemory 继承Parcelable,可以直接AIDL传输

 

    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

 

你可能感兴趣的:(android技术,ShareMemory,MemoryFile,跨进程,大数据通信)