2012-04-20 8 views
5

Desidero chiamare i metodi di classe Java da un file cpp che riceve le richiamate da un altro eseguibile.Condivisione di JavaVM * attraverso thread in NDK Android

Per ottenere ciò, ho recuperato un puntatore JavaVM utilizzando il metodo android :: AndroidRuntime :: getJavaVM() nel file cpp che riceve direttamente le chiamate al metodo JNI. Sto condividendo questo puntatore JavaVM tramite il costruttore per il file cpp eventuale dove ho chiamata richiesta metodi Java come segue:

/* 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");** 

Tuttavia, ottengo un errore SIGSEGV l'esecuzione di questo codice.

Secondo la documentazione JNI questo sembra essere il modo appropriato per ottenere MEnv in contesti arbitrari: http://java.sun.com/docs/books/jni/html/other.html#26206

Qualsiasi aiuto in questo senso sarà apprezzato.

saluti, Neeraj

+0

Che cos'è android :: AndroidRuntime :: getJavaVM)? Questa non è la funzione API pubblica NDK. Stai usando qualcosa di non documentato. Per ottenere JavaVM * in NDK devi impiantare la funzione globale JNI_OnLoad che viene chiamata automaticamente quando viene caricata la tua libreria condivisa. –

+0

Grazie per la tua risposta .. http://android.wooyd.org/JNIExample/#NWD1sCYeT-J - questo documento fornisce un'ottima intro a JNI_OnLoad, dove viene utilizzato android :: AndroidRuntime :: registerNativeMethods(). Sei sicuro che Android :: AndroidRuntime non sia documentato? – Neeraj

+0

Sì, funzione non documentata nel normale codice utente NDK. Leggi la documentazione JNI (da Sun) e controlla il file docs/STABLE-APIS.html nella tua cartella NDK per altre API legali e documentate. –

risposta

4

riferimenti globali non impedirà un segmentation fault in un nuovo thread se si tenta di utilizzare un riferimento MEnv o JavaVM senza associare il thread alla VM. Lo stavi facendo bene la prima volta, Mārtiņš Možeiko ha sbagliato a insinuare che c'era qualcosa di sbagliato in quello che stavi facendo.

Non rimuoverlo, impara solo come usarlo. Quel ragazzo non sa di cosa sta parlando, se è in jni.h puoi essere sicuro che non andrà da nessuna parte. Il motivo per cui non è documentato è probabilmente perché è ridicolmente auto esplicativo. Non è necessario creare oggetti GlobalReference o qualcosa del genere, basta fare qualcosa del genere:

#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

Dove ho detto che usare qualcosa da jni.h è sbagliato o non permesso? –

+1

"Questa non è la funzione API pubblica NDK. Stai utilizzando qualcosa di non documentato.Per ottenere JavaVM * in NDK devi impiantare la funzione globale JNI_OnLoad che viene chiamata automaticamente quando viene caricata la tua libreria condivisa. "Mi spiace dirlo ma l'intera affermazione è semplicemente errata –

+0

E questo è vero -' android :: AndroidRuntime :: getJavaVM' non è una funzione pubblica o un metodo in jni.h. Non ho mai detto che l'utilizzo di funzioni o metodi da jni.h (come Global JNI_OnLoad, o JavaVM o JNIEnv) non è consentito. non lo usa correttamente con le funzioni di jni.h. Come può farlo correttamente con la funzione ** android :: AndroidRuntime :: getJavaVM ** da internals Android che non è in jni.h? –

0

risolto il problema. L'errore di segmentazione era perché non riuscivo a recuperare un oggetto jclass dall'oggetto JNIEnv recuperato dal puntatore jvm condiviso.

Ho propogato un oggetto jclass di riferimento globale insieme a jvm e il problema è stato risolto.

Grazie per il vostro aiuto Mārtiņš Možeiko! ..

saluti, Neeraj