Android 调用CallVoidMethod时JNI崩溃

Android 调用CallVoidMethod时JNI崩溃,android,java-native-interface,Android,Java Native Interface,我试图在Android应用程序中从本机C代码调用java方法。使用JNI听起来很简单,但是当最终调用方法本身时,我的代码总是崩溃。 这是我的密码: 本机C代码: JNIEXPORT void JNICALL Java_com_path_to_my_package_renderStuff(JNIEnv* env, jobject jobj){ //... jclass clazz = env->FindClass("com/path/to/the/class"); jmethodID sh

我试图在Android应用程序中从本机C代码调用java方法。使用JNI听起来很简单,但是当最终调用方法本身时,我的代码总是崩溃。 这是我的密码: 本机C代码:

JNIEXPORT void JNICALL
Java_com_path_to_my_package_renderStuff(JNIEnv* env,  jobject jobj){
//...
jclass clazz = env->FindClass("com/path/to/the/class");
jmethodID showCar = env->GetMethodID(clazz,"showCar","()V" );
env->CallVoidMethod(jobj,showCar); //If I comment this out, it won't crash
//...
}
Java代码:

public void showCar(){      
    doSomething()
}

doSomething()甚至还没有到达,我可以在那里设置一个断点,它永远不会被击中。如上所述,只要我注释掉CallVoidMethod调用,它就不会崩溃,但显然也不会调用showCar()。有什么提示吗?

4个想法可以为您提供:

jclass clazz=env->FindClass(“com/path/to/the/class”)

您能否确认名称不是“com/path/to/the/MyClass”,其中类名是大写的第一个字符,显然名称“class”是一个保留字。在您的示例中,使用JNI C符号名“Java_com_path_to_my_package_renderStuff”和“com/path/to/the/class”上的FindClass()查找之间有一点不同。但是,由于您的stackoverflow不是一个关于不满意链接的错误,我只能猜测您提供的示例与自身不一致

使用我的示例,我希望JNI C符号名为“Java_com_path_to_the_MyClass_renderStuff”和“com/path/to/the/MyClass”上的FindClass()查找。类的大写第一个字母和方法名的小写第一个字母的使用对于链接目的可能很重要

您确定正在传递的“jobj”与正在查找的“com/path/to/the/class”类型相同吗?也许在Java代码中,您可以使用以下内容包装本机:

public void renderStuff() {
    if((this instanceof com.path.to.the.MyClass) == false)
        throw new RuntimeException("Unexpected class expected: com.path.to.the.MyClass");
     renderStuff_internal();
}
private native void renderStuff_internal();
这将确保Java代码中的这一问题不会导致JVM崩溃。您还需要调整C符号名称,将“\u 1internal”附加到“Java\u com\u path\u到\u MyClass\u renderStuff\u 1internal”的结尾(额外的“1”字符是需要的)

也许可以尝试在列出的每个语句之间检查皮带和大括号异常:

if(env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
}
这将在尝试进行反射时发现安全违规等情况,而反射可能是不允许的


删除FindClass()调用的另一个想法。这适用于GetMethodID处理的任何类,有点像动态类型/后期绑定。

您是否确保
FindClass
GetMethodID
实际返回非空结果?是的,我们检查了这两个结果,但其中似乎有二进制数据或其他内容。但它绝对不是空的。不幸的是,使用Android NDK和GDB调试本机代码非常困难,因为我们根本无法让C调试器工作。我需要知道的是使用GetObjectClass()而不是FindClass。如果使用env->GetObjectClass(jobj),则使用递归循环,并且方法showCar从不调用。
 jclass cls = env->GetObjectClass(jobj);  // instead of FindClass
 jmethodID mid = env->GetMethodID(cls, "showCar", "()V");
 if(!mid) return;  // whoops method does not exist
 env->CallVoidMethod(jobj, mid);