2013-08-20 53 views
0

當我的UDP程序調用我的JNI函數CallVoidMethod時,我的程序崩潰了。我在解決logcat問題時遇到了問題。任何幫助將不勝感激。當CallVoidMethod將java函數傳遞給handler時,JNI崩潰

我的代碼片段:

JNI功能:

jmethodID constructID, methodID; 
JNIEnv* env; 
jclass clazz; 
JavaVM *g_jm; 
int downLoad_speed_test_start(JNIEnv * envl, jobject thiz, int serverport) { 
     jobject obj; 


    struct sockaddr_in servAddr, clientAddr; 
    int slen = sizeof(clientAddr); 
    char buf[512]; 
    int socket_ovdp; 
    if ((socket_ovdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 
     __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", 
       "\nSocket() unsuccessful\n"); 
    else 
     __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", 
       "\nServer: Socket() successful\n"); 

    bzero(&servAddr, sizeof(servAddr)); 

    servAddr.sin_family = AF_INET; 
    servAddr.sin_port = htons(serverport); 
    inet_addr("127.0.0.1"); 
     clazz=env->GetObjectClass(thiz); 
     constructID = env->GetMethodID(clazz, "<init>","()V"); 
     methodID = env->GetMethodID(clazz,"jniCall","(I)V"); 
     obj=env->NewObject(clazz,constructID); 
     JavaVM *jm; 
     env->GetJavaVM(&jm); 

    if (bind(socket_ovdp, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) 
     __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", 
       "\nServer : bind() failed!\n"); 

    else 
    { 
     __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", 
       "\nServer : bind() successful\n"); 
    } 

    while (true) { 
     if (recvfrom(socket_ovdp, buf, 512, 0, (struct sockaddr*) &clientAddr, 
       &slen) == -1) 
      __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", 
        "\nRecvfrom() did not work\n"); 
     else 
     { 
     //handle message 
     __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", "\nReceived: %s\n\n", 
       buf); 
      int newbuf = 5; 
      env->CallVoidMethod(obj,methodID,newbuf); 
     } 
    } 

    return 0; 

} 

Java函數來處理:

void jniCall(int arg) 
    { 

     Message m = mHandler.obtainMessage(); 
     m.arg1=arg; 
     mHandler.sendMessageDelayed(m, 10/* ms */); 
     } 

public Handler mHandler = new Handler(Looper.getMainLooper()){ 
     @Override 
     public void handleMessage(Message msg){ 
      try{ 
       chatbox.setText("Got it!"); 
      }catch(Exception e){ 
       Log.i("MYLOG", "Message was not handled."); 
      } 
      //chatbox.setText(chatbox.getText() + "Got it!"); 
     } 
    }; 

我的logcat:

08-20 18:09:26.200: W/dalvikvm(3521): JNI WARNING: threadid=15 using env from threadid=16 
08-20 18:09:26.200: W/dalvikvm(3521):    in Lcom/WifiSpeedTest2/WifiSpeedTestActivity;.ovt_downLoad_speed_test_start:(I)I (CallVoidMethodV) 
08-20 18:09:26.210: I/dalvikvm(3521): "Thread-154" prio=5 tid=15 NATIVE 
08-20 18:09:26.210: I/dalvikvm(3521): | group="main" sCount=0 dsCount=0 obj=0x40d332f8 self=0x2a1b96f0 
08-20 18:09:26.221: I/dalvikvm(3521): | sysTid=3555 nice=0 sched=0/0 cgrp=apps handle=706079760 
08-20 18:09:26.221: I/dalvikvm(3521): | state=R schedstat=(12) utm=0 stm=0 core=0 
08-20 18:09:26.250: I/Thread:(3521): connected lost 
08-20 18:09:26.380: I/dalvikvm(3521): #00 pc 000012a0 /system/lib/libcorkscrew.so (unwind_backtrace_thread+27) 
08-20 18:09:26.411: I/dalvikvm(3521): #01 pc 0005faa8 /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+35) 
08-20 18:09:26.411: I/dalvikvm(3521): #02 pc 00053914 /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+303) 
08-20 18:09:26.420: I/dalvikvm(3521): #03 pc 000539ae /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25) 
08-20 18:09:26.420: I/dalvikvm(3521): #04 pc 00038aba /system/lib/libdvm.so 
08-20 18:09:26.430: I/dalvikvm(3521): #05 pc 0003fc24 /system/lib/libdvm.so 
08-20 18:09:26.430: I/dalvikvm(3521): #06 pc 0000150c /data/app-lib/com.WifiSpeedTest2-2/libwifiSpeedTest2.so (_JNIEnv::CallVoidMethod(_jobject*, _jmethodID*, ...)+60) 
08-20 18:09:26.430: I/dalvikvm(3521): #07 pc 00001c18 /data/app-lib/com.WifiSpeedTest2-2/libwifiSpeedTest2.so (ovt_downLoad_speed_test_start(_JNIEnv*, _jobject*, int)+956) 
08-20 18:09:26.430: I/dalvikvm(3521): #08 pc 00001e64 /data/app-lib/com.WifiSpeedTest2-2/libwifiSpeedTest2.so (ovt_downLoad_speed_test_start_jni(_JNIEnv*, _jobject*, int)+72) 
08-20 18:09:26.441: I/dalvikvm(3521): #09 pc 0001e290 /system/lib/libdvm.so (dvmPlatformInvoke+112) 
08-20 18:09:26.470: I/dalvikvm(3521): #10 pc 0004d1f8 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+391) 
08-20 18:09:26.470: I/dalvikvm(3521): #11 pc 00038b44 /system/lib/libdvm.so (dvmCheckCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+7) 
08-20 18:09:26.470: I/dalvikvm(3521): #12 pc 000276a0 /system/lib/libdvm.so 
08-20 18:09:26.470: I/dalvikvm(3521): #13 pc 0002b540 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184) 
08-20 18:09:26.470: I/dalvikvm(3521): #14 pc 0005f9d4 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+271) 
08-20 18:09:26.470: I/dalvikvm(3521): #15 pc 0005f9fe /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+19) 
08-20 18:09:26.470: I/dalvikvm(3521): #16 pc 00054576 /system/lib/libdvm.so 
08-20 18:09:26.481: I/dalvikvm(3521): #17 pc 0000e3b8 /system/lib/libc.so (__thread_entry+72) 
08-20 18:09:26.481: I/dalvikvm(3521): #18 pc 0000dab0 /system/lib/libc.so (pthread_create+160) 
08-20 18:09:26.481: I/dalvikvm(3521): at com.WifiSpeedTest2.WifiSpeedTestActivity.ovt_downLoad_speed_test_start(Native Method) 
08-20 18:09:26.491: I/dalvikvm(3521): at com.WifiSpeedTest2.WifiSpeedTestActivity$receiveVideoThread.run(WifiSpeedTestActivity.java:96) 
08-20 18:09:26.500: E/dalvikvm(3521): VM aborting 
08-20 18:09:26.500: A/libc(3521): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 3555 (Thread-154) 

