android类加载过程,Android类加载过程解析

涉及源码(Android 4.4.2):

/libcore/libart/src/main/java/java/lang/Class.java

/dalvik/vm/native/java_lang_Class.cpp

/dalvik/vm/native/InternalNative.cpp

/dalvik/vm/oo/Class.cpp

/libcore/libart/src/main/java/java/lang/Class.java

/libcore/libart/src/main/java/java/lang/ClassLoader.java

/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java

/libcore/dalvik/src/main/java/dalvik/system/DexFile.java

/dalvik/vm/native/dalvik_system_DexFile.cpp

/dalvik/vm/oo/Class.cpp

/dalvik/libdex/DexFile.cpp

从Class.forName()函数看起。

public static Class> forName(String className) throws ClassNotFoundException {

return forName(className, true, VMStack.getCallingClassLoader());

}

可以看到默认使用的classLoader是调用该函数的类的classLoader。

public static Class> forName(String className, boolean shouldInitialize,

ClassLoader classLoader) throws ClassNotFoundException {

if (classLoader == null) {

classLoader = ClassLoader.getSystemClassLoader();

}

Class> result;

try {

result = classForName(className, shouldInitialize, classLoader);

} catch (ClassNotFoundException e) {

Throwable cause = e.getCause();

if (cause instanceof LinkageError) {

throw (LinkageError) cause;

}

throw e;

}

return result;

}

static native Class> classForName(String className, boolean shouldInitialize,

ClassLoader classLoader) throws ClassNotFoundException;

最终会调用到native方法

/dalvik/vm/native/java_lang_Class.cpp

static void Dalvik_java_lang_Class_classForName(const u4* args, JValue* pResult)

{

StringObject* nameObj = (StringObject*) args[0];

bool initialize = (args[1] != 0);

Object* loader = (Object*) args[2];

RETURN_PTR(dvmFindClassByName(nameObj, loader, initialize));

}

/dalvik/vm/native/InternalNative.cpp

ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader,

bool doInit)

{

ClassObject* clazz = NULL;

char* name = NULL;

char* descriptor = NULL;

if (nameObj == NULL) {

dvmThrowNullPointerException("name == null");

goto bail;

}

name = dvmCreateCstrFromString(nameObj);

if (!dexIsValidClassName(name, true)) {

ALOGW("dvmFindClassByName rejecting '%s'", name);

dvmThrowClassNotFoundException(name);

goto bail;

}

descriptor = dvmDotToDescriptor(name);

if (descriptor == NULL) {

goto bail;

}

if (doInit)

clazz = dvmFindClass(descriptor, loader);

else

clazz = dvmFindClassNoInit(descriptor, loader);

if (clazz == NULL) {

LOGVV("FAIL: load %s (%d)", descriptor, doInit);

Thread* self = dvmThreadSelf();

Object* oldExcep = dvmGetException(self);

dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */

dvmClearException(self);

dvmThrowChainedClassNotFoundException(name, oldExcep);

dvmReleaseTrackedAlloc(oldExcep, self);

} else {

LOGVV("GOOD: load %s (%d) --> %p ldr=%p",

descriptor, doInit, clazz, clazz->classLoader);

}

bail:

free(name);

free(descriptor);

return clazz;

}

重点关注dvmFindClassNoInit方法。

/dalvik/vm/oo/Class.cpp

ClassObject* dvmFindClassNoInit(const char* descriptor,

Object* loader)

{

assert(descriptor != NULL);

//assert(loader != NULL);

LOGVV("FindClassNoInit '%s' %p", descriptor, loader);

if (*descriptor == '[') {

/*

* Array class. Find in table, generate if not found.

*/

return dvmFindArrayClass(descriptor, loader);

} else {

/*

* Regular class. Find in table, load if not found.

*/

if (loader != NULL) {

return findClassFromLoaderNoInit(descriptor, loader);

} else {

return dvmFindSystemClassNoInit(descriptor);

}

}

}

进入到findClassFromLoaderNoInit方法

static ClassObject* findClassFromLoaderNoInit(const char* descriptor,

Object* loader)

{

Thread* self = dvmThreadSelf();

// 1、首先进行查找是否以及进行了加载

ClassObject* clazz = dvmLookupClass(descriptor, loader, false);

if (clazz != NULL) {

LOGVV("Already loaded: %s %p", descriptor, loader);

return clazz;

} else {

LOGVV("Not already loaded: %s %p", descriptor, loader);

}

char* dotName = NULL;

StringObject* nameObj = NULL;

/* convert "Landroid/debug/Stuff;" to "android.debug.Stuff" */

dotName = dvmDescriptorToDot(descriptor);

if (dotName == NULL) {

dvmThrowOutOfMemoryError(NULL);

return NULL;

}

nameObj = dvmCreateStringFromCstr(dotName);

if (nameObj == NULL) {

assert(dvmCheckException(self));

goto bail;

}

dvmMethodTraceClassPrepBegin();

LOGVV("--- Invoking loadClass(%s, %p)", dotName, loader);

{

// 2、如果没有加载,这里调用java/lang/ClassLoader的loadClass函数来加载类

const Method* loadClass =

loader->clazz->vtable[gDvm.voffJavaLangClassLoader_loadClass];

JValue result;

dvmCallMethod(self, loadClass, loader, &result, nameObj);

clazz = (ClassObject*) result.l;

dvmMethodTraceClassPrepEnd();

Object* excep = dvmGetException(self);

if (excep != NULL) {

#if DVM_SHOW_EXCEPTION >= 2

ALOGD("NOTE: loadClass '%s' %p threw exception %s",

dotName, loader, excep->clazz->descriptor);

#endif

dvmAddTrackedAlloc(excep, self);

dvmClearException(self);

dvmThrowChainedNoClassDefFoundError(descriptor, excep);

dvmReleaseTrackedAlloc(excep, self);

clazz = NULL;

goto bail;

} else if (clazz == NULL) {

ALOGW("ClassLoader returned NULL w/o exception pending");

dvmThrowNullPointerException("ClassLoader returned null");

goto bail;

}

}

/* not adding clazz to tracked-alloc list, because it's a ClassObject */

dvmAddInitiatingLoader(clazz, loader);

LOGVV("--- Successfully loaded %s %p (thisldr=%p clazz=%p)",

descriptor, clazz->classLoader, loader, clazz);

bail:

dvmReleaseTrackedAlloc((Object*)nameObj, NULL);

free(dotName);

return clazz;

}

