Android-NDK/JNI

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

2018-09-18  本文已影响11人  Peakmain

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);
}
上一篇 下一篇

猜你喜欢

热点阅读