【问题标题】:JNI - Calling Java Method from C++JNI - 从 C++ 调用 Java 方法
【发布时间】:2013-02-12 16:07:05
【问题描述】:

所以我一直在尝试从 C++ 调用 java 方法,但没有任何运气。这是我收到的错误:

JNI 错误(应用程序错误):访问过时的本地引用 0x5cb00019(索引 6 在大小为 2 的表中) 虚拟机中止 0xdeadd00d (code=1) 处的致命信号 11 (SIGSEGV)

这是我在代码中所做的(java 端):

    public class Wrapper extends Activity{
        private native void initJNIBridge();
            static final String TAG = "Wrapper";

    protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);

            initJNIBridge(); // Calls C++ function.
    }

    public void upgradeAdFree() {
             Log.d(TAG, "Wrapper::upgradeAdFree()");
    }

这里是 C++ 方面:

    typedef struct JniMethodInfo_
    {
        JNIEnv *    env;
        jclass      classID;
        jmethodID   methodID;
    } JniMethodInfo;

    extern "C"
    {
static jobject javaObj;

// get env and cache it
static JNIEnv* getJNIEnv(void)
{

    JavaVM* jvm = cocos2d::JniHelper::getJavaVM();
    if (NULL == jvm) {
        LOGD("Failed to get JNIEnv. JniHelper::getJavaVM() is NULL");
        return NULL;
    }

    JNIEnv *env = NULL;
    // get jni environment
    jint ret = jvm->GetEnv((void**)&env, JNI_VERSION_1_4);

    switch (ret) {
        case JNI_OK :
            // Success!
            return env;

        case JNI_EDETACHED :
            // Thread not attached

            // TODO : If calling AttachCurrentThread() on a native thread
            // must call DetachCurrentThread() in future.
            // see: http://developer.android.com/guide/practices/design/jni.html

            if (jvm->AttachCurrentThread(&env, NULL) < 0)
            {
                LOGD("Failed to get the environment using AttachCurrentThread()");
                return NULL;
            } else {
                // Success : Attached and obtained JNIEnv!
                return env;
            }

        case JNI_EVERSION :
            // Cannot recover from this error
            LOGD("JNI interface version 1.4 not supported");
        default :
            LOGD("Failed to get the environment using GetEnv()");
            return NULL;
    }
}

// get class and make it a global reference, release it at endJni().
static jclass getClassID(JNIEnv *pEnv)
{
    jclass ret = pEnv->FindClass(CLASS_NAME);
    if (! ret)
    {
        LOGD("Failed to find class of %s", CLASS_NAME);
    }

    return ret;
}
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *methodName, const char *paramCode)
{
    jmethodID methodID = 0;
    JNIEnv *pEnv = 0;
    bool bRet = false;

    do 
    {
        pEnv = getJNIEnv();
        if (! pEnv)
        {
            break;
        }

        jclass classID = getClassID(pEnv);

        methodID = pEnv->GetMethodID(classID, methodName, paramCode);
        if (! methodID)
        {
            LOGD("Failed to find method id of %s", methodName);
            break;
        }

        methodinfo.classID = classID;
        methodinfo.env = pEnv;
        methodinfo.methodID = methodID;


        bRet = true;
    } while (0);

    return bRet;
}   

JNIEXPORT void JNICALL Java_org_test_games_Wrapper_initJNIBridge(JNIEnv *, jobject jobj){
    LOGD("Java_org_test_games_Wrapper_initJNIBridge()");

    javaObj = jobj;

    return;
}

void upgradeAdFreeJNI()
{      
    LOGD("upgradeAdFreeJNI");

    JniMethodInfo methodInfo;
    if (! getMethodInfo(methodInfo, "upgradeAdFree", "()V"))
    {
        LOGD("Cannot find method!");
        return;
    }

    methodInfo.env->CallVoidMethod(javaObj, methodInfo.methodID);
}


}

这里的任何建议都将不胜感激,因为我已经为此困扰了几天,而且调试它并不是世界上最简单的任务。

谢谢

【问题讨论】:

    标签: java android c++ crash java-native-interface


    【解决方案1】:

    问题是您指向作业的静态指针不再有效。您需要保护它免受任何垃圾收集器运行。这可以通过使用全局引用而不是本地引用来完成。 而不是仅仅分配指针,而是创建一个 globalRef。

    JNIEXPORT void JNICALL Java_org_test_games_Wrapper_initJNIBridge(JNIEnv *, jobject jobj)
    {
        LOGD("Java_org_test_games_Wrapper_initJNIBridge()");
    
        javaObj = env->NewGlobalRef(env, jobj);
    
    return;
    }
    

    但请注意,您还必须释放 globafRef。

    【讨论】:

      【解决方案2】:

      您不能像错误所说的那样简单地存储指向对象的指针。当你想存储它时,你必须存储对对象的本地或全局引用。见http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#global_local

      改为:

          JNIEXPORT void JNICALL Java_org_test_games_Wrapper_initJNIBridge(JNIEnv *env, jobject jobj){
              LOGD("Java_org_test_games_Wrapper_initJNIBridge()");
      
              javaObj = NewGlobalRef(env, jobj);
      
              return;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-15
        • 1970-01-01
        • 2012-07-04
        相关资源
        最近更新 更多