转载

JNI崩溃问题定位

一般native代码导致的崩溃问题,奔溃日志提示大概类似这样:

Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 13261

只有这样而没有详细的调用栈信息,这样我们开发者无法定位到JNI中到底哪一行导致程序崩掉的。根本无法定位问题所在,就更不用说解决问题了。

好在NDK给开发者们提供了ndk-stack工具(在NDK根目录下),我们可以通过ndk-stack工具来查看so库中崩溃的堆栈信息。

NDK编译时已DEBUG模式编译

如果是使用命令行编译,则使用如下语句:

ndk-build clean all NDK_DEBUG=1

clean all 的意思是编译之前先清理全部上次编译生成的内容。NDK_DEBUG=1 意思是生成调试版本的文件。加了这个参数后 调试的时候能定位到源码行数。

如果是使用gradle,则写法如下(注意这里已经覆盖了gradle默认的NDK编译,详细请前往 《Android Studio覆盖了gradle默认的NDK编译》 ):

task ndkBuild(type: Exec) {     commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath, 'clean','all', 'NDK_DEBUG=1' } tasks.withType(JavaCompile) {     compileTask -> compileTask.dependsOn ndkBuild }

最后记得在AndroidManifest.xml设置debuggable为true ,在Application节点中。

ndk编译so库并运行程序

前提是要搭建好NDK开发环境并在项目中集成NDK,不会的可以参考 Ubuntu下NDK编译环境搭建及在Android Studio中集成NDK 。

为了演示,我这里先模拟一个错误:

JNIEXPORT jstring JNICALL Java_com_liuling_ndkjnidemo_JniUtils_getStringFromC         (JNIEnv *env, jclass obj) {     int * p = NULL;     *p = 1;    //这里会导致程序崩溃     return (jstring)(*env)-> NewStringUTF(env, "I am string from jni");  }

使用ndk-stack工具定位崩溃信息

在命令行中执行如下命令:

adb logcat | 你的NDK所在的路径/ndk-stack -sym 你的项目所在的路径/app/src/main/obj/local/armeabi

这里要确定,ndk编译后生成了”你的项目所在的路径/app/src/main/obj/local/armeabi”目录,也就是这个目录要存在。

执行完这个命令之后,终端会阻塞在那,一旦程序崩溃,就会在终端打印出崩溃信息栈。如图所示:

JNI崩溃问题定位

从崩溃信息可以看出导致崩溃的代码是在com_liuling_ndkjnidemo_JniUtils.c中的13行。

打开com_liuling_ndkjnidemo_JniUtils.c文件查看代码,确实是在13行出的问题。

JNI崩溃问题定位

能够定位崩溃所在的位置,就对于我们排查问题来说有很大的帮助,其实修复bug大部分时间都是在找哪里出的问题,能够快速找出哪里出的问题,问题也就很快修复了。

​​

原文  http://liuling123.com/2016/06/ndk-stack.html
正文到此结束
Loading...