/* * This is the common message body for proxy methods. * * The method we're calling looks like: * public Object invoke(Object proxy, Method method, Object[] args) * * This means we have to create a Method object, box our arguments into * a new Object[] array, make the call, and unbox the return value if * necessary. */ static void proxyInvoker(const u4* args, JValue* pResult, const Method* method, Thread* self) { Object* thisObj = (Object*) args[0]; Object* methodObj = NULL; ArrayObject* argArray = NULL; Object* handler; Method* invoke; ClassObject* returnType; int hOffset; JValue invokeResult; /* * Retrieve handler object for this proxy instance. */ hOffset = dvmFindFieldOffset(thisObj->clazz, "h", "Ljava/lang/reflect/InvocationHandler;"); if (hOffset < 0) { LOGE("Unable to find 'h' in Proxy object\n"); dvmAbort(); } handler = dvmGetFieldObject(thisObj, hOffset); /* * Find the invoke() method, looking in "this"s class. (Because we * start here we don't have to convert it to a vtable index and then * index into this' vtable.) */ invoke = dvmFindVirtualMethodHierByDescriptor(handler->clazz, "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); if (invoke == NULL) { LOGE("Unable to find invoke()\n"); dvmAbort(); } LOGV("invoke: %s.%s, this=%p, handler=%s\n", method->clazz->descriptor, method->name, thisObj, handler->clazz->descriptor); /* * Create a java.lang.reflect.Method object for this method. * * We don't want to use "method", because that's the concrete * implementation in the proxy class. We want the abstract Method * from the declaring interface. We have a pointer to it tucked * away in the "insns" field. * * TODO: this could be cached for performance. */ methodObj = dvmCreateReflectMethodObject((Method*) method->insns); if (methodObj == NULL) { assert(dvmCheckException(self)); goto bail; } /* * Determine the return type from the signature. * * TODO: this could be cached for performance. */ returnType = dvmGetBoxedReturnType(method); if (returnType == NULL) { char* desc = dexProtoCopyMethodDescriptor(&method->prototype); LOGE("Could not determine return type for '%s'\n", desc); free(desc); assert(dvmCheckException(self)); goto bail; } LOGV(" return type will be %s\n", returnType->descriptor); /* * Convert "args" array into Object[] array, using the method * signature to determine types. If the method takes no arguments, * we must pass null. */ argArray = boxMethodArgs(method, args+1); if (dvmCheckException(self)) goto bail; /* * Call h.invoke(proxy, method, args). * * We don't need to repackage exceptions, so if one has been thrown * just jump to the end. */ dvmCallMethod(self, invoke, handler, &invokeResult, thisObj, methodObj, argArray); if (dvmCheckException(self)) goto bail; /* * Unbox the return value. If it's the wrong type, throw a * ClassCastException. If it's a null pointer and we need a * primitive type, throw a NullPointerException. */ if (returnType->primitiveType == PRIM_VOID) { LOGVV("+++ ignoring return to void\n"); } else if (invokeResult.l == NULL) { if (dvmIsPrimitiveClass(returnType)) { dvmThrowException("Ljava/lang/NullPointerException;", "null result when primitive expected"); goto bail; } pResult->l = NULL; } else { if (!dvmUnwrapPrimitive(invokeResult.l, returnType, pResult)) { dvmThrowExceptionWithClassMessage("Ljava/lang/ClassCastException;", ((Object*)invokeResult.l)->clazz->descriptor); goto bail; } } bail: dvmReleaseTrackedAlloc(methodObj, self); dvmReleaseTrackedAlloc((Object*)argArray, self); }
static void dalvik_dispatcher(const u4* args, jvalue* pResult, const Method* method, void* self) { ClassObject* returnType; jvalue result; ArrayObject* argArray; LOGD("dalvik_dispatcher source method: %s %s", method->name, method->shorty); Method* meth = (Method*) method->insns; meth->accessFlags = meth->accessFlags | ACC_PUBLIC; LOGD("dalvik_dispatcher target method: %s %s", method->name, method->shorty); returnType = dvmGetBoxedReturnType_fnPtr(method); if (returnType == NULL) { assert(dvmCheckException_fnPtr(self)); goto bail; } LOGD("dalvik_dispatcher start call->"); if (!dvmIsStaticMethod(meth)) { Object* thisObj = (Object*) args[0]; ClassObject* tmp = thisObj->clazz; thisObj->clazz = meth->clazz; argArray = boxMethodArgs(meth, args + 1); if (dvmCheckException_fnPtr(self)) goto bail; dvmCallMethod_fnPtr(self, (Method*) jInvokeMethod, dvmCreateReflectMethodObject_fnPtr(meth), &result, thisObj, argArray); thisObj->clazz = tmp; } else { argArray = boxMethodArgs(meth, args); if (dvmCheckException_fnPtr(self)) goto bail; dvmCallMethod_fnPtr(self, (Method*) jInvokeMethod, dvmCreateReflectMethodObject_fnPtr(meth), &result, NULL, argArray); } if (dvmCheckException_fnPtr(self)) { Object* excep = dvmGetException_fnPtr(self); jni_env->Throw((jthrowable) excep); goto bail; } if (returnType->primitiveType == PRIM_VOID) { LOGD("+++ ignoring return to void"); } else if (result.l == NULL) { if (dvmIsPrimitiveClass(returnType)) { jni_env->ThrowNew(NPEClazz, "null result when primitive expected"); goto bail; } pResult->l = NULL; } else { if (!dvmUnboxPrimitive_fnPtr(result.l, returnType, pResult)) { char msg[1024] = { 0 }; snprintf(msg, sizeof(msg) - 1, "%s!=%s\0", ((Object*) result.l)->clazz->descriptor, returnType->descriptor); jni_env->ThrowNew(CastEClazz, msg); goto bail; } } bail: dvmReleaseTrackedAlloc_fnPtr((Object*) argArray, self); }