/* * 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; }
/* * Create a "stock instance" of an exception class. */ static Object* createStockException(const char* descriptor, const char* msg) { Thread* self = dvmThreadSelf(); StringObject* msgStr = NULL; ClassObject* clazz; Method* init; Object* obj; /* find class, initialize if necessary */ clazz = dvmFindSystemClass(descriptor); if (clazz == NULL) { LOGE("Unable to find %s", descriptor); return NULL; } init = dvmFindDirectMethodByDescriptor(clazz, "<init>", "(Ljava/lang/String;)V"); if (init == NULL) { LOGE("Unable to find String-arg constructor for %s", descriptor); return NULL; } obj = dvmAllocObject(clazz, ALLOC_DEFAULT); if (obj == NULL) return NULL; if (msg == NULL) { msgStr = NULL; } else { msgStr = dvmCreateStringFromCstr(msg); if (msgStr == NULL) { LOGW("Could not allocate message string \"%s\"", msg); dvmReleaseTrackedAlloc(obj, self); return NULL; } } JValue unused; dvmCallMethod(self, init, obj, &unused, msgStr); if (dvmCheckException(self)) { dvmReleaseTrackedAlloc((Object*) msgStr, self); dvmReleaseTrackedAlloc(obj, self); return NULL; } dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL return obj; }
bool dvmGcStartupClasses() { ClassObject *klass = dvmFindSystemClass("Ljava/lang/Daemons;"); if (klass == NULL) { return false; } Method *method = dvmFindDirectMethodByDescriptor(klass, "start", "()V"); if (method == NULL) { return false; } Thread *self = dvmThreadSelf(); assert(self != NULL); JValue unusedResult; dvmCallMethod(self, method, NULL, &unusedResult); return true; }
/* * Wrap the now-pending exception in a different exception. This is useful * for reflection stuff that wants to hand a checked exception back from a * method that doesn't declare it. * * If something fails, an (unchecked) exception related to that failure * will be pending instead. */ void dvmWrapException(const char* newExcepStr) { Thread* self = dvmThreadSelf(); Object* origExcep; ClassObject* iteClass; origExcep = dvmGetException(self); dvmAddTrackedAlloc(origExcep, self); // don't let the GC free it dvmClearException(self); // clear before class lookup iteClass = dvmFindSystemClass(newExcepStr); if (iteClass != NULL) { Object* iteExcep; Method* initMethod; iteExcep = dvmAllocObject(iteClass, ALLOC_DEFAULT); if (iteExcep != NULL) { initMethod = dvmFindDirectMethodByDescriptor(iteClass, "<init>", "(Ljava/lang/Throwable;)V"); if (initMethod != NULL) { JValue unused; dvmCallMethod(self, initMethod, iteExcep, &unused, origExcep); /* if <init> succeeded, replace the old exception */ if (!dvmCheckException(self)) dvmSetException(self, iteExcep); } dvmReleaseTrackedAlloc(iteExcep, NULL); /* if initMethod doesn't exist, or failed... */ if (!dvmCheckException(self)) dvmSetException(self, origExcep); } else { /* leave OutOfMemoryError pending */ } } else { /* leave ClassNotFoundException pending */ } assert(dvmCheckException(self)); dvmReleaseTrackedAlloc(origExcep, self); }
/* * Create a wrapper object for a primitive data type. If "returnType" is * not primitive, this just casts "value" to an object and returns it. * * We could invoke the "toValue" method on the box types to take * advantage of pre-created values, but running that through the * interpreter is probably less efficient than just allocating storage here. * * The caller must call dvmReleaseTrackedAlloc on the result. */ DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType) { ClassObject* wrapperClass; DataObject* wrapperObj; s4* dataPtr; PrimitiveType typeIndex = returnType->primitiveType; const char* classDescriptor; if (typeIndex == PRIM_NOT) { /* add to tracking table so return value is always in table */ if (value.l != NULL) dvmAddTrackedAlloc((Object*)value.l, NULL); return (DataObject*) value.l; } classDescriptor = dexGetBoxedTypeDescriptor(typeIndex); if (classDescriptor == NULL) { return NULL; } wrapperClass = dvmFindSystemClass(classDescriptor); if (wrapperClass == NULL) { ALOGW("Unable to find '%s'", classDescriptor); assert(dvmCheckException(dvmThreadSelf())); return NULL; } wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); if (wrapperObj == NULL) return NULL; dataPtr = (s4*) wrapperObj->instanceData; /* assumes value is stored in first instance field */ /* (see dvmValidateBoxClasses) */ if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) *(s8*)dataPtr = value.j; else *dataPtr = value.i; return wrapperObj; }
/* * Create a Throwable and throw an exception in the current thread (where * "throwing" just means "set the thread's exception pointer"). * * "msg" and/or "cause" may be NULL. * * If we have a bad exception hierarchy -- something in Throwable.<init> * is missing -- then every attempt to throw an exception will result * in another exception. Exceptions are generally allowed to "chain" * to other exceptions, so it's hard to auto-detect this problem. It can * only happen if the system classes are broken, so it's probably not * worth spending cycles to detect it. * * We do have one case to worry about: if the classpath is completely * wrong, we'll go into a death spin during startup because we can't find * the initial class and then we can't find NoClassDefFoundError. We have * to handle this case. * * [Do we want to cache pointers to common exception classes?] */ void dvmThrowChainedException(const char* exceptionDescriptor, const char* msg, Object* cause) { ClassObject* excepClass; LOGV("THROW '%s' msg='%s' cause=%s\n", exceptionDescriptor, msg, (cause != NULL) ? cause->clazz->descriptor : "(none)"); if (gDvm.initializing) { if (++gDvm.initExceptionCount >= 2) { LOGE("Too many exceptions during init (failed on '%s' '%s')\n", exceptionDescriptor, msg); dvmAbort(); } } excepClass = dvmFindSystemClass(exceptionDescriptor); if (excepClass == NULL) { /* * We couldn't find the exception class. The attempt to find a * nonexistent class should have raised an exception. If no * exception is currently raised, then we're pretty clearly unable * to throw ANY sort of exception, and we need to pack it in. * * If we were able to throw the "class load failed" exception, * stick with that. Ideally we'd stuff the original exception * into the "cause" field, but since we can't find it we can't * do that. The exception class name should be in the "message" * field. */ if (!dvmCheckException(dvmThreadSelf())) { LOGE("FATAL: unable to throw exception (failed on '%s' '%s')\n", exceptionDescriptor, msg); dvmAbort(); } return; } dvmThrowChainedExceptionByClass(excepClass, msg, cause); }
static bool initFinalizerReference() { gDvm.classJavaLangRefFinalizerReference = dvmFindSystemClass("Ljava/lang/ref/FinalizerReference;"); return gDvm.classJavaLangRefFinalizerReference != NULL; }