/* * 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; }
/* * Get the address of a field from an object. This can be used with "get" * or "set". * * "declaringClass" is the class in which the field was declared. For an * instance field, "obj" is the object that holds the field data; for a * static field its value is ignored. * * "If the underlying field is static, the class that declared the * field is initialized if it has not already been initialized." * * On failure, throws an exception and returns NULL. * * The documentation lists exceptional conditions and the exceptions that * should be thrown, but doesn't say which exception previals when two or * more exceptional conditions exist at the same time. For example, * attempting to set a protected field from an unrelated class causes an * IllegalAccessException, while passing in a data type that doesn't match * the field causes an IllegalArgumentException. If code does both at the * same time, we have to choose one or othe other. * * The expected order is: * (1) Check for illegal access. Throw IllegalAccessException. * (2) Make sure the object actually has the field. Throw * IllegalArgumentException. * (3) Make sure the field matches the expected type, e.g. if we issued * a "getInteger" call make sure the field is an integer or can be * converted to an int with a widening conversion. Throw * IllegalArgumentException. * (4) Make sure "obj" is not null. Throw NullPointerException. * * TODO: we're currently handling #3 after #4, because we don't check the * widening conversion until we're actually extracting the value from the * object (which won't work well if it's a null reference). */ static JValue* getFieldDataAddr(Object* obj, ClassObject* declaringClass, int slot, bool isSetOperation, bool noAccessCheck) { Field* field; JValue* result; field = dvmSlotToField(declaringClass, slot); assert(field != NULL); /* verify access */ if (!noAccessCheck) { if (isSetOperation && dvmIsFinalField(field)) { dvmThrowException("Ljava/lang/IllegalAccessException;", "field is marked 'final'"); return NULL; } ClassObject* callerClass = dvmGetCaller2Class(dvmThreadSelf()->curFrame); /* * We need to check two things: * (1) Would an instance of the calling class have access to the field? * (2) If the field is "protected", is the object an instance of the * calling class, or is the field's declaring class in the same * package as the calling class? * * #1 is basic access control. #2 ensures that, just because * you're a subclass of Foo, you can't mess with protected fields * in arbitrary Foo objects from other packages. */ if (!dvmCheckFieldAccess(callerClass, field)) { dvmThrowException("Ljava/lang/IllegalAccessException;", "access to field not allowed"); return NULL; } if (dvmIsProtectedField(field)) { bool isInstance, samePackage; if (obj != NULL) isInstance = dvmInstanceof(obj->clazz, callerClass); else isInstance = false; samePackage = dvmInSamePackage(declaringClass, callerClass); if (!isInstance && !samePackage) { dvmThrowException("Ljava/lang/IllegalAccessException;", "access to protected field not allowed"); return NULL; } } } if (dvmIsStaticField(field)) { /* init class if necessary, then return ptr to storage in "field" */ if (!dvmIsClassInitialized(declaringClass)) { if (!dvmInitClass(declaringClass)) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } } result = dvmStaticFieldPtr((StaticField*) field); } else { /* * Verify object is of correct type (i.e. it actually has the * expected field in it), then grab a pointer to obj storage. * The call to dvmVerifyObjectInClass throws an NPE if "obj" is NULL. */ if (!dvmVerifyObjectInClass(obj, declaringClass)) { assert(dvmCheckException(dvmThreadSelf())); if (obj != NULL) { LOGD("Wrong type of object for field lookup: %s %s\n", obj->clazz->descriptor, declaringClass->descriptor); } return NULL; } result = dvmFieldPtr(obj, ((InstField*) field)->byteOffset); } return result; }