NDK env->FindClass源碼解析

在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的內部調用過程

  1. env->FindClass //尋找Java Class
  2. art/runtime/jni_internal.cc#FindClass() //實際調用此方法
  3. art/runtime/class_linker.cc#FindClass() //接着調用此方法
  4. art/runtime/class_linker.cc#DefineClass() //最終會返回DefineClass
  5. art/runtime/class_linker.cc#LoadClass() //DefineClass內部會調用LoadClass,將dex文件的信息,賦值給kclass
  6. art/runtime/class_linker.cc#LoadClassMembers() //調用LoadClassMembers,加載fields和methods,並賦值給kclass
  7. art/runtime/class_linker.cc#LinkCode() //鏈接字節碼
  8. art/runtime/oat_file.cc#LinkMethod() //LinkCode內部會調用LinkMethod,通過oat_method給函數設置一個默認的入口
  9. art/runtime/class_linker.cc#NeedsInterpreter() //是否是解釋器模式
  10. art/runtime/mirror/art_method.cc#UnregisterNative() //如果是Native方法會設置訪問權限、設置artmethod中的entry_point_from_jni_(表明是JNI函數)
  11. art/runtime/instrumentation.cc#UpdateMethodsCode() //更新方法的執行入口
  12. art/runtime/instrumentation.cc#UpdateEntrypoints() //UpdateMethodsCode會調用此方法,真正修改方法的執行入口

其他

源碼爲Android 5.1.0_r3

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章