
首先要清楚,odex隻是對代碼段(我将dex檔案與elf檔案類比,大家都将執行檔案分成不同的段)作優化,而其它用于類反射資訊的段都應用原來的dex,是以odex檔案内部還包含了一個dex。
打開一個dex或一個odex檔案,就是要将其中用于類反射的資訊加載到虛拟機運作時中。對于打開一個odex檔案,目的也是要将其中包含的dex部分的資訊進行加載。
dalvik(libdvm.so)打開dex檔案,實質就是要将dex裡的反射資訊加載到一個DexFile組織的結構體。這個結構有一個查找表,DexClassLookup。這個結構不直接被 libdvm.so 使用,而是由一個上層的DvmDex代替,為libdvm.so其它函數調用使用。但這個DvmDex不被JNI層,也就是libdvm.so最接近java的一層所直接使用,這裡有一個DexOrJar結構體關聯DvmDex,DexOrJar為最上層可尋找到的對象,并且插入到hash表中。
DexOrJar,JNI 層
DvmDex,libdvm 内部函數
DexFile,最後的執行委托處
對于dalvik.system.DexFile.openDexFile,它的native實作Dalvik_dalvik_system_DexFile_openDexFile的工作,就是調用libdvm内部相關的函數完成,從dex檔案加載進DexFile,配置設定DvmDex關聯DexFile,最後用一個DexOrJar關聯DvmDex,并将DexOrJar放入hash表中。
我們c/c++則可以直接繞開java層或jni,直接去調用libdvm.so的内部函數去進行打開,以及打開後的使用。這些内部函數使用的是DvmDex。
在内部支援的打開函數裡面,最上層的是dvmRawDexFileOpen,也就是Dalvik_dalvik_system_DexFile_openDexFile直接調用的内部函數。這個函數完成了比較多的事,如建立odex,優化dex進odex,然後才是實質上的打開。
實質上去打開dex的内部函數分别有dvmDexFileOpenFromFd以及dvmDexFileOpenPartial。dvmDexFileOpenFromFd的參數是odex的檔案描述符,dvmDexFileOpenPartial的參數是odex或dex的映像。這兩個函數都會傳回DvmDex。并且最終使用dexFileParse實質地将dex的反射内容加載進DexFile。
dvmRawDexFileOpen,最上層的内部打開函數
dvmDexFileOpenPartial和dvmDexFileOpenFromFd,傳回DvmDex,可用于其它内部函數調用
dexFileParse,最低端,也就是最實質的打開函數
使用dvmDefineClass就可是直接将類從Dex加載到ClassLoader,并不需要經過Java層或Jni來進行類的加載。
在libdvm.so隻有少數幾個函數是用extern "C"風格的連結符号導出的,dalvik卻是c++項目,也就是說其它符号都使用了c++的風格,是以你并不能直接通過直覺的函數名來進行函數符号的擷取,而必須使用它對應的c++風格的真實連結符号。
下面是我将python移植後使用的pyjni.py,使用ctypes擷取符号将名字做映射。這些符号可以通過objdump取得。
本文轉自zsdnr 51CTO部落格,原文連結:http://blog.51cto.com/12942149/1932726,如需轉載請自行聯系原作者