1、首先调用dvmLookupClass方法在gDvm.loadedClasses中查找是否存在该类,加载过的类都会存放到gDvm.loadedClasses中。

2、如果没有加载过。可以看到最终是调用java/lang/ClassLoader的loadClass函数来加载类,下面来看看ClassLoader的loadClass方法。

/libcore/libart/src/main/java/java/lang/ClassLoader.java

public Class> loadClass(String name) throws ClassNotFoundException {

return loadClass(name, false);

}

protected Class> loadClass(String className, boolean resolve) throws ClassNotFoundException {

// 查看该类是否以及加载

Class> clazz = findLoadedClass(className);

// 委托机制

if (clazz == null) {

ClassNotFoundException suppressed = null;

try {

clazz = parent.loadClass(className, false);

} catch (ClassNotFoundException e) {

suppressed = e;

}

// 最终如果没有找到该类,就自己来查找

if (clazz == null) {

try {

clazz = findClass(className);

} catch (ClassNotFoundException e) {

e.addSuppressed(suppressed);

throw e;

}

}

}

return clazz;

}

查看BaseDexClassLoader的findClass方法。

/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

List suppressedExceptions = new ArrayList();

Class c = pathList.findClass(name, suppressedExceptions);

if (c == null) {

ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);

for (Throwable t : suppressedExceptions) {

cnfe.addSuppressed(t);

}

throw cnfe;

}

return c;

}

/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java

public Class findClass(String name, List suppressed) {

// 遍历dexElements数组

for (Element element : dexElements) {

DexFile dex = element.dexFile;

if (dex != null) {

Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);

if (clazz != null) {

return clazz;

}

}

}

if (dexElementsSuppressedExceptions != null) {

suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));

}

return null;

}

/libcore/dalvik/src/main/java/dalvik/system/DexFile.java

public Class loadClassBinaryName(String name, ClassLoader loader, List suppressed) {

return defineClass(name, loader, mCookie, suppressed);

}

private static Class defineClass(String name, ClassLoader loader, int cookie,

List suppressed) {

Class result = null;

try {

result = defineClassNative(name, loader, cookie);

} catch (NoClassDefFoundError e) {

if (suppressed != null) {

suppressed.add(e);

}

} catch (ClassNotFoundException e) {

if (suppressed != null) {

suppressed.add(e);

}

}

return result;

}

private static native Class defineClassNative(String name, ClassLoader loader, int cookie)

throws ClassNotFoundException, NoClassDefFoundError;

/dalvik/vm/native/dalvik_system_DexFile.cpp

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);

descriptor = dvmDotToDescriptor(name);

ALOGV("--- Explicit class load '%s' l=%p c=0x%08x",

descriptor, loader, 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);

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方法

/dalvik/vm/oo/Class.cpp

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)

{

ClassObject* clazz;

// 查看是否以及加载

clazz = dvmLookupClass(descriptor, loader, true);

// 如果没有加载,则进行查找加载

if (clazz == NULL) {

if (pDvmDex == NULL) {

pDvmDex = searchBootPathForClass(descriptor, &pClassDef);

} else {

pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);

}

clazz = loadClassFromDex(pDvmDex, pClassDef, loader);

// 进行缓存

dvmAddClassToHash(clazz);

}

}

下面看看dexFindClass方法。

/dalvik/libdex/DexFile.cpp

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;

}

}

从DexFile的pClassLookup中进行查找

/dalvik/vm/oo/Class.cpp

bool dvmAddClassToHash(ClassObject* clazz)

{

void* found;

u4 hash;

hash = dvmComputeUtf8Hash(clazz->descriptor);

dvmHashTableLock(gDvm.loadedClasses);

found = dvmHashTableLookup(gDvm.loadedClasses, hash, clazz,

hashcmpClassByClass, true);

dvmHashTableUnlock(gDvm.loadedClasses);

ALOGV("+++ dvmAddClassToHash '%s' %p (isnew=%d) --> %p",

clazz->descriptor, clazz->classLoader,

(found == (void*) clazz), clazz);

//dvmCheckClassTablePerf();

/* can happen if two threads load the same class simultaneously */

return (found == (void*) clazz);

}

已经被加载过的类会存放到gDvm.loadedClasses里面去。

整个流程图基本如下:

23031578e654

dexload3.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值