【问题标题】:JNI loses reference to native methodsJNI 失去对本机方法的引用
【发布时间】:2010-03-16 10:52:08
【问题描述】:

作为以后在Android中使用的例子,我写了一个简单的回调接口。这样做时,我遇到了以下错误或错误或其他什么。在 C 中,应该执行两个注释行,从而调用 C 回调 onChange。但相反,我得到了一个 UnsatisfiedLinkError。直接在 Java 中调用本机方法就可以了。如示例中所示直接从 C 调用它也会产生 UnsatisfiedLinkError。我愿意接受有关此问题或解决方法等的任何建议。 Java部分:

import java.util.LinkedList;
import java.util.Random;

interface Listener {
    public void onChange(float f);
}
class Provider {
    LinkedList<Listener> all;
    public Provider() {
        all = new LinkedList<Listener>();
    }
    public void registerChange(Listener lst) {
        all.add(lst);
    }
    public void sendMsg() {
        Random rnd = new Random();
        for(Listener l : all) {
            try {
                l.onChange(rnd.nextFloat());
            }
            catch(Exception e) {
                System.out.println(e);
            }
        }
    }
}
class Inheritance implements Listener {
    static public void main(String[] args) {
        System.load(System.getProperty("user.dir") + "/libinheritance.so");
    }
    public native void onChange(float f);
}

C 部分:

#include "inheritance.h"

jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
    JNIEnv *env;
    (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4); 

    jclass inheritance = (*env)->FindClass(env, "Inheritance");
    jobject o_inheritance = (*env)->NewObject(env, inheritance, (*env)->GetMethodID(env, inheritance, "<init>", "()V"));
    jclass provider = (*env)->FindClass(env, "Provider");
    jobject o_provider = (*env)->NewObject(env, provider, (*env)->GetMethodID(env, provider, "<init>", "()V"));

    g_inheritance = (*env)->NewGlobalRef(env, inheritance);
    g_provider = (*env)->NewGlobalRef(env, provider);

    (*env)->CallVoidMethod(env, o_inheritance, (*env)->GetMethodID(env, inheritance, "onChange", "(F)V"), 1.0);

    //(*env)->CallVoidMethod(env, o_provider, (*env)->GetMethodID(env, provider, "registerChange", "(LListener;)V"), o_inheritance);
    //(*env)->CallVoidMethod(env, o_provider, (*env)->GetMethodID(env, provider, "sendMsg", "()V"));

    (*env)->DeleteLocalRef(env, o_inheritance);
    (*env)->DeleteLocalRef(env, o_provider);

    return JNI_VERSION_1_4;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) {
    JNIEnv *env;
    (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4); 
    (*env)->DeleteGlobalRef(env, g_inheritance);
    (*env)->DeleteGlobalRef(env, g_provider);
 }
JNIEXPORT void JNICALL Java_Inheritance_onChange(JNIEnv *env, jobject self, jfloat f) {
    printf("[C] %f\n", f);
}

头文件:

#include <jni.h>
/* Header for class Inheritance */

#ifndef _Included_Inheritance
#define _Included_Inheritance
#ifdef __cplusplus
extern "C" {
#endif

jclass g_inheritance, g_provider;

/*
 * Class:     Inheritance
 * Method:    onChange
 * Signature: (F)V
 */
JNIEXPORT void JNICALL Java_Inheritance_onChange(JNIEnv *, jobject, jfloat);

jint JNI_OnLoad(JavaVM *, void *);

#ifdef __cplusplus
}
#endif
#endif

编译:

gcc -c -fPIC -I /usr/lib/jvm/java-6-openjdk/include -I /usr/lib/jvm/java-6-openjdk/include/linux/inheritance.c inheritance.h
gcc -g -o -shared libinheritance.so -shared -Wl,-soname,libinheritance.so -lc inheritance.o

【问题讨论】:

    标签: java c callback java-native-interface


    【解决方案1】:

    阅读 GlobalRefs 上的 JNI 规范章节。您不能将 jobject 或 jclass 值存储在静态变量中,只能存储 GlobalRefs。

    【讨论】:

    • 作为唯一的函数是 JNI_OnLoad 现在调用 refs 应该不是问题。但是感谢您指出错误,以后可能会引起更多混乱。我相应地更改了代码。虽然主要问题仍然存在。
    • @lhw 你确定你提供给 GetMethodID() 的签名是正确的吗?您应该通过 javap -s 获取它们,而不是尝试自己手动构建它们。您还应该单独调用 GetMethodID() 并测试结果为零,而不是仅仅假设它有效。您必须在 JNI 中非常进行防御性编程。
    【解决方案2】:

    经过仔细考虑,如果不先注册本地方法,就不可能在 JNI_onLoad 中调用在同一共享对象中实现的本地方法。因为它们是在 JNI_onLoad 之后加载的。以下是问题的解决方案:

    继承.c

    #include "inheritance.h"
    
    jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
        JNIEnv *env;
        (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4); 
    
        jclass inheritance = (*env)->FindClass(env, "Inheritance");
        (*env)->RegisterNatives(env, inheritance, methods, 1);
    
        jobject o_inheritance = (*env)->NewObject(env, inheritance, (*env)->GetMethodID(env, inheritance, "<init>", "()V"));
        jclass provider = (*env)->FindClass(env, "Provider");
        jobject o_provider = (*env)->NewObject(env, provider, (*env)->GetMethodID(env, provider, "<init>", "()V"));
    
        (*env)->CallVoidMethod(env, o_provider, (*env)->GetMethodID(env, provider, "registerChange", "(LListener;)V"), o_inheritance);
        (*env)->CallVoidMethod(env, o_provider, (*env)->GetMethodID(env, provider, "sendMsg", "()V"));
    
        return JNI_VERSION_1_4;
    }
    void onChange(JNIEnv *env, jobject self, jfloat f) {
        printf("[C] %f\n", f);
    }
    

    继承.h

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class Inheritance */
    
    #ifndef _Included_Inheritance
    #define _Included_Inheritance
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    /*
     * Class:     Inheritance
     * Method:    onChange
     * Signature: (F)V
     */
    void onChange(JNIEnv *, jobject, jfloat);
    
    JNINativeMethod methods[] = {
        {"onChange", "(F)V", (void *)onChange}
    };
    
    jint JNI_OnLoad(JavaVM *, void *);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    继承.java

    import java.util.LinkedList;
    import java.util.Random;
    
    interface Listener {
        public void onChange(float f);
    }
    class Provider {
        LinkedList<Listener> all;
        public Provider() {
            all = new LinkedList<Listener>();
        }
        public void registerChange(Listener lst) {
            all.add(lst);
        }
        public void sendMsg() {
            Random rnd = new Random();
            for(Listener l : all) {
                try {
                    l.onChange(rnd.nextFloat());
                }
                catch(Exception e) {
                    System.out.println(e);
                }
            }
        }
    }
    class Inheritance implements Listener {
        static public void main(String[] args) {
            System.load(System.getProperty("user.dir") + "/libinheritance.so");
        }
        public native void onChange(float f);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-25
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      相关资源
      最近更新 更多