本文分析了一份标准的iOS应用程序的Crash报告,它通常由以下6个部分组成。
报告头(Header)
报告头包含了应用程序以其运行环境的一些基本信息,下面是报告头的一个例子。
复制代码
Incident Identifier: E6EBC860-0222-4B82-BF7A-2B1C26BE1E85
CrashReporter Key: 6196484647b3431a9bc2833c19422539549f3dbe
Hardware Model: iPhone6,1
Process: TheElements [4637]
Path: /private/var/mobile/Containers/Bundle/Application/5A9E4FC2-D03B-4E19-9A91-104A0D0C1D44/TheElements.app/TheElements
Identifier: com.example.apple-samplecode.TheElements
Version: 1.12
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2015-04-06 09:14:08.775 -0700
Launch Time: 2015-04-06 09:14:08.597 -0700OS
Version: iOS 8.1.3 (12B466)
Report Version: 105
异常代码(Exception Codes)
异常代码可能包含异常类型(Exception Type)、异常子类型(Exception Subtype)、处理器的详细异常代码(processor-specific Exception Codes)和其它能提供更多Crash信息的字段,最后一个字段列出了触发Crash的线程索引。下面是异常代码的示例。
复制代码
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 0
常见的异常类型有以下几种。
-
Bad Memory Access [EXC_BAD_ACCESS // SIGSEGV // SIGBUS]
此类型的Excpetion是最常见的Crash,通常由访问了无效的内存导致。
SIGSEGV:访问了无效地址,没有[物理内存]对应该地址,通常由于重复释放对象导致。
SIGBUS:总线错误,与 SIGSEGV 不同的是,SIGBUS 访问的是[有效地址]),但总线访问异常,通常是访问了未对齐的数据。
SEGV:代表无效内存地址,比如空指针、未初始化指针、栈溢出等。 -
Abnormal Exit [EXC_CRASH // SIGABRT]
进程异常退出,造成Crash通常是因为未捕获到Objective-C/C++的异常。
SIGABRT:收到Abort信号退出,通常Foundation库中的容器为了保护状态正常会做一些检测,例如插入nil到数组中等会遇到此类错误。 -
Trace Trap [EXC_BREAKPOINT // SIGTRAP]
这个异常是为了让一个附加的调试器有机会在执行过程中的某个特定时刻中断进程,我们可以在代码里面添加__builtin_trap()方法手动触发这个异常。如果没有附加调试器,则会生成crash文件。
较低级别的库(例如libdispatch)会在遇到致命错误时捕获该进程。
swift代码在遇到下面2种情况的时候也会抛出这个异常:
一个非可选类型的值为nil
错误的强制类型转换,如把NSString转换为NSDate等等。 -
Illegal Instruction [EXC_BAD_INSTRUCTION // SIGILL]
程序尝试的去执行一个非法的或者没有定义的指令。如果配置的函数地址有问题,进程在执行函数跳转的时候,就会发生这个crash。 -
Quit [SIGQUIT]
该进程在具有管理其生命周期的权限的另一进程的请求下终止。 SIGQUIT并不意味着进程崩溃,但是可以说明该进程存在一些问题。
比如在iOS中,第三方键盘应用可能在在其他APP中被唤起,但是如果键盘应用需要很长的时间去加载,则会被强制退出。 -
Killed [SIGKILL]
进程被系统强制结束,通过查看Termination Reason找到crash信息。Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
The exception code0x8badf00d
indicates that an application has been terminated by iOS because a watchdog timeout occurred. The application took too long to launch, terminate, or respond to system events. One common cause of this is doing synchronous networking on the main thread.
Whatever operation is onThread 0
needs to be moved to a background thread, or processed differently, so that it does not block the main thread.
异常代码 0x8badf00d 指示应用程序已终止的 iOS 因为看门狗超时发生。应用程序时间太长,启动、 终止,或对系统事件作出响应。一个常见的原因做在主线程上的同步联网 - 其它异常类型有些异常类型没有被命名,以16进制数字表示。
0xbaaaaaad:意味着该Crash log并非一个真正的Crash,它仅仅只是包含了整个系统某一时刻的运行状态,由用户同时按Home键和音量键触发。
0xbad22222:当VoIP程序在后台太过频繁的激活时,系统可能会终止此类程序。
0x8badf00d:程序启动或者恢复时间过长被watch dog终止。0xc00010ff:程序执行大量耗费CPU和GPU的运算,导致设备过热,触发系统过热保护被系统终止。
0xdead10cc:程序退到后台时还占用系统资源(如通讯录)被系统终止。
0xdeadfa11:程序无响应用户强制退出。当用户长按电源键,直到屏幕出现关机确认画面后再长按Home键,将强制退出应用。我们可以合理认为用户这么做的原因是应用程序没有响应。
关于符号化:http://blog.csdn.net/rainbowfactory/article/details/73332735
关于dsym文件:http://www.cocoachina.com/ios/20141219/10694.html
ips文件中各个线程都是地址,看不到具体的类和方法,需要通过解密,方法如下。
方式一
1.isp文件改为.crash文件
2.打包时产生的xcarchive包
3.连接设备使用log
4.把.crash文件丢进alllogs里
可以看到最终崩溃在28线程中的UACacheManager中。
方式二
使用dSYM工具
将 dSYM 拉入窗口的第一部分,
双击 dSYM 名称后,右边显示可选archive编译类型,
UUID 是自动的,请对好类型,
根据闪退信息填入对应的内存地址和Slide Address,
点击分析按钮,就会显示可能错误的地方了
方式三
1、找到symbolicatecrash
find /Applications/Xcode.app -name symbolicatecrash -type f
稍等一会就会有路径输出,这个路径就是symbolicatecrash的路径
2、用命令将symbolicatecrash拷贝到crash文件夹里面
3、将ips文件改为.crash文件导入,ipa包解压后的app文件导入,.dSYM文件导入
4、生成解析后文件
./symbolicatecrash .crash路径 .dSYM路径 >log.crash
5、这时候终端有可能会出现:
Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.
输入命令:
export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"