NDK 开发如何优雅的定位 Native 异常,看这篇就够了

  • 从何说起?
  • 摘要
  • 案例实操
    • aaddr2line
    • objdump
    • ndk-stack
      • 1、假设我们已经通过 adb logcat 拿到了程序崩溃的日志信息。
      • 2、我们没有 logcat 日志,但是有错误堆栈
  • 集成了腾讯 bugly 的 Native 项目线上崩溃了怎么办

从何说起?

  上周拿出 1/10 的本领教会妹子入门了 NDK之后,妹子QQ上留言给我说她还不满足。一瞬间我有点怀疑自己了,“年少有为,血气方刚,8块腹肌,一头浓发都满足不了妹子,难道我没有自己想的那么猛吗”?卧槽跑题了,咳咳。
  被妹子这么一说我肯定不舒服,就跑去问妹子了。“小爱,上周我们学的东西你都消化啦”?“嗯嗯,Q哥,我已经学得差不多了,你快教我一点新东西嘛~”,虽然听的我是一身的鸡皮疙瘩,但是本着助人为乐,共同学习,分享快乐的宗旨,我决定再从我已经不多的库存中忍痛割爱,好歹也要对的起妹子8块钱的“奈雪の茶”。

摘要

  喏,不管你是 Android 新手,或者说已经是职场老司机,如果你还不知道怎么定位工作学习中遇到的 Native 异常,别怕,看完这篇后就再也不怕定位不到问题了。
  在 Android 开发中我们常常碰见程序闪退的情况,应用层的异常最常见的就是 java.lang.NullPointerException,java.lang.IndexOutOfBoundsException,java.lang.NumberFormatException 等等,这些问题都很好定位,日志也全。而假如某次使用第三方 so 库的时候报错了,那就很让人抓狂了。因为 so 库一般都是 C 或 C++ 写的,对内存管理不好的同学,就会莫名其妙的出现野指针错误、内存访问错误、越界错误等等。那今天,学会下面这几个方法后,你就可以找到 so 库的开发,高傲的吐槽一波他们了(狗头)。

  其实 NDK 早已经帮我们想到了,在它的安装目录下有3款工具:arm-linux-androideabi-addr2line.exe ,arm-linux-androideabi-objdump.exe,ndk-stack.exe。前两个工具的前缀 “arm”根据不同的 ABI 平台不同,比如我们项目打的 armeabi-v8a 包,就是 aarch64-linux-android-addr2line.exe 和 aarch64-linux-android-objdump.exe。

  • aaddr2line 是标准 GNU tools 工具家族中的一部分,常用来将指令的地址和可执行映像转换成文件名、函数名和源代码行数。
  • objdump 是 linux 下的反汇编工具,常常用来反汇编二进制文件以分析其中的附加信息。
  • ndk-stack 从 ndk r6版本就已经引入,从 ndk r20 开始不再已 exe的形式存在,而是借助 python 脚本的形式存在,ndk-stack 可以帮助开发者 过滤 adb logcat 的堆栈跟踪信息,并可以把不认识的内存地址信息转换成可读的信息。

有了这3个神器,接下来就让我们跟着 Demo 实操一波。

案例实操

aaddr2line

下面的代码中我们定义了一个简单的test方法,在第三行有一个空指针 pvalue ,然后在第4行去访问这个空指针的下标,然后导出 so 库,到 android 下执行。

1 #include"test.h"
2 #include<iostream>
3 using namespace std;
4  int TESTSHARED_EXPORT test()
5  {6      int *pvalue = nullptr;
7      int temp = value[5];
8     return temp;
9  }

很明显这是一个空指针错误,不出意外会看到下面的错误信息:

