2012-04-20 17 views
5

Chcę wywołać metody klasy Java z pliku cpp, który odbiera wywołania zwrotne z innego pliku wykonywalnego.Udostępnianie JavaVM * dla wątków w systemie Android NDK

W tym celu pobrałem wskaźnik JavaVM za pomocą metody android :: AndroidRuntime :: getJavaVM() w pliku .cpp, który bezpośrednio odbiera wywołania metod JNI. Dzielę ten wskaźnik javavm przez konstruktora do ostatecznego pliku .cpp gdzie ja nazywam wymaganej metody Java w następujący sposób:

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

Jednak dostaję SIGSEGV usterkę działa ten kod.

Zgodnie z dokumentacją JNI to wydaje się być odpowiednim sposobem na uzyskanie JNIEnv w kontekstach arbitralne: http://java.sun.com/docs/books/jni/html/other.html#26206

Każda pomoc w tym zakresie zostaną docenione.

Pozdrowienia, Neeraj

+0

Co to jest Android :: AndroidRuntime :: getJavaVM)? To nie jest funkcja publicznego interfejsu NDK. Używasz czegoś nieudokumentowanego. Aby uzyskać JavaVM * w NDK, musisz implementować globalną funkcję JNI_OnLoad, która jest automatycznie wywoływana po załadowaniu biblioteki współdzielonej. –

+0

Dziękuję za odpowiedź .. http://android.wooyd.org/JNIExample/#NWD1sCYeT-J - ten dokument zawiera bardzo dobre intro do JNI_OnLoad, gdzie używany jest android :: AndroidRuntime :: registerNativeMethods(). Czy na pewno Android :: AndroidRuntime nie jest udokumentowany? – Neeraj

+0

Tak, to nieudokumentowana funkcja w normalnym kodzie NDK użytkownika. Przeczytaj dokumentację JNI (od firmy Sun) i sprawdź plik docs/STABLE-APIS.html w swoim folderze NDK, aby uzyskać dostęp do legalnego i udokumentowanego interfejsu API. –

Odpowiedz

4

Globalne referencje nie przeszkodzi błąd segmentacji w nowym wątku, jeśli spróbujesz użyć odwołania JNIEnv lub javavm bez przymocowania wątku do maszyny wirtualnej. Robiłeś to poprawnie za pierwszym razem, Mārtiņš Možeiko myli się sugerując, że coś było nie tak z tym, co robisz.

Nie należy go usuwać, po prostu nauczyć się z niego korzystać. Ten facet nie wie, o czym mówi, jeśli jest w jni.h, możesz być całkiem pewien, że nigdzie się nie wybiera. Przyczyna, dla której nie jest udokumentowana, jest prawdopodobnie dlatego, że jest śmiesznie wymowna. Nie musisz tworzyć obiektów GlobalReference ani niczego, po prostu zrób coś takiego:

#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

Skąd mogę powiedzieć, że użycie czegoś z jni.h jest złe lub niedozwolone? –

+1

"To nie jest funkcja publicznego interfejsu API NDK. Używasz czegoś nieudokumentowanego.Aby uzyskać JavaVM * w NDK, musisz wszczepić globalną funkcję JNI_OnLoad, która jest automatycznie wywoływana, gdy twoja biblioteka współdzielona zostanie załadowana. "Przykro mi to mówić, ale to całe stwierdzenie jest po prostu niepoprawne –

+0

A to prawda -' android :: AndroidRuntime :: getJavaVM' nie jest funkcją lub metodą publiczną w jni.h. Nigdy nie powiedziałem, że używanie funkcji lub metod z jni.h (takich jak globalne JNI_OnLoad, JavaVM lub JNIEnv) nie jest dozwolone, ale sugerowałeś, że powiedziałem coś o nie używa go poprawnie z funkcjami od jni.h. Jak może to robić właściwie za pomocą funkcji ** android :: AndroidRuntime :: getJavaVM ** z androida, której nie ma w jni.h? –

0

rozwiązało problem. Błąd segmentacji wynikał z tego, że nie mogłem pobrać obiektu klasy jclass z obiektu JNIEnv pobranego ze współużytkowanego wskaźnika jvm.

Propagowałem obiekt globalnej klasy jclass wraz z jvm i problem został rozwiązany.

Dzięki za pomoc Mārtiņš Možeiko! ..

Pozdrawiam, neeraj

Powiązane problemy