美文网首页Android-NDK/JNI
JNI 基础 - Android 共享内存的序列化过程

JNI 基础 - Android 共享内存的序列化过程

作者: Peakmain | 来源:发表于2018-09-18 11:41 被阅读11次

    Parcel源码分析

    parcel的简单使用

            Parcel parcel=Parcel.obtain();
            parcel.writeInt(12);
            parcel.writeInt(24);
            parcel.setDataPosition(0);
            int number1 = parcel.readInt();
            int number2 = parcel.readInt();
            Log.e(TAG, "number1: "+number1+",number2:"+number2 );
    

    Parcel.obtain()源码分析

     public static Parcel obtain() {
           //从缓冲池中取,没有就直接new
            final Parcel[] pool = sOwnedPool;
            synchronized (pool) {
                Parcel p;
                for (int i=0; i<POOL_SIZE; i++) {
                    p = pool[i];
                    if (p != null) {
                        pool[i] = null;
                        if (DEBUG_RECYCLE) {
                            p.mStack = new RuntimeException();
                        }
                        p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
                        return p;
                    }
                }
            }
            return new Parcel(0);
        }
    

    最终会走到

        private void init(long nativePtr) {
            if (nativePtr != 0) {
                mNativePtr = nativePtr;
                mOwnsNativeParcelObject = false;
            } else {
                mNativePtr = nativeCreate();
                mOwnsNativeParcelObject = true;
            }
        }
    

    nativeCreate源码分析

    private static native long nativeCreate();
    

    这时候我们去下载好的ndk源码.,找到,比如我的是放在D盘
    D:\ndk\android-6.0.1_r1\android-6.0.1_r1\frameworks\base\core\jni下面的android_os_Parcel.cpp

      {"nativeCreate",              "()J", (void*)android_os_Parcel_create},
    

    找到android_os_Parcel_create

    static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
    {
         //实际就是new个Parcel对象,并转换对象为long类型
        Parcel* parcel = new Parcel();
        return reinterpret_cast<jlong>(parcel);
    }
    

    parcel.writeInt()源码分析

      private static native void nativeWriteInt(long nativePtr, int val);
    

    继续看android_os_Parcel.cpp源码对nativeWriteInt分析

    {"nativeWriteInt",            "(JI)V", (void*)android_os_Parcel_writeInt},
    
    static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
         //long转换成Parcel对象
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            const status_t err = parcel->writeInt32(val);
            if (err != NO_ERROR) {
                signalExceptionForError(env, clazz, err);
            }
        }
    }
    

    writeInt32这个源码需要到D:\ndk\android-6.0.1_r1\android-6.0.1_r1\frameworks\native\libs\binder下面的Parcel.cpp

    status_t Parcel::writeInt32(int32_t val)
    {
        return writeAligned(val);
    }
    
    template<class T>//相当于java中的泛型
    status_t Parcel::writeAligned(T val) {
        COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
    
        if ((mDataPos+sizeof(val)) <= mDataCapacity) {
    restart_write:
            *reinterpret_cast<T*>(mData+mDataPos) = val;//mData代表首地址,mDataPos代表指针偏移量
            return finishWrite(sizeof(val));
        }
    
        status_t err = growData(sizeof(val));
        if (err == NO_ERROR) goto restart_write;
        return err;
    }
    

    finishWrite源码分析

    status_t Parcel::finishWrite(size_t len)
    {
        if (len > INT32_MAX) {
            // don't accept size_t values which may have come from an
            // inadvertent conversion from a negative int.
            return BAD_VALUE;
        }
    
        //printf("Finish write of %d\n", len);
        mDataPos += len;//指针向后+偏移量
        ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos);
        if (mDataPos > mDataSize) {
            mDataSize = mDataPos;
            ALOGV("finishWrite Setting data size of %p to %zu", this, mDataSize);
        }
        //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
        return NO_ERROR;
    }
    

    parcel.readInt()源码分析

    private static native int nativeReadInt(long nativePtr);
    
     {"nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},
    
    static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            return parcel->readInt32();
        }
        return 0;
    }
    

    最终会走到

    template<class T>
    status_t Parcel::readAligned(T *pArg) const {
        COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
    
        if ((mDataPos+sizeof(T)) <= mDataSize) {
            const void* data = mData+mDataPos;
             //指针向后移动
            mDataPos += sizeof(T);
           //取值
            *pArg =  *reinterpret_cast<const T*>(data);
            return NO_ERROR;
        } else {
            return NOT_ENOUGH_DATA;
        }
    }
    

    android自己动手实现内存共享

    首先还是使用

            Parcel parcel=new Parcel();
            parcel.writeInt(12);
            parcel.writeInt(24);
            parcel.setDataPosition(0);
            int number1 = parcel.readInt();
            int number2 = parcel.readInt();
            Log.e(TAG, "number1: "+number1+",number2:"+number2 );
    

    Parcel类的创建

    public class Parcel {
        private static long mNativePtr;
    
        static {
            System.loadLibrary("native-lib");
            mNativePtr = nativeCreate();
        }
        public void writeInt(int value) {
            nativeWriteInt(mNativePtr, value);
        }
    
        public void setDataPosition(int pos) {
            nativeSetDataPosition(mNativePtr, pos);
        }
        public final int readInt() {
            return nativeReadInt(mNativePtr);
        }
        //c层构建一个Parcel.cpp对象,然后指针地址
        private static native long nativeCreate();
        //写int
        private static native void nativeWriteInt(long mNativePtr, int value);
        //读int
        private static native int nativeReadInt(long nativePtr);
        //写完之后重新设置偏移位置
        private static native void nativeSetDataPosition(long nativePtr, int pos);
    }
    

    生成头文件,这里我就不阐述了,之前写过了。生成头文件后,我们就可以写c代码了

    #include <string>
    #include <malloc.h>
    #include <android/log.h>
    
    #define TAG "JNI_TAG"
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
    #include "com_peakmain_ndk_Parcel.h"
    extern "C"
    //c/c++  更加灵活,更加接近底层,操作的是一块内存
    class Parcel {
        char *mData;//char共享内存的首地址
        int mDataPos = 0;//=0,默认没有赋值的话
    public:
        Parcel() {
            mData = (char *) (malloc(1024));
        }
    
        void writeInt(jint value) {
            //赋值
            *reinterpret_cast<int *>(mData + mDataPos) = value;
            mDataPos += sizeof(int);
        }
        //设置当前指针的位置
        void setDataPosition(jint position) {
            mDataPos = position;
        }
        jint readInt() {
            int result = *reinterpret_cast<int*>(mData+mDataPos);//取当前地址的值
            mDataPos += sizeof(int);//指针偏移4
            return result;
        }
    };
    
    JNIEXPORT jlong JNICALL Java_com_peakmain_ndk_Parcel_nativeCreate
            (JNIEnv *env, jclass jclzz) {
        Parcel *parcel = new Parcel();
        return reinterpret_cast<jlong>(parcel);
    }
    
    
    JNIEXPORT void JNICALL Java_com_peakmain_ndk_Parcel_nativeWriteInt
            (JNIEnv *env, jclass clazz, jlong nativePtr, jint value) {
        Parcel *parcel = reinterpret_cast<Parcel *>(nativePtr);
        parcel->writeInt(value);
    
    }
    
    JNIEXPORT jint JNICALL Java_com_peakmain_ndk_Parcel_nativeReadInt
            (JNIEnv *env, jclass clazz, jlong nativePtr) {
        Parcel *parcel = reinterpret_cast<Parcel *>(nativePtr);
        return parcel->readInt();
    }
    
    JNIEXPORT void JNICALL Java_com_peakmain_ndk_Parcel_nativeSetDataPosition
            (JNIEnv *env, jclass jclazz, jlong nativePtr, jint value) {
        Parcel *parcel = (Parcel *) (nativePtr);
        parcel->setDataPosition(value);
    }
    

    相关文章

      网友评论

        本文标题:JNI 基础 - Android 共享内存的序列化过程

        本文链接:https://www.haomeiwen.com/subject/kkdlnftx.html