本文首發於微信公衆號「後廠技術官」html
關聯繫列
Android AOSP基礎系列
Android系統啓動系列
應用進程啓動系列
Android深刻四大組件系列
Android深刻理解Context系列
Android深刻理解JNI系列
Android解析WindowManager
Android解析WMS系列
Android解析AMS系列
Android包管理機制系列
Android輸入系統系列前端
原標題: Android Binder原理(六)Java Binder的初始化java
在Android Binder原理(一)學習Binder前必需要了解的知識點這篇文章中,我根據Android系統的分層,將Binder機制分爲了三層:android
在此前的文章中,我一直都在介紹Native Binder和Kernel Binder的內容,它們的架構簡單總結爲下圖。程序員
在Android Binder原理(二)ServiceManager中的Binder機制這篇文章中,我講過BpBinder是Client端與Server交互的代理類,而BBinder則表明了Server端,那麼上圖就能夠改成: 算法
從上圖能夠看到,Native Binder實際是基於C/S架構,Bpinder是Client端,BBinder是Server端,在 Android Binder原理(四)ServiceManager的啓動過程這篇文章中,咱們得知Native Binder經過ioctl函數和Binder驅動進行數據交互。 Java Binder是須要藉助Native Binder來進行工做的,所以Java Binder在設計上也是一個C/S架構,能夠說Java Binder是Native Binder的一個鏡像,因此在學習Java Binder前,最好先要學習此前文章講解的Native Binder的內容。本篇文章先來說解Java Binder是如何初始化的,即Java Binder的JNI註冊。Java Binder要想和Native Binder進行通訊,須要經過JNI,JNI的註冊是在Zygote進程啓動過程當中註冊的,代碼以下所示。
frameworks/base/core/jni/AndroidRuntime.cpp數組
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {//1
return;
}
onVmCreated(env);
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
}
複製代碼
註釋1處用於啓動Java虛擬機,註釋2處startReg函數用於完成虛擬機的JNI註冊,關於AndroidRuntime的start函數的具體分析見Android系統啓動流程(二)解析Zygote進程啓動過程這篇文章。 startReg函數以下所示。 frameworks/base/core/jni/AndroidRuntime.cppbash
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {//1
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}
複製代碼
註釋1處的register_jni_procs函數的做用就是循環調用gRegJNI數組的成員所對應的方法,以下所示。微信
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) {
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
複製代碼
gRegJNI數組中有100多個成員變量:架構
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
...
REG_JNI(register_android_os_Binder),//1
...
};
複製代碼
其中REG_JNI是一個宏定義:
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
複製代碼
實際上就是調用參數名所對應的函數。負責Java Binder和Native Binder通訊的函數爲註釋1處的register_android_os_Binder,代碼以下所示。
frameworks/base/core/jni/android_util_Binder.cpp
int register_android_os_Binder(JNIEnv* env) {
//註冊Binder類
if (int_register_android_os_Binder(env) < 0)
return -1;
//註冊BinderInternal類
if (int_register_android_os_BinderInternal(env) < 0)
return -1;
//註冊BinderProxy類
if (int_register_android_os_BinderProxy(env) < 0)
return -1;
...
return 0;
}
複製代碼
register_android_os_Binder函數作了三件事,分別是: 1.註冊Binder類 2.註冊BinderInternal類 3.註冊BinderProxy類
它們是Java Binder關聯類的一小部分,它們的關係以下圖所示。
FLAG_ONEWAY
的整形變量。客戶端發起調用時,客戶端通常會阻塞,直到服務端返回結果。設置FLAG_ONEWAY
後,客戶端只須要把請求發送到服務端就能夠當即返回,而不須要等待服務端的結果,這是一種非阻塞方式。下面分別對Binder、BinderInternal這兩個類的註冊進行分析。
調用int_register_android_os_Binder函數來完成Binder類的註冊,代碼以下所示。 frameworks/base/core/jni/android_util_Binder.cpp
static const JNINativeMethod gBinderMethods[] = {
/* name, signature, funcPtr */
{ "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
{ "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
{ "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
{ "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
{ "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
{ "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable }
};
const char* const kBinderPathName = "android/os/Binder";//1
static int int_register_android_os_Binder(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, kBinderPathName);//2
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);//3
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");//4
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie(
env, kBinderPathName,
gBinderMethods, NELEM(gBinderMethods));
}
複製代碼
註釋1處的kBinderPathName的值爲"android/os/Binder",這是Binder在Java Binder中的全路徑名。 註釋2處根據這個路徑名獲取Binder的Class對象,並賦值給jclass類型的變量clazz,clazz是Java層Binder在JNI層的表明。 註釋3處經過MakeGlobalRefOrDie函數將本地引用clazz轉變爲全局引用並賦值給gBinderOffsets.mClass。 註釋4處用於找到Java層的Binder的成員方法execTransact並賦值給gBinderOffsets.mExecTransact。 註釋5處用於找到Java層的Binder的成員變量mObject並賦值給gBinderOffsets.mObject。 最後一行經過RegisterMethodsOrDie函數註冊gBinderMethods中定義的函數,其中gBinderMethods是JNINativeMethod類型的數組,裏面存儲的是Binder的Native方法(Java層)與JNI層函數的對應關係。
gBinderMethods的定義以下所示。
static struct bindernative_offsets_t {
jclass mClass;
jmethodID mExecTransact;
jfieldID mObject;
} gBinderOffsets;
複製代碼
使用gBinderMethods來保存變量和方法有兩個緣由: 1.爲了效率考慮,若是每次調用相關的方法時都須要查詢方法和變量,顯然效率比較低。 2.這些成員變量和方法都是本地引用,在int int_register_android_os_Binder函數返回時,這些本地引用會被自動釋放,所以用gBinderOffsets來保存,以便於後續使用。
對於JNI不大熟悉的同窗能夠看Android深刻理解JNI(二)類型轉換、方法簽名和JNIEnv這篇文章。
調用int_register_android_os_BinderInternal函數來完成BinderInternal類的註冊,代碼以下所示。 frameworks/base/core/jni/android_util_Binder.cpp
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
static int int_register_android_os_BinderInternal(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, kBinderInternalPathName);
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
gSparseIntArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject,
"<init>", "()V");
gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
"(II)V");
BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
複製代碼
和int_register_android_os_Binder函數的實現相似,主要作了三件事: 1.獲取BinderInternal在JNI層的表明clazz。 2.將BinderInternal類中有用的成員變量和方法存儲到gBinderInternalOffsets中。 3.註冊BinderInternal類的Native方法對應的JNI函數。
還有一個BinderProxy類的註冊,它和Binder、BinderInternal的註冊過程差很少,這裏就再也不贅述了,有興趣的讀者能夠自行去看源碼。
更多的內容請關注個人獨立博客的知識體系:
liuwangshu.cn/system/
分享Java、Python、大數據、算法、大前端、AI相關技術,關注程序員技術提高和職場晉升,助力10W+程序員進階爲技術官和架構師!