Android JNI: GetObjectClass crashs with SIGSEGV (not a valid JNI reference)

Я пытаюсь создать новый поток, поэтому я передаю VM из моего метода initialize (вызываемого из Java) в мой новый поток. В потоке я вызываю AttachCurrentThread и получаю JNIEnv* env.

Позже я пытаюсь вызвать GetObjectClass со средой, и происходит сбой. Я полагаю, что это происходит потому, что объект может быть не инициализирован, но я пытаюсь вызвать метод, определенный в классе, который содержит родной метод. Я пытался следовать разделу 4.2 (начало) из http://java.sun.com/docs/books/jni/html/fldmeth.html.

Что-то очень странное: Я тестирую на HTC Dream под управлением 2.2, и следующий код не падает, но на Motorola Droid под управлением 2.2.2 он падает все время!

Вот мой код:

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

Новый поток:

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

Строка cls = env->GetObjectClass(javaObjHost); падает со следующим результатом:

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

Мой java код:

public class HostConnection {
    static {
        System.loadLibrary("hostConnection");
    }

    public void setStatus(boolean bool) {
        ...
    }

    public native void initialize(int defaultPort);
}

Может ли кто-нибудь помочь мне? Я хочу вызвать метод setStatus() внутри моего класса, не создавая новый объект.

EDIT:

Это новый код, в данный момент он разрушается.

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

Я получаю следующий сбой:

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

Я знаю, что сбой происходит на GetMethodID(). Я действительно не уверен, почему. Любая помощь была бы очень признательна.

Большое спасибо.

9
задан Jary 23 October 2011 в 18:52
поделиться