2013-02-12 2 views
3

그래서 저는 C++에서 java 메소드를 호출하지 않으려 고 노력했습니다.JNI - C++에서 Java 메소드 호출

JNI 에러 (앱 버그) : 액세스 부실 로컬 기준 0x5cb00019 0xdeadd00d에서 VM 중단 치명적인 신호 (11) (SIGSEGV) (크기 2의 테이블의 인덱스 6) (이는 I가받는 에러입니다 코드 = 1)

다음

내가 코드 (자바 쪽) 할 것입니다 :

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


} 

나는 이것을 며칠 동안 그리고이 문제를 디버깅하기위한 세계에서 가장 쉬운 작업이 아니기 때문에 여기에있는 모든 의견을 크게 기뻐할 것입니다.

감사

답변

4

문제는 당신하는 jobject에 정적 포인터가 더 이상 유효하지 않는다는 점이다. 가비지 컬렉터가 실행되지 않도록 보호해야합니다. 이것은 로컬 참조 대신 전역 참조를 사용하여 수행 할 수 있습니다. 포인터를 할당하는 대신 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도 해제해야합니다.

+0

감사 mkaes 님의 http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#global_local

변경을 참조하십시오! 그것은 트릭을했다. – kub

2

오류가 표시하는 것처럼 개체에 포인터를 저장하면 안됩니다. 이 객체를 저장하려면 객체에 대한 로컬 또는 전역 참조를 저장해야합니다. 답장을 보내

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