这篇文章通过Java Binder Parcel的例子,分析Java Parcel与Native Parcel的关系
Java Binder Parcel 示例代码
@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;
}
从代码可以看到Parcel相关的操作可以分为三部分,分别是:
- Parcel的创建
android.os.Parcel _data = android.os.Parcel.obtain();
- 通过Parcel存储和读取数据
存储:
_data.writeInt(first);
读取:
_result = _reply.readInt();
- 通过Parcel释放相关数据
_reply.recycle();
_data.recycle();
以下就三部分进行分析。
Parcel的创建
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];
从以上代码可知,obtain函数从全局变量sOwnedPool数组中取Parcel对象(见代码1),如果取不到,就创建一个(见代码2)。Parcel创建会执行构造函数,在构造函数中又会调用init函数(见代码3)。init函数此时参数为0,又会执行nativeCreate函数(见代码4)。nativeCreate函数是一个native函数,看下实现:
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
}
从以上代码可知,Java层的nativeCreate native函数在Jni层的实现是android_os_Parcel_create函数(见代码5)android_os_Parcel_create函数做了两件事情。第一件事情就是创建了一个native层的Parcel对象(见代码6)。第二件事情就是把这个Parcel对象的指针转化为long类型的数据并返回为Java层(见代码7)。
让我们再回到代码4处,nativeCreate函数的返回值会赋值给成员变量mNativePtr。到此,我们就分析完了Parcel.obtain。
总结如下:
- 从Parcel Pool中取Parcel对象,没有就创建一个Java Parcel对象。
- Java Parcel对象会通过Jni创建一个Native Parcel对象。
- 将Native Parcel对象的指针转化为long类型的数据赋值给Java层的mNativePtr成员变量。
通过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);
从以上代码可知:Parcel存储和读取数据调用的都是native方法,参数中都含有long类型的mNativePtr成员变量。我们看下jni层的函数实现:
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;
}
从以上代码可知:不管是nativeReadInt还是nativeWriteInt,其在jni层都是通过把上层的mNativePtr变量转化为Parcel指针来进行write或read操作。
通过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];
从以上代码可知,recycle主要做了两件事情,第一件事情就是执行freeBuffer函数(见代码8),第二件事情就是把Java Parcel对象存储于Parcel Pool中,以便Parcel的复用,减少内存性能开销。第二件事情在Java层就可以说清了,现在我们看下第一件事情:freeBuffer函数的核心操作是调用了nativeFreeBuffer,它是一个native函数,接收的参数也是long类型的成员变量mNativePtr。
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;
}
从以上代码可知,nativeFreeBuffer函数在jni层通过把上层的mNativePtr变量转化为Parcel指针来进行freeData操作。
总结:
从以上三部分分析可见:
- Java Parcel在创建的时候会创建Native Parcel,并把Native Parcel对象的指针转化为long类型保存到成员变量mNativePtr中。
- Java Parcel的write和read以及recycle操作都是借助Native Parcel来执行。