在NDK中,我們通過env->FindClass
來查找一個Java類,接下來,來看一下FindClass內部邏輯。
env->FindClass
實際會調用jni_internal.cc#FindClass
來看art/runtime/jni_internal.cc
再來看art/runtime/class_linker.cc
可以看到,這裏有個LookupClass,傳入要加載的類的簽名,hash值和classLoader,如果返回的kclass不爲null,則說明之前已經加載過,會直接return (雙親委託機制)。
如果不爲null, 來看2148行,class_loader如果獲取爲null,那麼調用FindInClassPath,從系統的啓動類裏去找,然後返回DifineClass。
如果class_loader不爲null,則也會調用FindInClassPath,返回DefineClass。
再來看DefineClass
來看這裏的LoadClass
先來看下它的參數
dex_file:dex文件
dex_class_def:要加載的類,在dex文件裏面的一些信息
kclass:加載完成的一個對象 (class)
class_loader:類加載器
通過dex_file.GetClassDescriptor(dex_class_def);
獲取class的描述
然後的一些代碼,都是給Kclass進行賦值,
所以這個方法的作用就是將dex文件的信息,賦值給kclass
最後,會調用LoadClassMembers,來加載fields和methods,並賦值給kclass
可以看到註釋,load fields,這裏可以看到用到了ArtField
load methods
NumdirectMethods:直接方法 ,這裏可以看到ArtMethod,後期會用到
NumVirtualMethods:虛方法
接着,再來看LinkCode,通過字面名稱,知曉是來鏈接字節碼的
method:ArtMethod
其中const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
,通過索引來找方法,然後調用oat_method.LinkMethod(method.Get());
,通過oat_method給函數設置一個默認的入口
來看art/runtime/oat_file.cc
method是ArtMethod,可以看到,根據解釋器模式和AOT模式,設置不同的參數,這裏的參數就是 art/runtime/mirror art_method.h
結構體中的字段
再往下看,bool enter_interpreter = NeedsInterpreter()
,用來判斷是否是解釋器模式
其中,isNative:是否是Native方法,ProxyMethod是否是代理方法,這兩個都沒有字節碼,就算是解釋器模式,也不需要使用解釋器執行。
再來往下看,LinkCode
方法中,根據是否是解釋器模式設置不同的方法執行入口
在往下看,如果是本地Native方法,那麼會調用method->UnregisterNative(Thread::Current());
來看art/runtime/mirror/art_method.cc#UnregisterNative
,
setAccessFlags:設置訪問權限
setEntryPointFromJni:設置artmethod中的entry_point_from_jni_,表明是JNI函數
在回來看art/runtime/class_linker.cc
,可以看到,這裏調用了Instrumentation.updateMethodsCode
來看art/runtime/instrumentation.cc
這裏來看updateEntryPoints
可以看到,這裏是更改方法的執行入口
#if defined(ART_USE_PORTABLE_COMPILER)
method->SetEntryPointFromPortableCompiledCode(portable_code);
#endif
method->SetEntryPointFromQuickCompiledCode(quick_code);
然後,設置method相應的屬性。(SetEntryPointFromInterpreter)
小結
env->FindClass
的內部調用過程
- env->FindClass //尋找Java Class
- art/runtime/jni_internal.cc#FindClass() //實際調用此方法
- art/runtime/class_linker.cc#FindClass() //接着調用此方法
- art/runtime/class_linker.cc#DefineClass() //最終會返回DefineClass
- art/runtime/class_linker.cc#LoadClass() //DefineClass內部會調用LoadClass,將dex文件的信息,賦值給kclass
- art/runtime/class_linker.cc#LoadClassMembers() //調用LoadClassMembers,加載fields和methods,並賦值給kclass
- art/runtime/class_linker.cc#LinkCode() //鏈接字節碼
- art/runtime/oat_file.cc#LinkMethod() //LinkCode內部會調用LinkMethod,通過oat_method給函數設置一個默認的入口
- art/runtime/class_linker.cc#NeedsInterpreter() //是否是解釋器模式
- art/runtime/mirror/art_method.cc#UnregisterNative() //如果是Native方法會設置訪問權限、設置artmethod中的entry_point_from_jni_(表明是JNI函數)
- art/runtime/instrumentation.cc#UpdateMethodsCode() //更新方法的執行入口
- art/runtime/instrumentation.cc#UpdateEntrypoints() //UpdateMethodsCode會調用此方法,真正修改方法的執行入口
其他
源碼爲Android 5.1.0_r3