ndk开发的异常定位与回调给java层
程序员文章站
2022-07-15 10:46:38
...
在做android端的ndk开发时,有时候抛出莫名其妙的异常,因为只有地址,不知道错误到底在哪个方法的哪一行,这样很头疼。另外,native层发生异常,java调用层无法感知,用户也就无法知道到底发生了什么事情。本篇文章主要讨论地址类型异常的定位以及异常回调给java层。
native层抛出的地址类型异常如下:
native: #10 pc 000c1bf7 /system/lib/libart.so (_ZN3art8CheckJNI16CallObjectMethodEP7_JNIEnvP8_jobjectP10_jmethodIDz+50)
看到这样的异常,摸不着头脑,到底是哪个方法哪一行出现问题了。不必担心,ndk源码路径下提供address2line的工具,可以把相对地址转换成对应文件的行数。我电脑的address2line路径是这样的:D:\android\android-ndk-r14b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows\bin,可以执行arm-linux-androideabi-addr2line -help命令查看使用方法:
从help帮助选项中,可以使用-e + 文件绝对路径 + 地址 进行地址与行数转换,具体使用如下:
从上面结果可知,错误位于media_player.c文件的227行,这样就可以定位到问题了。
/*********************************native层错误定位介绍完毕,下面是错误回调***************************************/
考虑到子线程调用,而不同线程的JNIEnv是不同的,这就需要先获取JavaVM:
//当调用System.loadLibrary时,会回调这个方法
jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
javaVM = vm;
return JNI_VERSION_1_6;
}
java层提供方法给native调用:
/**
* 当native报错时,回调这个方法
* @param errCode errCode
*/
public void errorFromNative(int errCode){
//接口回调
liveStateChangeListener.onError(errCode);
}
}
接口定义:public interface LiveStateChangeListener {
void onError(String msg);
}
实现接口,监听native层异常:
@Override
public void onError(String msg) {
Log.e(TAG, "errMsg=" + msg);
mHandler.obtainMessage(MSG_ERROR, msg).sendToTarget();
}
native异常错误回调方法:
//回调异常给java
void throw_error_to_java(int error_code){
JNIEnv* env;
(*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
jclass jclazz = (*env)->GetObjectClass(env, jobject_error);
jmethodID jmethod = (*env)->GetMethodID(env, jclazz, "errorFromNative", "(I)V");
(*env)->CallVoidMethod(env, jobject_error, jmethod, error_code);
(*javaVM)->DetachCurrentThread(javaVM);
}
这样java层就可以监听native的异常了。大家如果有什么建议或问题,欢迎交流。推荐阅读