Android Framework 系列教程:yuandaimaahao.github.io/AndroidFram...
视频教程、源码、答疑服务与进入 Framework 技术交流群请联系微信 zzh0838
Parcel 是一个横跨 Java 层与 Native 层的数据结构,扮演了 Binder 远程过程调用中数据传输载体的角色。客户端将数据写入 Parcel,服务端从 Parcel 中读出数据。接下来我们就从 Java 源码的角度来看看 Parcel 内部的实现原理。
Parcel 支持读写的数据类型如下:
- Primitives:基本数据类型
- Primitives Arrays:基本数据类型数组
- Parcelables:实现了 Parcelable 接口的数据类型
- Bundle 数据类型:Java 层封装的数据包,仅 Java 层支持
- Active Objects:IBinder 对象和 FileDescriptor 对象
- Untyped Containers:未指定泛型类型的 List Map SparseArray
Java 层的 Parcel 实际上只是一层对外提供接口的马甲,其内部核心实现都是通过 JNI 调用 Native 层的 Parcel。
Java 层 Parcel 的初始化
在 Java 层,使用 obtain 方法来获取一个 Parcel 对象:
java
Parcel mParcel = Parcel.obtain()
obtain 的具体实现如下:
java
// frameworks/base/core/java/android/os/Parcel.java
//缓存池
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
@NonNull
public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
//从缓存池里找一个 Parcel 对象返回
for (int i=0; i<POOL_SIZE; i++) {
p = pool[i];
if (p != null) {
//这里只是将对象的引用置为空,不是将对象本身置空
//引用置空,表示这个对象已被使用,下次 obtain 的时候就直接跳过
pool[i] = null;
if (DEBUG_RECYCLE) {
p.mStack = new RuntimeException();
}
p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
return p;
}
}
}
//缓存池里的对象都被使用了,就重新 new 一个
return new Parcel(0);
}
接下来我们来看看 Parcel 的构造函数:
java
// frameworks/base/core/java/android/os/Parcel.java
private Parcel(long nativePtr) {
if (DEBUG_RECYCLE) {
mStack = new RuntimeException();
}
//Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
init(nativePtr);
}
//接着调用 init
private void init(long nativePtr) {
if (nativePtr != 0) {
mNativePtr = nativePtr;
mOwnsNativeParcelObject = false;
} else { // nativePtr = 0 ,走这个分支
mNativePtr = nativeCreate();
mOwnsNativeParcelObject = true;
}
}
//接着调用 nativeCreate,nativeCreate 是一个 native 方法
private static native long nativeCreate();
// JNI 函数是在 Zygote 启动时注册的
// frameworks/base/core/jni/AndroidRuntime.cpp
REG_JNI(register_android_os_Parcel)
int register_android_os_Parcel(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kParcelPathName);
gParcelOffsets.clazz = MakeGlobalRefOrDie(env, clazz);
gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, clazz, "mNativePtr", "J");
gParcelOffsets.obtain = GetStaticMethodIDOrDie(env, clazz, "obtain", "()Landroid/os/Parcel;");
gParcelOffsets.recycle = GetMethodIDOrDie(env, clazz, "recycle", "()V");
return RegisterMethodsOrDie(env, kParcelPathName, gParcelMethods, NELEM(gParcelMethods));
}
//nativeCreate 对应的 native 函数定义在 frameworks/base/core/jni/android_os_Parcel.cpp 中:
//操作很简单,就是 new 一个 Parcel,然后把地址转成 long 返回给 Java 层
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel();
return reinterpret_cast<jlong>(parcel);
}
//回到 Java 层 init 中:
private void init(long nativePtr) {
if (nativePtr != 0) {
mNativePtr = nativePtr;
mOwnsNativeParcelObject = false;
} else { // nativePtr = 0 ,走这个分支
// Native 层返回的地址保存在 mNativePtr 成员变量中
mNativePtr = nativeCreate();
mOwnsNativeParcelObject = true;
}
}
自此,整个 Parcel 初始化过程就完成了,总结一下:
- 我们通过调用 Parcel 类的静态方法 obtain 来获取一个 Parcel 对象
- Parcel 中有一个缓存数组
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
,调用 obtain 方法时,会首先从这个缓存中找一个未被使用的 Parcel 对象返回,程序中通过数组中的引用是否为空来标记 Parcel 对象是否被使用 - 如果缓存数组中的对象都被使用了,就重新 new 一个 Parcel 返回
- Java 层的 Parcel 是一层提供 Java 层接口的马甲,其核心功能都是通过 Native 层的 Parcel 对象实现的。在构造方法中会通过 JNI 函数 new 一个 Native 层的 Parcel 对象,并把这个对象的内存地址存放在 Java 层的 mNativePtr 成员中
Java 层 Parcel 的回收与销毁
Java 层的 Parcel 在使用完成后,需要调用 recycle 方法来执行回收操作:
java
// frameworks/base/core/java/android/os/Parcel.java
public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
//调用 native 层的回收操作
freeBuffer();
final Parcel[] pool;
if (mOwnsNativeParcelObject) { //在 init 中初始化为 true,走这个分支
pool = sOwnedPool;
} else {
mNativePtr = 0;
pool = sHolderPool;
}
//将缓存池中第一个为 null 的引用指向当前对象
synchronized (pool) {
for (int i=0; i<POOL_SIZE; i++) {
if (pool[i] == null) {
pool[i] = this;
return;
}
}
}
}
private void freeBuffer() {
if (mOwnsNativeParcelObject) { //在 init 中初始化为 true,走这个分支
updateNativeSize(nativeFreeBuffer(mNativePtr));
}
mReadWriteHelper = ReadWriteHelper.DEFAULT;
}
// nativeFreeBuffer 是一个 native 方法,对应的 native 函数是 android_os_Parcel_freeBuffer
private static native long nativeFreeBuffer(long nativePtr);
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;
}
void Parcel::freeData()
{
freeDataNoInit();
initState();
}
void Parcel::freeDataNoInit()
{
if (mOwner) {
LOG_ALLOC("Parcel %p: freeing other owner data", this);
//ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
} else { // mOwner 初始化为空,走这个分支
LOG_ALLOC("Parcel %p: freeing allocated data", this);
//清理 mObjects 数组成员指向的 flat_binder_object 对象
releaseObjects();
//修改一些标记变量的值
if (mData) {
LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
if (mDataCapacity <= gParcelGlobalAllocSize) {
gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity;
} else {
gParcelGlobalAllocSize = 0;
}
if (gParcelGlobalAllocCount > 0) {
gParcelGlobalAllocCount--;
}
pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
//清理 mData 指向的内存
free(mData);
}
//清理 mObjects 指向的内存
if (mObjects) free(mObjects);
}
}
Parcel 中定义了 finalize 方法,用于在 gc 时回收对象:
java
// frameworks/base/core/java/android/os/Parcel.java
@Override
protected void finalize() throws Throwable {
if (DEBUG_RECYCLE) {
if (mStack != null) {
Log.w(TAG, "Client did not call Parcel.recycle()", mStack);
}
}
// 接着调用 destroy()
destroy();
}
private void destroy() {
if (mNativePtr != 0) {
if (mOwnsNativeParcelObject) {
//接着调用 nativeDestroy
nativeDestroy(mNativePtr);
updateNativeSize(0);
}
mNativePtr = 0;
}
mReadWriteHelper = null;
}
// nativeDestroy 是一个本地函数
private static native void nativeDestroy(long nativePtr);
// nativeDestroy 对应 native 层
// frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_destroy 函数
static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
//直接清除内存
delete parcel;
}
Java 层 Parcel 整型数据读写
Java 层提供了 writeInt 接口写入 Int 型数据:
java
// frameworks/base/core/java/android/os/Parcel.java
public final void writeInt(int val) {
nativeWriteInt(mNativePtr, val);
}
//进一步调用到 nativeWriteInt
private static native void nativeWriteInt(long nativePtr, int val);
//nativeWriteInt 是一个 native 方法
//nativeWriteInt 对应的 native 函数是
//frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_writeInt 函数
static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
//实际上就是调用 Native 层的 writeInt32
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeInt32(val);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
可以看出 java 层只是提供一个 writeInt 的对外接口,实际操作还是通过 native 层的 writeInt32 来完成,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++)
接下来我们来看 Java 层的 Int 数据读取操作:
java
// frameworks/base/core/java/android/os/Parcel.java
public final int readInt() {
return nativeReadInt(mNativePtr);
}
//实际是调用 native 方法
private static native int nativeReadInt(long nativePtr);
//对应的 native 函数
//frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_readInt 函数
static jint android_os_Parcel_readInt(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
//仍然是调用 native 层的 readInt32
return parcel->readInt32();
}
return 0;
}
可以看出 java 层只是提供一个 readInt 的对外接口,实际操作还是通过 native 层的 readInt32 来完成,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++)
String 类型的读取和 Int 类型一样也是委托给 Native 来做具体实现,这部分内容就留给读者自己分析了。
Java 层 Parcel IBinder 数据读写
接下来我们来看看 IBinder 类型的数据是怎么读写的:
java
// frameworks/base/core/java/android/os/Parcel.java
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
//对应的 native 函数
//frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_writeStrongBinder 函数
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
这里仍然是调用 native 层的 writeStrongBinder 来完成具体的读写,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++)
接下来我们把重点放在 ibinderForJavaObject,ibinderForJavaObject 的作用是把 java 层的 IBinder 转换为 Native 层的 IBinder:
在查看源码之前我们先回顾下 Binder Java 层的总体架构:
在 Java 层,服务端类是 Binder,其内部有一个 long 型数据是一个 Native 层指针,指向一个 native 层的 BBinder 对象。
在 Java 层,客户端类或者叫代理类是 BinderProxy,内部有一个 long 型数据是一个 Native 层指针,指向一个 native 层的 JavaBBinder 对象。JavaBBinder 对象内部又有指针执行一个 BBinder 对象,
接下来,我们就来看看 ibinderForJavaObject 的具体实现:
cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
//obj 类型是 Binder,服务端类
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
//获取到 Java 层 Binder 对应的 Native 层 JavaBBinderHolder 对象
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
//返回 JavaBBinderHolder 对象内部指针指向的 BBinder 对象
return jbh->get(env, obj);
}
//obj 类型是 BinderProxy,客户端类
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
//返回 Java 层 BinderProxy 对应的 Native 层 BpBinder 对象
return getBPNativeData(env, obj)->mObject;
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
接下来我们再来看看 IBinder 的读操作:
java
// frameworks/base/core/java/android/os/Parcel.java
public final IBinder readStrongBinder() {
return nativeReadStrongBinder(mNativePtr);
}
private static native IBinder nativeReadStrongBinder(long nativePtr);
//对应的 native 函数
//frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_readStrongBinder 函数
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
这里仍然是调用 native 层的 readStrongBinder 来完成具体的读写,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++)
接下来我们重点关注一下 javaObjectForIBinder 函数,这个函数用于将 Native 层的 IBinder 对象转换为 Java 层的 IBinder 对象:
cpp
//frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
//构造 BinderProxyNativeData 结构体
BinderProxyNativeData* nativeData = new BinderProxyNativeData();
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
//gBinderProxyOffsets 中保存了 BinderProxy 类相关的信息
//调用 Java 层 GetInstance 方法获得一个 BinderProxy 对象
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
if (env->ExceptionCheck()) { //异常处理
// In the exception case, getInstance still took ownership of nativeData.
return NULL;
}
//数据做一些检查修改操作
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
if (actualNativeData == nativeData) {
// Created a new Proxy
uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed);
uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed);
if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) {
// Multiple threads can get here, make sure only one of them gets to
// update the warn counter.
if (gProxiesWarned.compare_exchange_strong(numLastWarned,
numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed)) {
ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
}
}
} else {
delete nativeData;
}
//返回 BinderProxy
return object;
}