2011-09-19 9 views
1

소켓에서 데이터를 받아 Java에서 입력 매개 변수 인 ByteArray에 다시 쓸 수있는 네이티브 메서드를 작성하려고합니다. ByteArray를 Java 측에 할당하고 네이티브 메소드에 전달하기 때문에 GetPrimitiveArrayCritical()을 사용하여이 ByteArray의 포인터를 가져와야합니다.안드로이드 JNI 네이티브 C++ 코드 GetPrimitiveArrayCritical() 문제

는 그러나, 나는 여전히 스레드에서 실행하려면이 절차가 필요합니다, 그래서 구조체의 jbyteArray 변수가이 입력 된 ByteArray를 기억 socket_loop_native_data라고 사용하고 입력 매개 변수로이 구조체에 새로운 스레드를 시작하기는 pthread_create()를 사용 .

마지막으로, 스레드의 본체 코드에서, 나는 이전이 ByteArray의 포인터를 얻을 수 GetPrimitiveArrayCritical에()를 사용하지만,

오류 로그

은 ... 실패 :

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을 같은 실행 후 문

,617을 중단하다
nat->nativeBuffer = (jbyte *)(env->GetPrimitiveArrayCritical((nat->javaBuffer), NULL)); 

이렇게 ... 입력 ByteArray를 기억하고 다른 장소에서 GetPrimitiveArrayCritical()을 호출하기 위해 jbyteArray 변수를 사용할 수 없거나 사용할 수 없다는 의미입니까?

아니면, 내가 잊어 버린 것은 무엇입니까 ???

모든 의견을 크게 높이세요 !!!

+0

해결 : NewGlobalRef()를 사용해야합니다. –

답변

1

startSocketLoopNative에서 바이트 배열 nat->javaBuffer에 대한 포인터를 "NewGlobalRef"잊어 버린 것 같습니다.

당신은 (새 ENV는 내 경험에서 어떤에서, 이전의 모든 비 전역가 무효 AttachCurrentThread에 의해 생성된다)


같은 스레드에 아니에요 이후이 문제의 원인이 될한다 사이드 노트 : 결코 JNI/Android에서 개발되지 않으므로 코드가 항상 J2SE/JNI를 코딩 한 사람에게 이상한 것처럼 보입니다.

+0

고맙습니다. Cerber. 알았다. –