2011-09-19 138 views
1

我想編寫一個本地方法,它可以從套接字接收數據,然後寫回到從Java輸入參數的ByteArray。因爲我在Java端分配ByteArray,並將它傳遞給本地方法,所以我知道應該使用GetPrimitiveArrayCritical()來獲取此ByteArray的指針。我使用一個名爲socket_loop_native_data的結構體的jbyteArray變量來記住這個輸入的ByteArray,並使用pthread_create()以這個結構體作爲輸入參數啓動一個新的線程。Android JNI原生C++代碼GetPrimitiveArrayCritical()問題

最後,在線程的主體代碼,我用GetPrimitiveArrayCritical()來獲取先前的ByteArray的指針,但是失敗了......

錯誤日誌是:

14:09:32.350 Warning dalvikvm 2780 JNI WARNING: 0x4077ab48 is not a valid JNI reference 
14:09:32.350 Warning dalvikvm 2780    in Ldalvik/system/NativeStart;.run()V (GetPrimitiveArrayCritical) 

這件作品的我的本地代碼是像

struct socket_loop_native_data { 
     pthread_mutex_t thread_mutex; 
     pthread_t thread; 
     struct pollfd *pollData; 
     JavaVM *vm; 
     int envVer; 
     jobject me; 
     jbyteArray javaBuffer; 
     int bufferSize; 
     jbyte *nativeBuffer; 
     char *beginOfBuffer; 
     char *endOfBuffer; 
     int decodedDataSize; 
     bool running; 
}; 

typedef socket_loop_native_data native_data_t; 

static jfieldID field_mNativeDataSocket; 

static inline native_data_t *get_native_data(JNIEnv *env, jobject object) { 
    return (native_data_t *)(env->GetIntField(object, field_mNativeDataSocket)); 
} 

native_data_t *get_SocketLoop_native_data(JNIEnv *env, jobject object) { 
    return get_native_data(env, object); 
} 

JNIEXPORT void JNICALL Java_android_classInitNativeSocket(JNIEnv* env, jclass clazz) { 
    field_mNativeDataSocket = env->GetFieldID(clazz, "mNativeDataSocket", "I"); 
} 

JNIEXPORT void JNICALL Java_android_initializeNativeDataNativeSocket(JNIEnv* env, jobject object) { 

    native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); 
    if (NULL == nat) { 
     LOGD("%s: out of memory!", __FUNCTION__); 
     return; 
    } 
    memset(nat, 0, sizeof(native_data_t)); 

    pthread_mutex_init(&(nat->thread_mutex), NULL); 

    env->SetIntField(object, field_mNativeDataSocket, (jint)nat); 

} 

JNIEXPORT jboolean JNICALL Java_android_startSocketLoopNative(JNIEnv *env, jobject object, jint sock, jbyteArray buffer, jint size) { 

    jboolean result = JNI_FALSE; 

    socket_loop_native_data *nat = get_native_data(env, object); 

    pthread_mutex_lock(&(nat->thread_mutex)); 

    nat->running = false; 

    if (nat->pollData) { 
     LOGD("trying to start SocketLoop a second time!"); 
     pthread_mutex_unlock(&(nat->thread_mutex)); 
     return JNI_FALSE; 
    } 

    nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd)); 
    if (!nat->pollData) { 
     LOGD("out of memory error starting SocketLoop!"); 
     goto done; 
    } 

    memset(nat->pollData, 0, sizeof(struct pollfd)); 

    nat->pollData[0].fd = sock; 
    nat->pollData[0].events = POLLIN; 

    env->GetJavaVM(&(nat->vm)); 
    nat->envVer = env->GetVersion(); 

    nat->me = env->NewGlobalRef(object); 

    nat->javaBuffer = buffer; 
    nat->bufferSize = (int)size; 
    nat->decodedDataSize = 0; 

    pthread_create(&(nat->thread), NULL, socketLoopMain, nat); 
    result = JNI_TRUE; 

done: 
    if (JNI_FALSE == result) { 
     if (nat->me) env->DeleteGlobalRef(nat->me); 
     nat->me = NULL; 
     if (nat->pollData) free(nat->pollData); 
     nat->pollData = NULL; 
    } 

    pthread_mutex_unlock(&(nat->thread_mutex)); 

    return result; 
} 

static void *socketLoopMain(void *ptr) { 

    native_data_t *nat = (native_data_t *)ptr; 
    JNIEnv *env; 

    JavaVMAttachArgs args; 
    char name[] = "SocketLoop"; 
    args.version = nat->envVer; 
    args.name = name; 
    args.group = NULL; 

    nat->vm->AttachCurrentThread(&env, &args); 

    ... 

    nat->nativeBuffer = (jbyte *)(env->GetPrimitiveArrayCritical((nat->javaBuffer), NULL));  

    nat->beginOfBuffer = (char *)(&(nat->nativeBuffer[0])); 
    nat->endOfBuffer = (char *)(&(nat->nativeBuffer[0])) + (nat->bufferSize); 

    ... 
} 

的VM中止後,執行該語句

nat->nativeBuffer = (jbyte *)(env->GetPrimitiveArrayCritical((nat->javaBuffer), NULL)); 

因此...劑量這意味着我可以/不應該使用jbyteArray變量來記住輸入ByteArray並在另一個地方調用GetPrimitiveArrayCritical()?

或者,我忘了做什麼?

任何建議將不勝感激!

+0

解決方案:我應該使用NewGlobalRef()。 –

回答

1

看起來您忘記了「NewGlobalRef」指向您的startSocketLoopNative中的字節數組nat->javaBuffer

它應該是你的煩惱的原因,因爲你在同一個線程是不是(新ENV由AttachCurrentThread創建中,從我的經驗,以前所有的非全局無效)


附註:從未在JNI/Android下開發,所以你的代碼對於一個總是編碼J2SE/JNI的人來說似乎很奇怪:)

+0

謝謝,Cerber。我知道了。 –