編輯:添加的OnLoad等功能

int downLoad_speed_test_start_jni(JNIEnv * envl, jobject thiz, 
     int serverport) { 

    env = envl; 
    //env->GetJavaVM(&g_jm); 
    downLoad_speed_test_start(env, thiz, serverport); 
} 


jint JNI_OnLoad(JavaVM* vm, void* reserved) 

{ 

    jint result = -1; 
    g_jm = vm; 

    // catched_jvm = vm; 
    LOGE("JNI_OnLoad\n"); 
    static const char* const strClassName = 
      "com/WifiSpeedTest2/WifiSpeedTestActivity"; 
    //static const char* const strClassName = "com/MultPkg/Mult"; 

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 

     LOGE("ERROR: GetEnv failed\n"); 

     return result; 

    } 

    if (env == NULL) { 

     LOGE("ERROR: env is NULL\n"); 

     return result; 

    } 

    /* find the class handle */ 

    clazz = env->FindClass(strClassName); 

    if (clazz == NULL) { 

     LOGE("Can't find class %s\n", strClassName); 

     return result; 

    } 

    // fields.clazz = (jclass) env->NewGlobalRef(clazz); 

    /* register all the methods */ 

    if (env->RegisterNatives(clazz, gMethods, 
      sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK) 

    { 

     LOGE("Failed registering methods for %s\n", strClassName); 

     return result; 

    } 

    /* success -- return valid version number */ 

    result = JNI_VERSION_1_4; 
    __android_log_print(ANDROID_LOG_DEBUG, "MY_TAG", 
         "\nJNI OnLoad worked.\n"); 
    return result; 
} 

回答

5
JNI WARNING: threadid=15 using env from threadid=16 

你分享JNIEnv線程之間。不要那樣做 - JNIEnv是線程特定的。

可以使用從Java代碼調用的本地方法的第一個參數傳入的內容,或者在全局中保存JavaVM,並使用GetEnv call獲取JNIEnv

另請參閱​​頁面。

+0

很抱歉,你能否澄清一下你的意思是「使用什麼作爲從Java代碼調用的本機方法的第一個參數傳入?」?我想嘗試實現這個選項,但我不是很瞭解它。 – user2562568

+0

你有一個叫做「env」的全局JNIEnv,而不是JNIEnv作爲第一個參數傳遞給'downLoad_speed_test_start'(「envl」)。我的猜測是,當你在while(true)循環中時,另一個線程正在用它自己的線程本地JNIEnv替換「env」。此時該功能失敗。擺脫全局的「env」 - JNIEnv永遠不應該處於全局狀態 - 將「envl」參數重命名爲「env」,修復使用全局「env」的任何代碼,並且它應該起作用。 – fadden

+0

如果你想看看它,我增加了兩個更多的功能。我實際上認爲它使用了你在全球提到的第二個選項。我不是正確地將env傳遞給我的'download_speed_test_start'函數嗎? – user2562568

2

如果要使用JNIEnv,則必須在線程中調用AttachCurrentThread()將其自身附加到VM並獲取JNI接口指針。這裏是Oracle's JNI reference