/* * Common code for dvmCallMethodV/A and dvmInvokeMethod. * * Pushes a call frame on, advancing self->interpSave.curFrame. */ static ClassObject* callPrep(Thread* self, const Method* method, Object* obj, bool checkAccess) { ClassObject* clazz; #ifndef NDEBUG if (self->status != THREAD_RUNNING) { ALOGW("threadid=%d: status=%d on call to %s.%s -", self->threadId, self->status, method->clazz->descriptor, method->name); } #endif assert(self != NULL); assert(method != NULL); if (obj != NULL) clazz = obj->clazz; else clazz = method->clazz; //salma // __android_log_print(ANDROID_LOG_DEBUG, "DVM DEBUG","call prep: methodclazz=%s, methodname=%s", clazz->descriptor, method->name); //endsalma IF_LOGVV() { char* desc = dexProtoCopyMethodDescriptor(&method->prototype); LOGVV("thread=%d native code calling %s.%s %s", self->threadId, clazz->descriptor, method->name, desc); free(desc); } if (checkAccess) { /* needed for java.lang.reflect.Method.invoke */ if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame), method)) { /* note this throws IAException, not IAError */ dvmThrowIllegalAccessException("access to method denied"); return NULL; } } /* * Push a call frame on. If there isn't enough room for ins, locals, * outs, and the saved state, it will throw an exception. * * This updates self->interpSave.curFrame. */ if (dvmIsNativeMethod(method)) { /* native code calling native code the hard way */ if (!dvmPushJNIFrame(self, method)) { assert(dvmCheckException(self)); return NULL; } } else { /* native code calling interpreted code */ if (!dvmPushInterpFrame(self, method)) { assert(dvmCheckException(self)); return NULL; } } return clazz; }
/* * Alternate version of dvmResolveMethod(). * * Doesn't throw exceptions, and checks access on every lookup. * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx, MethodType methodType, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; Method* resMethod; assert(methodType == METHOD_DIRECT || methodType == METHOD_VIRTUAL || methodType == METHOD_STATIC); LOGVV("--- resolving method %u (referrer=%s)", methodIdx, referrer->descriptor); resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx); if (resMethod == NULL) { const DexMethodId* pMethodId; ClassObject* resClass; pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure); if (resClass == NULL) { /* * Can't find the class that the method is a part of, or don't * have permission to access the class. */ ALOGV("DexOpt: can't find called method's class (?.%s)", dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } return NULL; } if (dvmIsInterfaceClass(resClass)) { /* method is part of an interface; this is wrong method for that */ ALOGW("DexOpt: method is in an interface"); if (pFailure != NULL) *pFailure = VERIFY_ERROR_GENERIC; return NULL; } /* * We need to chase up the class hierarchy to find methods defined * in super-classes. (We only want to check the current class * if we're looking for a constructor.) */ DexProto proto; dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); if (methodType == METHOD_DIRECT) { resMethod = dvmFindDirectMethod(resClass, dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); } else { /* METHOD_STATIC or METHOD_VIRTUAL */ resMethod = dvmFindMethodHier(resClass, dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); } if (resMethod == NULL) { ALOGV("DexOpt: couldn't find method '%s'", dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_METHOD; return NULL; } if (methodType == METHOD_STATIC) { if (!dvmIsStaticMethod(resMethod)) { ALOGD("DexOpt: wanted static, got instance for method %s.%s", resClass->descriptor, resMethod->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } } else if (methodType == METHOD_VIRTUAL) { if (dvmIsStaticMethod(resMethod)) { ALOGD("DexOpt: wanted instance, got static for method %s.%s", resClass->descriptor, resMethod->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } } /* see if this is a pure-abstract method */ if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { ALOGW("DexOpt: pure-abstract method '%s' in %s", dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), resClass->descriptor); if (pFailure != NULL) *pFailure = VERIFY_ERROR_GENERIC; return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. * * We can only do this for static methods if we're not in "dexopt", * because the presence of a valid value in the resolution table * implies that the class containing the static field has been * initialized. */ if (methodType != METHOD_STATIC || gDvm.optimizing) dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); } LOGVV("--- found method %d (%s.%s)", methodIdx, resMethod->clazz->descriptor, resMethod->name); /* access allowed? */ tweakLoader(referrer, resMethod->clazz); bool allowed = dvmCheckMethodAccess(referrer, resMethod); untweakLoader(referrer, resMethod->clazz); if (!allowed) { IF_ALOGI() { char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype); ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)", resMethod->clazz->descriptor, resMethod->name, desc, referrer->descriptor); free(desc); }