Z 您现在的位置:首页>产业专栏>国内资讯> 技术贴:手游频繁崩溃”闪退”的原因是什么?

技术贴:手游频繁崩溃”闪退”的原因是什么?(2)

2015-04-30 14:57:04来源:优游网发布:优游网

三.crash日志的解析

如果是脚本层逻辑导致的crash,如上所述,这种情况是可以直接根据收集的日志内容来定位导致crash的逻辑的。如果是引擎层发生了问题,该如何定位解析呢。先来看一个crash的栗子:

技术贴:手游频繁崩溃”闪退”的原因是什么?

如上图所示,

1)crash标识是应用进程产生crash时的一些标识信息,它描述了该crash的唯一标识(E838FEFB-ECF6-498C-8B35-D40F0F9FEAE4),所发生的硬件设备类型(iphone3,1代表iphone4),以及App进程相关的信息等;

2)基本信息描述的是crash发生的时间和系统版本;

3)异常类型描述的是crash发生时抛出的异常类型和错误码;

4)线程回溯描述了crash发生时所有线程的回溯信息,每个线程在每一帧对应的函数调用信息(这里由于空间限制没有全部列出);

5)二进制映像是指crash发生时已加载的二进制文件。以上就是一份crash日志包含的所有信息,接下来就需要根据这些信息去解析定位导致crash发生的代码逻辑, 这就需要用到符号化解析的过程(洋名叫:symbolication)。

符号化解析过程有三种方法:

xcode可视化查看,

symbolicatecrash工具,

atos工具;但是这三种方法都需要用到构建app时生成的.app文件和.app.dsym这两个文件,第一种方式已经在第二章节提到过,不再赘述,下面介绍第二种和第三种解析的方式。

3.1 symbolicatecrash解析

symbolicatecrash是xcode自带的一个命令行工具,在xcode5.0以前的位置是/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources/,xcode5.0以后路径就变成了/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/

比如以上述提到的TestFlight App为例,将TestFlight .crash?TestFlight .app和TestFlight .app.dsym三个文件放在同一个目录下,然后运行 symbolicatecrash?TestFlight.crash TestFlight.app.dsym>?TestFlight .log,查看TestFlight.log文件的内容:

技术贴:手游频繁崩溃”闪退”的原因是什么?

从图中连线可以看出具体出现问题的逻辑代码是在那个文件的哪一行,这样就根据解析出来的指定函数来定位crash的发生原因。

3.2 atos方法

atos是一个BSD平台的通用指令,通过它可以将数字地址转换为对应的二进制映像或者进程的符号,通过该指令进行符号化解析的时候需要说明一点的是只有当.app文件、crash文件和.app.dsym文件三者的UUID都是一致的时候,该crash文件才能被正确解析,否则解析失败。(注:uuid是app应用在移动设备上的唯一标识)可以通过以下方式来查看.app和.app.dsym文件的uuid,以上述提到的TestFlight应用为例:

技术贴:手游频繁崩溃”闪退”的原因是什么?

而crash日志文件的uuid在二进制映像中的第一行:

技术贴:手游频繁崩溃”闪退”的原因是什么?

由此可见armv7架构下三者保持一致,都是4a42d422a466338aa56e88840b74de3d,那接下来开始进行符号化解析。

从上文crash日志文件的线程回溯可以发现闪退时函数的回溯列表里格式不是完全一致,比如下图中的方式1和方式2在第2列的表达方式上不太一样,方式1是用的库函数名,方式2则是一个基本地址。其实这两种方式都可以用一种通用的解析方式来搞定:

技术贴:手游频繁崩溃”闪退”的原因是什么?

首先计算加载地址(load address):

以方式1中的0x333d8049 UIApplicationMain + 1137 为例,这一帧对应的 load address=0x333d8049 -1137=0x333d7bd8

也就是UIApplicationMain的地址是0x333df12;方式2的0x00068b19 0x36000 + 207641,通过上述方式的计算就是load address=0x00068b19 -207641=0x36000 ,可以发现结果与第二列的值是相同的,也就是它的加载地址就是第二列的值0x36000? 然后用xcrun atos -arch armv7 -o TestFlight.app/TestFlight? 0x36000 0x00068b19 的指令来解析crash日志线程0和线程3中带有TestFlight模块的地址,结果发现TestFlight程序的代码回溯过程:

技术贴:手游频繁崩溃”闪退”的原因是什么?

可以看出base

address(基地址)是4000,函数的回溯过程是main.m文件的第16行的某个函数出现问题,然后该函数在逻辑调用中会调用到AFURLConnnectionOperation.m文件的第162行的某个函数,这个逻辑的调用与第一种方法解析的TestFlight.log文件作对比,crash的解析完全一致,由此就可以定位到crash的原因所在,接下来去解决crash文件也就水到渠成了。

四.小结

以上是根据自己的经验和理解对iOS平台下的crash问题(包括原理、收集和解析过程)进行的一次剖析,虽然苹果的沙盒系统对iOS平台的下的很多应用信息的提取有较多的限制,但是要相信方法总比问题多。对于crash问题的理解和收集过程可以很好地辅助项目组来提高项目的质量,同时对于更深入地理解iOS平台知识和crash原理有很好的帮助。当然,本文更多的涉及iOS平台下的crash问题,对于Android平台的crash问题涉及较少。虽然细节的实现上可能有差异,但是内部的原理逻辑应该是相同或者相似的,后续笔者还将继续关注关于Android平台相关问题的调研学习。

最新礼包
优游网订阅号