0x00
在DexClassLoader和PathClassLoader加载Dex流程一文中,我们分析了dex文件如何形成了DexFile结构体。本文中讲解类加载机制,实际上就是生成ClassObject对象。
我们以DexClassLoader为例,讲解类加载机制,PathClassLoader是一样的。
我们在加载类时通常会调用loadClass,那么我们就从loadClass来开始分析。
0x01
DexClassLoader类没有loadClass方法,所以调用的是父类ClassLoader类的loadClass方法,ClassLoader类的loadClass方法位于libcore\luni\src\main\java\java\lang\ClassLoader.java中。
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
try {
clazz = parent.loadClass(className, false);
} catch (ClassNotFoundException e) {
// Don‘t want to see this.
}
if (clazz == null) {
clazz = findClass(className);
}
}
return clazz;
} DexClassLoader复写了父类ClassLoader的findClass方法,所以调用子类DexClassLoader类的方法findClass,代码位于libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java。 @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (VERBOSE_DEBUG)
System.out.println("DexClassLoader " + this
+ ": findClass ‘" + name + "‘");
int length = mFiles.length;
for (int i = 0; i < length; i++) {
if (VERBOSE_DEBUG)
System.out.println(" Now searching: " + mFiles[i].getPath());
if (mDexs[i] != null) {
String slashName = name.replace(‘.‘, ‘/‘);
Class clazz = mDexs[i].loadClass(slashName, this);
if (clazz != null) {
if (VERBOSE_DEBUG)
System.out.println(" found");
return clazz;
}
}
}
throw new ClassNotFoundException(name + " in loader " + this);
} 这里调用的是DexFile类的loadClass方法,代码位于libcore\dalvik\src\main\java\dalvik\system\DexFile.java。 public Class loadClass(String name, ClassLoader loader) {
String slashName = name.replace(‘.‘, ‘/‘);
return loadClassBinaryName(slashName, loader);
} public Class loadClassBinaryName(String name, ClassLoader loader) {
return defineClass(name, loader, mCookie,
null);
//new ProtectionDomain(name) /*DEBUG ONLY*/);
} defineClass对应的是JNI方法,如下:native private static Class defineClass(String name, ClassLoader loader,
int cookie, ProtectionDomain pd); 还记得在DexClassLoader和PathClassLoader加载Dex流程一文中,openDexFile也是JNI方法,对应的native方法位于dalvik\vm\native\dalvik_system_DexFile.c。const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {
{ "openDexFile", "(Ljava/lang/String;Ljava/lang/String;I)I",
Dalvik_dalvik_system_DexFile_openDexFile },
{ "closeDexFile", "(I)V",
Dalvik_dalvik_system_DexFile_closeDexFile },
{ "defineClass", "(Ljava/lang/String;Ljava/lang/ClassLoader;ILjava/security/ProtectionDomain;)Ljava/lang/Class;",
Dalvik_dalvik_system_DexFile_defineClass },
{ "getClassNameList", "(I)[Ljava/lang/String;",
Dalvik_dalvik_system_DexFile_getClassNameList },
{ "isDexOptNeeded", "(Ljava/lang/String;)Z",
Dalvik_dalvik_system_DexFile_isDexOptNeeded },
{ NULL, NULL, NULL },
};
defineClass对应的是Dalvik_dalvik_system_DexFile_defineClass方法。注意defineClass函数传递进来的参数有一个是mCookie,就是在DexClassLoader和PathClassLoader加载Dex流程一文中,openDexFile生成的,利用这个mCookie可以在native层找到openDexFile生成的DexFile结构体。
Dalvik_dalvik_system_DexFile_defineClass代码位于dalvik\vm\native\dalvik_system_DexFile.c。
static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args,
JValue* pResult)
{
StringObject* nameObj = (StringObject*) args[0];
Object* loader = (Object*) args[1];
int cookie = args[2];
Object* pd = (Object*) args[3];
ClassObject* clazz = NULL;
DexOrJar* pDexOrJar = (DexOrJar*) cookie;
DvmDex* pDvmDex;
char* name;
char* descriptor;
name = dvmCreateCstrFromString(nameObj);
descriptor = dvmDotToDescriptor(name);
LOGV("--- Explicit class load ‘%s‘ 0x%08x\n", descriptor, cookie);
free(name);
if (!validateCookie(cookie))
RETURN_VOID();
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;
clazz = dvmDefineClass(pDvmDex, descriptor, loader);
......
......
free(descriptor);
RETURN_PTR(clazz);
} 首先通过cookie找到DexOrJar结构体pDexOrJar,然后根据pDexOrJar找到DvmDex结构体pDvmDex。下面我们来分析核心函数dvmDefineClass,这个用来生成ClassObject。dvmDefineClass,findClassNoInit 方法都位于dalvik\vm\oo\Class.c。
ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor,
Object* classLoader)
{
assert(pDvmDex != NULL);
return findClassNoInit(descriptor, classLoader, pDvmDex);
}static ClassObject* findClassNoInit(const char* descriptor, Object* loader,
DvmDex* pDvmDex)
{
Thread* self = dvmThreadSelf();
ClassObject* clazz;
bool profilerNotified = false;
......
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);
} else {
pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
}
......
/* found a match, try to load it */
clazz = loadClassFromDex(pDvmDex, pClassDef, loader);
......
if (!dvmAddClassToHash(clazz)) {
......
}
......
}
return clazz;
} 首先调用dvmLookupClass方法,根据目标类的描述符descriptor在系统已加载类中进行查找,如果已对其加载,则返回目标类的ClassObject对象;否则,将对目标类进行加载。我们假设没有对其加载过,然后调用dexFindClass方法找到DexClassDef结构体。我们首先来看下DexClassDef结构体,代码位于dalvik\vm\oo\Class.c。
typedef struct DexClassDef {
u4 classIdx; /* index into typeIds for this class */
u4 accessFlags;
u4 superclassIdx; /* index into typeIds for superclass */
u4 interfacesOff; /* file offset to DexTypeList */
u4 sourceFileIdx; /* index into stringIds for source file name */
u4 annotationsOff; /* file offset to annotations_directory_item */
u4 classDataOff; /* file offset to class_data_item */
u4 staticValuesOff; /* file offset to DexEncodedArray */
} DexClassDef; 为了方便理解以后的代码,我这里先附上一张图。DexClassDef就是图中最左边的部分class_def_item。
dexFindClass方法也位于dalvik\vm\oo\Class.c。
const DexClassDef* dexFindClass(const DexFile* pDexFile,
const char* descriptor)
{
const DexClassLookup* pLookup = pDexFile->pClassLookup;
u4 hash;
int idx, mask;
hash = classDescriptorHash(descriptor);
mask = pLookup->numEntries - 1;
idx = hash & mask;
/*
* Search until we find a matching entry or an empty slot.
*/
while (true) {
int offset;
offset = pLookup->table[idx].classDescriptorOffset;
if (offset == 0)
return NULL;
if (pLookup->table[idx].classDescriptorHash == hash) {
const char* str;
str = (const char*) (pDexFile->baseAddr + offset);
if (strcmp(str, descriptor) == 0) {
return (const DexClassDef*)
(pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
}
}
idx = (idx + 1) & mask;
}
} 最后返回值的地方解释下,pDexFile->baseAddr指向dex文件头部,后面加上的是DexClassDef结构体距离dex文件头部的偏移。
返回到findClassNoInit,继续执行loadClassFromDex方法,这是真正生成ClassObject对象的地方。代码位于dalvik\vm\oo\Class.c。
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) {
LOGV("CLASS: loading ‘%s‘...\n",
dexGetClassDescriptor(pDexFile, pClassDef));
}
pEncodedData = dexGetClassData(pDexFile, pClassDef);
if (pEncodedData != NULL) {
dexReadClassDataHeader(&pEncodedData, &header);
} else {
// Provide an all-zeroes header for the rest of the loading.
memset(&header, 0, sizeof(header));
}
result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData,
classLoader);
if (gDvm.verboseClass && (result != NULL)) {
LOGI("[Loaded %s from DEX %p (cl=%p)]\n",
result->descriptor, pDvmDex, classLoader);
}
return result;
} dexGetClassData方法用来获取上图中的第二部分class_data_item。代码位于dalvik\libdex\DexFile.h。DEX_INLINE const u1* dexGetClassData(const DexFile* pDexFile,
const DexClassDef* pClassDef)
{
if (pClassDef->classDataOff == 0)
return NULL;
return (const u1*) (pDexFile->baseAddr + pClassDef->classDataOff);
} loadClassFromDex0用于生成最终的ClassObject对象。代码位于dalvik\libdex\DexFile.h。static ClassObject* loadClassFromDex0(DvmDex* pDvmDex,
const DexClassDef* pClassDef, const DexClassDataHeader* pHeader,
const u1* pEncodedData, Object* classLoader)
{
ClassObject* newClass = NULL;
const DexFile* pDexFile;
const char* descriptor;
int i;
pDexFile = pDvmDex->pDexFile;
descriptor = dexGetClassDescriptor(pDexFile, pClassDef);
/*
* Make sure the aren‘t any "bonus" flags set, since we use them for
* runtime state.
*/
if ((pClassDef->accessFlags & ~EXPECTED_FILE_FLAGS) != 0) {
LOGW("Invalid file flags in class %s: %04x\n",
descriptor, pClassDef->accessFlags);
return NULL;
}
/*
* Allocate storage for the class object on the GC heap, so that other
* objects can have references to it. We bypass the usual mechanism
* (allocObject), because we don‘t have all the bits and pieces yet.
*
* Note that we assume that java.lang.Class does not override
* finalize().
*/
/* TODO: Can there be fewer special checks in the usual path? */
assert(descriptor != NULL);
if (classLoader == NULL &&
strcmp(descriptor, "Ljava/lang/Class;") == 0) {
assert(gDvm.classJavaLangClass != NULL);
newClass = gDvm.classJavaLangClass;
} else {
size_t size = classObjectSize(pHeader->staticFieldsSize);
newClass = (ClassObject*) dvmMalloc(size, ALLOC_DEFAULT);
}
if (newClass == NULL)
return NULL;
DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
dvmSetClassSerialNumber(newClass);
newClass->descriptor = descriptor;
assert(newClass->descriptorAlloc == NULL);
newClass->accessFlags = pClassDef->accessFlags;
dvmSetFieldObject((Object *)newClass,
offsetof(ClassObject, classLoader),
(Object *)classLoader);
newClass->pDvmDex = pDvmDex;
newClass->primitiveType = PRIM_NOT;
newClass->status = CLASS_IDX;
/*
* Stuff the superclass index into the object pointer field. The linker
* pulls it out and replaces it with a resolved ClassObject pointer.
* I‘m doing it this way (rather than having a dedicated superclassIdx
* field) to save a few bytes of overhead per class.
*
* newClass->super is not traversed or freed by dvmFreeClassInnards, so
* this is safe.
*/
assert(sizeof(u4) == sizeof(ClassObject*)); /* 32-bit check */
newClass->super = (ClassObject*) pClassDef->superclassIdx;
/*
* Stuff class reference indices into the pointer fields.
*
* The elements of newClass->interfaces are not traversed or freed by
* dvmFreeClassInnards, so this is GC-safe.
*/
const DexTypeList* pInterfacesList;
pInterfacesList = dexGetInterfacesList(pDexFile, pClassDef);
if (pInterfacesList != NULL) {
newClass->interfaceCount = pInterfacesList->size;
newClass->interfaces = (ClassObject**) dvmLinearAlloc(classLoader,
newClass->interfaceCount * sizeof(ClassObject*));
for (i = 0; i < newClass->interfaceCount; i++) {
const DexTypeItem* pType = dexGetTypeItem(pInterfacesList, i);
newClass->interfaces[i] = (ClassObject*)(u4) pType->typeIdx;
}
dvmLinearReadOnly(classLoader, newClass->interfaces);
}
/* load field definitions */
/*
* Over-allocate the class object and append static field info
* onto the end. It‘s fixed-size and known at alloc time. This
* seems to increase zygote sharing. Heap compaction will have to
* be careful if it ever tries to move ClassObject instances,
* because we pass Field pointers around internally. But at least
* now these Field pointers are in the object heap.
*/
if (pHeader->staticFieldsSize != 0) {
/* static fields stay on system heap; field data isn‘t "write once" */
int count = (int) pHeader->staticFieldsSize;
u4 lastIndex = 0;
DexField field;
newClass->sfieldCount = count;
for (i = 0; i < count; i++) {
dexReadClassDataField(&pEncodedData, &field, &lastIndex);
loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
}
}
if (pHeader->instanceFieldsSize != 0) {
int count = (int) pHeader->instanceFieldsSize;
u4 lastIndex = 0;
DexField field;
newClass->ifieldCount = count;
newClass->ifields = (InstField*) dvmLinearAlloc(classLoader,
count * sizeof(InstField));
for (i = 0; i < count; i++) {
dexReadClassDataField(&pEncodedData, &field, &lastIndex);
loadIFieldFromDex(newClass, &field, &newClass->ifields[i]);
}
dvmLinearReadOnly(classLoader, newClass->ifields);
}
/*
* Load method definitions. We do this in two batches, direct then
* virtual.
*
* If register maps have already been generated for this class, and
* precise GC is enabled, we pull out pointers to them. We know that
* they were streamed to the DEX file in the same order in which the
* methods appear.
*
* If the class wasn‘t pre-verified, the maps will be generated when
* the class is verified during class initialization.
*/
u4 classDefIdx = dexGetIndexForClassDef(pDexFile, pClassDef);
const void* classMapData;
u4 numMethods;
if (gDvm.preciseGc) {
classMapData =
dvmRegisterMapGetClassData(pDexFile, classDefIdx, &numMethods);
/* sanity check */
if (classMapData != NULL &&
pHeader->directMethodsSize + pHeader->virtualMethodsSize != numMethods)
{
LOGE("ERROR: in %s, direct=%d virtual=%d, maps have %d\n",
newClass->descriptor, pHeader->directMethodsSize,
pHeader->virtualMethodsSize, numMethods);
assert(false);
classMapData = NULL; /* abandon */
}
} else {
classMapData = NULL;
}
if (pHeader->directMethodsSize != 0) {
int count = (int) pHeader->directMethodsSize;
u4 lastIndex = 0;
DexMethod method;
newClass->directMethodCount = count;
newClass->directMethods = (Method*) dvmLinearAlloc(classLoader,
count * sizeof(Method));
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
if (classMapData != NULL) {
const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
newClass->directMethods[i].registerMap = pMap;
/* TODO: add rigorous checks */
assert((newClass->directMethods[i].registersSize+7) / 8 ==
newClass->directMethods[i].registerMap->regWidth);
}
}
}
dvmLinearReadOnly(classLoader, newClass->directMethods);
}
if (pHeader->virtualMethodsSize != 0) {
int count = (int) pHeader->virtualMethodsSize;
u4 lastIndex = 0;
DexMethod method;
newClass->virtualMethodCount = count;
newClass->virtualMethods = (Method*) dvmLinearAlloc(classLoader,
count * sizeof(Method));
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->virtualMethods[i]);
if (classMapData != NULL) {
const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
newClass->virtualMethods[i].registerMap = pMap;
/* TODO: add rigorous checks */
assert((newClass->virtualMethods[i].registersSize+7) / 8 ==
newClass->virtualMethods[i].registerMap->regWidth);
}
}
}
dvmLinearReadOnly(classLoader, newClass->virtualMethods);
}
newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);
/* caller must call dvmReleaseTrackedAlloc */
return newClass;
}
这里我们先看一下ClassObject结构体,代码位于dalvik\vm\oo\Object.h中。struct ClassObject {
Object obj; /* MUST be first item */
/* leave space for instance data; we could access fields directly if we
freeze the definition of java/lang/Class */
u4 instanceData[CLASS_FIELD_SLOTS];
/* UTF-8 descriptor for the class; from constant pool, or on heap
if generated ("[C") */
const char* descriptor;
char* descriptorAlloc;
/* access flags; low 16 bits are defined by VM spec */
u4 accessFlags;
/* VM-unique class serial number, nonzero, set very early */
u4 serialNumber;
/* DexFile from which we came; needed to resolve constant pool entries */
/* (will be NULL for VM-generated, e.g. arrays and primitive classes) */
DvmDex* pDvmDex;
/* state of class initialization */
ClassStatus status;
/* if class verify fails, we must return same error on subsequent tries */
ClassObject* verifyErrorClass;
/* threadId, used to check for recursive <clinit> invocation */
u4 initThreadId;
/*
* Total object size; used when allocating storage on gc heap. (For
* interfaces and abstract classes this will be zero.)
*/
size_t objectSize;
/* arrays only: class object for base element, for instanceof/checkcast
(for String[][][], this will be String) */
ClassObject* elementClass;
/* arrays only: number of dimensions, e.g. int[][] is 2 */
int arrayDim;
/* primitive type index, or PRIM_NOT (-1); set for generated prim classes */
PrimitiveType primitiveType;
/* superclass, or NULL if this is java.lang.Object */
ClassObject* super;
/* defining class loader, or NULL for the "bootstrap" system loader */
Object* classLoader;
/* initiating class loader list */
/* NOTE: for classes with low serialNumber, these are unused, and the
values are kept in a table in gDvm. */
InitiatingLoaderList initiatingLoaderList;
/* array of interfaces this class implements directly */
int interfaceCount;
ClassObject** interfaces;
/* static, private, and <init> methods */
int directMethodCount;
Method* directMethods;
/* virtual methods defined in this class; invoked through vtable */
int virtualMethodCount;
Method* virtualMethods;
/*
* Virtual method table (vtable), for use by "invoke-virtual". The
* vtable from the superclass is copied in, and virtual methods from
* our class either replace those from the super or are appended.
*/
int vtableCount;
Method** vtable;
/*
* Interface table (iftable), one entry per interface supported by
* this class. That means one entry for each interface we support
* directly, indirectly via superclass, or indirectly via
* superinterface. This will be null if neither we nor our superclass
* implement any interfaces.
*
* Why we need this: given "class Foo implements Face", declare
* "Face faceObj = new Foo()". Invoke faceObj.blah(), where "blah" is
* part of the Face interface. We can‘t easily use a single vtable.
*
* For every interface a concrete class implements, we create a list of
* virtualMethod indices for the methods in the interface.
*/
int iftableCount;
InterfaceEntry* iftable;
/*
* The interface vtable indices for iftable get stored here. By placing
* them all in a single pool for each class that implements interfaces,
* we decrease the number of allocations.
*/
int ifviPoolCount;
int* ifviPool;
/* instance fields
*
* These describe the layout of the contents of a DataObject-compatible
* Object. Note that only the fields directly defined by this class
* are listed in ifields; fields defined by a superclass are listed
* in the superclass‘s ClassObject.ifields.
*
* All instance fields that refer to objects are guaranteed to be
* at the beginning of the field list. ifieldRefCount specifies
* the number of reference fields.
*/
int ifieldCount;
int ifieldRefCount; // number of fields that are object refs
InstField* ifields;
/* bitmap of offsets of ifields */
u4 refOffsets;
/* source file name, if known */
const char* sourceFile;
/* static fields */
int sfieldCount;
StaticField sfields[]; /* MUST be last item */
} 这里我们着重关心Method结构体,代码位于dalvik\vm\oo\Object.h中。struct Method {
/* the class we are a part of */
ClassObject* clazz;
/* access flags; low 16 bits are defined by spec (could be u2?) */
u4 accessFlags;
/*
* For concrete virtual methods, this is the offset of the method
* in "vtable".
*
* For abstract methods in an interface class, this is the offset
* of the method in "iftable[n]->methodIndexArray".
*/
u2 methodIndex;
/*
* Method bounds; not needed for an abstract method.
*
* For a native method, we compute the size of the argument list, and
* set "insSize" and "registerSize" equal to it.
*/
u2 registersSize; /* ins + locals */
u2 outsSize;
u2 insSize;
/* method name, e.g. "<init>" or "eatLunch" */
const char* name;
/*
* Method prototype descriptor string (return and argument types).
*
* TODO: This currently must specify the DexFile as well as the proto_ids
* index, because generated Proxy classes don‘t have a DexFile. We can
* remove the DexFile* and reduce the size of this struct if we generate
* a DEX for proxies.
*/
DexProto prototype;
/* short-form method descriptor string */
const char* shorty;
/*
* The remaining items are not used for abstract or native methods.
* (JNI is currently hijacking "insns" as a function pointer, set
* after the first call. For internal-native this stays null.)
*/
/* the actual code */
const u2* insns; /* instructions, in memory-mapped .dex */
/* cached JNI argument and return-type hints */
int jniArgInfo;
/*
* Native method ptr; could be actual function or a JNI bridge. We
* don‘t currently discriminate between DalvikBridgeFunc and
* DalvikNativeFunc; the former takes an argument superset (i.e. two
* extra args) which will be ignored. If necessary we can use
* insns==NULL to detect JNI bridge vs. internal native.
*/
DalvikBridgeFunc nativeFunc;
/*
* Register map data, if available. This will point into the DEX file
* if the data was computed during pre-verification, or into the
* linear alloc area if not.
*/
const RegisterMap* registerMap;
/* set if method was called during method profiling */
bool inProfile;
} 我们着重分析ClassObject结构体中Method型的directMethods字段是怎么生成的。代码在loadClassFromDex0中,我们再次截取出来。 if (pHeader->directMethodsSize != 0) {
int count = (int) pHeader->directMethodsSize;
u4 lastIndex = 0;
DexMethod method;
newClass->directMethodCount = count;
newClass->directMethods = (Method*) dvmLinearAlloc(classLoader,
count * sizeof(Method));
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
if (classMapData != NULL) {
const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
newClass->directMethods[i].registerMap = pMap;
/* TODO: add rigorous checks */
assert((newClass->directMethods[i].registersSize+7) / 8 ==
newClass->directMethods[i].registerMap->regWidth);
}
}
}
dvmLinearReadOnly(classLoader, newClass->directMethods);
} dexReadClassDataMethod方法用于读取上图中的第三部分encoded_method。代码位于dalvik\libdex\DexClass.h中。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;
} 最后loadMethodFromDex是真正生成ClassObject结构体中Method型的directMethods字段的时候,代码位于dalvik\vm\oo\Class.c中。static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod,
Method* meth)
{
DexFile* pDexFile = clazz->pDvmDex->pDexFile;
const DexMethodId* pMethodId;
const DexCode* pDexCode;
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;
if (dvmCompareNameDescriptorAndMethod("finalize", "()V", meth) == 0) {
SET_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
}
pDexCode = dexGetCode(pDexFile, pDexMethod);
if (pDexCode != NULL) {
/* integer constants, copy over for faster access */
meth->registersSize = pDexCode->registersSize;
meth->insSize = pDexCode->insSize;
meth->outsSize = pDexCode->outsSize;
/* pointer to code area */
meth->insns = pDexCode->insns;
} else {
/*
* We don‘t have a DexCode block, but we still want to know how
* much space is needed for the arguments (so we don‘t have to
* compute it later). We also take this opportunity to compute
* JNI argument info.
*
* We do this for abstract methods as well, because we want to
* be able to substitute our exception-throwing "stub" in.
*/
int argsSize = dvmComputeMethodArgsSize(meth);
if (!dvmIsStaticMethod(meth))
argsSize++;
meth->registersSize = meth->insSize = argsSize;
assert(meth->outsSize == 0);
assert(meth->insns == NULL);
if (dvmIsNativeMethod(meth)) {
meth->nativeFunc = dvmResolveNativeMethod;
meth->jniArgInfo = computeJniArgInfo(&meth->prototype);
}
}
} Method结构体在上面我们已经介绍过了。这个方法的关键在于dexGetCode,这个方法用于找到DexCode结构体。我们首先介绍下DexCode结构体。代码位于dalvik\libdex\DexClass.h中。typedef struct DexCode {
u2 registersSize;
u2 insSize;
u2 outsSize;
u2 triesSize;
u4 debugInfoOff; /* file offset to debug info stream */
u4 insnsSize; /* size of the insns array, in u2 units */
u2 insns[1];
/* followed by optional u2 padding */
/* followed by try_item[triesSize] */
/* followed by uleb128 handlersSize */
/* followed by catch_handler_item[handlersSize] */
} DexCode; dexGetCode方法,位于dalvik\libdex\DexClass.h中。DEX_INLINE const DexCode* dexGetCode(const DexFile* pDexFile,
const DexMethod* pDexMethod)
{
if (pDexMethod->codeOff == 0)
return NULL;
return (const DexCode*) (pDexFile->baseAddr + pDexMethod->codeOff);
}
获取的DexCode其实就是上图中的第四部分code_item。这样逐层返回就生成了ClassObject对象,并返回给Java层,在Java层表现为Class。参见这个Java方法protected Class<?> loadClass(String className, boolean resolve)。
DexClassLoader和PathClassLoader类加载机制
原文:http://blog.csdn.net/jltxgcy/article/details/50556239