脱敏说明:本文根据真实稳定性建设笔记整理,已删除公司、业务、内部平台、内部链路和截图。文中的「某 App」「Crash 平台」「远端配置」均为泛化表达。

问题背景

移动端有一类故障很麻烦:服务端下发了异常数据,端上解析或渲染时触发 crash;由于本地缓存存在,异常数据不一定立刻被新数据覆盖,于是用户可能反复启动、反复崩溃。

从研发视角看,这只是一个 crash;从用户视角看,这是 App 完全不可用。

安全模式要解决的不是单次 crash,而是连续 crash 或潜在连续 crash 场景下的自救能力:

  • 用户能否重新进入 App?
  • 端上能否自动清理高风险缓存?
  • 远端配置能否快速关闭问题模块?
  • 研发能否尽早收到连续 crash 告警?

一种朴素方案:启动标记

很多安全模式的基础方案都来自一个简单思路:启动时写入一个 flag,正常启动完成后清除 flag。如果下一次启动时发现上次 flag 没有被清掉,就认为上次可能异常退出。

这个方案优点很明显:

  • 实现简单。
  • 对业务侵入低。
  • 不需要识别每一种异常类型。

缺点也同样明显:

  • 可能把系统 kill、用户强杀、低内存回收误判为 crash。
  • 无法区分 Java crash、native crash、ANR、OOM 等不同问题。
  • 对启动阶段和非启动阶段的区分不够精细。

所以它适合作为基础信号,但不适合作为唯一判断依据。

更稳的做法:分类型记录异常

在 Android 上,异常退出的来源很多,捕获方式也不一样:

  • Java uncaught exception 可以通过 crash 回调记录。
  • native crash 可以依赖 crash SDK 或 signal handler 记录现场,再在下次启动时读取落盘文件。
  • ANR 通常依赖系统痕迹、平台能力或额外监控。
  • OOM、系统 kill、主动退出并不总能用同一种方式捕获。

所以更合理的做法是把「异常类型」和「启动阶段」拆开记录。

例如:

  • 启动时设置 LaunchSuccessFlag
  • 首屏完成、关键启动任务完成或超过一个保守时间阈值后,更新启动成功状态。
  • crash 发生时记录当前是否仍处于启动阶段。
  • 对 Java crash、native crash、ANR 等类型分别计数。

这样安全模式可以更有针对性:启动连续 crash 应该优先自救,非启动阶段单点 crash 则可以先依赖常规 crash 平台和远端修复。

安全模式可以做什么

进入安全模式后,不建议把所有能力都暴露给用户选择。大多数用户不理解缓存、实验、动态化资源、远端配置这些概念,选择越多,成本越高。

比较好的方式是自动执行一组低风险恢复动作:

  1. 清理高风险业务缓存。
  2. 清理上次启动阶段加载的临时数据。
  3. 关闭高风险实验或动态模块。
  4. 拉取远端降级配置。
  5. 上报安全模式进入原因和恢复结果。

如果问题来自缓存或配置,这些动作通常能让用户重新进入 App。如果问题来自新版本代码,安全模式至少能提供更明确的信号,让研发更快判断是否需要热修、回滚或强制升级。

潜在 crash 的提前保护

安全模式不一定只在 crash 发生后才启动。有些风险可以提前识别:

  • 某个版本某个模块 crash 率突然升高。
  • 某类缓存命中后 crash 高发。
  • 某个实验组连续触发启动异常。
  • 某个动态化资源版本被集中命中。

这些信号可以通过远端配置提前保护用户,比如在下一次启动前关闭问题模块、清理指定缓存、跳过高风险资源加载。

这类能力的关键是「最小化」。配置项越细越强,但也越容易误伤。开始时只需要几个安全动作:清缓存、关实验、关模块、禁资源版本,就足够覆盖很多场景。

误判边界

安全模式一定有误判,设计时要接受这一点,并把误判成本降下来。

几个常见边界:

  • 启动后立刻被系统 kill,可能被误判为启动 crash。
  • 启动任务超过阈值后才 crash,可能被归为非启动 crash。
  • 首页可见但后台任务未完成,启动状态可能难以定义。
  • native crash 文件是否存在、何时清理,依赖 crash SDK 行为。

所以安全模式的阈值和阶段定义,最好来自线上数据,而不是拍脑袋。比如首屏完成时间、关键启动任务耗时、不同设备档位下的启动分布,都可以作为依据。

总结

安全模式不是为了替代 crash 修复,而是为了在故障已经发生时,让用户和研发都不至于完全被动。

一套可落地的 Android 安全模式,至少要回答四个问题:

  • 怎么判断异常退出?
  • 怎么区分启动 crash 和非启动 crash?
  • 进入安全模式后自动做哪些恢复动作?
  • 如何通过远端配置提前保护高风险用户?

它看起来像稳定性工具,实际上是移动端体验的最后一道保险。