🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
虽然Java层Binder系统是Native层Binder系统的一个Mirror,但这个Mirror终归还需借助Native层Binder系统来开展工作,即Mirror和Native层Binder有着千丝万缕的关系,一定要在Java层Binder正式工作之前建立这种关系。下面分析Java层Binder框架是如何初始化的。 在Android系统中,在Java初创时期,系统会提前注册一些JNI函数,其中有一个函数专门负责搭建Java Binder和Native Binder交互关系,该函数是register_android_os_Binder,代码如下: **android_util_Binder.cpp** ~~~ 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; return0; } ~~~ 据上面的代码可知,register_android_os_Binder函数完成了Java Binder架构中最重要的4个类的初始化工作。我们重点关注前3个。 1. Binder类的初始化 int_register_android_os_Binder函数完成了Binder类的初始化工作,代码如下: **android_util_Binder.cpp** ~~~ static int int_register_android_os_Binder(JNIEnv*env) { jclassclazz; //kBinderPathName为Java层中Binder类的全路径名,“android/os/Binder“ clazz =env->FindClass(kBinderPathName); /* gBinderOffSets是一个静态类对象,它专门保存Binder类的一些在JNI层中使用的信息, 如成员函数execTranscat的methodID,Binder类中成员mObject的fildID */ gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gBinderOffsets.mExecTransact = env->GetMethodID(clazz,"execTransact", "(IIII)Z"); gBinderOffsets.mObject = env->GetFieldID(clazz,"mObject", "I"); //注册Binder类中native函数的实现 returnAndroidRuntime::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** ~~~ static intint_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** ~~~ static intint_register_android_os_BinderProxy(JNIEnv* env) { jclassclazz; 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函数的实现 returnAndroidRuntime::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的工作流程。