数据结构
以下基于 Android_4.0.4源码进行分析。
先丢一张虚拟机用到的数据结构。我们的起点在
native private static int openDexFile(String sourceName, String outputName, int flags) throws IOException @ DexFile.java
//@dalvik/vm/native/dalvik_system_DexFile.cpp
static void Dalvik_dalvik_system_DexFile_openFile(const u4* args, JValue* pResult){
RawDexFile* pJarFile;
...
dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false);
...
}
//@dalvik/vm/RawDexFile.cpp
int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
RawDexFile** ppRawDexFile, bool isBootstrap){
DvmDex* pDvmDex = NULL;
...
//@dalvik/vm/analysis/DexPrepare
//优化
result = dvmOptimizeDexFile(optFd, dexOffset, fileSize, fileName, modTime, adler32, isBootstrap);
...
//@dalvik/vm/DvmDex.cpp
dvmDexFileOpenFromFd(optFd, &pDvmDex);
}
@dalvik/vm/DvmDex.cpp
int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex){
DvmDex* pDvmDex;
DexFile* pDexFile;
...
//重点 1,用以解析 Dex 文件,返回一个对应的 DexFile 数据结构
//@dalvik/libdex/DexFile.cpp
pDexFile = dexFileParse((u1*)memMap.addr, memMap.length, parseFlags);
// 重点 2,根据 DexFile 填充 DvmDex 信息
pDvmDex = allocateAuxStructures(pDexFile);
}
重点 1
//@dalvik/libdex/DexFile.cpp
DexFile* dexFileParse(const u1*data, size_t length, int flags){
DexFile* pDexFile = NULL;
const DexHeader* pHeader;
...
//分配内存
pDexFile = (DexFile*) malloc(sizeof(DexFile));
...
dexParseOptData(data, length, pDexFile);
...
//通过 Dex 文件信息,填充 DexFile 的信息
dexFileSetupBasicPointers(pDexFile, data);
...
}
//data 是打开的 Dex 文件在内存中的地址,而 DexHeader 中的形如 stringIdsOff 都是相对于文件首地址的偏移,因此在 DexFile 中的 pStringIds、pTypeIds 保存的是 Dex 文件中stringIds,TypeIds 等信息在内存中的实际地址。
void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data){
DexHeader *pHeader = (DexHeader*) data;
pDexFile->baseAddr = data;
pDexFile->pHeader = pHeader;
pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
}
重点 2
@DvmDex.cpp
//根据 DexFile 的信息填充 DvmDex
static DvmDex* allocateAuxStructres(DexFile* pDexFile){
DvmDex* pDvmDex;
const DexHeader* pHeader;
u4 stringCount, classCount, methodCount, fileCount;
pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
pDvmDex->pDexFile = pDexFile;
pDvmDex->pHeader = pDexFile->pHeader;
pHeader = pDvmDex->pHeader;
stringCount = pHeader->stringIdsSize;
classCount = pHeader->typeIdsSize;
methodCount = pHeader->methodIdsSize;
filedCount = pHeader->fileIdsSize;
//根据实际的数量分配内存
pDvmDex->pResStrings = (struct StringObject) calloc(stringCount, sizeof(struct stringObject));
pDvmDex->pResClasses = (struct ClassObject) calloc(ClassObject, sizeof(struct ClassObject));
pDvmDex->pResMethods = (struct Method) calloc(methodCount, sizeof(struct Method));
pDvmDex->pResFilds = (struct Field) calloc(fieldCount, sizeof(struct Field));
...
pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
}
*从上面看出来,DvmDex 包含 DexFile,DexFile 包含 DexHeader。通过解析 DexHeader,将常量池,方法区,字段等信息在内存的首地址存入 DexFile;然后通过 DexFile 的信息在 DvmDex 中分配合适的内存。于是 Dex 文件便初步解析完成了,并且保存在了内存。在进行类加载的时候,一个类的信息在内存中以 ClassObject 的结构保存。同时在 DexFile 中有一个 ClassLookup* pClassLookup 作为一个哈希表作为缓存保存已经加载了的类。
另外native private static int openDexFile(String sourceName, String outputName, int flags)的返回值是一个 int。明显这个 int 是对应 native 中一个对象的句柄。那么来看 Dalvik_dalvik_system_DexFile_openDexFile()@dalvik_system_DexFile.cpp 中的返回值是 DexOrJar。
于是在 DexFile 中的 cookie 保存的便是这个 DexOrJar 的地址。
https://github.com/Wi1ls/DexParse
opt
网友评论