你的 App 在 iOS 13 上被卡死了吗?

 

无法响应!...



作者 | 王晓晖、邓竹立、朴惠姝

问题表现


自从58同城iOS客户端9.0.0版本上线以来,陆续接到反馈说app有时,启动会超时,无法响应,然后被系统杀死,只有重启手机才能恢复。

得知存在app无法启动的,问题后,我们马上展开了调查。通过对触发此问题,的设备进行测试,发现此问题所影响的,不仅仅是58同城app的启动,另有如京东、大众点评、腾讯视频等其他app,也无法正常打开。
图1 App启动崩溃截屏


而且经过进一步测试,发现当此问题触发时,在任意app中进行剪贴板的,相关操作都会突然导致app卡死无法操作。
图2 App卡死截屏

如何找到崩溃堆栈?


虽然我们总结出了这种卡死app,问题的各种表现,但是如果没有清晰,的崩溃栈信息,就没有线索去解决这个问题。于是我们开始去bugly上查找有可能相,关联的崩溃信息,但是并没有收获。

为什么bugly上收集,不到崩溃信息?

之后我们拿到发生,崩溃的iphone设备,连接到电脑并通过”Xcode-Devices and Simulators-View Devices Logs”导出了设备的崩溃,日志去排查原因。它是在主线程(main-thread)中发生的崩溃,异常类型(Exception Type)为一个终止程序的信号(SIGKILL)类型,Code为0x8badf00d。如下所示:
图3崩溃信息描述


那Bugly为什么收集不到这种崩溃?

(1)信号类型

首先,信号是Unix、类unix以及其他posix兼容的操作系统中进程间通讯,的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件,已经发生。当一个信号发送给一个进程,操作系统中断了进程,正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了,信号的处理函数,那么它将被执行,否则就执行默认的处理函数。因此在应用的crash引起,的程序异常退出都会有signal。它的种类有多种,常见的有SIGSEGV,SIGILL,SIGABRT,SIGBUS,SIGKILL等等。

信号类型

信号解释

SIGSEGV

无效的内存地址引用信号,试图访问未分配给自己,的内存, 或试图往没有写,权限的内存地址写数据。

SIGILL

执行了非法指令,通常是因为可执行文件本身,出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生,这个信号。

SIGABRT

通常由于异常引起的中断信号,异常发生时系统会调用abort()函数发出该信号。

SIGBUS

非法地址, 包括内存地址对齐(alignment)出错。与sigsegv的区别在于后者是由于对合法存储,地址的非法访问触发的(如访问不属于自己存储,空间或只读存储空间)。

SIGKILL

用来立即结束程序的运行,该信号不能被阻塞、处理和忽略。
表 1 信号类型解释
其中本次发生崩溃的信号是终止程序的SIGKILL,它是不能被阻塞、处理和忽略。因此在应用中,不能捕获此类崩溃,第三方工具中是无法收集到。

(2)Code异常编码

异常编码也是分析崩溃原因的重要依据之一,该日志中Code码0x8badf00d,即“ate bad food”,表示在应用程序启动、终止或响应系统事件花费,的时间过长,应用程序已被系统终止,发生了监视程序超时。它是苹果设计的“看门狗”(watchdog)机制,若超出了该场景所规定,的运行时间,“看门狗”就会强制终结这个,应用的进程。

触发0x8badf00d的场景除了主线程被,卡死的情况,还有以下几种情况:

  • 在iOS11.0到iOS11.2以前系统手机在前台收到推送,后进入后台被杀死或可能会在前台杀死。
  • 开启任务后做了大量耗时操作,无法任务结束。
  • 系统挂起beginbackgroundtask方法回调中没有关闭后台任务,或添加两次或两次以上的回调无法一对一关闭后台任务。
  • 开启任务后在到期事件处理的,回调中开启子线程进行大量耗时操作等等。
因此以上的场景,均无法应用拦截,处理,不能上报到第三方崩溃收集,工具中。

借助隐私数据查询崩溃日志

既然第三方崩溃收集工具拿不到日志,那么我们之前是通过将,iphone设备连接到电脑中,通过”Xcode-Devices and Simulators-View Devices Logs”来导出当前设备发生的,崩溃日志。这种方式可以收集到所有,类型的崩溃。但是不可能人人都,具备xcode工具,也不可能时时刻刻都带电脑。而我们发现苹果会将当前设备,所发生的所有事件都记录到系统日志中,包括崩溃日志,CPU Usage日志。

在系统日志中崩溃日志名称,的格式为“进程名+日期+时间.ips.synced”或“进程名+日期+时间.ips”,如:“58tongcheng-2019-12-04-113614.ips”。该日志在iOS10.2以及以上系统的设备,上可以进入“设置-隐私-诊断与用量”中获取,iOS10.2以上系统的设备上可以进入“设置-隐私-分析-分析数据”中获取。因此,用户可以直接通过iphone,设备选择一个崩溃日志后,通过airdrops或其他三方app发送到电脑或崩溃,自动解析工具进行解析。
图4系统隐私数据


点对点分析崩溃日志

在获取到日志之后如何进行解析呢?针对指定的日志,进行日志解析,绝大多数ios开发者都会想到,使用符号表进行解析。但是原始的dsym文件可能,存在没有保存或者丢失的情况。因此58同城对日志,解析进行了相应的扩展,扩大了日志的解析的适用范围。除了使用原始的dsym符号,表文件进行日志解析外,58的点对点日志解析工具,还支持,针对bugly生成的符号,表symbol文件的解析,甚至在没有任何符号表,的情况下,也可以根据二进制,数据进行日志解析。

基于dSYM符号表

众所周知,崩溃日志符号化所需要的,符号表通常指dsym文件,dsym文件是用来记录调试,信息的文件,其数据存储格式为DWARF格式。其数据来源为应用,二进制文件的debug段,记录的信息主要包括:文件路径信息、行号信息、变量与地址的映射、函数与地址的映射等。正是因为其存在地址,与符号的映射关系,符号表才可以被用于,解析崩溃日志。在得到崩溃日志和,相应的dsym文件后,可借助symbolicatecrash工具,实现日志符号化。如果没有symbolicatecrash工具,那么dwarfdump命令也可以,逐条实现地址符号化。

在业务开发过程中,本地调试状态下打包是默认不,生成dsym文件的,但是这并不意味着调试信息和符号,信息丢失了。当我们本地xcode打出来的包发生(包,发生)偶现崩溃时,可以通过xcode提供的dsymutil工具将dsym文件从,应用程序的二进制文件中剥离。剥离出的dsym文件即可借助相应,symbolicatecrash实现地址符号化。

基于bugly符号表

在使用bugly进行崩溃统计时,我们需要将符号表上传到,bugly的后台。这个符号表并不是,原始的dsym文件,而是bugly从dsym文件,中提取的文本文件。其数据格式如下图所示:
图5 Symbol文件


bugly的符号表是bugly从dSYM文件中提取的函数地址与符号的映关系,其格式为:起始指令地址 + 结束指令地址 + 代码所在函数名 + 代码所在文件及行号。举例说明,假如我们拿到的崩溃偏移,地址为b,通过文本扫描后发现函数f的,l行代码的起始指令地址为a,结束指令地址C,地址满足A


    关注 CSDN


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册