/* * Get information about a field. */ bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo) { const DexFieldId* pFieldId; if (fieldIdx >= pDexFile->pHeader->fieldIdsSize) return false; pFieldId = dexGetFieldId(pDexFile, fieldIdx); pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx); pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); pFieldInfo->classDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx); return true; }
// Based on dvmResolveInstField/dvmResolveStaticField. static void preloadDexCachesResolveField(DvmDex* pDvmDex, uint32_t fieldIdx, bool instance) { Field* field = dvmDexGetResolvedField(pDvmDex, fieldIdx); if (field != NULL) { return; } const DexFile* pDexFile = pDvmDex->pDexFile; const DexFieldId* pFieldId = dexGetFieldId(pDexFile, fieldIdx); ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pFieldId->classIdx); if (clazz == NULL) { return; } // Skip static fields for uninitialized classes because a filled // cache entry implies the class is initialized. if (!instance && !dvmIsClassInitialized(clazz)) { return; } const char* fieldName = dexStringById(pDexFile, pFieldId->nameIdx); const char* signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); if (instance) { field = dvmFindInstanceFieldHier(clazz, fieldName, signature); } else { field = dvmFindStaticFieldHier(clazz, fieldName, signature); } if (field == NULL) { return; } // ALOGI("VMRuntime.preloadDexCaches found field %s %s.%s", // signature, clazz->descriptor, fieldName); dvmDexSetResolvedField(pDvmDex, fieldIdx, field); }
/* DexClassDef convenience - get superclass descriptor */ DEX_INLINE const char* dexGetSuperClassDescriptor(const DexFile* pDexFile, const DexClassDef* pClassDef) { if (pClassDef->superclassIdx == 0) return NULL; return dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx); }
CHAR const* get_class_name(DexFile * df, DexClassDef const* class_info) { IS_TRUE0(class_info); CHAR const* class_name = dexStringByTypeIdx(df, class_info->classIdx); IS_TRUE0(class_name); return class_name; }
CHAR const* AOC_DX_MGR::get_class_name_by_declaration_id(UINT cls_def_idx) { DexClassDef const* class_info = dexGetClassDef(m_df, cls_def_idx); CHAR const* class_name = dexStringByTypeIdx(m_df, class_info->classIdx); IS_TRUE0(class_name); return class_name; }
/* Perform static checks on a "new-array" instruction. Specifically, make sure they aren't creating an array of arrays that causes the number of dimensions to exceed 255. 对“new-instance”指令执行静态检查。具体来说,确保不会创建数组的维数超过255的数组 */ static bool checkNewArray(const DvmDex* pDvmDex, u4 idx) { const char* classDescriptor; if (idx >= pDvmDex->pHeader->typeIdsSize) { LOG_VFY("VFY: bad type index %d (max %d)", idx, pDvmDex->pHeader->typeIdsSize); return false; } classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx); int bracketCount = 0; const char* cp = classDescriptor; while (*cp++ == '[') bracketCount++; if (bracketCount == 0) { /* The given class must be an array type. */ LOG_VFY("VFY: can't new-array class '%s' (not an array)", classDescriptor); return false; } else if (bracketCount > 255) { /* It is illegal to create an array of more than 255 dimensions. */ LOG_VFY("VFY: can't new-array class '%s' (exceeds limit)", classDescriptor); return false; } return true; }
CHAR const* AOC_DX_MGR::get_class_name_by_method_id(UINT method_idx) { DexMethodId const* method_id = dexGetMethodId(m_df, method_idx); IS_TRUE0(method_id); CHAR const* class_name = dexStringByTypeIdx(m_df, method_id->classIdx); return class_name; }
//field_id: field number in dexfile. CHAR const* get_field_type_name(DexFile * df, UINT field_id) { DexFieldId const* fid = dexGetFieldId(df, field_id); IS_TRUE0(fid); //Get field's type name. return dexStringByTypeIdx(df, fid->typeIdx); }
/* * Dump an interface. */ void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem, int i) { const char* interfaceName = dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx); printf(" #%d : '%s'\n", i, interfaceName); }
/* * Dump a method. */ void dumpMethod(DexFile* pDexFile, const char* fileName, const DexMethod* pDexMethod, int i) { const DexMethodId* pMethodId; const DexCode* pCode; const char* classDescriptor; const char* methodName; int firstLine; /* abstract and native methods don't get listed */ if (pDexMethod->codeOff == 0) return; pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); methodName = dexStringById(pDexFile, pMethodId->nameIdx); classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); pCode = dexGetCode(pDexFile, pDexMethod); assert(pCode != NULL); /* * If the filename is empty, then set it to something printable * so that it is easier to parse. * * TODO: A method may override its class's default source file by * specifying a different one in its debug info. This possibility * should be handled here. */ if (fileName == NULL || fileName[0] == 0) { fileName = "(none)"; } firstLine = -1; dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx, pDexMethod->accessFlags, positionsCallback, NULL, &firstLine); char* className = descriptorToDot(classDescriptor); char* desc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); u4 insnsOff = pDexMethod->codeOff + offsetof(DexCode, insns); if (gParms.methodToFind != NULL && (strcmp(gParms.classToFind, className) != 0 || strcmp(gParms.methodToFind, methodName) != 0)) { goto skip; } printf("0x%08x %d %s %s %s %s %d\n", insnsOff, pCode->insnsSize * 2, className, methodName, desc, fileName, firstLine); skip: free(desc); free(className); }
/* * Resolve a static field reference. The DexFile format doesn't distinguish * between static and instance field references, so the "resolved" pointer * in the Dex struct will have the wrong type. We trivially cast it here. * * Causes the field's class to be initialized. */ StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexFieldId* pFieldId; StaticField* resField; pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); /* * Find the field's class. */ resClass = dvmResolveClass(referrer, pFieldId->classIdx, false); if (resClass == NULL) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } resField = dvmFindStaticFieldHier(resClass, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { dvmThrowNoSuchFieldError( dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); return NULL; } /* * If we're the first to resolve the field in which this class resides, * we need to do it now. Note that, if the field was inherited from * a superclass, it is not necessarily the same as "resClass". */ if (!dvmIsClassInitialized(resField->clazz) && !dvmInitClass(resField->clazz)) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } /* * If the class has been initialized, add a pointer to our data structure * so we don't have to jump through the hoops again. If it's still * initializing (i.e. this thread is executing <clinit>), don't do * the store, otherwise other threads could use the field without waiting * for class init to finish. */ if (dvmIsClassInitialized(resField->clazz)) { dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); } else { LOGVV("--- not caching resolved field %s.%s (class init=%d/%d)", resField->clazz->descriptor, resField->name, dvmIsClassInitializing(resField->clazz), dvmIsClassInitialized(resField->clazz)); } return resField; }
/* (documented in header file) */ const char* dexProtoGetReturnType(const DexProto* pProto) { #ifdef FASTIVA if (FASTIVA_IS_FASTIVA_PROTO(pProto)) { return d2f_getTypeDescriptor(FASTIVA_RET_TTYPE_ID(pProto)); } #endif const DexProtoId* protoId = getProtoId(pProto); return dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx); }
/* * 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; }
/* * Reads a type index as encoded for the debug info format, returning * a string pointer for its descriptor or NULL as appropriate. */ static const char* readTypeIdx(const DexFile* pDexFile, const u1** pStream) { u4 typeIdx = readUnsignedLeb128(pStream); // Remember, encoded type indicies have 1 added to them. if (typeIdx == 0) { return NULL; } else { return dexStringByTypeIdx(pDexFile, typeIdx - 1); } }
/* * Resolve an instance field reference. * * Returns NULL and throws an exception on error (no such field, illegal * access). */ InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexFieldId* pFieldId; InstField* resField; LOGVV("--- resolving field %u (referrer=%s cl=%p)", ifieldIdx, referrer->descriptor, referrer->classLoader); pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); /* * Find the field's class. */ resClass = dvmResolveClass(referrer, pFieldId->classIdx, false); if (resClass == NULL) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } resField = dvmFindInstanceFieldHier(resClass, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { dvmThrowNoSuchFieldError( dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); return NULL; } /* * Class must be initialized by now (unless verifier is buggy). We * could still be in the process of initializing it if the field * access is from a static initializer. */ assert(dvmIsClassInitialized(resField->clazz) || dvmIsClassInitializing(resField->clazz)); /* * The class is initialized (or initializing), the field has been * found. Add a pointer to our data structure so we don't have to * jump through the hoops again. * * Anything that uses the resolved table entry must have an instance * of the class, so any class init activity has already happened (or * been deliberately bypassed when <clinit> created an instance). * So it's always okay to update the table. */ dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField); LOGVV(" field %u is %s.%s", ifieldIdx, resField->clazz->descriptor, resField->name); return resField; }
/* * Dump the positions list. */ void dumpPositions(DexFile* pDexFile, const DexCode* pCode, const DexMethod *pDexMethod) { printf(" positions : \n"); const DexMethodId *pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); const char *classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx, pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL); }
const char* fastiva_dexGetReturnTypeDescriptor(const DexProto* pProto) { if (FASTIVA_IS_FASTIVA_PROTO(pProto)) { int ret_t = FASTIVA_RET_TTYPE_ID(pProto); const char* desc = d2f_getTypeDescriptor(ret_t); return desc; } else { const DexProtoId* protoId = getProtoId(pProto); const char* desc = dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx); return desc; } }
/* * Create the class lookup hash table. * * Returns newly-allocated storage. */ DexClassLookup* dexCreateClassLookup(DexFile* pDexFile) { DexClassLookup* pLookup; int allocSize; int i, numEntries; int numProbes, totalProbes, maxProbes; numProbes = totalProbes = maxProbes = 0; assert(pDexFile != NULL); /* * Using a factor of 3 results in far less probing than a factor of 2, * but almost doubles the flash storage requirements for the bootstrap * DEX files. The overall impact on class loading performance seems * to be minor. We could probably get some performance improvement by * using a secondary hash. */ numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2); allocSize = offsetof(DexClassLookup, table) + numEntries * sizeof(pLookup->table[0]); pLookup = (DexClassLookup*) calloc(1, allocSize); if (pLookup == NULL) return NULL; pLookup->size = allocSize; pLookup->numEntries = numEntries; for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) { const DexClassDef* pClassDef; const char* pString; pClassDef = dexGetClassDef(pDexFile, i); pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); classLookupAdd(pDexFile, pLookup, (u1*)pString - pDexFile->baseAddr, (u1*)pClassDef - pDexFile->baseAddr, &numProbes); if (numProbes > maxProbes) maxProbes = numProbes; totalProbes += numProbes; } LOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d" " total=%d max=%d\n", pDexFile->pHeader->classDefsSize, numEntries, (100 * pDexFile->pHeader->classDefsSize) / numEntries, allocSize, totalProbes, maxProbes); return pLookup; }
/* * Dump an instance field. */ void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i) { const DexFieldId* pFieldId; const char* backDescriptor; const char* name; const char* typeDescriptor; char* accessStr; pFieldId = dexGetFieldId(pDexFile, pIField->fieldIdx); name = dexStringById(pDexFile, pFieldId->nameIdx); typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx); accessStr = createAccessFlagStr(pIField->accessFlags, kAccessForField); printf(" #%d : (in %s)\n", i, backDescriptor); printf(" name : '%s'\n", name); printf(" type : '%s'\n", typeDescriptor); printf(" access : 0x%04x (%s)\n", pIField->accessFlags, accessStr); free(accessStr); }
/* * Get information about a method. */ bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo) { const DexMethodId* pMethodId; if (methodIdx >= pDexFile->pHeader->methodIdsSize) return false; pMethodId = dexGetMethodId(pDexFile, methodIdx); pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx); pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); pMethInfo->classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); return true; }
/* * Induce verification on all classes loaded from this DEX file as part * of pre-verification and optimization. This is never called from a * normally running VM. * * Returns "true" when all classes have been processed. */ bool dvmVerifyAllClasses(DexFile* pDexFile) { u4 count = pDexFile->pHeader->classDefsSize; u4 idx; assert(gDvm.optimizing); if (gDvm.classVerifyMode == VERIFY_MODE_NONE) { LOGV("+++ verification is disabled, skipping all classes\n"); return true; } if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE && gDvm.optimizingBootstrapClass) { LOGV("+++ verification disabled for bootstrap classes\n"); return true; } for (idx = 0; idx < count; idx++) { const DexClassDef* pClassDef; const char* classDescriptor; ClassObject* clazz; pClassDef = dexGetClassDef(pDexFile, idx); classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); /* all classes are loaded into the bootstrap class loader */ clazz = dvmLookupClass(classDescriptor, NULL, false); if (clazz != NULL) { if (clazz->pDvmDex->pDexFile != pDexFile) { LOGD("DexOpt: not verifying '%s': multiple definitions\n", classDescriptor); } else { if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) { assert((clazz->accessFlags & JAVA_FLAGS_MASK) == pClassDef->accessFlags); ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED; } /* keep going even if one fails */ } } else { LOGV("DexOpt: +++ not verifying '%s'\n", classDescriptor); } } return true; }
/* * Resolve an instance field reference. * * Returns NULL and throws an exception on error (no such field, illegal * access). */ InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexFieldId* pFieldId; InstField* resField; LOGVV("--- resolving field %u (referrer=%s cl=%p)\n", ifieldIdx, referrer->descriptor, referrer->classLoader); pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); /* * Find the field's class. */ resClass = dvmResolveClass(referrer, pFieldId->classIdx, false); if (resClass == NULL) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } resField = dvmFindInstanceFieldHier(resClass, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { dvmThrowException("Ljava/lang/NoSuchFieldError;", dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); return NULL; } /* * Class must be initialized by now (unless verifier is buggy). We * could still be in the process of initializing it if the field * access is from a static initializer. */ assert(dvmIsClassInitialized(resField->field.clazz) || dvmIsClassInitializing(resField->field.clazz)); /* * The class is initialized, the method has been found. Add a pointer * to our data structure so we don't have to jump through the hoops again. */ dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField); LOGVV(" field %u is %s.%s\n", ifieldIdx, resField->field.clazz->descriptor, resField->field.name); return resField; }
/* * Get the type descriptor for the next parameter, if any. This returns * NULL if the last parameter has already been consumed. */ const char* dexParameterIteratorNextDescriptor( DexParameterIterator* pIterator) { #ifdef FASTIVA if (pIterator->proto == NULL) { int id = ((JNI_ArgIterator*)pIterator)->nextID(); return d2f_getTypeDescriptor(id); } #endif u4 idx = dexParameterIteratorNextIndex(pIterator); if (idx == kDexNoIndex) { return NULL; } return dexStringByTypeIdx(pIterator->proto->dexFile, idx); }
/* * Resolve a static field reference. The DexFile format doesn't distinguish * between static and instance field references, so the "resolved" pointer * in the Dex struct will have the wrong type. We trivially cast it here. * * Causes the field's class to be initialized. */ StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexFieldId* pFieldId; StaticField* resField; pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); /* * Find the field's class. */ resClass = dvmResolveClass(referrer, pFieldId->classIdx, false); if (resClass == NULL) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } resField = dvmFindStaticFieldHier(resClass, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { dvmThrowException("Ljava/lang/NoSuchFieldError;", dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); return NULL; } /* * If we're the first to resolve the field in which this class resides, * we need to do it now. Note that, if the field was inherited from * a superclass, it is not necessarily the same as "resClass". */ if (!dvmIsClassInitialized(resField->field.clazz) && !dvmInitClass(resField->field.clazz)) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } /* * The class is initialized, the method has been found. Add a pointer * to our data structure so we don't have to jump through the hoops again. */ dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); return resField; }
/* * private static String[] getClassNameList(int cookie) * * Returns a String array that holds the names of all classes in the * specified DEX file. */ static void Dalvik_dalvik_system_DexFile_getClassNameList(const u4* args, JValue* pResult) { int cookie = args[0]; DexOrJar* pDexOrJar = (DexOrJar*) cookie; DvmDex* pDvmDex; DexFile* pDexFile; ArrayObject* stringArray; Thread* self = dvmThreadSelf(); if (!validateCookie(cookie)) RETURN_VOID(); if (pDexOrJar->isDex) pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile); else pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile); assert(pDvmDex != NULL); pDexFile = pDvmDex->pDexFile; int count = pDexFile->pHeader->classDefsSize; stringArray = dvmAllocObjectArray(gDvm.classJavaLangString, count, ALLOC_DEFAULT); if (stringArray == NULL) { /* probably OOM */ ALOGD("Failed allocating array of %d strings\n", count); assert(dvmCheckException(self)); RETURN_VOID(); } int i; for (i = 0; i < count; i++) { const DexClassDef* pClassDef = dexGetClassDef(pDexFile, i); const char* descriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); char* className = dvmDescriptorToDot(descriptor); StringObject* str = dvmCreateStringFromCstr(className); dvmSetObjectArrayElement(stringArray, i, (Object *)str); dvmReleaseTrackedAlloc((Object *)str, self); free(className); } dvmReleaseTrackedAlloc((Object*)stringArray, self); RETURN_PTR(stringArray); }
/* * Verify and/or optimize all classes that were successfully loaded from * this DEX file. */ static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify, bool doOpt) { u4 count = pDexFile->pHeader->classDefsSize; u4 idx; /* * Create a data structure for use by the bytecode optimizer. We * stuff it into a global so we don't have to pass it around as * a function argument. * * We could create this at VM startup, but there's no need to do so * unless we're optimizing, which means we're in dexopt, and we're * only going to call here once. */ if (doOpt) { gDvm.inlineSubs = dvmCreateInlineSubsTable(); if (gDvm.inlineSubs == NULL) return; } for (idx = 0; idx < count; idx++) { const DexClassDef* pClassDef; const char* classDescriptor; ClassObject* clazz; pClassDef = dexGetClassDef(pDexFile, idx); classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); /* all classes are loaded into the bootstrap class loader */ clazz = dvmLookupClass(classDescriptor, NULL, false); if (clazz != NULL) { verifyAndOptimizeClass(pDexFile, clazz, pClassDef, doVerify, doOpt); } else { // TODO: log when in verbose mode LOGV("DexOpt: not optimizing unavailable class '%s'\n", classDescriptor); } } if (gDvm.inlineSubs != NULL) { dvmFreeInlineSubsTable(gDvm.inlineSubs); gDvm.inlineSubs = NULL; } }
/* * Verify and/or optimize a specific class. */ static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz, const DexClassDef* pClassDef, bool doVerify, bool doOpt) { const char* classDescriptor; bool verified = false; classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); /* * First, try to verify it. */ if (doVerify) { if (clazz->pDvmDex->pDexFile != pDexFile) { LOGD("DexOpt: not verifying '%s': multiple definitions\n", classDescriptor); } else { if (dvmVerifyClass(clazz)) { /* * Set the "is preverified" flag in the DexClassDef. We * do it here, rather than in the ClassObject structure, * because the DexClassDef is part of the odex file. */ assert((clazz->accessFlags & JAVA_FLAGS_MASK) == pClassDef->accessFlags); ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED; verified = true; } else { // TODO: log when in verbose mode LOGV("DexOpt: '%s' failed verification\n", classDescriptor); } } } if (doOpt) { if (!verified && gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED) { LOGV("DexOpt: not optimizing '%s': not verified\n", classDescriptor); } else { dvmOptimizeClass(clazz, false); /* set the flag whether or not we actually changed anything */ ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISOPTIMIZED; } } }
/* Perform static checks on a "new-instance" instruction. Specifically, make sure the class reference isn't for an array class. We don't need the actual class, just a pointer to the class name. 对“new-instance”指令执行静态检查。具体来说,确保类引用不是一个数组类。 不需要真实的类,只是类名指针就可以。 */ static bool checkNewInstance(const DvmDex* pDvmDex, u4 idx) { const char* classDescriptor; if (idx >= pDvmDex->pHeader->typeIdsSize) { LOG_VFY("VFY: bad type index %d (max %d)", idx, pDvmDex->pHeader->typeIdsSize); return false; } classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx); if (classDescriptor[0] != 'L') { LOG_VFY("VFY: can't call new-instance on type '%s'", classDescriptor); return false; } return true; }
/* * private static String[] getClassNameList(int cookie) * * Returns a String array that holds the names of all classes in the * specified DEX file. */ static void Dalvik_dalvik_system_DexFile_getClassNameList(const u4* args, JValue* pResult) { int cookie = args[0]; DexOrJar* pDexOrJar = (DexOrJar*) cookie; DvmDex* pDvmDex; DexFile* pDexFile; ArrayObject* stringArray; if (!validateCookie(cookie)) RETURN_VOID(); if (pDexOrJar->isDex) pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile); else pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile); assert(pDvmDex != NULL); pDexFile = pDvmDex->pDexFile; int count = pDexFile->pHeader->classDefsSize; stringArray = dvmAllocObjectArray(gDvm.classJavaLangString, count, ALLOC_DEFAULT); if (stringArray == NULL) RETURN_VOID(); // should be an OOM pending StringObject** contents = (StringObject**) stringArray->contents; int i; for (i = 0; i < count; i++) { const DexClassDef* pClassDef = dexGetClassDef(pDexFile, i); const char* descriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); char* className = dvmDescriptorToDot(descriptor); contents[i] = dvmCreateStringFromCstr(className, ALLOC_DEFAULT); dvmReleaseTrackedAlloc((Object*) contents[i], NULL); free(className); } dvmReleaseTrackedAlloc((Object*)stringArray, NULL); RETURN_PTR(stringArray); }
/* * Dump the catches table associated with the code. */ void dumpCatches(DexFile* pDexFile, const DexCode* pCode) { u4 triesSize = pCode->triesSize; if (triesSize == 0) { printf(" catches : (none)\n"); return; } printf(" catches : %d\n", triesSize); const DexTry* pTries = dexGetTries(pCode); u4 i; for (i = 0; i < triesSize; i++) { const DexTry* pTry = &pTries[i]; u4 start = pTry->startAddr; u4 end = start + pTry->insnCount; DexCatchIterator iterator; printf(" 0x%04x - 0x%04x\n", start, end); dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff); for (;;) { DexCatchHandler* handler = dexCatchIteratorNext(&iterator); const char* descriptor; if (handler == NULL) { break; } descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" : dexStringByTypeIdx(pDexFile, handler->typeIdx); printf(" %s -> 0x%04x\n", descriptor, handler->address); } } }