06-09 10:19:07.202 27963-27963/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***Build fingerprint: 'Xiaomi/umi/umi:10/QKQ1.191117.002/V11.0.24.0.QJBCNXM:user/release-keys'Revision: '0'ABI: 'arm64'Timestamp: 2020-06-09 10:19:07+0800pid: 27929, tid: 27929, name: com.qht.jnatest  >>> com.qht.jnatest <<<uid: 10227signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x16Cause: null pointer dereferencex0  0000000000000014  x1  00000000000001f4  x2  0000000000000000  x3  0000000000000000x4  0000000000000000  x5  0000000000000000  x6  0000000000000000  x7  0000000000000000x8  0000000000000002  x9  86bc442885ebe4dc  x10 0000000000430000  x11 000000000000001ax12 000000000c25b618  x13 000000000048ed40  x14 0000000000000006  x15 ffffffffffffffffx16 0000007c7defdf70  x17 0000007d6cb81440  x18 0000007d6f318000  x19 0000007ff52e9278x20 0000007ff52e9700  x21 0000007ff52e9290  x22 0000007ff52e9278  x23 0000000000000000x24 0000007c7dea05cc  x25 0000000000000010  x26 00000000000000c9  x27 0000007c7defe218x28 0000007d6eaccb80  x29 0000007ff52e9200sp  0000007ff52e91b0  lr  0000007c7dee7e74  pc  0000007c7dea05dc
06-09 10:19:07.516 27963-27963/? A/DEBUG: backtrace:#00 pc 00000000000005dc  /data/app/com.qht.jnatest-olKAAEfG2oMHNZvfzn8-SQ==/lib/arm64/libsoTest.so (test+16) (BuildId: 11d09b93a1d89acbc83015d06a5fca2c3bc72adf)#01 pc 000000000000fe70  /data/app/com.qht.jnatest-olKAAEfG2oMHNZvfzn8-SQ==/lib/arm64/libjnidispatch.so (ffi_call_SYSV+96)#02 pc 000000000000f660  /data/app/com.qht.jnatest-olKAAEfG2oMHNZvfzn8-SQ==/lib/arm64/libjnidispatch.so (ffi_call+292)#03 pc 0000000000005b80  /data/app/com.qht.jnatest-olKAAEfG2oMHNZvfzn8-SQ==/lib/arm64/libjnidispatch.so#04 pc 00000000000079ec  /data/app/com.qht.jnatest-olKAAEfG2oMHNZvfzn8-SQ==/lib/arm64/libjnidispatch.so (Java_com_sun_jna_Native_invokeInt+32)#05 pc 0000000000140350  /apex/com.android.runtime/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 112fa750f6a9adbd7b599e735b27a900)#06 pc 00000000001375b8  /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 112fa750f6a9adbd7b599e735b27a900)

其实从上面的信息中已经能看到 Cause: null pointer dereference 字眼,但是却无法知道错误代码的行数。
平台是“arm64”,SIGSEGV 信号是 linux 系统发出的,错误码 11 一般代表了 空指针引用或者多次释放,linux 错误信号查看方法:

vim /usr/include/asm-generic/errno-base.h

虽然我们知道 libsoTest.so 发生了错误,但还是不知道出错在哪行,什么函数。

找到你安装ndk中 addr2line 的路径,打开 cmd 输入下面的命令(aarch64-linux-android-addr2line.exe --help 查看帮助):

D:/Java/android-ndk-r20/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-addr2line.exe -e libsoTest.so 00000000000005dc

-e:出错 so 库的路径
00000000000005dc: so 库出错的汇编地址,上面以 0000000000 开头的就是,后面都会用到这个地址
按下回车后,

addr2line 已经很明确的告诉我们出错在第 7 行了。
另外建议将 aarch64-linux-android-addr2line.exe 的绝对路径添加到环境变量,这样以后就不用去找这个东西了,

objdump

找到 objdump 的目录,和 addr2line 在同级目录下,cmd 输入如下指令(aarch64-linux-android-objdump.exe --help查看帮助):

D:/Java/android-ndk-r20/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-objdump.exe -S libsoTest.so > libsoTest.txt


  在上面输出的汇编指令中找到出错so库的汇编地址 00000000000005dc,可以看到出错地址介于空指针引用错误和 return 语句之前。
  我们这个案例属于比较简单的情况,大多数生产环境的代码比这要复杂的多,因此生成的汇编代码比较难懂,但是宗旨就是找出错的汇编地址,找到后,离具体的方法名和函数就不远了。

