Android 调用 Java 动态代理方法时 JNI 崩溃

Android JNI Crash when invoking Java Dynamic Proxy method

出于某种原因,我想用 JNI

调用动态代理 class 的方法

步骤:

  1. 创建动态代理实例
  2. 调用本机方法并将代理实例作为参数传递
  3. 使用 jni 调用代理实例上的一些方法

应用代码:

        val target = object : ProxyTest {
            override fun testVoid() {
                Log.e(TAG, "testVoid: ")
            }

            override fun testString(): String {
                Log.e(TAG, "testString: ")
                return "hello"
            }
        }

        val proxy = Proxy.newProxyInstance(
            classLoader, arrayOf(ProxyTest::class.java)
        ) { proxy, method, args ->
            // if open code below, it will crash on all device
            // if not open, it will crash only on android 6.0, mostly on Vivo Y67
            //val myargs = args ?: emptyArray()
            //method.invoke(target, *myargs)
        } as ProxyTest
        
        invokeProxyMethod(proxy)




interface ProxyTest {
    fun testVoid()
    fun testString(): String
}
  

本地代码:

extern "C"
JNIEXPORT void JNICALL
Java_com_aprz_mytestdemo_jni_JNIInvokeProxyMethodActivity_invokeProxyMethod(JNIEnv *env,
                                                                            __unused     jobject thiz,
                                                                            jobject proxy) {
    jclass proxy_class = env->GetObjectClass(proxy);
//    jmethodID test_void_method_id = env->GetMethodID(proxy_class, "testString", "()Ljava/lang/String;");
    jmethodID test_void_method_id = env->GetMethodID(proxy_class, "testVoid", "()V");
    LOGD("jmethodId = %d", test_void_method_id == nullptr);
    jvalue *args = {};
    jobject obj = env->NewLocalRef(proxy);
    env->CallVoidMethodA(obj, test_void_method_id, args);
}

这是 android M 预览中的错误,提交 ID:f015c2f4835a9985a8b31cfc810129b69865a6c4。

此外,android JNI 中还有一些错误。 例如:

check_jni.cc

bool CheckMethodAndSig(ScopedObjectAccess& soa, jobject jobj, jclass jc,
                         jmethodID mid, Primitive::Type type, InvokeType invoke)
{
...
// **this should be m->GetInterfaceMethodIfProxy(xx)->GetShorty(xxx);**
if (type != Primitive::GetType(m->GetShorty()[0])) {
...
}