使用JNIEnv全局变量调用FindClass()等函数发生crash

[Crash Log]

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x98
Stack frame D/CrashAnrDetector(  859):     #00 pc 000b16f4  /system/lib/libart.s
o (art::JniAbort(char const*, char const*)+47)
Stack frame D/CrashAnrDetector(  859):     #01 pc 000b2045  /system/lib/libart.s
o (art::JniAbortF(char const*, char const*, ...)+60)
Stack frame D/CrashAnrDetector(  859):     #02 pc 000b4d9f  /system/lib/libart.s
o (art::ScopedCheck::ScopedCheck(_JNIEnv*, int, char const*)+334)
Stack frame D/CrashAnrDetector(  859):     #03 pc 000b5e35  /system/lib/libart.s
o (art::CheckJNI::FindClass(_JNIEnv*, char const*)+20)
Stack frame D/CrashAnrDetector(  859):     #04 pc 0003f554  /data/app/com.nation
sky.rc.samsung-1/lib/arm/librc.so: Routine _JNIEnv::FindClass(char const*) at D:
/dev/android-ndk-r10e/platforms/android-21/arch-arm/usr/include/jni.h:519
Stack frame D/CrashAnrDetector(  859):     #05 pc 0007c174  /data/app/com.nation
sky.rc.samsung-1/lib/arm/librc.so: Routine event_handler at E:\MDM\RemoteControl
l-sansang2\RemoteControll-sansang/jni/remotecontroll/remotecontroll.cpp:35625
Stack frame D/CrashAnrDetector(  859):     #06 pc 000662b8  /data/app/com.nation
sky.rc.samsung-1/lib/arm/librc.so: Routine call_user at E:\MDM\RemoteControll-sa


[Crash原因分析]

出错的代码:

 jclass remotedesktopclass = sJniEnv->FindClass("com/xxx/xxx/xxx/xxx");

sJniEnv是一个全局变量,但其实不应该全局保存JNIEnv。

这是一个和thread紧密关联的变量,在其他线程中使用就会crash。


【参考】

http://blog.csdn.net/freechao/article/details/7692239


【解决方式】

1.参考了第一篇文章,保存一个JavaVM全局变量,然后再其他线程中使用AttachCurrentThread(),代码如下:

	JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, __null };
	JNIEnv* jniEvn = __null;
	int res = javaVm->AttachCurrentThread(&jniEvn, &args);
        jclass tmp = jniEvn->FindClass("com/xxx/xx/xx/xxxxx");

2.但这么做仍然后crash,是说4.0上回收机制有改变,需要使用NewGlobalRef()生成全局变量才能用
 remotedesktopclass = (jclass)jniEnv->NewGlobalRef(tmp);

 
  

3.上面两部修改后其实还是不行,Log如下:

	Line 2149: F/art     ( 1223): sart/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception 'java.lang.ClassNotFoundException' thrown in unknown throw location
	Line 2151: F/art     ( 1223): sart/runtime/check_jni.cc:65]     in call to NewGlobalRef
	Line 2153: F/art     ( 1223): sart/runtime/check_jni.cc:65] "keyPress" prio=5 tid=14 Runnable
	Line 2155: F/art     ( 1223): sart/runtime/check_jni.cc:65]   | group="main" sCount=0 dsCount=0 obj=0x12ccb080 self=0xb7c98350
	Line 2157: F/art     ( 1223): sart/runtime/check_jni.cc:65]   | sysTid=1271 nice=0 cgrp=apps/bg_non_interactive sched=0/0 handle=0xb7c94b20
	Line 2159: F/art     ( 1223): sart/runtime/check_jni.cc:65]   | state=R schedstat=( 1043961255 45210048 198 ) utm=94 stm=10 core=1 HZ=100

最终将NewGlobalRef()移到主线程后解决此问题。



总结:

修改地方1:

JNIEXPORT void JNICALL Java_xx_xx_xx_xx_xxx(JNIEnv * jniEnv, jobject object, jstring jflowNum, jstring judid){
     jniEnv->GetJavaVM(&javaVm);
     jclass tmp = jniEnv->FindClass("com/nationsky/rc/util/RemoteDesktopUtil");
     remotedesktopclass = (jclass)jniEnv->NewGlobalRef(tmp);
     .............
修改地方2:

static void keyPress(int keyCode){
	JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, __null };
	JNIEnv* jniEvn = __null;
	int res = javaVm->AttachCurrentThread(&jniEvn, &args);
    	method = jniEvn->GetStaticMethodID(remotedesktopclass,
    	                       "pressHome", "()V");
        .................



你可能感兴趣的:(Android,NDK)