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的工作流程。