调用CallVoidMethod时JNI崩溃

时间:2011-09-23 14:44:20

标签: 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 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()。任何提示?

2 个答案:

答案 0 :(得分:11)

为您提供的4个想法:

...

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

您能确认名称不是“com / path / to / the / MyClass”,其中classname是大写的第一个字符,显然名称“class”是保留字。在您的示例中,使用JNI C符号名称“Java_com_path_to_my_package_renderStuff”与“com / path / to / the / class”上的FindClass()查找之间存在轻微的差异。但由于您的stackoverflow不是关于UnsatisfiedLinkageError,我只能猜测您提供的示例与自身不一致。

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

...

你确定传递的“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符号名称以将“_1internal”附加到末尾,使“Java_com_path_to_the_MyClass_renderStuff_1internal”(额外的“1”字符是预期的)

...

也许在你列出的每个陈述之间尝试腰带和括号异常检查:

if(env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
}

当可能不允许进行反射时,这会触发安全违规等事情。

...

 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);

删除FindClass()调用的另一个想法。这适用于任何GetMethodID工作的类,有点类似于dyhamic类型/后期绑定。

答案 1 :(得分:1)

就我而言 我正在调用 Kotlin 函数。并且要调用 kotlin 函数,您需要在 kotlin 中的函数名称前写上 @JvmStatic

Kotlin 代码

@JvmStatic
fun ReceiveDataFromCpp(data: ShortArray)
{
    Log.d("Kotlin array Return -----> ", "arr: " + data
        .contentToString()
    );
}

Cpp 代码

JNIEnv * g_env;
g_env = getEnv();


 jmethodID jmethodId = g_env->GetStaticMethodID(clientClass, "ReceiveDataFromCpp",
                                        "([S)V");
 if (jmethodId == NULL)
 {
     return;
 }

 jshortArray dataArray = nullptr;
 dataArray = g_env->NewShortArray(480);
 g_env->SetShortArrayRegion(dataArray, 0, 480, mData);
 g_env->CallStaticVoidMethod(clientRecorderClass, jmethodId, dataArray);