ndk-stack

ndk-stack 的目的是帮助我们将晦涩难懂的汇编内存信息转换成能看懂的文件名+类名+函数名+行号信息。
ndk-stack 有两种用法:

1、假设我们已经通过 adb logcat 拿到了程序崩溃的日志信息。

这种情况一般是在开发中,或者是在测试过程中测试同学帮助我们保存了 logcat 日志。

D:/Java/android-ndk-r16-windows-x86_64/android-ndk-r16/prebuilt/windows-x86_64/bin/ndk-stack --sym  D:/WorkSoftware/AndroidWorkSpace/jnatest/app/libs/arm64-v8a --dump log1.txt


可以看到出错的文件名和行号。

2、我们没有 logcat 日志,但是有错误堆栈

比如线上环境,是没有 logcat 日志的,但是假如集成了 bugly 等工具,也是可以拿到错误堆栈的。然后将堆栈信息复制到 txt 文件中,并在文件的开头加上:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

因为 ndk-stack 会在开始解析 logcat 输出时查找第一行星号。

集成了腾讯 bugly 的 Native 项目线上崩溃了怎么办

我们的项目集成了腾讯的 bugly ,在线上版本发生崩溃后会上报堆栈信息到页面,但和本地一样,某些堆栈信息根本看不出来问题出到哪儿了。

bugly 支持 so 库符号表上传,具体参考:
Bugly Android 符号表配置

1、查看线上版本 so库的 UUID

2、找到本地对应版本的 so 库,并通过 bugly 提供的工具查看 UUID 是否对应
这儿有个前提条件,就是每次发版本前都要把我们打包的 so 库的 debug 版本保存一份,这样以后出现问题才能定位到问题在哪儿,否则 so 库版本不对应符号表就查不到了。

3、下载上图中的符号表工具,并解压,然后在 setting.txt 中配置 bugly 的 ID 和 Key。

4、cmd 输入如下指令:

C:\Users\HiWin10\Downloads\buglySymbolAndroid2.6.3>buglySymbolAndroid.bat -i E:\xxxx\arm64-v8a\libsoTest.so -o E:\xxxx\arm64-v8a\libsoTest.zip

上面的命令是生成 so 库对应的符号表文件,解压生成的 zip 后得到后缀是 .symbol 的文件,即为 bugly要求的符号表文件。然后使用文本打开此文件,可以看到这个 so 库的 UUID。

5、如果 UUID 和 bugly 页面上的 UUID 对应,即代表此 so 库版本为线上的版本。
然后将上面生成的 zip 文件上传到 bugly 符号表页面:

完成稍等一会儿应用成功后,再次打开我们的崩溃信息,可以看到已经可以定位到具体的类和行数了。


csdn地址:http://blog.csdn.net/u012534831
github地址:https://github.com/qht1003077897

如有帮助,请多多点赞支持。

