JNI вылетает при вызове CallVoidMethod

Я пытаюсь вызвать java-метод из собственного кода C в приложении для Android. Это звучит довольно просто с использованием 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 (). Какие-нибудь намеки?


person Lennart    schedule 23.09.2011    source источник
comment
Вы убедились, что FindClass и GetMethodID действительно возвращают ненулевые результаты?   -  person Stuart Cook    schedule 24.09.2011
comment
Да, мы проверили оба результата, но похоже, что в них есть двоичные данные или что-то в этом роде. Однако это определенно не нуль. К сожалению, отладка нативного кода с помощью Android NDK и GDB оказалась довольно сложной, так как мы вообще не можем заставить работать C Debugger.   -  person Lennart    schedule 24.09.2011


Ответы (1)


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» и поиском FindClass () в «com / path / to / the / class» в вашем примере. Но поскольку ваш stackoverflow не связан с UnsatisfiedLinkageError, я могу только догадываться, что ваш пример не согласуется с самим собой.

Используя мой пример, я ожидал бы, что имя символа JNI C будет «Java_com_path_to_the_MyClass_renderStuff», а поиск FindClass () - «com / path / to / the / MyClass». Использование 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, вроде динамической типизации / позднего связывания.

person Darryl Miles    schedule 25.09.2011
comment
Мне нужно было знать об использовании GetObjectClass () вместо FindClass. - person Alyoshak; 29.09.2014
comment
Имеет рекурсивный цикл, если используется env- ›GetObjectClass (jobj), а метод showCar никогда не вызывается. - person Anonimys; 21.02.2020