Android应用开发之Android系统开发之诊断原生代码崩溃问题分析
凌雪 2018-09-20 来源 :网络 阅读 1385 评论 0

摘要:本文将带你了解Android应用开发之Android系统开发之诊断原生代码崩溃问题分析,希望本文对大家学Android有所帮助。

本文将带你了解Android应用开发之Android系统开发之诊断原生代码崩溃问题分析,希望本文对大家学Android有所帮助。


诊断原生代码崩溃问题
    原生代码崩溃问题的类型
    以下部分详细介绍了最常见的几类原生代码崩溃问题。每类崩溃问题都包含一段debuggerd输出示例,其中的关键证据可以帮助您区分特定类型的崩溃问题(以橙色斜体突出显示)。
    中止
    中止操作很有趣,因为这是刻意而为。执行中止操作可通过多种不同的方法(包括调用abort(3)、使assert(3)失败、使用 Android 特有的严重记录类型之一)来实现,但所有这些方法都涉及到调用abort。一般来说,abort调用会向调用线程发出 SIGABRT 信号,因此为了识别这种情况,您需要在debuggerd输出中查找以下两项内容:libc.so中显示“abort”的帧,以及 SIGABRT 信号。
    如上文所述,您可能会看到明确的“中止消息”行。不过,您还应该查看logcat输出,了解此线程在刻意终止自身之前所记录的内容,因为与 assert(3) 或高级别的严重记录设备不同的是,abort(3) 不接受任何消息。
    当前版本的 Android 内嵌了tgkill(2)系统调用,因此它们的堆栈是最容易读取的,因为对 abort(3) 进行的调用位于最顶端:
