JNI - Call Java Method from C ++

So I am trying to call a Java method from C ++ with no luck. This is the error I am getting:

JNI ERROR (Application Error): Accessing Legacy Local Reference 0x5cb00019 (Index 6 in Size Table 2) VM Cancel Fatal 11 (SIGSEGV) at 0xdeadd00d (Code = 1)

This is what I am doing in code (java-side):

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

      

And here is the C ++ side:

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


}

      

Any suggestions here would be much appreciated as I have been stumped for days and this is not the easiest task in the world to debug this.

thank

+3


source to share


2 answers


The problem is that your static pointer to your jobject is no longer valid. You need to protect it from any garbage collection. This can be done by using global references instead of local ones. Instead of just assigning a pointer, create a 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;
}

      



But keep in mind that you must free globafRef as well.

+4


source


You shouldn't just store a pointer to an object as your error says. If you want to keep it, you need to keep a local or global reference to the object. See http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#global_local

Change to:



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

      

+2


source







All Articles