Android JNI调用Java动态代理方法时发生Crash的问题咨询
崩溃根因
场景1:放开代理中invoke代码时全设备崩溃
- JNI层参数传递错误:
jvalue *args = {}实际是将args初始化为空指针,CallVoidMethodA要求第三个参数必须是指向jvalue数组的有效指针,即使方法无入参也不能传入空指针,直接触发内存访问错误崩溃。 - 动态代理返回值不匹配:Kotlin的lambda默认将最后一行表达式的结果作为返回值,调用
method.invoke后,无返回值的void方法对应的invoke调用返回null,但部分场景下Kotlin会隐式返回Unit类型,与方法签名要求的返回值不匹配,触发ART虚拟机校验错误。
场景2:注释代理中invoke代码时仅Android 6.0(Vivo Y67等机型)崩溃
- Android 6.0(API 23)ART虚拟机的动态代理返回值校验存在兼容缺陷:注释invoke逻辑后,InvocationHandler的lambda没有显式返回值,默认返回Kotlin的Unit对象,而Android 6.0的ART在处理JNI调用动态代理void方法的场景下,无法识别Unit作为合法返回值,定制ROM(如Vivo的老版本系统)对ART的修改进一步放大了这个问题,直接触发崩溃。
解决方案
- 修复JNI层参数错误:将空指针的args替换为栈上分配的空jvalue数组,修改后代码如下:
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, "testVoid", "()V"); LOGD("jmethodId = %d", test_void_method_id == nullptr); // 替换为栈上分配的空数组,不要传空指针 jvalue args[0]; env->CallVoidMethodA(proxy, test_void_method_id, args); }
- 修复动态代理返回值兼容问题:显式指定InvocationHandler的返回值,void方法统一返回null,修改后代码如下:
val proxy = Proxy.newProxyInstance( classLoader, arrayOf(ProxyTest::class.java) ) { _, method, args -> val myargs = args ?: emptyArray() val result = method.invoke(target, *myargs) // 显式处理返回值,void方法返回null,匹配所有Android版本的ART校验规则 if (method.returnType == Void.TYPE) null else result } as ProxyTest
如果不需要执行target的方法,也要显式返回null,避免默认返回Unit:
val proxy = Proxy.newProxyInstance( classLoader, arrayOf(ProxyTest::class.java) ) { _, _, _ -> // 无业务逻辑时也显式返回null,兼容老版本系统 null } as ProxyTest
内容的提问来源于stack exchange,提问作者a5right
相关产品推荐
相关产品推荐

