NDK开发:JNI使用sigaction以及sigsetjmp的方式捕获以及处理异常

您所在的位置:网站首页 安卓native崩溃捕获 NDK开发:JNI使用sigaction以及sigsetjmp的方式捕获以及处理异常

NDK开发:JNI使用sigaction以及sigsetjmp的方式捕获以及处理异常

2024-01-15 16:51| 来源: 网络整理| 查看: 265

JNI的异常,会在Linux系统层发生崩溃的时候发送一些特定的信号,通过捕捉这些特定的信号来避免Jni 异常崩溃的发生,并回调到JAVA层去处理这个异常

项目中Native层的结构体有点庞大和复杂,在和java对象进行互相传递的过程中,如果对内存的使用不当(开辟新地址以及释放地址等)容易出现内存地址使用异常的情况,从而导致很匪夷所思的地方出现崩溃,如一下异常日志:

2021-07-20 10:41:09.868 3868-3968/? A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x7f93e00000 in tid 3968 (Thread-13) 2021-07-20 10:41:09.974 4270-4270/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 2021-07-20 10:41:09.974 4270-4270/? A/DEBUG: Build fingerprint: 'Android/msm8953_64/msm8953_64:7.1.2/N2G47H/root05281558:userdebug/JL-fly-keys-V1.0.2' 2021-07-20 10:41:09.974 4270-4270/? A/DEBUG: Revision: '0' 2021-07-20 10:41:09.974 4270-4270/? A/DEBUG: ABI: 'arm64' 2021-07-20 10:41:09.974 4270-4270/? A/DEBUG: pid: 3868, tid: 3968, name: Thread-13 >>> com.medlander.b40tablet FindClass("com/medlander/candjavaobject/JniException"); /* 如果这个异常类没有找到,VM会抛出一个NowClassDefFoundError异常 */ if (cls != NULL) { env->ThrowNew(cls, "异常了"); // 抛出指定名字的异常 } /* 释放局部引用 */ env->DeleteLocalRef(cls); return -1; } // 注册要捕捉的系统信号量 struct sigaction sigact; struct sigaction old_action; sigaction(SIGINT, NULL, &old_action); if (old_action.sa_handler != SIG_IGN) { sigset_t block_mask; sigemptyset(&block_mask); sigaddset(&block_mask, SIGABRT); // handler处理捕捉到的信号量时,需要阻塞的信号 sigaddset(&block_mask, SIGSEGV); // handler处理捕捉到的信号量时,需要阻塞的信号 sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_mask = block_mask; sigact.sa_handler = exception_handler; sigaction(SIGINT, &sigact, NULL); // 注册要捕捉的信号 sigaction(SIGABRT, &sigact, NULL); // 注册要捕捉的信号 sigaction(SIGSEGV, &sigact, NULL); // 注册要捕捉的信号 } int sum = add(); __android_log_print(ANDROID_LOG_INFO, "jni_jokey", "sum %d", sum); return sum; } #include #include #include /* jni捕获异常的方法之二:捕捉系统崩溃信号,适用于代码量大的情况。 */ // 定义代码跳转锚点 sigjmp_buf JUMP_ANCHOR; volatile sig_atomic_t error_cnt = 0; void exception_handler(int errorCode) { error_cnt += 1; __android_log_print(ANDROID_LOG_INFO, "jni_jokey", "JNI_ERROR, error code %d, cnt %d", errorCode, error_cnt); // DO SOME CLEAN STAFF HERE... // jump to main function to do exception process siglongjmp(JUMP_ANCHOR, 1); }

很明显add()会报异常崩溃,我们在native开头注册了捕捉的信号,当异常发生时会跳转到exception_handler,再通过siglongjmp跳转到sigsetjmp段,进行处理,记得env->ExceptionClear();来清除异常阻止崩溃,然后env->ThrowNew(cls, "异常了");来抛给Java处理

注意: sigsetjmp(JUMP_ANCHOR, 1);的返回值就是siglongjmp(JUMP_ANCHOR, 1);的第二个参数



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3