Android JNI: GetObjectClass se bloquea con SIGSEGV (no es una referencia JNI válida)
Estoy intentando crear un nuevo hilo, así que estoy pasando la VM de mi método initialize (llamado de Java) a mi nuevo hilo. En el hilo, llamo AttachCurrentThread y obtengo el JNIEnv * env.
Más adelante, intento llamar a GetObjectClass con el entorno y se bloquea. Creo que esto es porque el objeto no puede ser inicializar, pero estoy tratando de llamar a un método que se define en la clase que contiene el método nativo. He estado tratando de seguir la Sección 4.2 (principio) de http://java.sun.com/docs/books/jni/html/fldmeth.html .
- No se encontró JNI_OnLoad en ... saltando init
- Cómo devolver array int de Java a JNI
- Archivo de Android.mk - incluye todos los archivos de origen en diferentes carpetas y subcarpetas
- Cómo encontrar fugas de memoria del código nativo en android
- Ptrace devuelve -1 en Android
Algo muy extraño: estoy probando con un HTC Dream corriendo 2.2 y el siguiente código no se bloquea, pero con un Motorola Droid ejecutando 2.2.2 se bloquea todo el tiempo!
Este es mi código:
C ++
JNIEXPORT void JNICALL Java_com_device_client_HostConnection_initialize (JNIEnv * env, jobject obj, jint port) { JavaVM *vm; jint result = env->GetJavaVM(&vm); if (result < 0) { LOGE("Error using GetJavaVM\n"); exit(-1); } struct javaInfo* data = (struct javaInfo*) malloc(sizeof(struct javaInfo)); data->vm = vm; data->javaObjHost = obj; pthread_t pth; pthread_create(&pth, NULL, startServer, (void *) data); }
El nuevo hilo:
void *startServer(void* arg) { jclass cls; jmethodID mid; JNIEnv* env = NULL; struct javaInfo* data = (struct javaInfo*) arg; JavaVM* vm = data->vm; jobject javaObjHost = data->javaObjHost; if (vm == NULL) { LOGE("VM is null\n"); } vm->AttachCurrentThread(&env, NULL); cls = env->GetObjectClass(javaObjHost); mid = env->GetMethodID(cls, "setStatus", "(Z)V"); if (mid == 0) { LOGD("ERROR: GetMethodID\n"); exit(-1); } env->CallVoidMethod(javaObjHost, mid, false);
La línea cls = env-> GetObjectClass (javaObjHost); Se bloquea con la siguiente salida:
W/dalvikvm( 5827): JNI WARNING: 0x44872da0 is not a valid JNI reference W/dalvikvm( 5827): in Ldalvik/system/NativeStart;.run ()V (GetObjectClass) I/dalvikvm( 5827): "Thread-9" prio=5 tid=8 RUNNABLE I/dalvikvm( 5827): | group="main" sCount=0 dsCount=0 s=N obj=0x448734c8 self=0x229da8 I/dalvikvm( 5827): | sysTid=5834 nice=0 sched=0/0 cgrp=default handle=2265136 I/dalvikvm( 5827): | schedstat=( 885010 3631591 2 ) I/dalvikvm( 5827): at dalvik.system.NativeStart.run(Native Method) I/dalvikvm( 5827): E/dalvikvm( 5827): VM aborting I/DEBUG ( 5511): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG ( 5511): Build fingerprint: 'verizon/voles/sholes/sholes:2.2.2/FRG83G/91102:user/release-keys' I/DEBUG ( 5511): pid: 5827, tid: 5834 >>> com.device.client <<< I/DEBUG ( 5511): signal 11 (SIGSEGV), fault addr deadd00d ....
Mi código java:
public class HostConnection { static { System.loadLibrary("hostConnection"); } public void setStatus(boolean bool) { ... } public native void initialize(int defaultPort); }
¿Podría alguien ayudarme por favor? Me gustaría llamar al método setStatus () dentro de mi clase, sin crear un nuevo objeto.
EDITAR:
Este es el nuevo código, se está estrellando en el momento de estrellarse.
JNIEXPORT void JNICALL Java_com_device_client_HostConnection_initialize (JNIEnv * env, jobject obj, jint port) { JavaVM *vm; jint result = env->GetJavaVM(&vm); if (result < 0) { LOGE("Error using GetJavaVM\n"); exit(-1); } jclass clsLocal = env->GetObjectClass(obj); if (clsLocal == NULL) { LOGE("ERROR: Cannot find class HostConnection\n"); exit(-1); } jclass hostClass = (jclass) env->NewWeakGlobalRef(clsLocal); if (hostClass == NULL) { LOGE("ERROR: Run out of memory for weak global ref\n"); exit(-1); } struct javaInfo* data = (struct javaInfo*) malloc(sizeof(struct javaInfo)); data->vm = vm; data->hostClass = hostClass; pthread_t pth; pthread_create(&pth, NULL, startServer, (void *) data); } void *startServer(void* arg) { JNIEnv* env = NULL; jmethodID mid; struct fb_var_screeninfo vinfo; char server[MAXHOSTNAMELEN]; struct javaInfo* data = (struct javaInfo*) arg; JavaVM* vm = data->vm; jclass hostClass = data->hostClass; if (vm == NULL) { LOGE("VM is null\n"); } vm->AttachCurrentThread(&env, NULL); mid = env->GetMethodID(hostClass, "setStatus", "(Z)V"); if (mid == 0) { LOGD("ERROR: GetMethodID\n"); exit(-1); } env->CallVoidMethod(hostClass, mid, false); }
Estoy recibiendo el siguiente accidente:
W/dalvikvm( 7650): JNI WARNING: jclass points to invalid object 0xda88d23f I/dalvikvm( 7650): "Thread-9" prio=5 tid=8 NATIVE I/dalvikvm( 7650): | group="main" sCount=0 dsCount=0 s=N obj=0x448734f8 self=0x228a20 I/dalvikvm( 7650): | sysTid=7657 nice=0 sched=0/0 cgrp=default handle=2260192 I/dalvikvm( 7650): | schedstat=( 854493 9155273 2 ) I/dalvikvm( 7650): at dalvik.system.NativeStart.run(Native Method) I/dalvikvm( 7650): E/dalvikvm( 7650): VM aborting I/DEBUG ( 5511): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG ( 5511): Build fingerprint: 'verizon/voles/sholes/sholes:2.2.2/FRG83G/91102:user/release-keys' I/DEBUG ( 5511): pid: 7650, tid: 7657 >>> com.device.client <<< I/DEBUG ( 5511): signal 11 (SIGSEGV), fault addr deadd00d
Sé que se bloquea en GetMethodID (). Realmente no estoy seguro de por qué. Cualquier ayuda sería muy apreciada.
Muchas gracias.
- Crear mapa de bits de la matriz de bytes, que se descomprime desde un archivo JPEG a través de libjpeg
- JNI CALL cambia el parámetro jclass o cómo obtener un jobject desde un parámetro jclass
- Cómo crear jni y Android.mk?
- Cómo convertir char a jstring en JNI?
- Android: Xamarin JNI Binding - Herencia de clase abstracta
- ¿Cómo puedo copiar mis bibliotecas .so en el dispositivo Android?
- JNI ERROR (bug de la aplicación): desbordamiento de la tabla de referencia local (máx = 512)
- Cambiar Actividad con JNI Llamar o usar Openfeint provoca App-Crash
Estás recibiendo el object
de Java_com_device_client_HostConnection_initialize
como una referencia local, y luego lo pasas a tu nuevo hilo en tu estructura javaInfo
.
La referencia local es válida sólo en el subproceso actual, de la misma manera que el puntero JNIEnv*
.
Por lo tanto, cuando se obtiene de la estructura en el nuevo hilo, tiene una referencia no válida al objeto, lo que explica el bloqueo.
Trate de obtener una referencia WeakGlobal en el método NewWeakGlobalRef
utilizando el método JNIEnv
de JNIEnv
.
Lea el capítulo cinco de los documentos de la JNI para entender las diferencias entre las referencias globales locales, globales y débiles.