The relationship between Android Java Parcel and Native Parcel

This article analyzes the relationship between Java Parcel and Native Parcel through the example of Java Binder Parcel

Java Binder Parcel Sample Code

@Override
public int add(int first, int second) throws android.os.RemoteException {
    
    
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
    
    
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeInt(first);
        _data.writeInt(second);
        boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
        if (!_status && getDefaultImpl() != null) {
    
    
            return getDefaultImpl().add(first, second);
        }
        _reply.readException();
        _result = _reply.readInt();
    } finally {
    
    
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

From the code, we can see that Parcel-related operations can be divided into three parts, namely:

  1. Parcel Creation
android.os.Parcel _data = android.os.Parcel.obtain();

  1. Store and read data through Parcel Storage
    :
_data.writeInt(first);

read:

_result = _reply.readInt();

  1. Release related data through Parcel
_reply.recycle();
_data.recycle();

The following three parts are analyzed.

Parcel Creation

public static Parcel obtain() {
    
    
    final Parcel[] pool = sOwnedPool;
    synchronized (pool) {
    
    
        Parcel p;
        for (int i=0; i<POOL_SIZE; i++) {
    
    
            p = pool[i]; //1
            if (p != null) {
    
    
                pool[i] = null;
                if (DEBUG_RECYCLE) {
    
    
                    p.mStack = new RuntimeException();
                }
                p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
                return p;
            }
        }
    }
    return new Parcel(0); //2
}

private Parcel(long nativePtr) {
    
    
    if (DEBUG_RECYCLE) {
    
    
        mStack = new RuntimeException();
    }
    //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
    init(nativePtr); //3
}

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

private static native long nativeCreate();

private long mNativePtr;
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];

As can be seen from the above code, the obtain function takes the Parcel object from the global variable sOwnedPool array (see code 1), and creates one if it cannot be obtained (see code 2). Parcel creation will execute the constructor, and the init function will be called in the constructor (see code 3). The parameter of the init function is 0 at this time, and the nativeCreate function will be executed again (see code 4). The nativeCreate function is a native function, see the implementation:

base/core/jni/android_os_Parcel.cpp

static const JNINativeMethod gParcelMethods[] = {
    
    
    ...
    {
    
    "nativeCreate",              "()J", (void*)android_os_Parcel_create},//5
    ...
};

static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
    
    
    Parcel* parcel = new Parcel(); //6
    return reinterpret_cast<jlong>(parcel); //7
}

It can be seen from the above code that the nativeCreate native function of the Java layer is implemented in the Jni layer as the android_os_Parcel_create function (see code 5). The android_os_Parcel_create function does two things. The first thing is to create a Parcel object of the native layer (see Listing 6). The second thing is to convert the pointer of this Parcel object into long type data and return it to the Java layer (see code 7).
Let's go back to code 4, the return value of the nativeCreate function will be assigned to the member variable mNativePtr. At this point, we have finished analyzing Parcel.obtain.
Summarized as follows:

  1. Get the Parcel object from the Parcel Pool, if not, create a Java Parcel object.
  2. The Java Parcel object will create a Native Parcel object through Jni.
  3. Convert the pointer of the Native Parcel object into long type data and assign it to the mNativePtr member variable of the Java layer.

Store and read data through Parcel

public final void writeInt(int val) {
    
    
    nativeWriteInt(mNativePtr, val);
}

public final int readInt() {
    
    
    return nativeReadInt(mNativePtr);
}

@CriticalNative
private static native int nativeReadInt(long nativePtr);

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

From the above code, we can see that Parcel stores and reads data and calls native methods, and the parameters all contain mNativePtr member variables of long type. Let's look at the function implementation of the jni layer:

base/core/jni/android_os_Parcel.cpp

static const JNINativeMethod gParcelMethods[] = {
    
    
    ...
    // @FastNative
    {
    
    "nativeWriteInt",            "(JI)V", (void*)android_os_Parcel_writeInt},
    ...
    // @CriticalNative
    {
    
    "nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},
    ...
};

static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
    
    
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
    
    
        const status_t err = parcel->writeInt32(val);
        if (err != NO_ERROR) {
    
    
            signalExceptionForError(env, clazz, err);
        }
    }
}

static jint android_os_Parcel_readInt(jlong nativePtr)
{
    
    
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
    
    
        return parcel->readInt32();
    }
    return 0;
}

From the above code, it can be seen that whether it is nativeReadInt or nativeWriteInt, the jni layer performs write or read operations by converting the upper layer mNativePtr variable into a Parcel pointer.

Release related data through Parcel

public final void recycle() {
    
    
    if (DEBUG_RECYCLE) mStack = null;
    freeBuffer();//8

    final Parcel[] pool;
    if (mOwnsNativeParcelObject) {
    
    
        pool = sOwnedPool;
    } else {
    
    
        mNativePtr = 0;
        pool = sHolderPool;
    }

    synchronized (pool) {
    
    
        for (int i=0; i<POOL_SIZE; i++) {
    
    
            if (pool[i] == null) {
    
    
                pool[i] = this;//9
                return;
            }
        }
    }
}

private void freeBuffer() {
    
    
    if (mOwnsNativeParcelObject) {
    
    
        updateNativeSize(nativeFreeBuffer(mNativePtr));
    }
    mReadWriteHelper = ReadWriteHelper.DEFAULT;
}

private static native long nativeFreeBuffer(long nativePtr);

private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];

As can be seen from the above code, recycle mainly does two things. The first thing is to execute the freeBuffer function (see code 8), and the second thing is to store Java Parcel objects in the Parcel Pool, so as to reuse Parcel and reduce memory. performance overhead. The second thing can be explained clearly at the Java layer. Now let’s look at the first thing: the core operation of the freeBuffer function is to call nativeFreeBuffer, which is a native function, and the received parameter is also the member variable mNativePtr of type long.

base/core/jni/android_os_Parcel.cpp

static const JNINativeMethod gParcelMethods[] = {
    
    
    ...
    {
    
    "nativeFreeBuffer",          "(J)J", (void*)android_os_Parcel_freeBuffer},
    ...
};

static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    
    
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
    
    
        parcel->freeData();
        return parcel->getOpenAshmemSize();
    }
    return 0;
}

As can be seen from the above code, the nativeFreeBuffer function performs the freeData operation by converting the upper layer mNativePtr variable into a Parcel pointer in the jni layer.

Summarize:

From the analysis of the above three parts, it can be seen that:

  1. When a Java Parcel is created, it will create a Native Parcel, and convert the pointer of the Native Parcel object into a long type and save it in the member variable mNativePtr.
  2. The write, read and recycle operations of Java Parcel are all performed with the help of Native Parcel.

at last

If you want to become an architect or want to break through the 20-30K salary range, then don't be limited to coding and business, but you must be able to select models, expand, and improve programming thinking. In addition, a good career plan is also very important, and the habit of learning is very important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here I would like to share with you a set of "Advanced Notes on the Eight Major Modules of Android" written by the senior architect of Ali, to help you organize the messy, scattered and fragmented knowledge systematically, so that you can systematically and efficiently Master the various knowledge points of Android development.
insert image description here
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

Full set of video materials:

1. Interview collection

insert image description here
2. Source code analysis collection
insert image description here

3. The collection of open source frameworks
insert image description here
welcomes everyone to support with one click and three links. If you need the information in the article, directly scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓

PS: There is also a ChatGPT robot in the group, which can answer your work or technical questions

Guess you like

Origin blog.csdn.net/weixin_43440181/article/details/131283964