2011-09-23 17 views
8

Estoy tratando de llamar a un método de Java desde el código C nativo en una aplicación de Android. Esto suena bastante simple con el uso de JNI, pero mi código siempre se cuelga cuando finalmente llama al método en sí. Aquí está mi código: código nativo C:JNI se bloquea al llamar a CallVoidMethod

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 
//... 
} 

Código Java:

public void showCar(){  
    doSomething() 
} 

doSomething() no está aún alcanzado, puedo poner un breakpoint allí, que nunca será alcanzado. Y como dije anteriormente, tan pronto como comente la llamada CallVoidMethod, no se bloqueará, pero obviamente tampoco llamará a showCar(). ¿Algún consejo?

+0

¿Se ha asegurado de que 'FindClass' y' GetMethodID' realmente devuelvan resultados no nulos? –

+0

Sí, hemos verificado ambos resultados, pero parece que hay datos binarios o algo en él. Definitivamente no es nulo, sin embargo.Desafortunadamente, la depuración del código nativo con Android NDK y GDB resultó ser bastante difícil, ya que no podemos hacer que C Depurador funcione en absoluto. – Lennart

Respuesta

11

4 ideas para que proporcionan:

...

jclass clazz = env> FindClass ("com/ruta/a/la/clase");

Puede confirmar que el nombre no es "com/path/to/the/MyClass" donde el nombre de clase es mayúscula primero y obviamente el nombre "clase" es una palabra reservada. Existe una ligera discrepancia entre el uso del nombre del símbolo JNI C "Java_com_path_to_my_package_renderStuff" y la búsqueda FindClass() en "com/path/to/the/class" en su ejemplo. Pero dado que su stackoverflow no es sobre UnsatisfiedLinkageError, solo puedo adivinar que su ejemplo proporcionado no es coherente consigo mismo.

Usando mi ejemplo, yo esperaría que el nombre del símbolo JNI C como "Java_com_path_to_the_MyClass_renderStuff" y el() de búsqueda en "com/ruta/a/la/MiClase" FindClass. El uso de mayúscula primera letra de clase y minúscula primera letra del nombre del método puede ser importante para fines de vinculación.

...

¿Estás seguro de que el "jobj" que se pasa es el mismo tipo que el "com/ruta/a/la/clase" que están mejorando? Tal vez en su código Java que puede envolver su nativa con:

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

lo que garantizará que la materia en código Java sin causar un accidente de JVM. También tendría que ajustar su nombre de símbolo C para anexar la "_1internal" en la toma final "Java_com_path_to_the_MyClass_renderStuff_1internal" (el personaje extra "1" se pretende)

...

tratan Tal vez el cinturón y tirantes excepción comprobar en entre cada declaración acerca de que la lista:

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

esto será como violaciónes de seguridad cuando se trata de hacer la reflexión cuando no podría permitirse.

...

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

Otra idea para eliminar la llamada FindClass(). Esto funcionaría con cualquier clase en la que GetMethodID trabajara, algo así como typing dyham/último enlace.

+0

El uso de GetObjectClass() en lugar de FindClass era lo que necesitaba saber. – Alyoshak

Cuestiones relacionadas