The following is the stacktrace. The source code where the crash originates is here.
I traced the stacktrace until android's source code which is here.
I'm unable to understand what this means and why it happens only sometimes. Any help would be appreciated. Happy to share more details.
We have been able to reproduce this crash on an android 7.0 device. But it isn't 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)
It looks like you function is called from native thread and it leads to crashes of call to FindClass and other JNI methods which tries to work with java code
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 your code in 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 line static_vm->AttachCurrentThread(&env, NULL);
you try to attach current thread to JVM with null JNIEnv pointer. You've declared it, but never assigned. I was looking for JNI_OnLoad function in your files but didn't find it. It's good practice to get JavaVM once in this method and store it somewhere, so you can get JNIEnv pointer from it where you need.It could be function like following:
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 you must call java_machine->DetachCurrentThread();
in the end of method, because if attached native thread exits without detaching, it will cause java machine crash.
You also could write RAII wrapper for this to be shure that your thread been 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 method could look like this (need to 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...
...
});
Next thing which need to be taken into accout is that you can't use FindClass function to find custom classes if a callstack didn't started in your java code. So in native threads (no matter attached or not) call to FindClass will cause crash in most cases. You need to find 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);
}
So 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...
...
});
UPDATED:
Piece of code from 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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With