pid:   4637, tid: 4637, name: crasher  >>> crasher <<>>   crasher <<>>   crasher <<>> crasher <<>> crasher   <<>>   crasher <<>> crasher   <<>> crasher <<<此行可标识崩溃进程中的特定线程。在这种情况下,它是进程的主线程,因此进程 id="">>> 和 <<< 中间的名称是进程名称。对于应用,进程名称通常是完全限定的文件包名称(如   com.facebook.katana),这在提交错误或尝试在 Google Play 中查找相应应用时很有用。在查找崩溃问题之前的相关日志行方面,pid 和 tid   也很有用。 signal 6   (SIGABRT), code -6 (SI_TKILL), fault addr --------您可从该行得知接收的信号 (SIGABRT) 以及有关如何接收该信号的更多信息 (SI_TKILL)。debuggerd 报告的信号是 SIGABRT、SIGBUS、SIGFPE、SIGILL、SIGSEGV   和 SIGTRAP。信号专用的代码因特定信号而异。 Abort message:   'some_file.c:123: some_function: assertion "false" failed'并非所有崩溃问题都会有中止消息行,但发生中止时,会出现该消息行。这是从此   pid/tid 的最后一行严重 logcat 输出中自动收集而来的,而在有意中止的情况下,这可以解释该程序自行终止的原因。 r0   00000000 r1 00000678 r2 00000006 r3 f70b6dc8r4 f70b6dd0 r5 f70b6d80 r6   00000002 r7 0000010cr8 ffffffed r9 00000000 sl 00000000 fp ff96ae1cip   00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010寄存器转储显示收到信号时 CPU 寄存器的内容。(本区段在各 ABI 之间变化很大。)这些内容的有用程度取决于确切的崩溃问题。 backtrace: #00   pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1   /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87   /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so   (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so   (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06   pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21   /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09   pc 00000abc /system/xbin/crasher您可以通过回溯得知崩溃问题发生时我们所处的代码位置。第一列是帧号(与 gdb 的样式一致,其中最底下的帧是 0)。PC 值与共享库的位置(而非绝对地址)相关。下一列是映射区域的名称(通常是共享库或可执行文件,但可能不适用于经过 JIT 编译的代码)。最后,如果有符号,则会显示与 PC 值对应的符号以及到该符号的偏移量(以字节为单位)。您可以结合使用此符号和 objdump(1) 来找到相应的编译器指令。 TombstoneTombstone written to:   /data/tombstones/tombstone_06您可由此得知 debuggerd 写入额外信息的位置。 debuggerd 会保留最多 10 个   tombstone,从编号 00 至 09 循环并根据需要覆盖现有 tombstone。 Tombstone   包含与崩溃转储相同的信息,还包含一些其他信息。例如,它包含所有线程(不仅仅是崩溃线程)的回溯、浮点寄存器、原始堆栈转储,以及寄存器中地址周围的内存转储。最有用的是,它还包含完整的内存映射(类似于 /proc/pid/maps)。以下是 32 位 ARM   进程崩溃的示例(带注释): memory   map: (fault address prefixed with --->)--->ab15f000-ab162fff r-x 0 4000   /system/xbin/crasher (BuildId:b9527db01b5cf8f5402f899f64b9b121)这里需要注意两点。第一点是该行带有前缀“--->”。当您的崩溃问题不仅仅是 Null 指针解引用时,这些映射最有用。如果故障地址较小,则其很可能是 Null 指针解引用的某个变体。否则,通过查看故障地址周围的映射,您通常可以了解发生的问题。通过查看映射可识别的一些可能存在的问题包括: 读/写延伸到内存块末尾之外。在内存块开始之前读/写。尝试执行非代码内容。在堆栈末尾之外运行。尝试写入代码(如上例所述)。需要注意的第二点是,可执行文件和共享库文件将在 Android M 和更高版本中显示 BuildId(如果有),因此您可以确切地看到崩溃代码的版本。(从 Android M 开始,平台二进制文件默认包含 BuildId。NDK   r12 和更高版本还会自动将   -Wl,--build-id 传递到链接器。) ab163000-ab163fff   r--30001000  /system/xbin/crasherab164000-ab164fff   rw-01000f6c80000-f6d7ffff rw-0 100000  [anon:libc_malloc]在 Android 上,该堆不一定是单个区域。堆区域将被标记为 [anon:libc_malloc]。 f6d82000-f6da1fff r--0  20000    /dev/__properties__/u:object_r:logd_prop:s0f6da2000-f6dc1fff r--0    20000  /dev/__properties__/u:object_r:default_prop:s0f6dc2000-f6de1fff   r--0  20000  /dev/__properties__/u:object_r:logd_prop:s0f6de2000-f6de5fff   r-x04000  /system/lib/libnetd_client.so (BuildId:   08020aa06ed48cf9f6971861abf06c9d)f6de6000-f6de6fff r--30001000    /system/lib/libnetd_client.sof6de7000-f6de7fff rw-40001000    /system/lib/libnetd_client.sof6dec000-f6e74fff r-x0  89000    /system/lib/libc++.so (BuildId: 8f1f2be4b37d7067d366543fafececa2) (load base   0x2000)f6e75000-f6e75fff ---01000f6e76000-f6e79fff r--  890004000    /system/lib/libc++.sof6e7a000-f6e7afff rw-  8d0001000  /system/lib/libc++.sof6e7b000-f6e7bfff   rw-01000  [anon:.bss]f6e7c000-f6efdfff r-x0  82000    /system/lib/libc.so (BuildId:   d189b369d1aafe11feb7014d411bb9c3)f6efe000-f6f01fff r--  810004000    /system/lib/libc.sof6f02000-f6f03fff rw-  850002000    /system/lib/libc.sof6f04000-f6f04fff rw-01000    [anon:.bss]f6f05000-f6f05fff r--01000  [anon:.bss]f6f06000-f6f0bfff   rw-06000  [anon:.bss]f6f0c000-f6f21fff r-x0  16000    /system/lib/libcutils.so (BuildId: d6d68a419dadd645ca852cd339f89741)f6f22000-f6f22fff   r--  150001000  /system/lib/libcutils.sof6f23000-f6f23fff rw-    160001000  /system/lib/libcutils.sof6f24000-f6f31fff r-x0e000    /system/lib/liblog.so (BuildId: e4d30918d1b1028a1ba23d2ab72536fc)f6f32000-f6f32fff   r--d0001000  /system/lib/liblog.sof6f33000-f6f33fff rw-e0001000    /system/lib/liblog.so通常,共享库会有 3 个相邻条目。一个是可读且可执行条目(代码),一个是只读条目(只读数据),还有一个是读写条目(可变数据)。第一列显示映射的地址范围,第二列显示权限(采用常规 Unix ls(1) 样式),第三列显示到文件的偏移量(十六进制),第四列显示区域大小(十六进制),第五列显示文件(或其他区域名称)。 f6f34000-f6f53fff r-x0  20000    /system/lib/libm.so (BuildId:   76ba45dcd9247e60227200976a02c69b)f6f54000-f6f54fff ---01000f6f55000-f6f55fff   r--  200001000  /system/lib/libm.sof6f56000-f6f56fff rw-    210001000  /system/lib/libm.sof6f58000-f6f58fff   rw-01000f6f59000-f6f78fff r--0  20000    /dev/__properties__/u:object_r:default_prop:s0f6f79000-f6f98fff r--0    20000  /dev/__properties__/properties_serialf6f99000-f6f99fff   rw-01000  [anon:linker_alloc_vector]f6f9a000-f6f9afff r--01000    [anon:atexit handlers]f6f9b000-f6fbafff r--0  20000    /dev/__properties__/properties_serialf6fbb000-f6fbbfff rw-01000    [anon:linker_alloc_vector]f6fbc000-f6fbcfff rw-01000    [anon:linker_alloc_small_objects]f6fbd000-f6fbdfff rw-01000    [anon:linker_alloc_vector]f6fbe000-f6fbffff rw-02000    [anon:linker_alloc]f6fc0000-f6fc0fff r--01000    [anon:linker_alloc]f6fc1000-f6fc1fff rw-01000    [anon:linker_alloc_lob]f6fc2000-f6fc2fff r--01000    [anon:linker_alloc]f6fc3000-f6fc3fff rw-01000    [anon:linker_alloc_vector]f6fc4000-f6fc4fff rw-01000    [anon:linker_alloc_small_objects]f6fc5000-f6fc5fff rw-01000    [anon:linker_alloc_vector]f6fc6000-f6fc6fff rw-01000  [anon:linker_alloc_small_objects]f6fc7000-f6fc7fff   rw-01000  [anon:arc4random _rsx structure]f6fc8000-f6fc8fff   rw-01000  [anon:arc4random _rs structure]f6fc9000-f6fc9fff   r--01000  [anon:atexit handlers]f6fca000-f6fcafff ---01000    [anon:thread signal stack guard page]请注意,从 Android 5.0 (Lollipop) 开始,C 库会对其大部分匿名的映射区域进行命名,因此无名区域将会有所减少。 f6fcb000-f6fccfff rw- 0 2000 [stack:5081]名为 [stack:tid] 的区域是指定线程的堆栈。 f6fcd000-f702afff   r-x0  5e000  /system/bin/linker (BuildId:   84f1316198deee0591c8ac7f158f28b7)f702b000-f702cfff r--  5d0002000    /system/bin/linkerf702d000-f702dfff rw-  5f0001000    /system/bin/linkerf702e000-f702ffff rw-02000f7030000-f7030fff   r--01000f7031000-f7032fff rw-02000ffcd7000-ffcf7fff rw-0    21000ffff0000-ffff0fff r-x01000  [vectors]您看到的是 [vector] 还是 [vdso] 取决于架构。ARM 使用   [vector],而所有其他架构均使用   [vdso]。    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注移动开发之Android频道!

本文由 @凌雪 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程