面试题十五:如何全局捕获Native异常?(待完善)
如何全局捕获Native异常?
一、面试官视角:这道题想考察什么?
- 是否熟悉Linux的信号
- 是否熟悉Native层任意位置获取jclass的方法
- 是否熟悉底层线程与Java虚拟机的关系
- 通过实现细节的考察,确认候选人的项目经验
二、题目剖析
1、如何捕获Native异常?
- 捕获Native异常
Native异常每次都能看到signal(信号),那我们直接捕获signal就好了。
1 |
|
传递异常到Java层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 当signal触发的时候,会调用此函数
// signum:表示信号
static void android_signal_handler(int signum, siginfo_t *info, void *reserved) {
if(javaVM) {
JNIEnvHelper jniEnvHelper;
jclass errorHandleClass = findClass(jniEnvHelper.env, "io/github/apkok/nativec/HandleNativeError");
if(errorHandleClass == NULL) {
LOGE("Cannot get error handler class.");
}else {
jmethodID errorHandleMethod = jniEnvHelper.env -> GetStaticMethodID(errorHandleClass, "nativeErrorCallback", "(I)V");
if(errorHandleMethod == NULL) {
LOGE("Cannot get error handle method.");
}else {
LOGE("Call java back to notify a native crash!");
jniEnvHelper.env -> CallStaticVoidMethod(errorHandleClass, errorHandleMethod, signum);
}
}
}else {
LOGE("Jni unloaded.");
}
old_signalhandlers[signum].sa_handler(signum);
}捕获Native异常堆栈
捕获Native异常需要获取到底层的堆栈
- 设置备用栈,防止SIGSEGV因栈溢出而出现堆栈被破环
- 创建独立线程专门用于堆栈收集并回调至Java层
- 收集堆栈信息
- [4.1.1, 5.0]使用内置libcorkscrew.so
- [5.0, +∞]使用自己编译的libunwind
- 通过线程关联Native异常对应的Java堆栈
2、如何清理Native层和Java层的资源?
3、如何为问题的排查提供支持?
三、题目结论
- 通过捕获信号来捕获Native异常
- 使用 JNIEnv 的 FindClass 的原理以及限制
- Native线程绑定到 Jvm 及解绑的细节
- Java 对象的全局引用的应用
- Native 层调用 Java 方法
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!