/* * Try to load all classes in the specified DEX. If they have some sort * of broken dependency, e.g. their superclass lives in a different DEX * that wasn't previously loaded into the bootstrap class path, loading * will fail. This is the desired behavior. * * We have no notion of class loader at this point, so we load all of * the classes with the bootstrap class loader. It turns out this has * exactly the behavior we want, and has no ill side effects because we're * running in a separate process and anything we load here will be forgotten. * * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions. * This works because we only call here as part of optimization / pre-verify, * not during verification as part of loading a class into a running VM. * * This returns "false" if the world is too screwed up to do anything * useful at all. */ static bool loadAllClasses(DvmDex* pDvmDex) { u4 count = pDvmDex->pDexFile->pHeader->classDefsSize; u4 idx; int loaded = 0; LOGV("DexOpt: +++ trying to load %d classes\n", count); dvmSetBootPathExtraDex(pDvmDex); /* * We have some circularity issues with Class and Object that are most * easily avoided by ensuring that Object is never the first thing we * try to find. Take care of that here. (We only need to do this when * loading classes from the DEX file that contains Object, and only * when Object comes first in the list, but it costs very little to * do it in all cases.) */ if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) { LOGE("ERROR: java.lang.Class does not exist!\n"); return false; } for (idx = 0; idx < count; idx++) { const DexClassDef* pClassDef; const char* classDescriptor; ClassObject* newClass; pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx); classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx); LOGV("+++ loading '%s'", classDescriptor); //newClass = dvmDefineClass(pDexFile, classDescriptor, // NULL); newClass = dvmFindSystemClassNoInit(classDescriptor); if (newClass == NULL) { LOGV("DexOpt: failed loading '%s'\n", classDescriptor); dvmClearOptException(dvmThreadSelf()); } else if (newClass->pDvmDex != pDvmDex) { /* * We don't load the new one, and we tag the first one found * with the "multiple def" flag so the resolver doesn't try * to make it available. */ LOGD("DexOpt: '%s' has an earlier definition; blocking out\n", classDescriptor); SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS); } else { loaded++; } } LOGV("DexOpt: +++ successfully loaded %d classes\n", loaded); dvmSetBootPathExtraDex(NULL); return true; }
/* * Alternate version of dvmResolveClass for use with verification and * optimization. Performs access checks on every resolve, and refuses * to acknowledge the existence of classes defined in more than one DEX * file. * * Exceptions caused by failures are cleared before returning. * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; /* * Check the table first. If not there, do the lookup by name. */ resClass = dvmDexGetResolvedClass(pDvmDex, classIdx); if (resClass == NULL) { const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx); if (className[0] != '\0' && className[1] == '\0') { /* primitive type */ resClass = dvmFindPrimitiveClass(className[0]); } else { resClass = dvmFindClassNoInit(className, referrer->classLoader); } if (resClass == NULL) { /* not found, exception should be raised */ ALOGV("DexOpt: class %d (%s) not found", classIdx, dexStringByTypeIdx(pDvmDex->pDexFile, classIdx)); if (pFailure != NULL) { /* dig through the wrappers to find the original failure */ Object* excep = dvmGetException(dvmThreadSelf()); while (true) { Object* cause = dvmGetExceptionCause(excep); if (cause == NULL) break; excep = cause; } if (strcmp(excep->clazz->descriptor, "Ljava/lang/IncompatibleClassChangeError;") == 0) { *pFailure = VERIFY_ERROR_CLASS_CHANGE; } else { *pFailure = VERIFY_ERROR_NO_CLASS; } } dvmClearOptException(dvmThreadSelf()); return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. */ dvmDexSetResolvedClass(pDvmDex, classIdx, resClass); } /* multiple definitions? */ if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) { ALOGI("DexOpt: not resolving ambiguous class '%s'", resClass->descriptor); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_CLASS; return NULL; } /* access allowed? */ tweakLoader(referrer, resClass); bool allowed = dvmCheckClassAccess(referrer, resClass); untweakLoader(referrer, resClass); if (!allowed) { ALOGW("DexOpt: resolve class illegal access: %s -> %s", referrer->descriptor, resClass->descriptor); if (pFailure != NULL) *pFailure = VERIFY_ERROR_ACCESS_CLASS; return NULL; } return resClass; }