Android JNI:GetObjectClass 因 SIGSEGV 崩溃(不是有效的 JNI 引用)

发布于 2024-12-11 04:46:00 字数 5259 浏览 0 评论 0原文

我正在尝试创建一个新线程,因此我将 VM 从我的方法初始化(从 Java 调用)传递到我的新线程。在线程中,我调用 AttachCurrentThread 并获取 JNIEnv* env。

后来,我尝试使用环境调用 GetObjectClass,但它崩溃了。我相信这是因为该对象可能未初始化,但我试图调用包含本机方法的类中定义的方法。我一直在尝试遵循 http://java 的第 4.2 节(开始) .sun.com/docs/books/jni/html/fldmeth.html

非常奇怪的事情:我正在使用运行 2.2 的 HTC Dream 进行测试,以下代码不会崩溃,但使用运行 2.2.2 的 Motorola Droid 时,它总是崩溃!

这是我的代码:

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() 方法,而不创建新对象。

编辑:

这是新代码,当前正在崩溃。

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() 上崩溃。我真的不知道为什么。任何帮助将不胜感激。

非常感谢。

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

Later on, I try to call GetObjectClass with the environment and it crashes. I believe this is because the object may not be initialize, but I am trying to call a method that is defined in the class that contains the native method. I have been trying to follow Section 4.2 (beginning) of http://java.sun.com/docs/books/jni/html/fldmeth.html.

Something very strange: I am testing with an HTC Dream running 2.2 and the following code does not crash, but with a Motorola Droid running 2.2.2 it does crash 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);
}

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

The line cls = env->GetObjectClass(javaObjHost); is crashing 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:

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

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

    public native void initialize(int defaultPort);
}

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

EDIT:

This is the new code, it 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 am getting 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 it crashes on GetMethodID(). I am really not sure why. Any help would really be greatly appreciated.

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挥剑断情 2024-12-18 04:46:00

您将从 Java_com_device_client_HostConnection_initialize 获取 object 作为本地引用,然后将其传递给 javaInfo 结构中的新线程。

本地引用仅在当前线程中有效,与JNIEnv*指针的方式相同。

因此,当您从新线程中的结构中获取它时,您将获得对该对象的无效引用,这解释了崩溃。

尝试使用 JNIEnv 中的 NewWeakGlobalRef 方法在 Java_com_device_client_HostConnection_initialize 方法中获取 WeakGlobal 引用。

阅读 JNI 文档的第五章,了解本地引用、全局引用和弱全局引用之间的区别。

You're getting the object from Java_com_device_client_HostConnection_initialize as a local reference, then you pass it to your new thread in your javaInfo struct.

Local reference are valid only in the current thread, in the same manner as JNIEnv* pointer.

Thus, when you get it from the struct in the new thread, you have an invalid reference to the object, which explains the crash.

Try to get a WeakGlobal reference in Java_com_device_client_HostConnection_initialize method using NewWeakGlobalRef method from JNIEnv.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文