Parcel 详解
Parcel.java 内部与 Handler 体系的Message.java一致,内部持有一个缓存池,使用 obtain( )来获取一个 Parcel.java对象。先来看 Parcel 的构造函数。
//Parcel.cpp
private Parcel(long native){
init(nativePtr)
}
//从 obtain( )中的初始化,nativePtr 传值为 0
private void init(long nativePtr){
if(nativePtr != 0){
}else{
mNativePtr = nativeCreate( );
mOwnsNativeParcelObject = true;
}
}
//android_os_Parcel.java
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz){
Parcel* parcel = new Parcel( );
return reinterpret_cast<jlong>(parcel);
}
//Parcel.cpp
Parcel::Parcel(){
//该方法初始化 Parcel 的成员变量
initState( );
}
到现在还是没有看到 Parcel 到底是如何存储数据的,那么就以一个比较难的例子来说明
Parcel 对于 String,Int 等数据无非是直接写入值,然后增加指针。特殊的点在于 IBinder 的序列化能力
//Parcel.java
//以 ActivityManagerService.java 为例
public final void writeStrongBinder(IBinder val){
nativeWriteStrongBinder(mNativePtr, val);
}
//android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object){
//从 Parcel.java 中的 nativePtr 获得 native 层的 Parce.cpp 对象
Parcel* parcel = reinterpret_cast<Parcel>(nativePtr);
parcel->writeStrongBinder(ibinderForJavaObject(env, object));
}
//android_util_Binder.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj){
if(env->IsInstanceOf(obj, gBinderOffsets.mClass)){
//gBinderOffsets.mClass 的值是"android/os/Binder"
//走这个分支说明 obj 是 android.os.Binder.java 类型
//返回一个 JavaBBinderHolder
JavaBBinderHolder* jbh = (JavaBBinderHolder*)env-GetLongField(obj, gBinderOffsets.mObject);
return jbh->get(env, obj);
}
if(env->IsInstanceOf(obj, gBinderProxyOffsets.mClass){
//gBinderProxyOffsets.mClass 是 android/os/BinderProxy
//走这个分支,说明 obj是 android.os.BinderProxy 类型
//返回的是 BinderProxy.java 中对应的 native 层的 BpBinder 对象
return (IBinder*)env->GetLongFiled(obj, gBinderProxyOffsets.mObject)
}
}
关于这个JavaBBinderHolder 现在来说一说,众所周知,能进行跨进程通信的类会实现 IBinder接口,Android 默认实现了 Binder.java和 BinderProxy.java 对象,前者是本地实体,后者是远端代理。像 ActivityManagerService 就是属于 AMS 进程的本地实体对象,而用户端使用的的其远程代理对象。AMS 派生自 ActivityManagerNative.java,后者派生自 Binder.java ,说明其是本地服务实体对象,在 Binder.java 的构造函数中,会调用 init( )函数,在 c++层进行一些初始化。
//Binder.java
public Binder(){
init( );
}
//android_util_Binder.cpp
static void android_os_Binder_init(JNIEnv* env, jobject obj){
JavaBBinderHolder* jbh = new JavaBBinderHolder( );
//于是 mObject@Binder.java是一个 native 层的 JavaBBinderHolder() 对象
env->SetLongField(obj, gBinderOffsets.mObject,(jlong)jbh);
}
所以每一个 Binder.java 对象,在 c++层都会对应一个 JavaBBinderHolder 对象
继续看 ibinderForJavaObject
class JavaBBinderHolder:public RefBase{
sp<JavaBBinder> get(JNIEnv* env, jobject obj){
sp<JavaBBinder> b = mBinder.promote();
if(b == NULL){
b = new JavaBBinder(env, obj);
mBinder = b;
}
}
return b;
}
private :
wp<JavaBBinder> mBinder;
};
class JavaBBinder : public BBinder{
public:
JavaBBinder(JNIEnv* env, jobject object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)){
}
}
private:
JavaVM* const mVM;
jobject const mObject;
从上面的代码很容易看出来,当Server 本地对象即 Binder.java 的子类时,会在 native 层构造一个 JavaBBinderHolder.cpp 对象,将其保存在 mObject@Bidner.java 中。该 Binder写入到 Parcel 的时,会在 native 层构造一个 JavaBBinder.cpp 对象,且 JavaBBinder.cpp 会持有该 Binder.java对象的引用。
于是对于 ActivityManagerService.java 来说,其内部 mObject 成员变量指向 native 层 JavaBBinderHolder.cpp 对象,JavaBBinderHolder.cpp 对象内部有一个 JavaBBinder.cpp 对象(派生自 BBinder.cpp), JavaBBinder.cpp 对象内部又有 ActivityManagerService.java 的引用。于是无论获得哪一个,都可以由这个闭环找到另外 2 个对象。
parcel->writeStrongBinder(ibinderForJavaObject(env, object));
等价于
parcel->writeStrongBinder(JavaBBinder.cpp)
//Parcel.cpp
//val 在这里实际为 JavaBBinder.cpp
status_t Parcel:writeStrongBinder(const sp<IBinder>& val){
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& , const sp<IBinder>& binder, Parcel* out){
//IBinder 对象在 Parcel 中的表示
flat_binder_object obj;
if(binder != NULL){
IBinder *local = binder->localBinder( );
if(!local){
//proxy 走这个分支
}else{
//本地对象走这个分支
//说明,传递的是本地对象
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
}
return finish_flatten_binder(binder, obj, out)
}
inline statuc status_t finish_flatten_binder(const sp<IBinder>&, const flat_binder_object& flat, Parcel* out){
//将 flat_binder_object 写入到 Parcel 中
return out->writeObject(flat, flase);
}
多说一句,Binder 驱动会对传递的信息进行处理,因此在接收方收到的其实是被 Binder 驱动调包的信息。比如Binder 会将一个本地对象替换为目标进程对应的 proxy 对象等。