前面一篇文章中讲到Dex的加载过程,其中涉及到的结构体有:
struct DexOrJar {
char* fileName;
bool isDex;
bool okayToFree;
RawDexFile* pRawDexFile;
JarFile* pJarFile;
u1* pDexMemory; // malloc()ed memory, if any
};
如果是dex文件就会调用dvmRawDexFileOpen填充RawDexFile结构,如果是jar文件就会调用dvmJarFileOpen填充JarFile。结构如下:
struct RawDexFile {
char* cacheFileName;
DvmDex* pDvmDex;
};
struct JarFile {
ZipArchive archive;
char* cacheFileName;
DvmDex* pDvmDex;
};
其中最重要的就是pDvmDex这个结构体。
struct DvmDex {
DexFile* pDexFile; //odex的信息
const DexHeader* pHeader; //dex文件头相关信息
struct StringObject** pResStrings; //字符串
struct ClassObject** pResClasses; //通过DexFile里的ClassDefItem构造出来的一个结构体(类信息)
struct Method** pResMethods; //通过Method_Item构造出来的结构体(方法信息)
struct Field** pResFields;
struct AtomicCache* pInterfaceCache;
bool isMappedReadOnly;
MemMapping memMap;
jobject dex_object;
pthread_mutex_t modLock;
};
DexFile结构体存储了odex文件的一些信息。
struct DexFile {
/* directly-mapped “opt” header */
const DexOptHeader* pOptHeader;
/* pointers to directly-mapped structs and arrays in base DEX */
const DexHeader* pHeader;
const DexStringId* pStringIds;
const DexTypeId* pTypeIds;
const DexFieldId* pFieldIds;
const DexMethodId* pMethodIds;
const DexProtoId* pProtoIds;
const DexClassDef* pClassDefs;
const DexLink* pLinkData;
const DexClassLookup* pClassLookup;
const void* pRegisterMapPool; // RegisterMapClassPool
const u1* baseAddr;
int overhead;
};
其中DexClassLookup结构体是用来方便快速查找某个类的一个hash表。
struct DexClassLookup {
int size; // total size, including “size”
int numEntries; // size of table[]; always power of 2
struct {
u4 classDescriptorHash; // class descriptor hash code
int classDescriptorOffset; // in bytes, from start of DEX
int classDefOffset; // in bytes, from start of DEX
} table[1];
};
关于DexClassLookup结构 可以参考:
http://blog.csdn.net/roland_sun/article/details/46877563
这篇文章。
然后再来看看Dalvik_dalvik_system_DexFile_defineClassNative方法是怎么找到类信息的。
代码地址:http://androidxref.com/4.4_r1/xref/dalvik/vm/native/dalvik_system_DexFile.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | static void Dalvik_dalvik_system_DexFile_defineClassNative(const u4* args, JValue* pResult) { StringObject* nameObj = (StringObject*) args[0]; Object* loader = (Object*) args[1]; int cookie = args[2]; ClassObject* clazz = NULL; DexOrJar* pDexOrJar = (DexOrJar*) cookie; DvmDex* pDvmDex; char* name; char* descriptor; name = dvmCreateCstrFromString(nameObj); //把com.monkey.test 转成Lcom/monkey/test; descriptor = dvmDotToDescriptor(name); ALOGV("--- Explicit class load '%s' l=%p c=0x%08x", descriptor, loader, cookie); free(name); if (!validateCookie(cookie)) RETURN_VOID(); //获取pDvmDex if (pDexOrJar->isDex) pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile); else pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile); /* once we load something, we can't unmap the storage */ pDexOrJar->okayToFree = false; //获取ClassObject clazz = dvmDefineClass(pDvmDex, descriptor, loader); Thread* self = dvmThreadSelf(); if (dvmCheckException(self)) { /* * If we threw a "class not found" exception, stifle it, since the * contract in the higher method says we simply return null if * the class is not found. */ Object* excep = dvmGetException(self); if (strcmp(excep->clazz->descriptor, "Ljava/lang/ClassNotFoundException;") == 0 || strcmp(excep->clazz->descriptor, "Ljava/lang/NoClassDefFoundError;") == 0) { dvmClearException(self); } clazz = NULL; } free(descriptor); RETURN_PTR(clazz); } |
然后看里面的dvmDefineClass方法:
1 2 3 4 5 6 7 | ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor, Object* classLoader) { assert(pDvmDex != NULL); return findClassNoInit(descriptor, classLoader, pDvmDex); } |
这里调用了findClassNoInit函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | static ClassObject* findClassNoInit(const char* descriptor, Object* loader, DvmDex* pDvmDex) { Thread* self = dvmThreadSelf(); ClassObject* clazz; .............. clazz = dvmLookupClass(descriptor, loader, true); //判断当前的类是否已经加载 if (clazz == NULL) { const DexClassDef* pClassDef; if (pDvmDex == NULL) { assert(loader == NULL); /* shouldn't be here otherwise */ pDvmDex = searchBootPathForClass(descriptor, &pClassDef);//如果pDvmDex为NULL,从系统缺省的库目录里加载 } else { pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor); //从dex文件中找到目标类的classDefItem数据 } .............. /* found a match, try to load it */ clazz = loadClassFromDex(pDvmDex, pClassDef, loader); //通过dex文件对象,目标类的ClassDefItem,classloader来加载目标类到内存中,最后会构造一个ClassObject结构 .............. dvmLockObject(self, (Object*) clazz); if (!dvmAddClassToHash(clazz)) { //加到hash_table的时候出错的一些处理 } } } struct ClassObject : Object { u4 instanceData[CLASS_FIELD_SLOTS]; const char* descriptor; char* descriptorAlloc; u4 accessFlags; u4 serialNumber; DvmDex* pDvmDex; ClassStatus status; ClassObject* verifyErrorClass; u4 initThreadId; size_t objectSize; ClassObject* elementClass; int arrayDim; PrimitiveType primitiveType; ClassObject* super; Object* classLoader; InitiatingLoaderList initiatingLoaderList; int interfaceCount; ClassObject** interfaces; int directMethodCount; Method* directMethods; int virtualMethodCount; Method* virtualMethods; int vtableCount; Method** vtable; int iftableCount; InterfaceEntry* iftable; int ifviPoolCount; int* ifviPool; int ifieldCount; int ifieldRefCount; InstField* ifields; u4 refOffsets; const char* sourceFile; int sfieldCount; StaticField sfields[0]; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | static ClassObject* loadClassFromDex(DvmDex* pDvmDex, const DexClassDef* pClassDef, Object* classLoader) { ClassObject* result; DexClassDataHeader header; const u1* pEncodedData; const DexFile* pDexFile; assert((pDvmDex != NULL) && (pClassDef != NULL)); pDexFile = pDvmDex->pDexFile; if (gDvm.verboseClass) { ALOGV("CLASS: loading '%s'...", dexGetClassDescriptor(pDexFile, pClassDef)); } pEncodedData = dexGetClassData(pDexFile, pClassDef); //得到classDefItem里的ClassData if (pEncodedData != NULL) { dexReadClassDataHeader(&pEncodedData, &header); //读取classDefItem的头信息 } else { // Provide an all-zeroes header for the rest of the loading. memset(&header, 0, sizeof(header)); } result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData, classLoader); //根据一系列类的数据,对ClassObject这个结构体的字段进行填充处理 if (gDvm.verboseClass && (result != NULL)) { ALOGI("[Loaded %s from DEX %p (cl=%p)]", result->descriptor, pDvmDex, classLoader); } return result; } |
最后调用loadClassFromDex0填充ClassObject结构。
类加载完了,还有类的方法的加载:
上面的loadClassFromDex0函数里面会调用dexReadClassDataMethod来读取Method信息,
DEX_INLINE void dexReadClassDataMethod(const u1** pData, DexMethod* pMethod,
u4* lastIndex) {
u4 index = *lastIndex + readUnsignedLeb128(pData);
pMethod->accessFlags = readUnsignedLeb128(pData);
pMethod->codeOff = readUnsignedLeb128(pData);
pMethod->methodIdx = index;
*lastIndex = index;
}
然后通过函数
static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod, Method* meth)来根据methodid找到method信息。
pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
meth->name = dexStringById(pDexFile, pMethodId->nameIdx);
dexProtoSetFromMethodId(&meth->prototype, pDexFile, pMethodId);
meth->shorty = dexProtoGetShorty(&meth->prototype);
meth->accessFlags = pDexMethod->accessFlags;
meth->clazz = clazz;
meth->jniArgInfo = 0;
meth->registersSize = pDexCode->registersSize;
meth->insSize = pDexCode->insSize;
meth->outsSize = pDexCode->outsSize;
meth->insns = pDexCode->insns;
if (dvmIsNativeMethod(meth)) {
meth->nativeFunc = dvmResolveNativeMethod;
meth->jniArgInfo = computeJniArgInfo(&meth->prototype);
}
Permalink
牛。。。大神。。。