iOS App 后台 Crash 调查

Apple 一直在逐步放大 App 后台运行的权限,到今天为止,已知的 iOS App 后台运行场景有:

Background Task

通常情况下,App 一旦进入后台,只有数秒的时间继续执行代码,之后就会被系统 Suspend。除非 App 显示的调用 beginBackgroundTaskWithExpirationHandler API,能延迟 App 在后台运行代码的时间,iOS 7 之前是 10 分钟,iOS 7 之后缩减至 3 分钟。一旦时间期限到,系统依旧会 Suspend 进程。

Suspend 进程意味着系统会中断 App 的一切代码逻辑,比如所有线程会暂停,内存读写会暂停,文件访问也会中断,比如 sqlite 读写操作即使写至一半,也会进入暂停状态。理解这一点,能更好的分析我们 App 在后台的行为。

对于大部分 App 来说,都会利用 Background Task 机制来延长后台运行时间,不过一旦 App 体量增大,业务场景增加,我们很难保证所有的代码在进入后台之后,都会被封装到 Background Task 之中执行,很难确保 Background Task 一旦 expire,App 会主动暂停所有内部逻辑,做一个 iOS 系统遵法守纪的好公民。

想象下,App 在 Background Task 里发送一个网络请求,由于延迟较大,后台运行 3 分钟即将超时 response 才回来,进而触发一些列代码逻辑,比如写数据库,此时由于后台时间额度已用完,iOS 系统会强行终止进程,App 的状态会变得不可预知。

虽然 Apple 建议 App 在进入后台后应该运行尽可能少的关键任务,但这种规范对于业务类型复杂的 App 很难遵循,我们能做的,就是在进入后台 3 分钟之内,尽可能完成核心任务,而且不触发新的代码流程。

Background Mode

开启这种模式的 App 可以一直在后台运行,像早期的 VOIP 类应用,导航类 App,支持后台播放音乐的 App 以及一些蓝牙类 App 都需要这种 Background Mode 来正常运行核心功能。开启这种模式的副作用是审核严苛,而且耗电严重,用户会比较敏感。

Background Fetch

这是 Apple 提供的,在系统指定的时间段唤醒 App 并执行少量逻辑的机制,限制较多,唤醒并不可靠,比如被用户强杀的 App 无法唤醒,比如有些用户为了省电考虑,会在系统设置里强行关闭所有的 background fetch。

Silent Push

这是通过 APN 里设置特定字段来唤醒 App 的机制,同 Background fetch 限制较多,在强杀时无法唤醒。

PushKit

PushKit 是用来替代 VOIP 后台运行模式的新机制,在收到语音或者视频电话时,可以通过 PushKit 的通知来唤醒 App,从而避免 App 在后台一直运行。通过 PushKit 唤醒来唤醒 App 非常可靠,基本上具备 VOIP 功能的 App 都会使用这一机制来提升 App 体验。

PushKit 的后台运行模式非常有趣,据我观察,一般情况下,后台唤醒后有 30 秒(并不精准,只是大致接近)的运行时间,如果唤醒后开启 Background Task 能将运行时间延长至 40 秒。

如果 30 秒内连续收到两个 PushKit 通知,那么 App 总共的后台运行时间加起来还是 30 秒,如果 30 秒之后被 Suspend,再收到第二个 Push,那么又可以获得额外的 30 秒。有点类似 Session 的概念,每次收到 Push 可以启动一个 30 秒的 Session,一个 Session 可以处理多个 Push,一旦 Session 结束就被系统 Suspend,再次收到 Push 时可以启动一个新的 Session。

Background Crash 调查

以上是 iOS App 后台运行的现有机制的简单介绍,最近在调查一个 background crash,需要用到上述的后台运行机制。

用户抱怨 App 的 cold start 非常频繁,导致耗电严重。

起初怀疑是 background crash,问题是,开发人员检查了后台日志,发现并无相关的 crash 记录。那么有可能是 BOOM,但 BOOM 发生的概率一般来说比较低。

后来在拿到问题手机之后,查看 analytics 日志,发现如下 crash report:

image.png

很显然 App 是在后台时被系统强杀,原因是在后台运行时还持有某个 db 文件的锁。code 为 0xdead10cc,搜索 Apple 官方文档:

The exception code 0xdead10cc indicates that an application has been terminated by iOS because it held on to a system resource (like the address book database) while running in the background.

原因有了大致方向,接下来时分析具体 Crash 场景。通过仔细查看 App 的运行日志之后,分析出以下行为:

App 在后台首先通过 PushKit 被唤醒,获得 30 秒的运行时间,在 30 秒即将结束的时候,收到新的 PushKit 通知,进而触发一些列流程,比如 sqlite 读写,而因为 30 秒后台时间已用完,系统会强行 suspend App 进程。

系统在 suspend 进程之前,会多做一道检查,如果 App 此时持有 sqlite db 文件的锁(比如正在进行写操作),而且所访问的 sqlite db 文件是位于 shared container 目录下,系统会强杀进程,并生成一个类似上面的 Crash Report。

系统为什么要这么做?很简单,如果 sqlite db 文件是位于 shared container,意味着该文件会同时被 App 和 Extension 访问,假设 App 的写操作在执行中途被 suspend 暂停,Extension 唤醒后也对同一个 db 文件执行写操作,那么当 App 被重新唤醒继续之前写操作时,写操作和 db 文件就会处于一个不可预知的状态,有可能造成写操作失败或者 db 文件损坏,所以系统选择强杀 App。

即使明白了 Crash 过程,要修复却并不简单。原因就像文章开头提到的,一个大体量的 App 在进入后台之后,其代码的执行场景会变得十分复杂,我们并没有简单的机制来确保,进入后台后的流程都能在系统限制的时间内完成,只能通过日志一个个模块排查,简化 App 进入后台之后的行为。

其他收获

另外值得一提的是,从这次 Crash 调查可以看出,并不是所有的 Crash 都能通过 App 内部的 Crash 收集工具获得日志,已知的至少有这几类 Crash 是无法被 App 捕获的:

  • 前台主线程卡死,App 被 Watchdog 强杀

  • App 在前台或者后台使用过多的内存,被系统强杀,分别为 FOOM 和 BOOM。

  • App 在后台被 suspend 之后,由于违反 Apple 的某个 policy,而被系统强杀。

所以你的 App 即使有了成熟的 Crash 采集工具和后台,有时候还是需要登陆 Itunes Connect 后台去查看下日志,或者通过 Xcode 直接查看,因为有些系统强杀并不会通知 App,只有系统能生成和获取日志。这些日记也可以通过用户手机查看,位于 Settings->Privacy->Analytics->Analytics Data。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,706评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,002评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,462评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,375评论 0 216
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,763评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,849评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,033评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,768评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,490评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,734评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,204评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,566评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,227评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,137评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,934评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,926评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,774评论 2 274

推荐阅读更多精彩内容