1. 程式人生 > >使用 libdvm.so 內部函數dvm* 加載 dex

使用 libdvm.so 內部函數dvm* 加載 dex

尋找 log types ndk logs 是我 lib 找到 objdump

技術分享

首先要清楚,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取得。

技術分享

這樣我就能在程序運行的同時手動去使用libdvm.so的內部函數,像命令一樣使用,而不用每次都進行ndk編譯。

使用 libdvm.so 內部函數dvm* 加載 dex