Android Dalvik 下的类加载

前言

之前了解了 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,这个函数中回去申请内存创建一个新的类,或者从已经加载的列表中找到

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值