native crash : JNI DETECTED ERROR IN APPLICATION: [thread] using JNIEnv* from [thread]
The following is the stack trace. The source code for the origin of the crash ishere
I trace the stack trace until the source code for android is here
I can’t understand what that means and why it just happens sometimes. Any help would be appreciated. Happy to share more details.
We have been able to reproduce this crash on Android 7.0 devices. But it’s not consistent.
06-28 19:09:26.147 5696 5696 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
06-28 19:09:26.147 5696 5696 F DEBUG : Native Crash TIME: 265472
06-28 19:09:26.147 5696 5696 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
06-28 19:09:26.148 5696 5696 F DEBUG : Build fingerprint: 'Karbonn/K9_Smart_Eco/K9_Smart_Eco:7.0/NRD90M/1498048597:user/release-keys'
06-28 19:09:26.148 5696 5696 F DEBUG : Revision: '0'
06-28 19:09:26.148 5696 5696 F DEBUG : ABI: 'arm'
06-28 19:09:26.148 5696 5696 F DEBUG : pid: 5587, tid: 5689, name: JS Thread >>> com.hashcube.sqmtest <<<
06-28 19:09:26.149 5696 5696 F DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
06-28 19:09:26.152 5696 5696 F DEBUG : Abort message: 'art/runtime/java_vm_ext.cc:470] JNI DETECTED ERROR IN APPLICATION: thread Thread[54,tid=5689,Native,Thread*=0x8a4de500,peer= 0x12dc89d0,"JS Thread"] using JNIEnv* from thread Thread[54,tid=5689,Native,Thread*=0x8a4de500,peer=0x12dc89d0,"JS Thread"]'
06-28 19:09:26.152 5696 5696 F DEBUG : r0 00000000 r1 00001639 r2 00000006 r3 00000008
06-28 19:09:26.152 5696 5696 F DEBUG : r4 899ff978 r5 00000006 r6 899ff920 r7 0000010c
06-28 19:09:26.152 5696 5696 F DEBUG : r8 00000000 r9 add696a4 sl 00000ac4 fp add2eecf
06-28 19:09:26.153 5696 5696 F DEBUG : ip 0000000b sp 899feb50 lr b039a597 pc b039cdf4 cpsr 20070010
06-28 19:09:26.192 5696 5696 F DEBUG :
06-28 19:09:26.192 5696 5696 F DEBUG : backtrace:
06-28 19:09:26.193 5696 5696 F DEBUG : #00 pc 00049df4 /system/lib/libc.so (tgkill+12)
06-28 19:09:26.193 5696 5696 F DEBUG : #01 pc 00047593 /system/lib/libc.so (pthread_kill+34)
06-28 19:09:26.193 5696 5696 F DEBUG : #02 pc 0001d855 /system/lib/libc.so (raise+10)
06-28 19:09:26.193 5696 5696 F DEBUG : #03 pc 000193a1 /system/lib/libc.so (__libc_android_abort+34)
06-28 19:09:26.193 5696 5696 F DEBUG : #04 pc 00017014 /system/lib/libc.so (abort+4)
06-28 19:09:26.193 5696 5696 F DEBUG : #05 pc 003188f5 /system/lib/libart.so (_ZN3art7Runtime5AbortEv+252)
06-28 19:09:26.194 5696 5696 F DEBUG : #06 pc 000b4e79 /system/lib/libart.so (_ZN3art10LogMessageD2Ev+864)
06-28 19:09:26.194 5696 5696 F DEBUG : #07 pc 00238971 /system/lib/libart.so (_ZN3art9JavaVMExt8JniAbortEPKcS2_+1664)
06-28 19:09:26.194 5696 5696 F DEBUG : #08 pc 00238b63 /system/lib/libart.so (_ZN3art9JavaVMExt9JniAbortVEPKcS2_St9__va_list+58)
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)
06-28 19:09:26.194 5696 5696 F DEBUG : #11 pc 000c941f /system/lib/libart.so (_ZN3art11ScopedCheck22CheckPossibleHeapValueERNS_18ScopedObjectAccessEcNS_12JniValueTypeE+26)
06-28 19:09:26.195 5696 5696 F DEBUG : #12 pc 000c88fb /system/lib/libart.so (_ZN3art11ScopedCheck5CheckERNS_18ScopedObjectAccessEbPKcPNS_12JniValueTypeE+802)
06-28 19:09:26.195 5696 5696 F DEBUG : #13 pc 000cdd79 /system/lib/libart.so (_ZN3art8CheckJNI8GetFieldEPKcP7_JNIEnvP8_jobjectP9_jfieldIDbNS_9Primitive4TypeE+496)
06-28 19:09:26.195 5696 5696 F DEBUG : #14 pc 000c2eef /system/lib/libart.so (_ZN3art8CheckJNI11GetIntFieldEP7_JNIEnvP8_jobjectP9_jfieldID+42)
06-28 19:09:26.195 5696 5696 F DEBUG : #15 pc 0009a35c /data/app/com.hashcube.sqmtest-1/lib/arm/libtealeaf.so (_Z19navigator_info_initv+252)
06-28 19:09:26.195 5696 5696 F DEBUG : #16 pc 00084ca0 /data/app/com.hashcube.sqmtest-1/lib/arm/libtealeaf.so (_Z25js_navigator_get_templatev+100)
06-28 19:09:26.196 5696 5696 F DEBUG : #17 pc 0007caf0 /data/app/com.hashcube.sqmtest-1/lib/arm/libtealeaf.so (init_js+740)
06-28 19:09:26.196 5696 5696 F DEBUG : #18 pc 00089dc4 /data/app/com.hashcube.sqmtest-1/lib/arm/libtealeaf.so (core_init_js+36)
06-28 19:09:26.196 5696 5696 F DEBUG : #19 pc 00099a28 /data/app/com.hashcube.sqmtest-1/lib/arm/libtealeaf.so (Java_com_tealeaf_NativeShim_initJS+180)
06-28 19:09:26.196 5696 5696 F DEBUG : #20 pc 0088494d /data/app/com.hashcube.sqmtest-1/oat/arm/base.odex (offset 0x82e000)
Solution
It looks like your function was called from a native thread, and it caused the call to FindClass and other JNI methods that tried to use java code to crash
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)
In the code in the file jni/platform/native_shim.cpp, I can see:
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;
}
in static_vm->AttachCurrentThread(&env, NULL);
line, you try to attach the current thread to the JVM by using an empty JNIEnv pointer. You have declared it, but never assigned it. I looked for the JNI_OnLoad function in your file and didn’t find it. It’s best to get the JavaVM once in this method and store it somewhere so you can get the JNIEnv pointer from it where you need it. Its functions may look like this:
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
}
And the java_machine->DetachCurrentThread() must be called at the end of the method;
, because if the attached native thread exits without decoupling, it will cause the java machine to crash.
You can also write a RAII wrapper for this to ensure that your threads are detached on all method branches.
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<typename Callable>
auto call_in_attached_thread(Callable func) {
attached_env env;
return func(env.env());
}
So your approach might look something like this (need to be precise, see below):
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...
...
});
The next thing to note is that you cannot use the FindClass function to find custom classes if the call stack is not started in your Java code. Therefore, in most cases, calling FindClass in a native thread, whether attached or not, results in a crash. You need to find the classes in JNI_OnLoad and store them in global variables using global java references:
jclass globalDisplayMetricsClassRef;
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
//
previous code here
//
auto localRef = env->FindClass("android/util/DisplayMetrics");
globalDisplayMetricsClassRef = (jclass)env->NewGlobalRef(localRef);
}
Finally we get:
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...
...
});
Update:
A piece of code from the ART CheckThread function
// 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<Thread>(*self).c_str(), ToStr<Thread>(*soa_. Self()).c_str());
return;
}
}