gpt4 book ai didi

android - 无法在任意上下文中获取 JNIEnv* 值

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:10:33 26 4
gpt4 key购买 nike

我对 NDK 有疑问。

在我的 JNI_OnLoad 方法中,我缓存了 JavaVm 指针、调用该方法的类以及我稍后使用的方法 ID:

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved){
JNIEnv *env;
cachedJVM = jvm;
if((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6)){
LOG_ERROR("Could not get JNIEnv*");
return JNI_ERR;
}
javaClass = (*env)->FindClass(env, "org/test/opensl/AudioProcessor");
if(javaClass == NULL){
LOG_ERROR("Could not get java class");
return JNI_ERR;
}
javaCallbackMID = (*env)->GetMethodID(env, javaClass, "enqueueAudio", "([B)V");
if(javaCallbackMID == NULL){
LOG_ERROR("Could not get method identifier");
return JNI_ERR;
}
return JNI_VERSION_1_6;
}

我有一个小的实用方法定义如下,它应该给我一个指向 JNIEnv 的指针:

JNIEnv* JNU_GetEnv(){
JNIEnv* env;
(*cachedJVM)->GetEnv(cachedJVM, (void**)&env, JNI_VERSION_1_6);
return env;
}

最后,我有一个来自 OpenSL ES SLAndroidSimpleBufferQueueItf 的回调,我想处理来自 SLRecordItf 的录制音频:

void recorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context){
SLresult result;
JNIEnv* env;
recorderContext* thisContext = (recorderContext*)context;
env = JNU_GetEnv();
if(env == NULL){
LOG_ERROR("Could not get JNIEnv*");
return;
}
jbyteArray data = (*env)->NewByteArray(env, MAX_PACKET_SIZE);
if(data == NULL){
LOG_ERROR("No memory could be allocated for buffer");
return;
}
(*env)->SetByteArrayRegion(env, data, 0, MAX_PACKET_SIZE, recorderBuffer);
(*env)->CallByteMethodA(env, thisContext->caller, javaCallbackMID, data);
(*env)->DeleteLocalRef(env, data);
result = (*bq)->Enqueue(bq, recorderBuffer,
RECORDER_FRAMES * sizeof(jbyte));
checkError(result, "Unable to enqueue new buffer");
}

回调方法的上下文参数仅包含对调用 native 方法的对象的引用。它是一个像这样的自定义结构:

typedef struct recorderContext{
jobject caller;
} recorderContext;

但是,每次我尝试运行它时,我都会从回调方法中收到 "Could not get JNIEnv*" 错误消息。

我的问题基本上可以归结为:为什么我可以在 JNI_OnLoad 方法中获得指向 JNIEnv 的指针,而不是在 recorderCallback 中,因为两者使用相同的 Java VM 指针来获得 JNIEnv?

我需要这个回调来将录制的音频传回我的 Java 层以进行进一步处理...

最佳答案

Why can I get a pointer to the JNIEnv in the JNI_OnLoad method, but not in the recorderCallback, as both use the same Java VM pointer to get the JNIEnv?

因为回调发生在一些 native 线程上,不同于加载库的 VM 线程。 JNI 实现为每个线程维护一个JNIEnv,并将指针放在线程本地存储中。它仅针对附加到 VM 的 native 线程进行初始化。您需要在回调中调用 AttachCurrentThread()(或者更可能是 AttachCurrentThreadAsDaemon())以获得对该线程有效的 JNIEnv 指针。这会在第一次调用时将线程附加到 VM,此后是一个 nop。

参见 http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

警告:此答案假设正确的 Java。您看到的问题表明 Dalvik 的行为与 JVM 相同。

关于android - 无法在任意上下文中获取 JNIEnv* 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5991615/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com