Android JNI: GetObjectClass crashing with SIGSEGV (not valid JNI reference)

I am trying to create a new thread, and so I am passing the VM from my initialize method (called from Java) to my new thread. In the thread, I call AttachCurrentThread and get JNIEnv * env.

Later I try to call GetObjectClass with the environment and it will work. I believe this is because the object cannot be initialized, but I'm trying to call a method defined in a class that contains its own method. I am trying to follow section 4.2 (start) of http://java.sun.com/docs/books/jni/html/fldmeth.html .

Something very strange: I am testing with HTC Dream running 2.2, and the following code does not crash, but with a Motorola Droid running 2.2.2, it crashes all the time!

This is my code:

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); } 

New thread:

 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); 

String cls = env-> GetObjectClass (javaObjHost); failure with the following output:

 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 .... 

My Java code is:

 public class HostConnection { static { System.loadLibrary("hostConnection"); } public void setStatus(boolean bool) { ... } public native void initialize(int defaultPort); } 

Can anyone help me out? I would like to call the setStatus () method inside my class without creating a new object.

EDIT:

This is new code that is crashing currently crashing.

 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); } 

I get the following crash:

 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 

I know that it crashes on GetMethodID (). I really don't know why. Any help would be greatly appreciated.

Many thanks.

+7
source share
1 answer

You get the object from Java_com_device_client_HostConnection_initialize as a local link, then pass it to your new thread in your javaInfo structure.

A local link is only valid in the current thread, just like the JNIEnv* pointer.

That way, when you get it from the structure in a new thread, you have an invalid object reference, which explains the crash.

Try to get the WeakGlobal link in the Java_com_device_client_HostConnection_initialize method using the NewWeakGlobalRef method from JNIEnv .

Read the fifth chapter of the JNI docs to understand the differences between local, global, and weak global links.

+9
source

All Articles