前言
之前了解了 dalvik 下的 dex 文件加载过程,下面开始了解一下当一个 apk 运行起来以后,一个类是如何加载的,虚拟机都做了什么事情。原发分析使用的是 4.4.4 的版本
开始
要加载一个类,java 提供的接口是 Class.forName 方法
public static Class<?> forName(String className)
throws ClassNotFoundException
{
return forName(className, true,VMStack.getCallingClassLoader());
}
很简单, 就是调用了另一个 forName 方法
203 public static Class<?> forName(String className, boolean initializeBoolean,
204 ClassLoader classLoader) throws ClassNotFoundException {
205
206 if (classLoader == null) {
207 classLoader = ClassLoader.getSystemClassLoader();
208 }
...
215 Class<?> result;
216 try {
217 result = classForName(className, initializeBoolean,
218 classLoader);
219 } catch (ClassNotFoundException e) {
220 Throwable cause = e.getCause();
221 if (cause instanceof ExceptionInInitializerError) {
222 throw (ExceptionInInitializerError) cause;
223 }
224 throw e;
225 }
226 return result;
227 }
这个函数也很简单,看看 classForName 函数
static native Class<?> classForName(String className, boolean initializeBoolean,ClassLoader classLoader) throws ClassNotFoundException;
欧耶,是个native 函数,下面进入 native 层
路径在 dalvik/vm/native/java_lang_Class.cpp
123static void Dalvik_java_lang_Class_classForName(const u4* args, JValue* pResult)
124{
125 StringObject* nameObj = (StringObject*) args[0];
126 bool initialize = (args[1] != 0);
127 Object* loader = (Object*) args[2];
128
129 RETURN_PTR(dvmFindClassByName(nameObj, loader, initialize));
130}
传递一下参数,然后调用 dvmFindClassByName 函数
177 ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader,
178 bool doInit)
179{
180 ClassObject* clazz = NULL;
181 char* name = NULL;
182 char* descriptor = NULL;
183
184 if (nameObj == NULL) {
185 dvmThrowNullPointerException("name == null");
186 goto bail;
187 }
188 name = dvmCreateCstrFromString(nameObj);
189
190 /*
191 * We need to validate and convert the name (from x.y.z to x/y/z). This
192 * is especially handy for array types, since we want to avoid
193 * auto-generating bogus array classes.
194 */
195 if (!dexIsValidClassName(name, true)) {
196 ALOGW("dvmFindClassByName rejecting '%s'", name);
197 dvmThrowClassNotFoundException(name);
198 goto bail;
199 }
200
201 descriptor = dvmDotToDescriptor(name);
202 if (descriptor == NULL) {
203 goto bail;
204 }
205
206 if (doInit)
207 clazz = dvmFindClass(descriptor, loader);
208 else
209 clazz = dvmFindClassNoInit(descriptor, loader);
210
211 if (clazz == NULL) {
212 LOGVV("FAIL: load %s (%d)", descriptor, doInit);
213 Thread* self = dvmThreadSelf();
214 Object* oldExcep = dvmGetException(self);
215 dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */
216 dvmClearException(self);
217 dvmThrowChainedClassNotFoundException(name, oldExcep);
218 dvmReleaseTrackedAlloc(oldExcep, self);
219 } else {
220 LOGVV("GOOD: load %s (%d) --> %p ldr=%p",
221 descriptor, doInit, clazz, clazz->classLoader);
222 }
223
224bail:
225 free(name);
226 free(descriptor);
227 return clazz;
228}
函数有点长,开始做了一些参数检查,然后将 java 中的 a.b.c 形式的类名转成 a/b/c 的 c 语言形式。doInit 是 java 传进来的 false,所以会调用 dvmFindClassNoInit 去查找要加载的类,最后将找到的结果返回。看一下 dvmFindClassNoInit 是怎么查找的
1285 ClassObject* dvmFindClassNoInit(const char* descriptor, Object* loader)
1287 {
1288 assert(descriptor != NULL);
1289 //assert(loader != NULL);
1290
1291 LOGVV("FindClassNoInit '%s' %p", descriptor, loader);
1292
1293 if (*descriptor == '[') {
1294 /*
1295 * Array class. Find in table, generate if not found.
1296 */
1297 return dvmFindArrayClass(descriptor, loader);
1298 } else {
1299 /*
1300 * Regular class. Find in table, load if not found.
1301 */
1302 if (loader != NULL) {
1303 return findClassFromLoaderNoInit(descriptor, loader);
1304 } else {
1305 return dvmFindSystemClassNoInit(descriptor);
1306 }
1307 }
1308 }
这个函数判断要加载的类是什么, 数组,系统类还是一般的类,可以先看看加载一般类是的处理 findClassFromLoaderNoInit
1316 static ClassObject* findClassFromLoaderNoInit(const char* descriptor,
1317 Object* loader)
1318 {
1319 //ALOGI("##### findClassFromLoaderNoInit (%s,%p)",
1320 // descriptor, loader);
1321
1322 Thread* self = dvmThreadSelf();
1323
1324 assert(loader != NULL);
1325
1326 /*
1327 * Do we already have it?
1328 *
1329 * The class loader code does the "is it already loaded" check as
1330 * well. However, this call is much faster than calling through
1331 * interpreted code. Doing this does mean that in the common case
1332 * (365 out of 420 calls booting the sim) we're doing the
1333 * lookup-by-descriptor twice. It appears this is still a win, so
1334 * I'm keeping it in.
1335 */
1336 ClassObject* clazz = dvmLookupClass(descriptor, loader, false);
1337 if (clazz != NULL) {
1338 LOGVV("Already loaded: %s %p", descriptor, loader);
1339 return clazz;
1340 } else {
1341 LOGVV("Not already loaded: %s %p", descriptor, loader);
1342 }
1343
1344 char* dotName = NULL;
1345 StringObject* nameObj = NULL;
1346
1347 /* convert "Landroid/debug/Stuff;" to "android.debug.Stuff" */
1348 dotName = dvmDescriptorToDot(descriptor);
1349 if (dotName == NULL) {
1350 dvmThrowOutOfMemoryError(NULL);
1351 return NULL;
1352 }
1353 nameObj = dvmCreateStringFromCstr(dotName);
1354 if (nameObj == NULL) {
1355 assert(dvmCheckException(self));
1356 goto bail;
1357 }
1358
1359 dvmMethodTraceClassPrepBegin();
1360
1361 /*
1362 * Invoke loadClass(). This will probably result in a couple of
1363 * exceptions being thrown, because the ClassLoader.loadClass()
1364 * implementation eventually calls VMClassLoader.loadClass to see if
1365 * the bootstrap class loader can find it before doing its own load.
1366 */
1367 LOGVV("--- Invoking loadClass(%s, %p)", dotName, loader);
1368 {
1369 const Method* loadClass =
1370 loader->clazz->vtable[gDvm.voffJavaLangClassLoader_loadClass];
1371 JValue result;
1372 dvmCallMethod(self, loadClass, loader, &result, nameObj);
1373 clazz = (ClassObject*) result.l;
1374
1375 dvmMethodTraceClassPrepEnd();
1376 Object* excep = dvmGetException(self);
1377 if (excep != NULL) {
1378 #if DVM_SHOW_EXCEPTION >= 2
1379 ALOGD("NOTE: loadClass '%s' %p threw exception %s",
1380 dotName, loader, excep->clazz->descriptor);
1381 #endif
1382 dvmAddTrackedAlloc(excep, self);
1383 dvmClearException(self);
1384 dvmThrowChainedNoClassDefFoundError(descriptor, excep);
1385 dvmReleaseTrackedAlloc(excep, self);
1386 clazz = NULL;
1387 goto bail;
1388 } else if (clazz == NULL) {
1389 ALOGW("ClassLoader returned NULL w/o exception pending");
1390 dvmThrowNullPointerException("ClassLoader returned null");
1391 goto bail;
1392 }
1393 }
1394
1395 /* not adding clazz to tracked-alloc list, because it's a ClassObject */
1396
1397 dvmAddInitiatingLoader(clazz, loader);
1398
1399 LOGVV("--- Successfully loaded %s %p (thisldr=%p clazz=%p)",
1400 descriptor, clazz->classLoader, loader, clazz);
1401
1402 bail:
1403 dvmReleaseTrackedAlloc((Object*)nameObj, NULL);
1404 free(dotName);
1405 return clazz;
1406 }
函数有点长,函数一开始先调用 dvmLookupClass 取查找已经加载的类,找到了直接返回,没有找到的话就去要自己去加载了,一些字符串的处理就不解释了,往后看,注意这段代码
const Method* loadClass =
1370 loader->clazz->vtable[gDvm.voffJavaLangClassLoader_loadClass];
1371 JValue result;
1372 dvmCallMethod(self, loadClass, loader, &result, nameObj);
1373 clazz = (ClassObject*) result.l;
这里 loader->clazz->vtable[gDvm.voffJavaLangClassLoader_loadClass],初始化的时候是这样的
{ &gDvm.voffJavaLangClassLoader_loadClass, "Ljava/lang/ClassLoader;", "loadClass","(Ljava/lang/String;)Ljava/lang/Class;" },
也就是说这个值取出来的是 ClassLoader 类的 loadClass 方法的对象,往后看
dvmCallMethod(self, loadClass, loader, &result, nameObj);
clazz = (ClassObject*) result.l;
调用了 loadClass 方法,就是又回到了 java 层去加载这个类,最后层层返回就结束了。
下面看看 loadClass 是怎么实现的
public Class<?> loadClass(String className) throws ClassNotFoundException {
457 return loadClass(className, false);
458 }
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
487 Class<?> clazz = findLoadedClass(className);
488
489 if (clazz == null) {
490 try {
491 clazz = parent.loadClass(className, false);
492 } catch (ClassNotFoundException e) {
493 // Don't want to see this.
494 }
495
496 if (clazz == null) {
497 clazz = findClass(className);
498 }
499 }
500
501 return clazz;
502 }
实现很简单,先调用了自己的另一个 loadClass 方法,在这个方法中调用 findLoadedClass 去查找已经加载的类,如果没有就去调用父类的 loadClass 方法, 如果都没有找到就会调用 findClass
/**
321 * Overridden by subclasses, throws a {@code ClassNotFoundException} by
322 * default. This method is called by {@code loadClass} after the parent
323 * {@code ClassLoader} has failed to find a loaded class of the same name.
324 *
325 * @param className
326 * the name of the class to look for.
327 * @return the {@code Class} object that is found.
328 * @throws ClassNotFoundException
329 * if the class cannot be found.
330 */
331 protected Class<?> findClass(String className) throws ClassNotFoundException {
332 throw new ClassNotFoundException(className);
333 }
findClass 里就只是抛了个异常,看看注视就知道了,这个函数需要在子类中被实现,当父类找不到需要的类时,就会调用子类的这个实现,下面看看都有谁继承了 ClassLoader, 可以看到 BaseDexClassLoader 继承了
public class BaseDexClassLoader extends ClassLoader
它的 findclass 方法
@Override
52 protected Class<?> findClass(String name) throws ClassNotFoundException {
53 List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
54 Class c = pathList.findClass(name, suppressedExceptions);
55 if (c == null) {
56 ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
57 for (Throwable t : suppressedExceptions) {
58 cnfe.addSuppressed(t);
59 }
60 throw cnfe;
61 }
62 return c;
63 }
真正的工作甩给了 pathList.findClass,去看看
public Class findClass(String name, List<Throwable> suppressed) {
318 for (Element element : dexElements) {
319 DexFile dex = element.dexFile;
320
321 if (dex != null) {
322 Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
323 if (clazz != null) {
324 return clazz;
325 }
326 }
327 }
328 if (dexElementsSuppressedExceptions != null) {
329 suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
330 }
331 return null;
332 }
看看 dex.loadClassBinaryName
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
215 return defineClass(name, loader, mCookie, suppressed);
216 }
private static Class defineClass(String name, ClassLoader loader, int cookie,
219 List<Throwable> suppressed) {
220 Class result = null;
221 try {
222 result = defineClassNative(name, loader, cookie);
223 } catch (NoClassDefFoundError e) {
224 if (suppressed != null) {
225 suppressed.add(e);
226 }
227 } catch (ClassNotFoundException e) {
228 if (suppressed != null) {
229 suppressed.add(e);
230 }
231 }
232 return result;
233 }
234
235 private static native Class defineClassNative(String name, ClassLoader loader, int cookie)
236 throws ClassNotFoundException, NoClassDefFoundError;
最后调用到了 defineClassNative 方法,路径在 dalvik/vm/native/dalvik_system_DexFile.cpp
static void Dalvik_dalvik_system_DexFile_defineClassNative(const u4* args,
350 JValue* pResult)
351 {
352 StringObject* nameObj = (StringObject*) args[0];
353 Object* loader = (Object*) args[1];
354 int cookie = args[2];
355 ClassObject* clazz = NULL;
356 DexOrJar* pDexOrJar = (DexOrJar*) cookie;
357 DvmDex* pDvmDex;
358 char* name;
359 char* descriptor;
360
361 name = dvmCreateCstrFromString(nameObj);
362 descriptor = dvmDotToDescriptor(name);
363 ALOGV("--- Explicit class load '%s' l=%p c=0x%08x",
364 descriptor, loader, cookie);
365 free(name);
366
367 if (!validateCookie(cookie))
368 RETURN_VOID();
369
370 if (pDexOrJar->isDex)
371 pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
372 else
373 pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);
374
375 /* once we load something, we can't unmap the storage */
376 pDexOrJar->okayToFree = false;
377
378 clazz = dvmDefineClass(pDvmDex, descriptor, loader);
379 Thread* self = dvmThreadSelf();
380 if (dvmCheckException(self)) {
381 /*
382 * If we threw a "class not found" exception, stifle it, since the
383 * contract in the higher method says we simply return null if
384 * the class is not found.
385 */
386 Object* excep = dvmGetException(self);
387 if (strcmp(excep->clazz->descriptor,
388 "Ljava/lang/ClassNotFoundException;") == 0 ||
389 strcmp(excep->clazz->descriptor,
390 "Ljava/lang/NoClassDefFoundError;") == 0)
391 {
392 dvmClearException(self);
393 }
394 clazz = NULL;
395 }
396
397 free(descriptor);
398 RETURN_PTR(clazz);
399 }
函数挺长的,但不复杂,开始也是对参数的一下检测,然后判断一下是 dex 还是 jar,这里我们假设是 dex,或来到 dvmGetRawDexFileDex 取出 pDvmDex 结构,然后调用 dvmDefineClass,最后将找到或者加载完成的类返回,整个流程就结束了。 看看 dvmDefineClass
1413 ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor,
1414 Object* classLoader)
1415 {
1416 assert(pDvmDex != NULL);
1417
1418 return findClassNoInit(descriptor, classLoader, pDvmDex);
1419 }
没干什么正事,看看 findClassNoInit, 函数很长分段看吧,开始是一些参数检验就不说了,然后就会看到又来到了 dvmLookupClass,不过要解释一下,这次调用和上次调用是不同的,上次是在系统的 loader 中或者是某个 basedexclassloader 的子类中,在这些loader 中的 dex 文件可能是不全,但是这次是在父类里 也就是 basedexclassloader 里,所有的 dex 都在这个类对象里保存着,如果还是没有那就是真没有了
1473 static ClassObject* findClassNoInit(const char* descriptor, Object* loader,
1474 DvmDex* pDvmDex)
1475 {
1476 Thread* self = dvmThreadSelf();
1477 ClassObject* clazz;
1478 bool profilerNotified = false;
1479
1480 if (loader != NULL) {
1481 LOGVV("#### findClassNoInit(%s,%p,%p)", descriptor, loader,
1482 pDvmDex->pDexFile);
1483 }
1484
1485 /*
1486 * We don't expect an exception to be raised at this point. The
1487 * exception handling code is good about managing this. This *can*
1488 * happen if a JNI lookup fails and the JNI code doesn't do any
1489 * error checking before doing another class lookup, so we may just
1490 * want to clear this and restore it on exit. If we don't, some kinds
1491 * of failures can't be detected without rearranging other stuff.
1492 *
1493 * Most often when we hit this situation it means that something is
1494 * broken in the VM or in JNI code, so I'm keeping it in place (and
1495 * making it an informative abort rather than an assert).
1496 */
1497 if (dvmCheckException(self)) {
1498 ALOGE("Class lookup %s attempted with exception pending", descriptor);
1499 ALOGW("Pending exception is:");
1500 dvmLogExceptionStackTrace();
1501 dvmDumpAllThreads(false);
1502 dvmAbort();
1503 }
1504
1505 clazz = dvmLookupClass(descriptor, loader, true);
1506 if (clazz == NULL) {
1507 const DexClassDef* pClassDef;
1508
1509 dvmMethodTraceClassPrepBegin();
1510 profilerNotified = true;
1511
1512 #if LOG_CLASS_LOADING
1513 u8 startTime = dvmGetThreadCpuTimeNsec();
1514 #endif
1515
1516 if (pDvmDex == NULL) {
1517 assert(loader == NULL); /* shouldn't be here otherwise */
1518 pDvmDex = searchBootPathForClass(descriptor, &pClassDef);
1519 } else {
1520 pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
1521 }
1522
1523 if (pDvmDex == NULL || pClassDef == NULL) {
1524 if (gDvm.noClassDefFoundErrorObj != NULL) {
1525 /* usual case -- use prefabricated object */
1526 dvmSetException(self, gDvm.noClassDefFoundErrorObj);
1527 } else {
1528 /* dexopt case -- can't guarantee prefab (core.jar) */
1529 dvmThrowNoClassDefFoundError(descriptor);
1530 }
1531 goto bail;
1532 }
1533
1534 /* found a match, try to load it */
1535 clazz = loadClassFromDex(pDvmDex, pClassDef, loader);
1536 if (dvmCheckException(self)) {
1537 /* class was found but had issues */
1538 if (clazz != NULL) {
1539 dvmFreeClassInnards(clazz);
1540 dvmReleaseTrackedAlloc((Object*) clazz, NULL);
1541 }
1542 goto bail;
1543 }
1544
1545 /*
1546 * Lock the class while we link it so other threads must wait for us
1547 * to finish. Set the "initThreadId" so we can identify recursive
1548 * invocation. (Note all accesses to initThreadId here are
1549 * guarded by the class object's lock.)
1550 */
1551 dvmLockObject(self, (Object*) clazz);
1552 clazz->initThreadId = self->threadId;
1553
1554 /*
1555 * Add to hash table so lookups succeed.
1556 *
1557 * [Are circular references possible when linking a class?]
1558 */
1559 assert(clazz->classLoader == loader);
1560 if (!dvmAddClassToHash(clazz)) {
1561 /*
1562 * Another thread must have loaded the class after we
1563 * started but before we finished. Discard what we've
1564 * done and leave some hints for the GC.
1565 *
1566 * (Yes, this happens.)
1567 */
1568 //ALOGW("WOW: somebody loaded %s simultaneously", descriptor);
1569 clazz->initThreadId = 0;
1570 dvmUnlockObject(self, (Object*) clazz);
1571
1572 /* Let the GC free the class.
1573 */
1574 dvmFreeClassInnards(clazz);
1575 dvmReleaseTrackedAlloc((Object*) clazz, NULL);
1576
1577 /* Grab the winning class.
1578 */
1579 clazz = dvmLookupClass(descriptor, loader, true);
1580 assert(clazz != NULL);
1581 goto got_class;
1582 }
1583 dvmReleaseTrackedAlloc((Object*) clazz, NULL);
1584
1585 #if LOG_CLASS_LOADING
1586 logClassLoadWithTime('>', clazz, startTime);
1587 #endif
1588 /*
1589 * Prepare and resolve.
1590 */
1591 if (!dvmLinkClass(clazz)) {
1592 assert(dvmCheckException(self));
1593
1594 /* Make note of the error and clean up the class.
1595 */
1596 removeClassFromHash(clazz);
1597 clazz->status = CLASS_ERROR;
1598 dvmFreeClassInnards(clazz);
1599
1600 /* Let any waiters know.
1601 */
1602 clazz->initThreadId = 0;
1603 dvmObjectNotifyAll(self, (Object*) clazz);
1604 dvmUnlockObject(self, (Object*) clazz);
1605
1606 #if LOG_CLASS_LOADING
1607 ALOG(LOG_INFO, "DVMLINK FAILED FOR CLASS ", "%s in %s",
1608 clazz->descriptor, get_process_name());
1609
1610 /*
1611 * TODO: It would probably be better to use a new type code here (instead of '<') to
1612 * indicate the failure. This change would require a matching change in the parser
1613 * and analysis code in frameworks/base/tools/preload.
1614 */
1615 logClassLoad('<', clazz);
1616 #endif
1617 clazz = NULL;
1618 if (gDvm.optimizing) {
1619 /* happens with "external" libs */
1620 ALOGV("Link of class '%s' failed", descriptor);
1621 } else {
1622 ALOGW("Link of class '%s' failed", descriptor);
1623 }
1624 goto bail;
1625 }
1626 dvmObjectNotifyAll(self, (Object*) clazz);
1627 dvmUnlockObject(self, (Object*) clazz);
1628
1629 /*
1630 * Add class stats to global counters.
1631 *
1632 * TODO: these should probably be atomic ops.
1633 */
1634 gDvm.numLoadedClasses++;
1635 gDvm.numDeclaredMethods +=
1636 clazz->virtualMethodCount + clazz->directMethodCount;
1637 gDvm.numDeclaredInstFields += clazz->ifieldCount;
1638 gDvm.numDeclaredStaticFields += clazz->sfieldCount;
1639
1640 /*
1641 * Cache pointers to basic classes. We want to use these in
1642 * various places, and it's easiest to initialize them on first
1643 * use rather than trying to force them to initialize (startup
1644 * ordering makes it weird).
1645 */
1646 if (gDvm.classJavaLangObject == NULL &&
1647 strcmp(descriptor, "Ljava/lang/Object;") == 0)
1648 {
1649 /* It should be impossible to get here with anything
1650 * but the bootclasspath loader.
1651 */
1652 assert(loader == NULL);
1653 gDvm.classJavaLangObject = clazz;
1654 }
1655
1656 #if LOG_CLASS_LOADING
1657 logClassLoad('<', clazz);
1658 #endif
1659
1660 } else {
1661 got_class:
1662 if (!dvmIsClassLinked(clazz) && clazz->status != CLASS_ERROR) {
1663 /*
1664 * We can race with other threads for class linking. We should
1665 * never get here recursively; doing so indicates that two
1666 * classes have circular dependencies.
1667 *
1668 * One exception: we force discovery of java.lang.Class in
1669 * dvmLinkClass(), and Class has Object as its superclass. So
1670 * if the first thing we ever load is Object, we will init
1671 * Object->Class->Object. The easiest way to avoid this is to
1672 * ensure that Object is never the first thing we look up, so
1673 * we get Foo->Class->Object instead.
1674 */
1675 dvmLockObject(self, (Object*) clazz);
1676 if (!dvmIsClassLinked(clazz) &&
1677 clazz->initThreadId == self->threadId)
1678 {
1679 ALOGW("Recursive link on class %s", clazz->descriptor);
1680 dvmUnlockObject(self, (Object*) clazz);
1681 dvmThrowClassCircularityError(clazz->descriptor);
1682 clazz = NULL;
1683 goto bail;
1684 }
1685 //ALOGI("WAITING for '%s' (owner=%d)",
1686 // clazz->descriptor, clazz->initThreadId);
1687 while (!dvmIsClassLinked(clazz) && clazz->status != CLASS_ERROR) {
1688 dvmObjectWait(self, (Object*) clazz, 0, 0, false);
1689 }
1690 dvmUnlockObject(self, (Object*) clazz);
1691 }
1692 if (clazz->status == CLASS_ERROR) {
1693 /*
1694 * Somebody else tried to load this and failed. We need to raise
1695 * an exception and report failure.
1696 */
1697 throwEarlierClassFailure(clazz);
1698 clazz = NULL;
1699 goto bail;
1700 }
1701 }
1702
1703 /* check some invariants */
1704 assert(dvmIsClassLinked(clazz));
1705 assert(gDvm.classJavaLangClass != NULL);
1706 assert(clazz->clazz == gDvm.classJavaLangClass);
1707 assert(dvmIsClassObject(clazz));
1708 assert(clazz == gDvm.classJavaLangObject || clazz->super != NULL);
1709 if (!dvmIsInterfaceClass(clazz)) {
1710 //ALOGI("class=%s vtableCount=%d, virtualMeth=%d",
1711 // clazz->descriptor, clazz->vtableCount,
1712 // clazz->virtualMethodCount);
1713 assert(clazz->vtableCount >= clazz->virtualMethodCount);
1714 }
1715
1716 bail:
1717 if (profilerNotified)
1718 dvmMethodTraceClassPrepEnd();
1719 assert(clazz != NULL || dvmCheckException(self));
1720 return clazz;
1721 }
先看一下 dvmLookupClass 函数吧, 这样后面就好理解了
1121 ClassObject* dvmLookupClass(const char* descriptor, Object* loader,
1122 bool unprepOkay)
1123 {
1124 ClassMatchCriteria crit;
1125 void* found;
1126 u4 hash;
1127
1128 crit.descriptor = descriptor;
1129 crit.loader = loader;
1130 hash = dvmComputeUtf8Hash(descriptor);
1131
1132 LOGVV("threadid=%d: dvmLookupClass searching for '%s' %p",
1133 dvmThreadSelf()->threadId, descriptor, loader);
1134
1135 dvmHashTableLock(gDvm.loadedClasses);
1136 found = dvmHashTableLookup(gDvm.loadedClasses, hash, &crit,
1137 hashcmpClassByCrit, false);
1138 dvmHashTableUnlock(gDvm.loadedClasses);
1139
1140 /*
1141 * The class has been added to the hash table but isn't ready for use.
1142 * We're going to act like we didn't see it, so that the caller will
1143 * go through the full "find class" path, which includes locking the
1144 * object and waiting until it's ready. We could do that lock/wait
1145 * here, but this is an extremely rare case, and it's simpler to have
1146 * the wait-for-class code centralized.
1147 */
1148 if (found && !unprepOkay && !dvmIsClassLinked((ClassObject*)found)) {
1149 ALOGV("Ignoring not-yet-ready %s, using slow path",
1150 ((ClassObject*)found)->descriptor);
1151 found = NULL;
1152 }
1153
1154 return (ClassObject*) found;
1155 }
主要就是在 gDvm.loadedClasses 这个表中看看有没有我们要的类,这个表里记录了所有已经加载的类
回来往后看有一个超大的 if…else 两个分支一个是没有找到,一个是找到了,分开看
1506 if (clazz == NULL) {
1507 const DexClassDef* pClassDef;
1508
1509 dvmMethodTraceClassPrepBegin();
1510 profilerNotified = true;
1511
1512 #if LOG_CLASS_LOADING
1513 u8 startTime = dvmGetThreadCpuTimeNsec();
1514 #endif
1515
1516 if (pDvmDex == NULL) {
1517 assert(loader == NULL); /* shouldn't be here otherwise */
1518 pDvmDex = searchBootPathForClass(descriptor, &pClassDef);
1519 } else {
1520 pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
1521 }
1522
1523 if (pDvmDex == NULL || pClassDef == NULL) {
1524 if (gDvm.noClassDefFoundErrorObj != NULL) {
1525 /* usual case -- use prefabricated object */
1526 dvmSetException(self, gDvm.noClassDefFoundErrorObj);
1527 } else {
1528 /* dexopt case -- can't guarantee prefab (core.jar) */
1529 dvmThrowNoClassDefFoundError(descriptor);
1530 }
1531 goto bail;
1532 }
1533
1534 /* found a match, try to load it */
1535 clazz = loadClassFromDex(pDvmDex, pClassDef, loader);
1536 if (dvmCheckException(self)) {
1537 /* class was found but had issues */
1538 if (clazz != NULL) {
1539 dvmFreeClassInnards(clazz);
1540 dvmReleaseTrackedAlloc((Object*) clazz, NULL);
1541 }
1542 goto bail;
1543 }
1544
1545 /*
1546 * Lock the class while we link it so other threads must wait for us
1547 * to finish. Set the "initThreadId" so we can identify recursive
1548 * invocation. (Note all accesses to initThreadId here are
1549 * guarded by the class object's lock.)
1550 */
1551 dvmLockObject(self, (Object*) clazz);
1552 clazz->initThreadId = self->threadId;
1553
1554 /*
1555 * Add to hash table so lookups succeed.
1556 *
1557 * [Are circular references possible when linking a class?]
1558 */
1559 assert(clazz->classLoader == loader);
1560 if (!dvmAddClassToHash(clazz)) {
1561 /*
1562 * Another thread must have loaded the class after we
1563 * started but before we finished. Discard what we've
1564 * done and leave some hints for the GC.
1565 *
1566 * (Yes, this happens.)
1567 */
1568 //ALOGW("WOW: somebody loaded %s simultaneously", descriptor);
1569 clazz->initThreadId = 0;
1570 dvmUnlockObject(self, (Object*) clazz);
1571
1572 /* Let the GC free the class.
1573 */
1574 dvmFreeClassInnards(clazz);
1575 dvmReleaseTrackedAlloc((Object*) clazz, NULL);
1576
1577 /* Grab the winning class.
1578 */
1579 clazz = dvmLookupClass(descriptor, loader, true);
1580 assert(clazz != NULL);
1581 goto got_class;
1582 }
1583 dvmReleaseTrackedAlloc((Object*) clazz, NULL);
1584
1585 #if LOG_CLASS_LOADING
1586 logClassLoadWithTime('>', clazz, startTime);
1587 #endif
1588 /*
1589 * Prepare and resolve.
1590 */
1591 if (!dvmLinkClass(clazz)) {
1592 assert(dvmCheckException(self));
1593
1594 /* Make note of the error and clean up the class.
1595 */
1596 removeClassFromHash(clazz);
1597 clazz->status = CLASS_ERROR;
1598 dvmFreeClassInnards(clazz);
1599
1600 /* Let any waiters know.
1601 */
1602 clazz->initThreadId = 0;
1603 dvmObjectNotifyAll(self, (Object*) clazz);
1604 dvmUnlockObject(self, (Object*) clazz);
1605
1606 #if LOG_CLASS_LOADING
1607 ALOG(LOG_INFO, "DVMLINK FAILED FOR CLASS ", "%s in %s",
1608 clazz->descriptor, get_process_name());
1609
1610 /*
1611 * TODO: It would probably be better to use a new type code here (instead of '<') to
1612 * indicate the failure. This change would require a matching change in the parser
1613 * and analysis code in frameworks/base/tools/preload.
1614 */
1615 logClassLoad('<', clazz);
1616 #endif
1617 clazz = NULL;
1618 if (gDvm.optimizing) {
1619 /* happens with "external" libs */
1620 ALOGV("Link of class '%s' failed", descriptor);
1621 } else {
1622 ALOGW("Link of class '%s' failed", descriptor);
1623 }
1624 goto bail;
1625 }
1626 dvmObjectNotifyAll(self, (Object*) clazz);
1627 dvmUnlockObject(self, (Object*) clazz);
1628
1629 /*
1630 * Add class stats to global counters.
1631 *
1632 * TODO: these should probably be atomic ops.
1633 */
1634 gDvm.numLoadedClasses++;
1635 gDvm.numDeclaredMethods +=
1636 clazz->virtualMethodCount + clazz->directMethodCount;
1637 gDvm.numDeclaredInstFields += clazz->ifieldCount;
1638 gDvm.numDeclaredStaticFields += clazz->sfieldCount;
1639
1640 /*
1641 * Cache pointers to basic classes. We want to use these in
1642 * various places, and it's easiest to initialize them on first
1643 * use rather than trying to force them to initialize (startup
1644 * ordering makes it weird).
1645 */
1646 if (gDvm.classJavaLangObject == NULL &&
1647 strcmp(descriptor, "Ljava/lang/Object;") == 0)
1648 {
1649 /* It should be impossible to get here with anything
1650 * but the bootclasspath loader.
1651 */
1652 assert(loader == NULL);
1653 gDvm.classJavaLangObject = clazz;
1654 }
1655
1656 #if LOG_CLASS_LOADING
1657 logClassLoad('<', clazz);
1658 #endif
1659
1660 }
这里就是没从已经加载的表中找到,那么就只能从 dex 文件里把这个 class 抠出来。dexFindClass 就是干这事,先走流程一会看。往后走,判断 pDvmDex == NULL || pClassDef == NULL 要是成立就出问题了,要不就没有 odex 要不就是类找不到。找到了 pClassDef 有了 pDvmDex,就可以从 dex 中把类加载到内存了, loadClassFromDex 这个函数就是加载类。加载成功了之后就是把它加入到刚才提到的 gDvm.loadedClasses 表中,下次就好找了。最后就是链接这个类,最后更新一下各个参数,说明已经加载成功了。看看几个关键函数 dexFindClass
441 const DexClassDef* dexFindClass(const DexFile* pDexFile,
442 const char* descriptor)
443 {
444 const DexClassLookup* pLookup = pDexFile->pClassLookup;
445 u4 hash;
446 int idx, mask;
447
448 hash = classDescriptorHash(descriptor);
449 mask = pLookup->numEntries - 1;
450 idx = hash & mask;
451
452 /*
453 * Search until we find a matching entry or an empty slot.
454 */
455 while (true) {
456 int offset;
457
458 offset = pLookup->table[idx].classDescriptorOffset;
459 if (offset == 0)
460 return NULL;
461
462 if (pLookup->table[idx].classDescriptorHash == hash) {
463 const char* str;
464
465 str = (const char*) (pDexFile->baseAddr + offset);
466 if (strcmp(str, descriptor) == 0) {
467 return (const DexClassDef*)
468 (pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
469 }
470 }
471
472 idx = (idx + 1) & mask;
473 }
474 }
这个函数没什么好说的,就是遍历 dex 中的 pClassLookup 结构,下一个 loadClassFromDex
1953 static ClassObject* loadClassFromDex(DvmDex* pDvmDex,
1954 const DexClassDef* pClassDef, Object* classLoader)
1955 {
1956 ClassObject* result;
1957 DexClassDataHeader header;
1958 const u1* pEncodedData;
1959 const DexFile* pDexFile;
1960
1961 assert((pDvmDex != NULL) && (pClassDef != NULL));
1962 pDexFile = pDvmDex->pDexFile;
1963
1964 if (gDvm.verboseClass) {
1965 ALOGV("CLASS: loading '%s'...",
1966 dexGetClassDescriptor(pDexFile, pClassDef));
1967 }
1968
1969 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1970
1971 if (pEncodedData != NULL) {
1972 dexReadClassDataHeader(&pEncodedData, &header);
1973 } else {
1974 // Provide an all-zeroes header for the rest of the loading.
1975 memset(&header, 0, sizeof(header));
1976 }
1977
1978 result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData,
1979 classLoader);
1980
1981 if (gDvm.verboseClass && (result != NULL)) {
1982 ALOGI("[Loaded %s from DEX %p (cl=%p)]",
1983 result->descriptor, pDvmDex, classLoader);
1984 }
1985
1986 return result;
1987 }
首先还是解析 dex 结构,找的函数的数据部分,然后调用 loadClassFromDex0 进行实际的加载
1727 static ClassObject* loadClassFromDex0(DvmDex* pDvmDex,
1728 const DexClassDef* pClassDef, const DexClassDataHeader* pHeader,
1729 const u1* pEncodedData, Object* classLoader)
1730 {
1731 ClassObject* newClass = NULL;
1732 const DexFile* pDexFile;
1733 const char* descriptor;
1734 int i;
1735
1736 pDexFile = pDvmDex->pDexFile;
1737 descriptor = dexGetClassDescriptor(pDexFile, pClassDef);
1738
1739 /*
1740 * Make sure the aren't any "bonus" flags set, since we use them for
1741 * runtime state.
1742 */
1743 /* bits we can reasonably expect to see set in a DEX access flags field */
1744 const uint32_t EXPECTED_FILE_FLAGS = (ACC_CLASS_MASK | CLASS_ISPREVERIFIED |
1745 CLASS_ISOPTIMIZED);
1746 if ((pClassDef->accessFlags & ~EXPECTED_FILE_FLAGS) != 0) {
1747 ALOGW("Invalid file flags in class %s: %04x",
1748 descriptor, pClassDef->accessFlags);
1749 return NULL;
1750 }
1751
1752 /*
1753 * Allocate storage for the class object on the GC heap, so that other
1754 * objects can have references to it. We bypass the usual mechanism
1755 * (allocObject), because we don't have all the bits and pieces yet.
1756 *
1757 * Note that we assume that java.lang.Class does not override
1758 * finalize().
1759 */
1760 /* TODO: Can there be fewer special checks in the usual path? */
1761 assert(descriptor != NULL);
1762 if (classLoader == NULL &&
1763 strcmp(descriptor, "Ljava/lang/Class;") == 0) {
1764 assert(gDvm.classJavaLangClass != NULL);
1765 newClass = gDvm.classJavaLangClass;
1766 } else {
1767 size_t size = classObjectSize(pHeader->staticFieldsSize);
1768 newClass = (ClassObject*) dvmMalloc(size, ALLOC_NON_MOVING);
1769 }
1770 if (newClass == NULL)
1771 return NULL;
1772
1773 DVM_OBJECT_INIT(newClass, gDvm.classJavaLangClass);
1774 dvmSetClassSerialNumber(newClass);
1775 newClass->descriptor = descriptor;
1776 assert(newClass->descriptorAlloc == NULL);
1777 SET_CLASS_FLAG(newClass, pClassDef->accessFlags);
1778 dvmSetFieldObject((Object *)newClass,
1779 OFFSETOF_MEMBER(ClassObject, classLoader),
1780 (Object *)classLoader);
1781 newClass->pDvmDex = pDvmDex;
1782 newClass->primitiveType = PRIM_NOT;
1783 newClass->status = CLASS_IDX;
1784
1785 /*
1786 * Stuff the superclass index into the object pointer field. The linker
1787 * pulls it out and replaces it with a resolved ClassObject pointer.
1788 * I'm doing it this way (rather than having a dedicated superclassIdx
1789 * field) to save a few bytes of overhead per class.
1790 *
1791 * newClass->super is not traversed or freed by dvmFreeClassInnards, so
1792 * this is safe.
1793 */
1794 assert(sizeof(u4) == sizeof(ClassObject*)); /* 32-bit check */
1795 newClass->super = (ClassObject*) pClassDef->superclassIdx;
1796
1797 /*
1798 * Stuff class reference indices into the pointer fields.
1799 *
1800 * The elements of newClass->interfaces are not traversed or freed by
1801 * dvmFreeClassInnards, so this is GC-safe.
1802 */
1803 const DexTypeList* pInterfacesList;
1804 pInterfacesList = dexGetInterfacesList(pDexFile, pClassDef);
1805 if (pInterfacesList != NULL) {
1806 newClass->interfaceCount = pInterfacesList->size;
1807 newClass->interfaces = (ClassObject**) dvmLinearAlloc(classLoader,
1808 newClass->interfaceCount * sizeof(ClassObject*));
1809
1810 for (i = 0; i < newClass->interfaceCount; i++) {
1811 const DexTypeItem* pType = dexGetTypeItem(pInterfacesList, i);
1812 newClass->interfaces[i] = (ClassObject*)(u4) pType->typeIdx;
1813 }
1814 dvmLinearReadOnly(classLoader, newClass->interfaces);
1815 }
1816
1817 /* load field definitions */
1818
1819 /*
1820 * Over-allocate the class object and append static field info
1821 * onto the end. It's fixed-size and known at alloc time. This
1822 * seems to increase zygote sharing. Heap compaction will have to
1823 * be careful if it ever tries to move ClassObject instances,
1824 * because we pass Field pointers around internally. But at least
1825 * now these Field pointers are in the object heap.
1826 */
1827
1828 if (pHeader->staticFieldsSize != 0) {
1829 /* static fields stay on system heap; field data isn't "write once" */
1830 int count = (int) pHeader->staticFieldsSize;
1831 u4 lastIndex = 0;
1832 DexField field;
1833
1834 newClass->sfieldCount = count;
1835 for (i = 0; i < count; i++) {
1836 dexReadClassDataField(&pEncodedData, &field, &lastIndex);
1837 loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
1838 }
1839 }
1840
1841 if (pHeader->instanceFieldsSize != 0) {
1842 int count = (int) pHeader->instanceFieldsSize;
1843 u4 lastIndex = 0;
1844 DexField field;
1845
1846 newClass->ifieldCount = count;
1847 newClass->ifields = (InstField*) dvmLinearAlloc(classLoader,
1848 count * sizeof(InstField));
1849 for (i = 0; i < count; i++) {
1850 dexReadClassDataField(&pEncodedData, &field, &lastIndex);
1851 loadIFieldFromDex(newClass, &field, &newClass->ifields[i]);
1852 }
1853 dvmLinearReadOnly(classLoader, newClass->ifields);
1854 }
1855
1856 /*
1857 * Load method definitions. We do this in two batches, direct then
1858 * virtual.
1859 *
1860 * If register maps have already been generated for this class, and
1861 * precise GC is enabled, we pull out pointers to them. We know that
1862 * they were streamed to the DEX file in the same order in which the
1863 * methods appear.
1864 *
1865 * If the class wasn't pre-verified, the maps will be generated when
1866 * the class is verified during class initialization.
1867 */
1868 u4 classDefIdx = dexGetIndexForClassDef(pDexFile, pClassDef);
1869 const void* classMapData;
1870 u4 numMethods;
1871
1872 if (gDvm.preciseGc) {
1873 classMapData =
1874 dvmRegisterMapGetClassData(pDexFile, classDefIdx, &numMethods);
1875
1876 /* sanity check */
1877 if (classMapData != NULL &&
1878 pHeader->directMethodsSize + pHeader->virtualMethodsSize != numMethods)
1879 {
1880 ALOGE("ERROR: in %s, direct=%d virtual=%d, maps have %d",
1881 newClass->descriptor, pHeader->directMethodsSize,
1882 pHeader->virtualMethodsSize, numMethods);
1883 assert(false);
1884 classMapData = NULL; /* abandon */
1885 }
1886 } else {
1887 classMapData = NULL;
1888 }
1889
1890 if (pHeader->directMethodsSize != 0) {
1891 int count = (int) pHeader->directMethodsSize;
1892 u4 lastIndex = 0;
1893 DexMethod method;
1894
1895 newClass->directMethodCount = count;
1896 newClass->directMethods = (Method*) dvmLinearAlloc(classLoader,
1897 count * sizeof(Method));
1898 for (i = 0; i < count; i++) {
1899 dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
1900 loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
1901 if (classMapData != NULL) {
1902 const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
1903 if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
1904 newClass->directMethods[i].registerMap = pMap;
1905 /* TODO: add rigorous checks */
1906 assert((newClass->directMethods[i].registersSize+7) / 8 ==
1907 newClass->directMethods[i].registerMap->regWidth);
1908 }
1909 }
1910 }
1911 dvmLinearReadOnly(classLoader, newClass->directMethods);
1912 }
1913
1914 if (pHeader->virtualMethodsSize != 0) {
1915 int count = (int) pHeader->virtualMethodsSize;
1916 u4 lastIndex = 0;
1917 DexMethod method;
1918
1919 newClass->virtualMethodCount = count;
1920 newClass->virtualMethods = (Method*) dvmLinearAlloc(classLoader,
1921 count * sizeof(Method));
1922 for (i = 0; i < count; i++) {
1923 dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
1924 loadMethodFromDex(newClass, &method, &newClass->virtualMethods[i]);
1925 if (classMapData != NULL) {
1926 const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
1927 if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
1928 newClass->virtualMethods[i].registerMap = pMap;
1929 /* TODO: add rigorous checks */
1930 assert((newClass->virtualMethods[i].registersSize+7) / 8 ==
1931 newClass->virtualMethods[i].registerMap->regWidth);
1932 }
1933 }
1934 }
1935 dvmLinearReadOnly(classLoader, newClass->virtualMethods);
1936 }
1937
1938 newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);
1939
1940 /* caller must call dvmReleaseTrackedAlloc */
1941 return newClass;
1942 }
函数比较长,慢慢看。开始试一下文件权限检查,然后是参数检查,看看 loader 是不是要加载系统类,这里肯定不是,所以会走 dvmMalloc 这里开辟了一块内存,然后设置一些类的属性,然后就是设置接口、变量和方法信息,然后返回。加载到内存后就是链接,来看看 dvmLinkClass 都干了什么
2507 bool dvmLinkClass(ClassObject* clazz)
2508 {
2509 u4 superclassIdx = 0;
2510 u4 *interfaceIdxArray = NULL;
2511 bool okay = false;
2512 int i;
2513
2514 assert(clazz != NULL);
2515 assert(clazz->descriptor != NULL);
2516 assert(clazz->status == CLASS_IDX || clazz->status == CLASS_LOADED);
2517 if (gDvm.verboseClass)
2518 ALOGV("CLASS: linking '%s'...", clazz->descriptor);
2519
2520 assert(gDvm.classJavaLangClass != NULL);
2521 assert(clazz->clazz == gDvm.classJavaLangClass);
2522 assert(dvmIsClassObject(clazz));
2523 if (clazz->classLoader == NULL &&
2524 (strcmp(clazz->descriptor, "Ljava/lang/Class;") == 0))
2525 {
2526 if (gDvm.classJavaLangClass->ifieldCount > CLASS_FIELD_SLOTS) {
2527 ALOGE("java.lang.Class has %d instance fields (expected at most %d)",
2528 gDvm.classJavaLangClass->ifieldCount, CLASS_FIELD_SLOTS);
2529 dvmAbort();
2530 }
2531 if (gDvm.classJavaLangClass->sfieldCount != CLASS_SFIELD_SLOTS) {
2532 ALOGE("java.lang.Class has %d static fields (expected %d)",
2533 gDvm.classJavaLangClass->sfieldCount, CLASS_SFIELD_SLOTS);
2534 dvmAbort();
2535 }
2536 }
2537
2538 /* "Resolve" the class.
2539 *
2540 * At this point, clazz's reference fields may contain Dex file
2541 * indices instead of direct object references. Proxy objects are
2542 * an exception, and may be the only exception. We need to
2543 * translate those indices into real references, and let the GC
2544 * look inside this ClassObject.
2545 */
2546 if (clazz->status == CLASS_IDX) {
2547 if (clazz->interfaceCount > 0) {
2548 /* Copy u4 DEX idx values out of the ClassObject* array
2549 * where we stashed them.
2550 */
2551 assert(sizeof(*interfaceIdxArray) == sizeof(*clazz->interfaces));
2552 size_t len = clazz->interfaceCount * sizeof(*interfaceIdxArray);
2553 interfaceIdxArray = (u4*)malloc(len);
2554 if (interfaceIdxArray == NULL) {
2555 ALOGW("Unable to allocate memory to link %s", clazz->descriptor);
2556 goto bail;
2557 }
2558 memcpy(interfaceIdxArray, clazz->interfaces, len);
2559
2560 dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
2561 memset(clazz->interfaces, 0, len);
2562 dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
2563 }
2564
2565 assert(sizeof(superclassIdx) == sizeof(clazz->super));
2566 superclassIdx = (u4) clazz->super;
2567 clazz->super = NULL;
2568 /* After this line, clazz will be fair game for the GC. The
2569 * superclass and interfaces are all NULL.
2570 */
2571 clazz->status = CLASS_LOADED;
2572
2573 if (superclassIdx != kDexNoIndex) {
2574 ClassObject* super = dvmResolveClass(clazz, superclassIdx, false);
2575 if (super == NULL) {
2576 assert(dvmCheckException(dvmThreadSelf()));
2577 if (gDvm.optimizing) {
2578 /* happens with "external" libs */
2579 ALOGV("Unable to resolve superclass of %s (%d)",
2580 clazz->descriptor, superclassIdx);
2581 } else {
2582 ALOGW("Unable to resolve superclass of %s (%d)",
2583 clazz->descriptor, superclassIdx);
2584 }
2585 goto bail;
2586 }
2587 dvmSetFieldObject((Object *)clazz,
2588 OFFSETOF_MEMBER(ClassObject, super),
2589 (Object *)super);
2590 }
2591
2592 if (clazz->interfaceCount > 0) {
2593 /* Resolve the interfaces implemented directly by this class. */
2594 assert(interfaceIdxArray != NULL);
2595 dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
2596 for (i = 0; i < clazz->interfaceCount; i++) {
2597 assert(interfaceIdxArray[i] != kDexNoIndex);
2598 clazz->interfaces[i] =
2599 dvmResolveClass(clazz, interfaceIdxArray[i], false);
2600 if (clazz->interfaces[i] == NULL) {
2601 const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
2602
2603 assert(dvmCheckException(dvmThreadSelf()));
2604 dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
2605
2606 const char* classDescriptor;
2607 classDescriptor =
2608 dexStringByTypeIdx(pDexFile, interfaceIdxArray[i]);
2609 if (gDvm.optimizing) {
2610 /* happens with "external" libs */
2611 ALOGV("Failed resolving %s interface %d '%s'",
2612 clazz->descriptor, interfaceIdxArray[i],
2613 classDescriptor);
2614 } else {
2615 ALOGI("Failed resolving %s interface %d '%s'",
2616 clazz->descriptor, interfaceIdxArray[i],
2617 classDescriptor);
2618 }
2619 goto bail;
2620 }
2621
2622 /* are we allowed to implement this interface? */
2623 if (!dvmCheckClassAccess(clazz, clazz->interfaces[i])) {
2624 dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
2625 ALOGW("Interface '%s' is not accessible to '%s'",
2626 clazz->interfaces[i]->descriptor, clazz->descriptor);
2627 dvmThrowIllegalAccessError("interface not accessible");
2628 goto bail;
2629 }
2630 LOGVV("+++ found interface '%s'",
2631 clazz->interfaces[i]->descriptor);
2632 }
2633 dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
2634 }
2635 }
2636 /*
2637 * There are now Class references visible to the GC in super and
2638 * interfaces.
2639 */
2640
2641 /*
2642 * All classes have a direct superclass, except for
2643 * java/lang/Object and primitive classes. Primitive classes are
2644 * are created CLASS_INITIALIZED, so won't get here.
2645 */
2646 assert(clazz->primitiveType == PRIM_NOT);
2647 if (strcmp(clazz->descriptor, "Ljava/lang/Object;") == 0) {
2648 if (clazz->super != NULL) {
2649 /* TODO: is this invariant true for all java/lang/Objects,
2650 * regardless of the class loader? For now, assume it is.
2651 */
2652 dvmThrowClassFormatError("java.lang.Object has a superclass");
2653 goto bail;
2654 }
2655
2656 /* Don't finalize objects whose classes use the
2657 * default (empty) Object.finalize().
2658 */
2659 CLEAR_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
2660 } else {
2661 if (clazz->super == NULL) {
2662 dvmThrowLinkageError("no superclass defined");
2663 goto bail;
2664 }
2665 /* verify */
2666 if (dvmIsFinalClass(clazz->super)) {
2667 ALOGW("Superclass of '%s' is final '%s'",
2668 clazz->descriptor, clazz->super->descriptor);
2669 dvmThrowIncompatibleClassChangeError("superclass is final");
2670 goto bail;
2671 } else if (dvmIsInterfaceClass(clazz->super)) {
2672 ALOGW("Superclass of '%s' is interface '%s'",
2673 clazz->descriptor, clazz->super->descriptor);
2674 dvmThrowIncompatibleClassChangeError("superclass is an interface");
2675 goto bail;
2676 } else if (!dvmCheckClassAccess(clazz, clazz->super)) {
2677 ALOGW("Superclass of '%s' (%s) is not accessible",
2678 clazz->descriptor, clazz->super->descriptor);
2679 dvmThrowIllegalAccessError("superclass not accessible");
2680 goto bail;
2681 }
2682
2683 /* Inherit finalizability from the superclass. If this
2684 * class also overrides finalize(), its CLASS_ISFINALIZABLE
2685 * bit will already be set.
2686 */
2687 if (IS_CLASS_FLAG_SET(clazz->super, CLASS_ISFINALIZABLE)) {
2688 SET_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
2689 }
2690
2691 /* See if this class descends from java.lang.Reference
2692 * and set the class flags appropriately.
2693 */
2694 if (IS_CLASS_FLAG_SET(clazz->super, CLASS_ISREFERENCE)) {
2695 u4 superRefFlags;
2696
2697 /* We've already determined the reference type of this
2698 * inheritance chain. Inherit reference-ness from the superclass.
2699 */
2700 superRefFlags = GET_CLASS_FLAG_GROUP(clazz->super,
2701 CLASS_ISREFERENCE |
2702 CLASS_ISWEAKREFERENCE |
2703 CLASS_ISFINALIZERREFERENCE |
2704 CLASS_ISPHANTOMREFERENCE);
2705 SET_CLASS_FLAG(clazz, superRefFlags);
2706 } else if (clazz->classLoader == NULL &&
2707 clazz->super->classLoader == NULL &&
2708 strcmp(clazz->super->descriptor,
2709 "Ljava/lang/ref/Reference;") == 0)
2710 {
2711 u4 refFlags;
2712
2713 /* This class extends Reference, which means it should
2714 * be one of the magic Soft/Weak/PhantomReference classes.
2715 */
2716 refFlags = CLASS_ISREFERENCE;
2717 if (strcmp(clazz->descriptor,
2718 "Ljava/lang/ref/SoftReference;") == 0)
2719 {
2720 /* Only CLASS_ISREFERENCE is set for soft references.
2721 */
2722 } else if (strcmp(clazz->descriptor,
2723 "Ljava/lang/ref/WeakReference;") == 0)
2724 {
2725 refFlags |= CLASS_ISWEAKREFERENCE;
2726 } else if (strcmp(clazz->descriptor,
2727 "Ljava/lang/ref/FinalizerReference;") == 0)
2728 {
2729 refFlags |= CLASS_ISFINALIZERREFERENCE;
2730 } else if (strcmp(clazz->descriptor,
2731 "Ljava/lang/ref/PhantomReference;") == 0)
2732 {
2733 refFlags |= CLASS_ISPHANTOMREFERENCE;
2734 } else {
2735 /* No-one else is allowed to inherit directly
2736 * from Reference.
2737 */
2738 //xxx is this the right exception? better than an assertion.
2739 dvmThrowLinkageError("illegal inheritance from Reference");
2740 goto bail;
2741 }
2742
2743 /* The class should not have any reference bits set yet.
2744 */
2745 assert(GET_CLASS_FLAG_GROUP(clazz,
2746 CLASS_ISREFERENCE |
2747 CLASS_ISWEAKREFERENCE |
2748 CLASS_ISFINALIZERREFERENCE |
2749 CLASS_ISPHANTOMREFERENCE) == 0);
2750
2751 SET_CLASS_FLAG(clazz, refFlags);
2752 }
2753 }
2754
2755 /*
2756 * Populate vtable.
2757 */
2758 if (dvmIsInterfaceClass(clazz)) {
2759 /* no vtable; just set the method indices */
2760 int count = clazz->virtualMethodCount;
2761
2762 if (count != (u2) count) {
2763 ALOGE("Too many methods (%d) in interface '%s'", count,
2764 clazz->descriptor);
2765 goto bail;
2766 }
2767
2768 dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
2769
2770 for (i = 0; i < count; i++)
2771 clazz->virtualMethods[i].methodIndex = (u2) i;
2772
2773 dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
2774 } else {
2775 if (!createVtable(clazz)) {
2776 ALOGW("failed creating vtable");
2777 goto bail;
2778 }
2779 }
2780
2781 /*
2782 * Populate interface method tables. Can alter the vtable.
2783 */
2784 if (!createIftable(clazz))
2785 goto bail;
2786
2787 /*
2788 * Insert special-purpose "stub" method implementations.
2789 */
2790 if (!insertMethodStubs(clazz))
2791 goto bail;
2792
2793 /*
2794 * Compute instance field offsets and, hence, the size of the object.
2795 */
2796 if (!computeFieldOffsets(clazz))
2797 goto bail;
2798
2799 /*
2800 * Cache field and method info for the class Reference (as loaded
2801 * by the boot classloader). This has to happen after the call to
2802 * computeFieldOffsets().
2803 */
2804 if ((clazz->classLoader == NULL)
2805 && (strcmp(clazz->descriptor, "Ljava/lang/ref/Reference;") == 0)) {
2806 if (!precacheReferenceOffsets(clazz)) {
2807 ALOGE("failed pre-caching Reference offsets");
2808 dvmThrowInternalError(NULL);
2809 goto bail;
2810 }
2811 }
2812
2813 /*
2814 * Compact the offsets the GC has to examine into a bitmap, if
2815 * possible. (This has to happen after Reference.referent is
2816 * massaged in precacheReferenceOffsets.)
2817 */
2818 computeRefOffsets(clazz);
2819
2820 /*
2821 * Done!
2822 */
2823 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED))
2824 clazz->status = CLASS_VERIFIED;
2825 else
2826 clazz->status = CLASS_RESOLVED;
2827 okay = true;
2828 if (gDvm.verboseClass)
2829 ALOGV("CLASS: linked '%s'", clazz->descriptor);
2830
2831 /*
2832 * We send CLASS_PREPARE events to the debugger from here. The
2833 * definition of "preparation" is creating the static fields for a
2834 * class and initializing them to the standard default values, but not
2835 * executing any code (that comes later, during "initialization").
2836 *
2837 * We did the static prep in loadSFieldFromDex() while loading the class.
2838 *
2839 * The class has been prepared and resolved but possibly not yet verified
2840 * at this point.
2841 */
2842 if (gDvm.debuggerActive) {
2843 dvmDbgPostClassPrepare(clazz);
2844 }
2845
2846 bail:
2847 if (!okay) {
2848 clazz->status = CLASS_ERROR;
2849 if (!dvmCheckException(dvmThreadSelf())) {
2850 dvmThrowVirtualMachineError(NULL);
2851 }
2852 }
2853 if (interfaceIdxArray != NULL) {
2854 free(interfaceIdxArray);
2855 }
2856
2857 return okay;
2858 }
代码很长,但是不复杂,首先是处理当前类的接口类和父类,关键函数 dvmResolveClass 。
63 ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx,
64 bool fromUnverifiedConstant)
65 {
66 DvmDex* pDvmDex = referrer->pDvmDex;
67 ClassObject* resClass;
68 const char* className;
69
70 /*
71 * Check the table first -- this gets called from the other "resolve"
72 * methods.
73 */
74 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
75 if (resClass != NULL)
76 return resClass;
77
78 LOGVV("--- resolving class %u (referrer=%s cl=%p)",
79 classIdx, referrer->descriptor, referrer->classLoader);
80
81 /*
82 * Class hasn't been loaded yet, or is in the process of being loaded
83 * and initialized now. Try to get a copy. If we find one, put the
84 * pointer in the DexTypeId. There isn't a race condition here --
85 * 32-bit writes are guaranteed atomic on all target platforms. Worst
86 * case we have two threads storing the same value.
87 *
88 * If this is an array class, we'll generate it here.
89 */
90 className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
91 if (className[0] != '\0' && className[1] == '\0') {
92 /* primitive type */
93 resClass = dvmFindPrimitiveClass(className[0]);
94 } else {
95 resClass = dvmFindClassNoInit(className, referrer->classLoader);
96 }
97
98 if (resClass != NULL) {
99 /*
100 * If the referrer was pre-verified, the resolved class must come
101 * from the same DEX or from a bootstrap class. The pre-verifier
102 * makes assumptions that could be invalidated by a wacky class
103 * loader. (See the notes at the top of oo/Class.c.)
104 *
105 * The verifier does *not* fail a class for using a const-class
106 * or instance-of instruction referring to an unresolveable class,
107 * because the result of the instruction is simply a Class object
108 * or boolean -- there's no need to resolve the class object during
109 * verification. Instance field and virtual method accesses can
110 * break dangerously if we get the wrong class, but const-class and
111 * instance-of are only interesting at execution time. So, if we
112 * we got here as part of executing one of the "unverified class"
113 * instructions, we skip the additional check.
114 *
115 * Ditto for class references from annotations and exception
116 * handler lists.
117 */
118 if (!fromUnverifiedConstant &&
119 IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED))
120 {
121 ClassObject* resClassCheck = resClass;
122 if (dvmIsArrayClass(resClassCheck))
123 resClassCheck = resClassCheck->elementClass;
124
125 if (referrer->pDvmDex != resClassCheck->pDvmDex &&
126 resClassCheck->classLoader != NULL)
127 {
128 ALOGW("Class resolved by unexpected DEX:"
129 " %s(%p):%p ref [%s] %s(%p):%p",
130 referrer->descriptor, referrer->classLoader,
131 referrer->pDvmDex,
132 resClass->descriptor, resClassCheck->descriptor,
133 resClassCheck->classLoader, resClassCheck->pDvmDex);
134 ALOGW("(%s had used a different %s during pre-verification)",
135 referrer->descriptor, resClass->descriptor);
136 dvmThrowIllegalAccessError(
137 "Class ref in pre-verified class resolved to unexpected "
138 "implementation");
139 return NULL;
140 }
141 }
142
143 LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d",
144 resClass->descriptor, referrer->descriptor, referrer->pDvmDex,
145 referrer->classLoader, classIdx);
146
147 /*
148 * Add what we found to the list so we can skip the class search
149 * next time through.
150 *
151 * TODO: should we be doing this when fromUnverifiedConstant==true?
152 * (see comments at top of oo/Class.c)
153 */
154 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
155 } else {
156 /* not found, exception should be raised */
157 LOGVV("Class not found: %s",
158 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
159 assert(dvmCheckException(dvmThreadSelf()));
160 }
161
162 return resClass;
163 }
这个函数里又看到了 dvmFindClassNoInit, 也就是说父类或者接口类没有被加载的时候会再次走一遍之前的流程进行加载。在父类和接口类都加载好之后,要统计当前类的虚方法表, createVtable 使用这个函数,然后计算属性的大小 computeFieldOffsets 得出类的大小,一切就绪后程序返回,这个流程就结束了,就是在已加载列表中没有找到需要的类,就会自己去加载一份,malloc 申请内存,初始化类的属性、方法和父类。看后面的 else 就比较简单了,就是看一下找到的人这个类是不是已经链接好了。整个流程基本就结束了
总结
总结一下整个流程,加载一个类的时候首先 子类loader 层层委派父类 最后到达 Classloader.loadclass 方法,在这个方法中如果没有找到,就会调用子类的 findclass,也就是 BaseDexClassloader ,最终在使用 dex 类的 defineClass 进入native 层,在 native 层中参数层层传递来到 findClassNoInit,这个函数中回去申请内存创建一个新的类,或者从已经加载的列表中找到