java 崩溃_java-本机崩溃:应用程序中JNI检测到错误:...

看起来您是从本地线程调用函数的,这导致对FindClass和其他尝试使用Java代码的JNI方法的调用崩溃

06-28 19:09:26.194 5696 5696 F DEBUG : #09 pc 000ca81b /system/lib/libart.so (_ZN3art11ScopedCheck6AbortFEPKcz+46)

06-28 19:09:26.194 5696 5696 F DEBUG : #10 pc 000ca305 /system/lib/libart.so (_ZN3art11ScopedCheck11CheckThreadEP7_JNIEnv+104)

在文件jni / platform / native_shim.cpp中的代码中,我可以看到:

static JNIEnv* get_env() {

JNIEnv* env;

static_vm->AttachCurrentThread(&env, NULL);

return env;

}

native_shim *get_native_shim() {

if(shim.instance == NULL) {

LOG("{native} ERROR: Tried to get native shim when there wasn't one");

#if DEBUG

*((int*)0) = -1;

#else

exit(1);

#endif

}

shim.env = get_env();

return &shim;

}

在static_vm-> AttachCurrentThread(& env,NULL);行中您尝试使用空的JNIEnv指针将当前线程附加到JVM.您已经声明了它,但从未分配过.我在您的文件中寻找JNI_OnLoad函数,但没有找到它.在这种方法中一次获取JavaVM并将其存储在某个地方是个好习惯,因此您可以在需要的地方从它获取JNIEnv指针,其功能可能如下所示:

JavaVM *java_machine;

jint JNI_OnLoad(JavaVM *vm, void *reserved) {

java_machine = vm;

}

int get_env(JNIEnv **g_env) {

int getEnvStat = java_machine->GetEnv((void **) g_env, JNI_VERSION_1_6);

if (getEnvStat == JNI_EDETACHED) {

if (java_machine->AttachCurrentThread(g_env, nullptr) != 0) {

__android_log_print(ANDROID_LOG_ERROR, "GetEnvironmentRoutine", "FAILED ATTACH THREAD");

return 2; //Failed to attach

}

return 1; //Attached. Need detach

}

return 0;//Already attached

}

而且您必须调用java_machine-> DetachCurrentThread();在方法的末尾,因为如果附加的本机线程退出而没有分离,则将导致Java机器崩溃.

您也可以编写RAII包装器,以确保线程在所有方法分支上均已分离.

class attached_env final {

public:

attached_env() {

auto resCode = get_env(&mEnv);

if (resCode == 2)

throw std::runtime_error("Cannot retrieve JNI environment");

needDetach = (resCode == 1);

}

~attached_env() {

if (needDetach) {

java_machine->DetachCurrentThread();

}

}

JNIEnv *env() const noexcept {

return mEnv;

}

private:

JNIEnv *mEnv;

bool needDetach;

};

template

auto call_in_attached_thread(Callable func) {

attached_env env;

return func(env.env());

}

因此您的方法可能如下所示(需要精确,请参见下文):

navigator_info* navigator_info_init() {

call_in_attached_thread([=](auto env) {

jclass display_metrics_class = (jclass)env->FindClass("android/util/DisplayMetrics");//WILL NOT WORK! SEE BELOW

jfieldID density_dpi = env->GetFieldID(display_metrics_class, "densityDpi", "I");

jfieldID xdpi = env->GetFieldID(display_metrics_class, "xdpi", "F");

//And so on...

...

});

accout中需要考虑的下一件事是,如果未在Java代码中启动调用堆栈,则无法使用FindClass函数查找自定义类.因此,在本机线程中(无论是否连接),在大多数情况下,对FindClass的调用都会导致崩溃.您需要在JNI_OnLoad中找到类,并使用全局java引用将它们存储在全局变量中:

jclass globalDisplayMetricsClassRef;

jint JNI_OnLoad(JavaVM *vm, void *reserved) {

//

//previous code here

//

auto localRef = env->FindClass("android/util/DisplayMetrics");

globalDisplayMetricsClassRef = (jclass)env->NewGlobalRef(localRef);

}

所以最后我们得到:

navigator_info* navigator_info_init() {

call_in_attached_thread([=](auto env) {

jfieldID density_dpi = env->GetFieldID(globalDisplayMetricsClassRef, "densityDpi", "I");

jfieldID xdpi = env->GetFieldID(display_metrics_class, "xdpi", "F");

//And so on...

...

});

更新:

ART CheckThread函数的一段代码

// Verify that the current thread is (a) attached and (b) associated with

// this particular instance of JNIEnv.

if (soa_.Env() != threadEnv) {

if (soa_.Vm()->work_around_app_jni_bugs) {

// If we're keeping broken code limping along, we need to suppress the abort...

LOG(ERROR) << "APP BUG DETECTED: thread " << *self << " using JNIEnv* from thread " << *soa_.Self();

} else {

JniAbortF(function_name_, "thread %s using JNIEnv* from thread %s",

ToStr(*self).c_str(), ToStr(*soa_.Self()).c_str());

return;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值