欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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开发的异常定位与回调给java层
看到这样的异常,摸不着头脑,到底是哪个方法哪一行出现问题了。不必担心,ndk源码路径下提供address2line的工具,可以把相对地址转换成对应文件的行数。我电脑的address2line路径是这样的:D:\android\android-ndk-r14b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows\bin,可以执行arm-linux-androideabi-addr2line -help命令查看使用方法:

ndk开发的异常定位与回调给java层

从help帮助选项中,可以使用-e + 文件绝对路径 + 地址 进行地址与行数转换,具体使用如下:

ndk开发的异常定位与回调给java层

从上面结果可知,错误位于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的异常了。大家如果有什么建议或问题,欢迎交流。