Parcel 详解

2019-10-31  本文已影响0人  Wi1ls努力努力再努力

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 对象等。

上一篇 下一篇

猜你喜欢

热点阅读