2012-04-20 18 views
5

Quiero llamar a los métodos de clase Java desde un archivo cpp que recibe llamadas de otro ejecutable.Compartir un JavaVM * entre hilos en Android NDK

Para lograr esto, se han recuperado un puntero JavaVM utilizando el androide Android Runtime :: :: getJavaVM método() en el archivo .cpp que recibe directamente el método JNI llamadas. Estoy compartiendo este puntero JavaVM a través del constructor para el archivo .cpp eventual donde yo llamo requieren métodos de Java de la siguiente manera:

/* All the required objects(JNIEnv*,jclass,jmethodID,etc) are appropriately declared. */ 
**JNIEnv* env; 
jvm->AttachCurrentThread(&env, NULL); 
clazz = env->FindClass("com/skype/ref/NativeCodeCaller"); 
readFromAudioRecord = env->GetStaticMethodID(clazz, "readFromAudioRecord", "([B)I"); 
writeToAudioTrack = env->GetStaticMethodID(clazz, "writeToAudioTrack", "([B)I");** 

Sin embargo, me sale un error de SIGSEGV ejecutar este código.

De acuerdo con la documentación JNI esto parece ser la forma apropiada para obtener JNIEnv en contextos arbitrarios: http://java.sun.com/docs/books/jni/html/other.html#26206

será apreciado Cualquier ayuda en este sentido.

Saludos, Neeraj

+0

¿Qué es android :: AndroidRuntime :: getJavaVM)? Esa no es la función de API pública de NDK. Estás usando algo no documentado. Para obtener JavaVM * en NDK, debe implementar la función global JNI_OnLoad que se llama automáticamente cuando se carga su biblioteca compartida. –

+0

Gracias por su respuesta .. http://android.wooyd.org/JNIExample/#NWD1sCYeT-J - este documento ofrece una muy buena introducción a JNI_OnLoad, donde se usa android :: AndroidRuntime :: registerNativeMethods(). ¿Estás seguro de que android :: AndroidRuntime no está documentado? – Neeraj

+0

Sí, es una característica no documentada en el código NDK de usuario normal. Lea la documentación de JNI (desde Sun) y verifique el archivo docs/STABLE-APIS.html en su carpeta NDK para obtener otra API legal y documentada. –

Respuesta

4

referencias globales no impedirá que un fallo de segmentación en un nuevo hilo si se intenta utilizar una referencia JNIEnv o JavaVM sin asociar la hilo a la VM. Lo hiciste correctamente la primera vez, Mārtiņš Možeiko se equivoca al dar a entender que había algo mal con lo que estabas haciendo.

No lo quite, solo aprenda a usarlo. Ese tipo no sabe de lo que está hablando, si está en jni.h puedes estar bastante seguro de que no irá a ninguna parte. La razón por la que no está documentado es probablemente porque es ridículamente explicativo. No necesita crear objetos GlobalReference ni nada, simplemente haga algo como esto:

#include <jni.h> 
#include <string.h> 
#include <stdio.h> 
#include <android/log.h> 
#include <linux/threads.h> 
#include <pthread.h> 

#define LOG_TAG "[NDK]" 
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) 
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 

static pthread_mutex_t thread_mutex; 
static pthread_t thread; 
static JNIEnv* jniENV; 

void *threadLoop() 
{ 
    int exiting; 
    JavaVM* jvm; 
    int gotVM = (*jniENV)->GetJavaVM(jniENV,&jvm); 
    LOGI("Got JVM: %s", (gotVM ? "false" : "true")); 
    jclass javaClass; 
    jmethodID javaMethodId; 
    int attached = (*jvm)->AttachCurrentThread(jvm, &jniENV,NULL); 
    if(attached>0) 
    { 
     LOGE("Failed to attach thread to JavaVM"); 
     exiting = 1; 
    } 
    else{ 
     javaClass= (*jniENV)->FindClass(jniENV, "com/justinbuser/nativecore/NativeThread"); 
     javaMethodId= (*jniENV)->GetStaticMethodID(jniENV, javaClass, "javaMethodName", "()V"); 
    } 
    while(!exiting) 
    { 
     pthread_mutex_lock(&thread_mutex); 
     (*jniENV)->CallStaticVoidMethod(jniENV, javaClass, javaMethodId); 
     pthread_mutex_unlock(&thread_mutex); 
    } 
    LOGE("Thread Loop Exiting"); 
    void* retval; 
    pthread_exit(retval); 
    return retval; 
} 

void start_thread(){ 
    if(thread < 1) 
     { 
      if(pthread_mutex_init(&thread_mutex, NULL) != 0) 
      { 
       LOGE("Error initing mutex"); 
      } 
      if(pthread_create(&thread, NULL, threadLoop, NULL) == 0) 
      { 
       LOGI("Started thread#: %d", thread); 
       if(pthread_detach(thread)!=0) 
       { 
        LOGE("Error detaching thread"); 
       } 
      } 
      else 
      { 
       LOGE("Error starting thread"); 
      } 
     } 
} 

JNIEXPORT void JNICALL 
Java_com_justinbuser_nativecore_NativeMethods_startThread(JNIEnv * env, jobject this){ 
    jniENV = env; 
    start_thread(); 
} 
+0

¿Dónde dije que usar algo de jni.h es incorrecto o no está permitido? –

+1

"Esa no es la función de API pública de NDK. Está utilizando algo no documentado.Para obtener JavaVM * en NDK debe implementar la función global JNI_OnLoad que se llama automáticamente cuando se carga su biblioteca compartida. "Siento decirlo, pero toda esa declaración es simplemente incorrecta. –

+0

Y eso es cierto -' android :: AndroidRuntime :: getJavaVM' no es una función o método público en jni.h. Nunca dije que usar funciones o métodos de jni.h (como JNI_OnLoad global, o JavaVM, o JNIEnv) no está permitido. Pero usted insinuó que dije algo sobre él no lo usa correctamente con las funciones de jni.h. ¿Cómo puede hacerlo correctamente con la función ** android :: AndroidRuntime :: getJavaVM ** desde el interior de Android que no está en jni.h? –

0

resuelto el problema. El error de segmentación se debió a que no pude recuperar un objeto jclass del objeto JNIEnv recuperado del puntero jvm compartido.

Propogé un objeto jclass de referencia global junto con el jvm y se solucionó el problema.

Gracias por su ayuda Mārtiņš Možeiko! ..

Saludos, Neeraj