ReactNative进阶(五⼗):IOS系统Crash⽇志分析实战
⽂章⽬录
⼀、前⾔
当应⽤程序在IOS 设备上崩溃(例如,闪退)时,⼀份“Crash崩溃报告”将在该设备上创建并存储起来。崩溃报告描述了应⽤程序是在何种条件下崩溃的,⼤部分情况下包含⼀份当前正在运⾏线程的完整堆栈跟踪。
如果设备就在⾝边,可以连接设备,打开Xcode - Window - Organizer,在左侧⾯板中选择Device Logs(可以选择具体设备的Device Logs或者Library下所有设备的Device Logs),然后根据时间排序查看设备上的crash⽇志。这是开发、测试阶段最经常采⽤的⽅式。
如果应⽤程序已经提交到App Store发布,⽤户已经安装使⽤了,那么开发者可以 通过iTunes Connect (Manage Your Applications - View Details - Crash Reports)获取⽤户的crash⽇志。不过这并不是100%有效的,⽽且⼤多数开发者并不依赖于此,因为这需要⽤户设备同意上传相关信息。
产⽣崩溃⽇志的原因
应⽤违反操作系统规则,包括在启动、恢复、挂起、退出时 watchdog 超时、⽤户强制退出和低内存终⽌等。
应⽤中有Bug!
从多任务窗⼝中终⽌⼀个暂停的应⽤程序不会产⽣崩溃⽇志。Apple官⽅认为⼀旦⼀个应⽤被暂停,它有资格被iOS在任何时间终⽌,因此不会产⽣崩溃⽇志。
⼆、Crash 崩溃报告分析实战
在IOS设置-隐私-分析与改进-分析数据中查当前⽇期的应⽤崩溃⽇志mrcs-2021-08-31-091354.ips,⽇志内容⼤致如下:
{"app_name":"mrcs","timestamp":"2021-08-31 09:13:54.00 +0800","app_version":"2.1.7","slice_uuid":"85fda4ca-6eae-3600-91c8-6fa83b827d7a","adam_id ":0,"build_version":"9","platform":2,"bundleID":"com.*.*","share_with_app_devs":0,"is_first_party":0,"bug_type":"109","os_version":"iPhone OS 14.6 (18F72)" ,"incident_id":"3ADDB9E3-657A-4ECC-B1B1-377A79F793BB","name":"mrcs"}
Incident Identifier: 3ADDB9E3-657A-4ECC-B1B1-377A79F793BB //崩溃报告的唯⼀标识符
CrashReporter Key: 7643d5953a8b0562ded233540a11c1beabbb8b58 //设备标识相对应的唯⼀键值(并⾮真正的设备的UDID,为保护隐私iOS6以后已⽆法获取)
Hardware Model: iPhone10,3//发⽣Crash的设备类型
Process: mrcs [8968]//Crash的进程名称,通常都是我们的App的名字, []⾥⾯是当时进程的ID
Path:/private/var/containers/Bundle/Application/A09D22A5-324F-4686-964B-51AE831927B7/mrcs.app/mrcs //可执⾏程序在⼿机上的存储位置,注意路径是到x.app/x,x.app其实是作为⼀个Bundle的,真正的可执⾏⽂件其实是Bundle⾥⾯的x
Identifier: com.*.*//App的Indentifier,通常为“”
Version:9(2.1.7)//App的版本号,由Info.plist中
Code Type: ARM-64(Native)//App的CPU架构
Role: Foreground
Parent Process: launchd [1]//当前进程的⽗进程,由于iOS中App通常都是单进程的,⼀般⽗进程都是launchd
Coalition: com.*.ccmsm [421]
Date/Time:2021-08-3109:13:53.8890+0800//Crash发⽣的时间
reactnative开发Launch Time:2021-08-3109:13:18.1164+0800//系统登陆时间
OS Version: iPhone OS 14.6(18F72)//系统版本,括号内的数字代表的时Bulid号
Release Type: User
Baseband Version: 6.71.01
Report Version:104
Exception Type: EXC_CRASH (SIGABRT)//异常类型
Exception Codes:0x0000000000000000,0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread:21
Application Specific Information:
Application Specific Information:
abort() called ...................................
Thread 21 name: Dispatch queue: act.ShadowQueue Thread 21 Crashed:
//编号⼆进制库名调⽤⽅法的地址基本地址 + 偏移
0 libsystem_kernel.dylib 0x00000001d73517b00x1d732a000+161712
1 libsystem_pthread.dylib 0x00000001f39dc9c00x1f39d2000+43456
2 libsystem_c.dylib 0x00000001b4243a440x1b41d0000+473668
3 mrcs 0x0000000102dd4e180x102c08000+1887768
4 mrcs 0x0000000102dd4d9c0x102c08000+1887644
5 mrcs 0x0000000102ddd0340x102c08000+1921076
6 mrcs 0x0000000102ddd0d00x102c08000+1921232
7 mrcs 0x0000000102ddd0d00x102c08000+1921232
8 mrcs 0x0000000102ddd0d00x102c08000+1921232
9 mrcs 0x0000000102ddd0d00x102c08000+1921232
10 mrcs 0x0000000102ddd0d00x102c08000+1921232
11 mrcs 0x0000000102dda3240x102c08000+1909540
12 mrcs 0x0000000102dd89080x102c08000+1902856
13 mrcs 0x0000000102ddda4c0x102c08000+1923660
14 mrcs 0x0000000102dd96e80x102c08000+1906408
15 mrcs 0x0000000102dd89080x102c08000+1902856
16 mrcs 0x0000000102ddda4c0x102c08000+1923660
17 mrcs 0x0000000102dd96e80x102c08000+1906408
18 mrcs 0x0000000102dd89080x102c08000+1902856
19 mrcs 0x0000000102ddda4c0x102c08000+1923660
20 mrcs 0x0000000102dd96e80x102c08000+1906408
21 mrcs 0x0000000102dd89080x102c08000+1902856
22 mrcs 0x0000000102dddf380x102c08000+1924920
23 mrcs 0x0000000102dd9e140x102c08000+1908244
24 mrcs 0x0000000102dd89080x102c08000+1902856
25 mrcs 0x0000000102ddb5980x102c08000+1914264
26 mrcs 0x0000000102dd89080x102c08000+1902856
27 mrcs 0x0000000102dda9400x102c08000+1911104
28 mrcs 0x0000000102dd89080x102c08000+1902856
29 mrcs 0x0000000102dda9400x102c08000+1911104
30 mrcs 0x0000000102dd89080x102c08000+1902856
31 mrcs 0x0000000102ddb5980x102c08000+1914264
32 mrcs 0x0000000102dd89080x102c08000+1902856
33 mrcs 0x0000000102dda9400x102c08000+1911104
34 mrcs 0x0000000102dd89080x102c08000+1902856
35 mrcs 0x0000000102dda9400x102c08000+1911104
36 mrcs 0x0000000102dd89080x102c08000+1902856
37 mrcs 0x0000000102dda9400x102c08000+1911104
38 mrcs 0x0000000102dd89080x102c08000+1902856
39 mrcs 0x0000000102dda9400x102c08000+1911104
40 mrcs 0x0000000102dd89080x102c08000+1902856
41 mrcs 0x0000000102ddb5980x102c08000+1914264
42 mrcs 0x0000000102dd89080x102c08000+1902856
43 mrcs 0x0000000102dda9400x102c08000+1911104
44 mrcs 0x0000000102dd89080x102c08000+1902856
45 mrcs 0x0000000102dda9400x102c08000+1911104
46 mrcs 0x0000000102dd89080x102c08000+1902856
47 mrcs 0x0000000102dda9400x102c08000+1911104
48 mrcs 0x0000000102dd89080x102c08000+1902856
49 mrcs 0x0000000102dda9400x102c08000+1911104
50 mrcs 0x0000000102dd89080x102c08000+1902856
51 mrcs 0x0000000102dda9400x102c08000+1911104
52 mrcs 0x0000000102dd89080x102c08000+1902856
53 mrcs 0x0000000102ddc09c0x102c08000+1917084
54 mrcs 0x0000000102cfe1040x102c08000+1007876
55 mrcs 0x0000000102cf2e100x102c08000+962064
56 mrcs 0x0000000102d0b8000x102c08000+1062912
57 mrcs 0x0000000102d0f8600x102c08000+1079392
58 mrcs 0x0000000102cd0efc0x102c08000+823036
59 libdispatch.dylib 0x00000001ab2562b00x1ab1f6000+393904
59 libdispatch.dylib 0x00000001ab2562b00x1ab1f6000+393904
60 libdispatch.dylib 0x00000001ab2572980x1ab1f6000+397976
61 libdispatch.dylib 0x00000001ab2333440x1ab1f6000+250692
62 libdispatch.dylib 0x00000001ab233e2c0x1ab1f6000+253484
63 libdispatch.dylib 0x00000001ab23d66c0x1ab1f6000+292460
64 libsystem_pthread.dylib 0x00000001f39dd5bc0x1f39d2000+46524
65 libsystem_pthread.dylib 0x00000001f39e086c0x1f39d2000+59500
Thread 22:
0 libsystem_pthread.dylib 0x00000001f39e08640x1f39d2000+59492
//Crash时发⽣时刻,线程的状态(寄存器中的值)
Thread 21 crashed with ARM Thread State (64-bit):
x0:0x0000000000000000 x1:0x0000000000000000 x2:0x0000000000000000 x3:0x0000000000000000
x4:0x000000010378c20c x5:0x000000016dc98930 x6:0x000000000000000a x7:0x0000000102dd7248
x8:0x000000016dc9f000 x9:0xef6382e5d8fc5092 x10:0x0000000000000002 x11:0x00000000fffffffd
x12:0x0000010000000000 x13:0x0000000000000000 x14:0x0000000000000000 x15:0x0000000000000000
x16:0x0000000000000148 x17:0x0000000000000002 x18:0x0000000000000000 x19:0x0000000000000006
x20:0x0000000000006e4b x21:0x000000016dc9f0e0 x22:0x0000000000000000 x23:0x0000000144f1ff80
x24:0x0000000000000002 x25:0x0000000000000000 x26:0x0000000000000002 x27:0x0000000000000000
x28:0x0000000000000001 fp:0x000000016dc98880 lr:0x00000001f39dc9c0
sp:0x000000016dc98860 pc:0x00000001d73517b0 cpsr:0x40000000
esr:0x56000080 Address size fault
//Crash时刻App加载的所有库,其中第⼀⾏是Crash发⽣时我们App可执⾏⽂件的信息,可以看出为arm64,可执⾏⽂件包的uuid为c0f……cd65,解析Crash的时候dsym⽂件的uuid必须和这个⼀样才能完成Crash的符号化解析。
Binary Images:
0x102c08000-0x103933fff mrcs arm64 <85fda4ca6eae360091c86fa83b827d7a>/var/containers/Bundle/Application/A09D22A5-324F-4686-964B-51AE8 31927B7/mrcs.app/mrcs
0x103d60000-0x103dcbfff dyld arm64 <c5d2aaed4aeb3e18a5d2c8b681a2d6eb>/usr/lib/dyld
.....................
EOF
由以上崩溃报告内容可知,Thread * 表⽰发⽣Crash的线程调⽤栈,从上到下分别代表调⽤顺序,最上⾯的⼀个表⽰抛出异常的位置,依次往下可以看到API的调⽤顺序。重点由以下内容定位Crash异常类型、错误码、导致异常发⽣的线程。
Exception Type: EXC_CRASH (SIGABRT)//异常类型
Exception Codes:0x0000000000000000,0x0000000000000000//异常类型代码
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread:21
有以上可知,线程21导致应⽤崩溃问题产⽣。
注意⚠ :包含堆栈跟踪的崩溃报告需要先进⾏符号化(symbolicated)才可以进⾏分析。符号化的过程是将内存地址替换为便于阅读的函数名称和⾏号。如果通过Xcode的Organizer窗⼝获取崩溃⽇志,那么该报告将在⼏秒钟后⾃动进⾏符号化。否则需要将.crash⽂件导⼊
到Xcode的Organizer进⾏符号化。
三、常见 Exception Type
EXC_BAD_ACCESS 通常由于访问了不该访问的内存导致。⼀般EXC_BAD_ACCESS后⾯的"()"还会带有补充信息。
SIGSEGV: 通常由于重复释放对象导致,这种类型在切换ARC之后已经很少见到。当我们收到 SIGSEGV 信号时,可以往以下⼏个⽅⾯考虑:
1. 访问⽆效内存地址,⽐如访问Zombie对象;
2. 尝试往只读区域写数据;
3. 引⽤空指针;
4. 使⽤未初始化的指针;
5. 栈溢出;
SIGABRT: 收到Abort信号退出,通常Foundation库中的容器为了保护状态正常会做⼀些检测,例如插⼊null到数组中等会遇到此类错误。
SEGV:(Segmentation Violation),代表⽆效内存地址,⽐如空指针,未初始化指针,栈溢出等;
SIGBUS:总线错误,与 SIGSEGV 不同的是,SIGSEGV 访问的是⽆效地址,⽽ SIGBUS 访问的是有效地址,但总线访问异常(如地址对齐问题);
SIGILL:尝试执⾏⾮法指令,可能不被识别或者没有权限;
EXC_BAD_INSTRUCTION,此类异常通常由于线程执⾏⾮法指令导致;
EXC_ARITHMETIC,除零错误会抛出此类异常;
SIGFPE:Floating Point Error,数学计算相关问题(可能不限于浮点计算),⽐如除零操作;
SIGPIPE:管道另⼀端没有进程接收数据;
由以上分析内容可知,异常代码是SIGABRT。通常, SIGABRT 异常是由于某个对象接收到未实现的消息引起的。 或者,简单来说,在某个对象上调⽤了不存在的⽅法。
这种情况⼀般不会发⽣,因为A对象调⽤了B⽅法,如果B⽅法不存在,编译器会报错。但是,如果你是使⽤selector间接调⽤⽅法的,编译器则⽆法检测对象是否存在该⽅法了。
此外,⽐较常见的崩溃基本都源于代码bug,⽐如数组越界、插空、多线程安全性、访问野指针、发送未实现的selector等。
四、拓展阅读
《》
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论