6.1.3 gBinderOffsets结构体解析
创建JavaBBinderHolder后,需要调用SetIntField将其存入gBinderOffsets.mObject中。SetIntField是JNI函数,其函数原型如下:
void SetIntField(jobject obj, jfieldID fieldID, NativeType value);
三个参数的说明如下。
Obj:非空的Java对象。
fieldID:Java对象的fieldID。
value:为fieldID设置的值。
SetIntField方法的作用是,将Native层的value存入Java层对象的某个成员变量中,其中Java层对象由obj表示,该对象的成员变量由fieldID表示。
本例中,obj即Java层的PowerManagerService对象;fieldID由gBinderOffsets.mObject指定,代表PowerManagerService的一个成员变量;value即Native层创建的JavaBBinderHolder。
通过gBinderOffsets.mObject指定了fieldID,那么这个fieldID是什么呢?
首先分析gBinderOffsets,其定义在android_util_Binder.cpp中,代码如下:
static struct bindernative_offsets_t
{
jclass mClass;
jmethodID mExecTransact;
jfieldID mObject;
}gBinderOffsets;
可见,gBinderOffsets是一个bindernative_offsets_t类型的结构体,该结构体有三个成员:mClass、mExecTransact和mObject。上文中用到了mObject成员,那么gBinderOffsets结构体是在何时初始化的呢?答案是:在Android启动阶段,通过AndroidRuntime的startReg注册JNI方法时初始化的。startReg在第4章已经分析过,该方法会执行register_android_os_Binder注册JNI方法,其位于android_util_Binder.cpp中,代码如下:
int register_android_os_Binder(JNIEnv*env)
{
//初始化Java层的android/os/Binder类与Native层的映射关系并注册JNI方法
if(int_register_android_os_Binder(env)<0)
return-1;
if(int_register_android_os_BinderInternal(env)<0)
return-1;
if(int_register_android_os_BinderProxy(env)<0)
return-1;
jclass clazz;
//初始化Java层的android/util/Log类与Native层的映射关系
clazz=env->FindClass("android/util/Log");
gLogOffsets.mClass=(jclass)env->NewGlobalRef(clazz);
gLogOffsets.mLogE=env->GetStaticMethodID(clazz,"e",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
//建立ParcelFileDescriptor的映射关系
clazz=env->FindClass("android/os/ParcelFileDescriptor");
……//与Log的映射方式类似,省略部分代码
//建立StrictMode的映射关系
clazz=env->FindClass("android/os/StrictMode");
……//与Log的映射方式类似,省略部分代码
return 0;
}
register_android_os_Binder的主要工作是建立Java层Binder、BinderInternal、BinderProxy、Log、ParcelFileDescriptor、StrictMode与其Native层的映射关系,并对Binder、BinderInternal、BinderProxy这三个IPC通信相关的类注册其JNI方法。在int_register_android_os_Binder方法中完成了gBinderOffsets的初始化,其代码如下:
const char*const kBinderPathName="android/os/Binder";
static int int_register_android_os_Binder(JNIEnv*env)
{
jclass clazz;
//通过JNI函数得到Java层android/os/Binder类的类信息
clazz=env->FindClass(kBinderPathName);
//将android/os/Binder的类信息存入gBinderOffsets的mClass成员中
gBinderOffsets.mClass=(jclass)env->NewGlobalRef(clazz);
/*将android/os/Binder类的execTransact方法的Method ID
存入gBinderOffsets的mExecTransact成员/
gBinderOffsets.mExecTransact
=env->GetMethodID(clazz,"execTransact","(IIII)Z");
/*将android/os/Binder类的mObject成员变量的Field ID存入
gBinderOffsets的mObject成员/
gBinderOffsets.mObject
=env->GetFieldID(clazz,"mObject","I");
//注册android/os/Binder的JNI方法
return AndroidRuntime:registerNativeMethods(
env, kBinderPathName, gBinderMethods, NELEM(gBinderMethods));
}
可见,gBinderOffsets结构体是在系统启动阶段完成初始化的,其内部存储了android/os/Binder类的一些信息。
由上述代码可知,env->SetIntField(obj, gBinderOffsets.mObject,(int)jbh)将Java层的android/os/Binder类的mObject成员变量设置成JavaBBinderHolder对象的地址,而JavaBBinderHolder对象内部持有的是JavaBBinder对象的wp指针。通过gBinderOffsets, Java层的Binder类在成员变量mObject中持有Native层的JavaBBinderHolder的地址,这样Java层和Native层便建立了映射关系,通过Java层的Binder类的mObject成员变量可以获得Native层的JavaBBinderHolder对象,进而获得JavaBBinder对象。其具体的映射关系如图6-2所示。
图 6-2 Java层和Native层的映射关系
分析到这里,获得了一个JavaBBinderHolder对象,它持有(Hold)了JavaBBinder的wp指针,而JavaBBinder是BBinder的子类,它存储了Java层系统服务的引用。因此,可以将JavaBBinder视为Java层系统服务在Native层的代表,它们都是Binder体系结构的Server端。