/* * private Object invokeNative(Object obj, Object[] args, Class declaringClass, * Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck) * * Invoke a static or virtual method via reflection. */ static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* methObj = (Object*) args[1]; // null for static methods ArrayObject* argList = (ArrayObject*) args[2]; ClassObject* declaringClass = (ClassObject*) args[3]; ArrayObject* params = (ArrayObject*) args[4]; ClassObject* returnType = (ClassObject*) args[5]; int slot = args[6]; bool noAccessCheck = (args[7] != 0); const Method* meth; Object* result; /* * "If the underlying method is static, the class that declared the * method is initialized if it has not already been initialized." */ meth = dvmSlotToMethod(declaringClass, slot); assert(meth != NULL); if (dvmIsStaticMethod(meth)) { if (!dvmIsClassInitialized(declaringClass)) { if (!dvmInitClass(declaringClass)) goto init_failed; } } else { /* looks like interfaces need this too? */ if (dvmIsInterfaceClass(declaringClass) && !dvmIsClassInitialized(declaringClass)) { if (!dvmInitClass(declaringClass)) goto init_failed; } /* make sure the object is an instance of the expected class */ if (!dvmVerifyObjectInClass(methObj, declaringClass)) { assert(dvmCheckException(dvmThreadSelf())); RETURN_VOID(); } /* do the virtual table lookup for the method */ meth = dvmGetVirtualizedMethod(methObj->clazz, meth); if (meth == NULL) { assert(dvmCheckException(dvmThreadSelf())); RETURN_VOID(); } } /* * If the method has a return value, "result" will be an object or * a boxed primitive. */ result = dvmInvokeMethod(methObj, meth, argList, params, returnType, noAccessCheck); RETURN_PTR(result); init_failed: /* * If initialization failed, an exception will be raised. */ ALOGD("Method.invoke() on bad class %s failed", declaringClass->descriptor); assert(dvmCheckException(dvmThreadSelf())); RETURN_VOID(); }
/* * 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; }