gpt4 book ai didi

android - JNI - 在 NewObjectArray 上崩溃

转载 作者:行者123 更新时间:2023-11-28 04:44:52 27 4
gpt4 key购买 nike

我有这个代码:

JNI 调用的包装器:

/// <summary>
/// Simple JNI class wrapper
/// </summary>
struct SimpleJNIClass{
JavaVM* vm = nullptr;
jobject instanceRef = nullptr;
JNIEnv *lockedEnv = nullptr;

SimpleJNIClass(JNIEnv *env, jobject instanceRef){
//Returns the Java VM interface (used in the Invocation API) associated with the current thread.
//The result is placed at the location pointed to by the second argument, vm.
env->GetJavaVM(&this->vm);
this->instanceRef = (jobject)env->NewGlobalRef(instanceRef);
};

SimpleJNIClass(JNIEnv * env){
env->GetJavaVM(&this->vm);
};

virtual ~SimpleJNIClass() {
if (this->vm == nullptr) {
return;
}

if (JNIEnv * env = GetEnv()){
env->DeleteGlobalRef(instanceRef);
instanceRef = nullptr;
FreeEnv(env);
}
};


JNIEnv * LockEnv() {
this->lockedEnv = this->GetEnv();

return this->lockedEnv;
}

void UnLockEnv() {
this->lockedEnv = nullptr;
this->FreeEnv(this->lockedEnv);
}

JNIEnv * GetEnv(){
if (this->lockedEnv != nullptr) {
return this->lockedEnv;
}

JNIEnv * env = nullptr;
int getEnvStat = vm->GetEnv((void **)&env, JNI_VERSION_1_4);

if (getEnvStat == JNI_EDETACHED){
if (vm->AttachCurrentThread(&env, NULL) != 0){
MY_LOG_ERROR("AttachCurrentThread was not successful. "
"This may be due to the thread being attached already to another JVM instance.");
}
else{
attachCurrentThread = true;
}
}
else if (getEnvStat == JNI_OK){
//no need to attach, already attached
}
else if (getEnvStat == JNI_EVERSION){
MY_LOG_ERROR("GetEnv: version not supported");
}

return env;
};

void FreeEnv(JNIEnv * env) {
if (this->lockedEnv != nullptr) {
return;
}
if (attachCurrentThread) {
vm->DetachCurrentThread();
attachCurrentThread = false;
}
}

protected:
bool attachCurrentThread = false;
};


struct JNICallback : public SimpleJNIClass
{

jmethodID callbackMethod = nullptr;

JNICallback(JNIEnv *env, jobject classRef,
const std::string & methodName, const std::string & methodSignature)
: SimpleJNIClass(env, classRef) {
jclass callbackClass = (jclass)env->GetObjectClass(this->instanceRef);
this->callbackMethod = env->GetMethodID(callbackClass, methodName.c_str(), methodSignature.c_str());
};

virtual ~JNICallback() {
callbackMethod = nullptr;
}

template<typename... Args>
void RunVoid(Args... args) {
JNIEnv *env = this->GetEnv();
env->CallVoidMethod(this->instanceRef, this->callbackMethod, args...);
FreeEnv(env);
}
};

struct JNIClass : public SimpleJNIClass {

jclass callbackClass;
std::unordered_map<std::string, jmethodID> callbacks;


JNIClass(JNIEnv *env, jobject classRef)
: SimpleJNIClass(env, classRef) {
this->callbackClass = (jclass)env->NewGlobalRef((jclass)env->GetObjectClass(this->instanceRef));
};

JNIClass(JNIEnv *env, const std::string & classRefName)
: SimpleJNIClass(env) {
this->callbackClass = (jclass)env->NewGlobalRef(env->FindClass(classRefName.c_str()));
};

virtual ~JNIClass() {

if (JNIEnv * env = GetEnv()) {
env->DeleteGlobalRef(callbackClass);
callbackClass = nullptr;
FreeEnv(env);
}
callbacks.clear();
};

void AddMethod(const std::string & methodName, const std::string & methodSignature) {

JNIEnv *env = this->GetEnv();
this->callbacks[methodName] = env->GetMethodID(this->callbackClass, methodName.c_str(), methodSignature.c_str());
FreeEnv(env);
};


template<typename... Args>
void InitNewInstance(Args... args) {
JNIEnv *env = this->GetEnv();
this->SetInstance(env->NewObject(this->callbackClass, this->callbacks["<init>"], args...));
FreeEnv(env);
}

void SetInstance(jobject instRef) {
JNIEnv *env = this->GetEnv();
env->DeleteGlobalRef(this->instanceRef);
this->instanceRef = env->NewGlobalRef(instRef);
FreeEnv(env);
}

template<typename... Args>
void RunVoid(const std::string & name, Args... args) {
JNIEnv *env = this->GetEnv();
env->CallVoidMethod(this->instanceRef, this->callbacks[name], args...);
FreeEnv(env);
};
};

在 JNI_OnLoad 中我设置了全局变量 JNIClass * fcDataClass:

 fcDataClass = new JNIClass(env, "com/example/MyClass");

然后在来自 Android 的一些 JNI 回调中,我有:

 int resCount = 3;
JNIEnv *lockedEnv = fcDataClass->LockEnv();
jobjectArray dataArray = lockedEnv->NewObjectArray(resCount, fcDataClass->callbackClass, NULL);

//do something with data
fcDataClass->UnLockEnv();

问题是,NewObjectArray 使整个应用崩溃:SIGSEGV(信号 SIGSEGV:无效地址(故障地址:0x9c))

使用调用栈:

art::JavaVMExt::JniAbort(char const*, char const*) 0x00000000ef74815c
art::JavaVMExt::JniAbortV(char const*, char const*, std::__va_list) 0x00000000ef7495ba
art::ScopedCheck::AbortF(char const*, ...) 0x00000000ef5d8eee
art::ScopedCheck::CheckThread(_JNIEnv*) 0x00000000ef5d8a0a
art::ScopedCheck::CheckPossibleHeapValue(art::ScopedObjectAccess&, char, art::JniValueType) 0x00000000ef5d7af2
art::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::JniValueType*) 0x00000000ef5d6fce
art::CheckJNI::NewObjectArray(_JNIEnv*, int, _jclass*, _jobject*) 0x00000000ef5d3808
_JNIEnv::NewObjectArray(int, _jclass*, _jobject*) jni.h:858

最佳答案

参见 CheckThread()来源。如果当前线程未附加,或者如果您尝试使用属于不同 trhead 的 JNIEnv*,它将中止。

您的fcDataClass->LockEnv() 似乎不依赖于线程。获取正确的 JNIEnv* 的合法方法是调用 AttachCurrentThread() ( see how WebRTC does this )。不要忘记在处理此类线程之前使用 DetachCurrentThread()

关于android - JNI - 在 NewObjectArray 上崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49456677/

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