在 Android NDK 中跨线程共享 JavaVM* [英] Sharing a JavaVM* across threads in Android NDK

查看:63
本文介绍了在 Android NDK 中跨线程共享 JavaVM*的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从接收来自另一个可执行文件的回调的 cpp 文件中调用 Java 类方法.

I want to call Java class methods from a cpp file that receives call backs from another executable.

为了实现这一点,我使用直接接收 JNI 方法调用的 .cpp 文件中的 android::AndroidRuntime::getJavaVM() 方法检索了一个 JavaVM 指针.我通过构造函数将这个 JavaVM 指针共享给最终的 .cpp 文件,在那里我调用所需的 Java 方法如下:

To achieve this, I have retrieved a JavaVM pointer using the android::AndroidRuntime::getJavaVM() method in the .cpp file that directly receives JNI method calls. I am sharing this JavaVM pointer via the constructor to the eventual .cpp file where I call required Java methods as follows:

/* All the required objects(JNIEnv*,jclass,jmethodID,etc) are appropriately declared. */
**JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL);
clazz = env->FindClass("com/skype/ref/NativeCodeCaller");
readFromAudioRecord = env->GetStaticMethodID(clazz, "readFromAudioRecord", "([B)I");
writeToAudioTrack = env->GetStaticMethodID(clazz, "writeToAudioTrack", "([B)I");** 

但是,我在运行此代码时遇到 SIGSEGV 错误.

However, I get a SIGSEGV fault running this code.

根据 JNI 文档,这似乎是在任意上下文中获取 JNIEnv 的合适方法:http://java.sun.com/docs/books/jni/html/other.html#26206

According to the JNI documentation this seems to be the appropriate way to obtain JNIEnv in arbitary contexts: http://java.sun.com/docs/books/jni/html/other.html#26206

在这方面的任何帮助将不胜感激.

Any help in this regard will be appreciated.

问候,尼拉吉

推荐答案

如果您尝试使用 JNIEnv 或 JavaVM 引用而不将线程附加到 VM,则全局引用将不会阻止新线程中的分段错误.你第一次做的很好,Mārtiņš Možeiko 错误地暗示你做的事情有问题.

Global references will NOT prevent a segmentation fault in a new thread if you try to use a JNIEnv or JavaVM reference without attaching the thread to the VM. You were doing it properly the first time around, Mārtiņš Možeiko is mistaken in implying that there was something wrong with what you were doing.

不要删除它,只需学习如何使用它.那家伙不知道他在说什么,如果它在 jni.h 中,你可以很确定它不会去任何地方.它没有被记录的原因可能是因为它是荒谬的自我解释.您不需要创建 GlobalReference 对象或任何东西,只需执行以下操作:

Don't remove it, just learn how to use it. That guy doesn't know what he's talking about, if it's in jni.h you can be pretty sure it's not going anywhere. The reason it's not documented is probably because it's ridiculously self explanatory. You don't need to create GlobalReference objects or anything either, just do something like this:

#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#include <linux/threads.h>
#include <pthread.h>

#define  LOG_TAG    "[NDK]"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

static pthread_mutex_t thread_mutex;
static pthread_t thread;
static JNIEnv* jniENV;

void *threadLoop()
{
    int exiting;
    JavaVM* jvm;
    int gotVM = (*jniENV)->GetJavaVM(jniENV,&jvm);
    LOGI("Got JVM: %s", (gotVM ? "false" : "true") );
    jclass javaClass;
    jmethodID javaMethodId;
    int attached = (*jvm)->AttachCurrentThread(jvm, &jniENV,NULL);
    if(attached>0)
    {
        LOGE("Failed to attach thread to JavaVM");
        exiting = 1;
    }
    else{
        javaClass= (*jniENV)->FindClass(jniENV, "com/justinbuser/nativecore/NativeThread");
        javaMethodId= (*jniENV)->GetStaticMethodID(jniENV, javaClass, "javaMethodName", "()V");
    }
    while(!exiting)
    {
        pthread_mutex_lock(&thread_mutex);
        (*jniENV)->CallStaticVoidMethod(jniENV, javaClass, javaMethodId);
        pthread_mutex_unlock(&thread_mutex);
    }
    LOGE("Thread Loop Exiting");
    void* retval;
    pthread_exit(retval);
    return retval;
}

void start_thread(){
    if(thread < 1)
        {
            if(pthread_mutex_init(&thread_mutex, NULL) != 0)
            {
                LOGE( "Error initing mutex" );
            }
            if(pthread_create(&thread, NULL, threadLoop, NULL) == 0)
            {
                LOGI( "Started thread#: %d", thread);
                if(pthread_detach(thread)!=0)
                {
                    LOGE( "Error detaching thread" );
                }
            }
            else
            {
                LOGE( "Error starting thread" );
            }
        }
}

JNIEXPORT void JNICALL
Java_com_justinbuser_nativecore_NativeMethods_startThread(JNIEnv * env, jobject this){
    jniENV = env;
    start_thread();
}

这篇关于在 Android NDK 中跨线程共享 JavaVM*的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