NDK撩妹三部曲(四)—NDK 开发如何优雅的定位 Native 异常,看这篇就够了相关推荐

  1. NDK撩妹三部曲(一)—站住同学,我这有个C++的so库,底层运算效率飞起,想不想要?

    NDK撩妹三部曲(二)--论"Android 实战如何使用 C++(Qt) so 库这个神秘武器?"之带妹实战篇 从何说起?   前段时间,公司有个前端妹子找到我说:"Q ...

  2. 99. 中高级开发面试必问的Redis,看这篇就够了

    中高级开发面试必问的Redis,看这篇就够了! 一.概述 二.数据类型 STRING LIST SET HASH ZSET 三.数据结构 字典 跳跃表 四.使用场景 计数器 缓存 查找表 消息队列 会 ...

  3. NDK撩妹三部曲(三)—美女,我看你婀娜多姿,宛若天仙,这本“ndk排错指南”就送你了

    从何说起?   昨天算是真正的带妹子入坑了,这不,又给我买奶茶了. But,路漫漫其修远兮,没过两天,妹子就又来找我了."Q哥,我最近碰到一些问题,麻烦你帮我看一下呗"? 妹子是个 ...

  4. NDK 环境配置看这篇就够了!

    JNI-Android Studio下的 NDK 环境配置 JNI与NDK的理解 JNI 什么是JNI呢? 为什么用JNI呢? 怎么学JNI呢? NDK 什么是NDK呢? 为什么用NDK呢? 怎么学N ...

  5. 中高级开发面试必问的Redis面试题,看这篇就够了!

    精彩推荐 一百期Java面试题汇总 SpringBoot内容聚合 IntelliJ IDEA内容聚合 Mybatis内容聚合 出自:https://github.com/CyC2018/CS-Note ...

  6. iOS开发技巧-国际化(Localization),只看一篇就够了

    转:https://www.jianshu.com/p/f8edd7b7a217 本文主要涉及iOS的国际化,网上虽然有很多相关的文章,但是仔细阅读下来感觉都不太全面,因此重开一篇总结,记录项目中遇到 ...

  7. 准备开发一个智能硬件,得先看这篇文章!

    一个智能硬件生命周期内所需要经历的全部流程,以及产品经理需负责的相关工作分为以下各阶段, 我们一起看看这个过程有多长,又有哪些经验可以分享. 一.市场分析 如同互联网产品一样,除了在立项之前需要对市场 ...

  8. 通俗易懂 !Kafka 开发快速入门看这篇就够了

    写在前面:我是「云祁」,一枚热爱技术.会写诗的大数据开发猿.昵称来源于王安石诗中一句 [ 云之祁祁,或雨于渊 ] ,甚是喜欢.写博客一方面是对自己学习的一点点总结及记录,另一方面则是希望能够帮助更多对 ...

  9. Android开发如何理解Java静态代理 动态代理及动态生成代理对象原理 看这篇就够了

    动态代理与静态代理 前言 代理模式 静态代理 动态代理 JDK代理 动态生成代理对象原理 生成class数据源码 动态代理类真身 总结 前言 近期在研究Hook技术,需要用到动态代理,说到动态代理就会 ...

最新文章

  1. springwebflux 页面_Spring WebFlux 入门
  2. 中国虚拟电厂运行状况及竞争力分析报告2022-2028年版
  3. openresty开发系列19--lua的table操作
  4. 共模电压和差模电压-(定义及测量)
  5. matlab离散点用折线连接起来
  6. android应用对于内存的大小是有限制的,Android 的内存限制
  7. mysql数据库存储多语言_数据库---数据控制语言(DCL)
  8. Linux学习总结(六十六)打印一串数字的脚本
  9. python运维案例开发_python运维开发之第六天
  10. Spark部署模式、任务提交
  11. easyui获取图片路径_Python玩转图片九宫格
  12. 2022年电工杯数学建模A题思路/2022电工杯A题思路解析
  13. 【Arduino】颜色识别的智能搬运机器人设计
  14. 不已0开头的数字正则
  15. 网页编程html报错502,Nginx将不会使用自定义502错误页面
  16. 获取wifi 的ssid出现unknown ssid
  17. VOT2021比赛简介
  18. GitHub 上受欢迎的 Android UI Library 整理
  19. (淘宝无限适配)移动手机端rem布局详解(转载非原创)
  20. QGIS官网安装包下载与安装

热门文章

  1. C语言编译器开发之旅(二):解析器
  2. 微信公众号订阅通知(go+vue)
  3. 电脑缺失ACPI.sys
  4. PHP匿名在线聊天室系统源码
  5. html title中加图标,科技常识:HTML中title前面小图标的实现_如何给网页标题添加icon小图标...
  6. JAVA软件海豚_海豚调度系统Apache DolphinScheduler单机部署官方文档(Standalone)
  7. linux mysql 命令行查询 乱码_mysql命令提示行连接乱码的解决
  8. 剑指offe JZ18 删除链表的节点
  9. DVI接口关于技术性的知识导论
  10. ECM技术学习:解码端帧内模式推导(Decoder-side Intra Mode Derivation )