multithreading - r16 - Compartir un JavaVM*entre hilos en Android NDK
ndk r13 (2)
Resuelve 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 Global jclass de referencia junto con el jvm y el problema fue resuelto.
Gracias por su ayuda Mārtiņš Možeiko! ..
Saludos, Neeraj
Quiero llamar a los métodos de clase de Java desde un archivo cpp que recibe llamadas de otro ejecutable.
Para lograr esto, he recuperado un puntero JavaVM usando el método android :: AndroidRuntime :: getJavaVM () en el archivo .cpp que recibe directamente las llamadas al método JNI. Estoy compartiendo este puntero de JavaVM a través del constructor con el eventual archivo .cpp al que llamo los métodos de Java requeridos 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, obtengo un error SIGSEGV al ejecutar este código.
Según la documentación de JNI, esta parece ser la forma adecuada de obtener JNIEnv en contextos arbitrarios: http://java.sun.com/docs/books/jni/html/other.html#26206
Cualquier ayuda en este sentido será apreciada.
Saludos, Neeraj
Las referencias globales NO evitarán un error de segmentación en un nuevo hilo si intenta utilizar una referencia JNIEnv o JavaVM sin conectar el 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 elimine, solo aprenda cómo 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();
}