Multithreading 在Android NDK中跨线程共享JavaVM*
我想从接收来自另一个可执行文件的回调的cpp文件调用Java类方法 为了实现这一点,我在.cpp文件中使用直接接收JNI方法调用的android::AndroidRuntime::getJavaVM()方法检索了一个JavaVM指针。我通过构造函数共享这个JavaVM指针,指向最终的.cpp文件,在该文件中我调用所需的Java方法,如下所示:Multithreading 在Android NDK中跨线程共享JavaVM*,multithreading,android-ndk,java-native-interface,Multithreading,Android Ndk,Java Native Interface,我想从接收来自另一个可执行文件的回调的cpp文件调用Java类方法 为了实现这一点,我在.cpp文件中使用直接接收JNI方法调用的android::AndroidRuntime::getJavaVM()方法检索了一个JavaVM指针。我通过构造函数共享这个JavaVM指针,指向最终的.cpp文件,在该文件中我调用所需的Java方法,如下所示: /* All the required objects(JNIEnv*,jclass,jmethodID,etc) are appropriately d
/* 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错误
根据JNI文档,这似乎是在任意上下文中获得JNIEnv的适当方式:
在此方面的任何帮助都将不胜感激
问候,,
Neeraj解决了这个问题。分段错误是因为我无法从从共享jvm指针检索的JNIEnv对象检索jclass对象 我与jvm一起提出了一个全局引用jclass对象,问题就解决了 谢谢你的帮助,玛蒂·莫泽科 问候,,
如果您尝试使用JNIEnv或JavaVM引用而不将线程附加到VM,则Neeraj全局引用将不会阻止新线程中出现分段错误。你第一次做得很好,玛蒂莫季科错误地暗示你所做的事情有问题 不要移除它,只是学习如何使用它。那家伙不知道他在说什么,如果是在jni.h你可以很肯定它不会去任何地方。它没有被记录的原因可能是因为它可笑地不言自明。您也不需要创建GlobalReference对象或任何东西,只需执行以下操作:
#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();
}
#包括
#包括
#包括
#包括
#包括
#包括
#定义日志标签“[NDK]”
#定义LOGI(…)\uuuuuAndroid\uLog\uPrint(android\uLog\uInfo、log\uTag、VA\uArgs\uuuu)
#定义LOGW(…)\uuuuuAndroid\uLog\uPrint(android\uLog\uWarn、log\uTag、VA\uArgs\uuuuu)
#定义日志(…)\uuuuuAndroid\uLog\uPrint(android\uLog\uError,log\uTag,\uuuU VA\uArgs\uuuuu)
静态pthread_mutex_t thread_mutex;
静态pthread\u t线程;
静态JNIEnv*JNIEnv;
void*threadLoop()
{
int退出;
JavaVM*jvm;
int-gotVM=(*jniENV)->GetJavaVM(jniENV和jvm);
LOGI(“获得JVM:%s”,(gotVM?false):“true”);
jclass-javaClass;
jmethodidejavamethodid;
int attached=(*jvm)->AttachCurrentThread(jvm,&jniENV,NULL);
如果(已附加>0)
{
LOGE(“未能将线程连接到JavaVM”);
退出=1;
}
否则{
javaClass=(*jniENV)->FindClass(jniENV,“com/justinbuser/nativecore/NativeThread”);
javaMethodId=(*jniENV)->GetStaticMethodID(jniENV,javaClass,“javaMethodName”,“()V”);
}
当(!退出)
{
pthread_mutex_lock(&thread_mutex);
(*jniENV)->CallStaticVoidMethod(jniENV,javaClass,javaMethodId);
pthread_mutex_unlock(&thread_mutex);
}
LOGE(“线程循环退出”);
作废*收回;
pthread_退出(retval);
返回返回;
}
无效开始线程(){
如果(螺纹<1)
{
if(pthread\u mutex\u init(&thread\u mutex,NULL)!=0)
{
LOGE(“启动互斥锁时出错”);
}
if(pthread_create(&thread,NULL,threadLoop,NULL)==0)
{
LOGI(“已启动线程:%d”,线程);
如果(pthread_detach(thread)!=0)
{
LOGE(“螺纹分离错误”);
}
}
其他的
{
LOGE(“错误启动线程”);
}
}
}
JNIEXPORT void JNICALL
Java_com_justinbuser_nativecore_NativeMethods_startThread(JNIEnv*env,jobject this){
jniENV=env;
启动_线程();
}
什么是android::AndroidRuntime::getJavaVM)?这不是NDK公共API函数。您正在使用未记录的内容。要在NDK中获取JavaVM*,您必须实现JNI_OnLoad全局函数,该函数在加载共享库时自动调用。感谢您的响应..-本文档非常好地介绍了JNI_OnLoad,其中使用了android::AndroidRuntime::registerNativeMethods()。你确定android::AndroidRuntime是非文档化的吗?是的,它是普通用户NDK代码中未文档化的功能。阅读JNI文档(来自Sun)并检查NDK文件夹中的docs/STABLE-API.html文件,以了解其他法律和文档化的API。该文档是关于NDK问世之前的Android编程的。请阅读第一节“重要通知”。再次感谢您指出这一点。我删除了对android::AndroidRuntime::getJavaVM()的调用,并使用JNI_onLoad来传播JavaVM*指针。但是,仍然会出现相同的SIGSEGV故障。有什么想法吗?我在哪里说过使用jni.h中的东西是错误的或不允许的?“这不是NDK公共API函数。您使用的是未记录的东西。要在NDK中获得JavaVM*,您必须实现jni_OnLoad全局函数,该函数在加载共享库时自动调用。”很抱歉这么说,但整个语句显然是不正确的。这是真的-android::AndroidRuntime::getJavaVM
在jni.h中不是一个公共函数或方法。我从来没有说过不允许使用jni.h中的函数或方法(例如全局jni_OnLoad、JavaVM或JNIEnv)。但是你暗示我说了一些关于他没有正确使用jni.h函数的事情。他怎么能用android内部的android::AndroidRuntime::getJavaVM函数正确地完成它,而jni.h中没有这个函数?是的,它是jni.h中的一个公共函数,如果您费心仔细查看的话,我在上面的源代码中包括了一个具体如何使用它的示例。他所做的是正确的,你告诉他他错了,这就是我的反应。这是NDK r8d平台\android-14\arch arm\usr\include\jni.h的jni.h文件。请告诉我android
和AndroidRuntime
名称空间在哪里。