2.2.2 初始化Java层Binder框架

虽然Java层Binder系统是Native层Binder系统的一个Mirror,但这个Mirror终归还需借助Native层Binder系统来开展工作,即它和Native层Binder有着千丝万缕的关系,故一定要在Java层Binder正式工作之前建立这种关系。下面分析Java层Binder框架是如何初始化的。

在Android系统中,在Java世界初创时期,系统会提前注册一些JNI函数,其中有一个函数专门负责搭建Java Binder和Native Binder的交互关系,该函数是register_android_os_Binder,代码如下:

[—>android_util_Binder.cpp:register_android_os_Binder]


int register_android_os_Binder(JNIEnv*env)

{

//初始化Java Binder类和Native层的关系

if(int_register_android_os_Binder(env)<0)

return-1;

//初始化Java BinderInternal类和Native层的关系

if(int_register_android_os_BinderInternal(env)<0)

return-1;

//初始化Java BinderProxy类和Native层的关系

if(int_register_android_os_BinderProxy(env)<0)

return-1;

//初始化Java Parcel类和Native层的关系

if(int_register_android_os_Parcel(env)<0)

return-1;

return 0;

}


根据上面的代码可知,register_android_os_Binder函数完成了Java层Binder架构中最重要的4个类的初始化工作。我们重点关注前3个。

1.Binder类的初始化


int_register_android_os_Binder函数完成了Binder类的初始化工作,代码如下:


[—>android_util_Binder.cpp:int_register_android_os_Binder]


static int int_register_android_os_Binder(JNIEnv*env)

{

jclass clazz;

//kBinderPathName为Java层中Binder类的全路径名,“android/os/Binder”

clazz=env->FindClass(kBinderPathName);

/*

gBinderOffsets是一个静态类对象,它专门保存Binder类的一些在JNI层中使用的信息,

如成员函数execTransact的methodID, Binder类中成员mObject的fieldID

*/

gBinderOffsets.mClass=(jclass)env->NewGlobalRef(clazz);

gBinderOffsets.mExecTransact

=env->GetMethodID(clazz,"execTransact","(IIII)Z");

gBinderOffsets.mObject

=env->GetFieldID(clazz,"mObject","I");

//注册Binder类中native函数的实现

return AndroidRuntime:registerNativeMethods(

env, kBinderPathName,

gBinderMethods, NELEM(gBinderMethods));

}


从上面的代码可知,gBinderOffsets对象保存了和Binder类相关的某些在JNI层中使用的信息。

建议 如果读者对JNI不是很清楚,可参阅卷I第2章“深入理解JNI”。

2.BinderInternal类的初始化

下一个初始化的类是BinderInternal,其代码在int_register_android_os_BinderInternal函数中。

[—>android_util_Binder.cpp:int_register_android_os_BinderInternal]


static int int_register_android_os_BinderInternal(JNIEnv*env)

{

jclass clazz;

//根据BinderInternal的全路径名找到代表该类的jclass对象。全路径名为

//"com/android/internal/os/BinderInternal"

clazz=env->FindClass(kBinderInternalPathName);

//gBinderInternalOffsets也是一个静态对象,用来保存BinderInternal类的一些信息

gBinderInternalOffsets.mClass=(jclass)env->NewGlobalRef(clazz);

//获取forceBinderGc的methodID

gBinderInternalOffsets.mForceGc

=env->GetStaticMethodID(clazz,"forceBinderGc","()V");

//注册BinderInternal类中native函数的实现

return AndroidRuntime:registerNativeMethods(

env, kBinderInternalPathName,

gBinderInternalMethods, NELEM(gBinderInternalMethods));

}


int_register_android_os_BinderInternal的工作内容和int_register_android_os_Binder的工作内容类似,包括以下两方面:

获取一些有用的methodID和fieldID。这表明JNI层一定会向上调用Java层的函数。

注册相关类中native函数的实现。

3.BinderProxy类的初始化

int_register_android_os_BinderProxy完成了BinderProxy类的初始化工作,代码稍显复杂,如下所示:

[—>android_util_Binder.cpp:int_register_android_os_BinderProxy]]


static int int_register_android_os_BinderProxy(JNIEnv*env)

{

jclass clazz;

clazz=env->FindClass("java/lang/ref/WeakReference");

//gWeakReferenceOffsets用来和WeakReference类打交道

gWeakReferenceOffsets.mClass=(jclass)env->NewGlobalRef(clazz);

//获取WeakReference类get函数的methodID

gWeakReferenceOffsets.mGet=env->GetMethodID(clazz,"get",

"()Ljava/lang/Object;");

clazz=env->FindClass("java/lang/Error");

//gErrorOffsets用来和Error类打交道

gErrorOffsets.mClass=(jclass)env->NewGlobalRef(clazz);

clazz=env->FindClass(kBinderProxyPathName);

//gBinderProxyOffsets用来和BinderProxy类打交道

gBinderProxyOffsets.mClass=(jclass)env->NewGlobalRef(clazz);

gBinderProxyOffsets.mConstructor=env->GetMethodID(clazz,"<init>","()V");

……//获取BinderProxy的一些信息

clazz=env->FindClass("java/lang/Class");

//gClassOffsets用来和Class类打交道

gClassOffsets.mGetName=env->GetMethodID(clazz,

"getName","()Ljava/lang/String;");

//注册BinderProxy native函数的实现

return AndroidRuntime:registerNativeMethods(env,

kBinderProxyPathName, gBinderProxyMethods,

NELEM(gBinderProxyMethods));

}


根据上面的代码可知,int_register_android_os_BinderProxy函数除了初始化BinderProxy类外,还获取了WeakReference类和Error类的一些信息。由此可见,BinderProxy对象的生命周期会委托WeakReference来管理,故JNI层会获取该类get函数的MethodID。

至此,Java Binder几个重要成员的初始化已完成,同时在代码中定义了几个全局静态对象,分别是gBinderOffsets、gBinderInternalOffsets和gBinderProxyOffsets。

这几个对象的命名中都有一个Offsets,我觉得这非常别扭,不知道读者是否有同感。

框架的初始化其实就是提前获取一些JNI层的使用信息,如类成员函数的MethodID、类成员变量的FieldID等。这项工作是必需的,因为它能节省每次使用时获取这些信息的时间。当Binder调用频繁时,这些时间累积起来还是不容小觑的。

下面我们通过一个例子来分析Java层Binder的工作流程。