Android ANR 原理浅析

文章目录

    • [一、ANR 概述](#一、ANR 概述)
    • [二、ANR 的三种类型及触发条件](#二、ANR 的三种类型及触发条件)
    • [三、ANR 的核心原理(重点)](#三、ANR 的核心原理(重点))
      • [3.1 Input ANR 机制](#3.1 Input ANR 机制)
      • [3.2 Service/Broadcast ANR 机制](#3.2 Service/Broadcast ANR 机制)
      • [3.3 主线程阻塞的底层原因](#3.3 主线程阻塞的底层原因)
    • [四、ANR 的触发流程(源码级别)](#四、ANR 的触发流程(源码级别))
    • [五、ANR 的排查思路(面试加分项)](#五、ANR 的排查思路(面试加分项))
    • [六、常见导致 ANR 的编码错误(面试应答示例)](#六、常见导致 ANR 的编码错误(面试应答示例))
    • 七、优化与预防(展示工程能力)
    • 八、面试中可能遇到的追问
    • 九、总结一句话(面试金句)
    • 十、扩展阅读

一、ANR 概述

定义:ANR(Application Not Responding)即应用无响应,当应用的主线程在特定时间内未能处理完某个事件时,系统弹出的对话框。

核心原因:主线程被阻塞,无法及时响应输入事件或组件生命周期回调。

二、ANR 的三种类型及触发条件

类型 触发场景 超时时间 关键组件
Input ANR 按键/触摸事件未响应 5秒 InputDispatcher
Service ANR Service 启动/绑定超时 20秒(前台)/ 200秒(后台) ActivityManagerService
Broadcast ANR 广播接收者 onReceive 未执行完 10秒 BroadcastQueue
ContentProvider ANR ContentProvider 发布超时 10秒 ContentProviderPublisher

注:Android 12 后对后台广播限制更严,前台广播超时仍为 10 秒。

三、ANR 的核心原理(重点)

3.1 Input ANR 机制

  • InputDispatcher 负责分发输入事件,会记录每个事件的开始时间。
  • 事件发送给应用主线程后,主线程通过 Looper 循环处理。
  • 如果事件处理完成后,应用未在 5 秒内 通知 InputDispatcher 处理完成,InputDispatcher 会检查应用主线程是否阻塞。
  • 阻塞判定:inputDispatchingTimeout 超时 && 应用主线程正在处理上一个事件或处于等待状态 → 触发 ANR。

3.2 Service/Broadcast ANR 机制

  • AMS 在启动 Service 或发送广播时,会通过 Handler 发送一个延时消息(超时消息)。
  • 如果组件在超时前正常完成,会移除该延时消息。
  • 超时消息到时触发,AMS 检查组件状态 → 若未完成 → 触发 ANR。

源码关键路径

  • ActiveServices.scheduleServiceTimeoutLocked()SERVICE_TIMEOUT_MSG
  • BroadcastQueue.processNextBroadcast()BROADCAST_TIMEOUT_MSG

3.3 主线程阻塞的底层原因

Android 应用运行基于 消息驱动模型(MessageQueue + Looper)。主线程不断从 MessageQueue 中取消息执行。如果某消息执行耗时过长,后续消息(包括触摸事件、生命周期的下一动作)无法及时处理,就会导致 ANR。

四、ANR 的触发流程(源码级别)

  1. 系统服务(AMS/InputDispatcher)检测到超时。
  2. 调用 appNotResponding() 方法。
  3. 收集进程状态:主线程堆栈(traces.txt)、CPU 使用情况、内存信息。
  4. 向 SystemServer 中的 Watchdog 报告。
  5. 弹出 ANR 对话框(或后台直接杀进程,取决于场景)。

五、ANR 的排查思路(面试加分项)

步骤 操作 关键命令/文件
1 抓取 ANR 日志 adb pull /data/anr/traces.txt
2 查看主线程堆栈 搜索 "main" prio= 找到主线程,关注 waitingsleepingmonitor 状态
3 确认 ANR 类型 从 logcat 中搜索 ANR inInput dispatching timed out
4 分析卡顿点 堆栈中的业务代码行号,定位耗时操作
5 系统负载检查 logcat 中搜索 CPU usageload average

六、常见导致 ANR 的编码错误(面试应答示例)

  • ❌ 主线程直接执行网络请求、数据库批量操作
  • ❌ 主线程持有锁并等待子线程的某个条件(死锁)
  • ❌ 使用 Thread.sleep()wait() 在主线程
  • ❌ BroadcastReceiver 的 onReceive() 中执行耗时操作(应使用 goAsync() 或启动 Service)
  • ❌ 多进程下的 ContentProvider 调用在主线程同步等待

七、优化与预防(展示工程能力)

  • 使用 StrictMode 检测主线程 IO/网络
  • 异步处理:AsyncTask(已废弃)、HandlerThreadCoroutines
  • 启动优化:延迟初始化、Application.onCreate 轻量化
  • 使用 Systrace / Perfetto 分析主线程卡顿点
  • 采用 ViewStub、异步 Inflate 优化布局加载

八、面试中可能遇到的追问

Q1:ANR 和 Crash 的区别?

  • Crash 是未捕获异常导致进程中止;ANR 是进程活着但无响应,系统会弹框让用户选择「等待」或「关闭」。

Q2:能否避免 ANR 对话框弹出?

  • 不能完全避免,但可以通过优化保证应用始终响应。系统设置的 ANR 弹框默认开启,但车机场景可通过 Settings.Global.ANR_SHOW_NOTIFICATION 等配置关闭(需系统权限)。

Q3:Service 的 ANR 超时时间为什么比 Broadcast 长?

  • Service 通常是后台长时间运行操作,允许更长的启动时间;Broadcast 期望快速完成(沾到主线程),超时更短。

Q4:traces.txt 文件中没有主线程堆栈怎么办?

  • 尝试手动抓取:adb shell kill -3 <pid> 生成当前线程堆栈。如果依然没有,可能是进程已死或权限问题。

九、总结一句话(面试金句)

ANR 是 Android 系统为保证应用响应性而设计的软限流机制,本质是主线程阻塞导致消息处理超时,通过 InputDispatcherAMS 的延时消息机制触发,排查的核心是分析 /data/anr/traces.txt 中的主线程调用栈。


建议背诵:类型、超时时间、触发机制、排查命令、常见原因。结合一两个实际项目中的 ANR 案例说明会更出彩。

十、扩展阅读

理解Android ANR的触发原理

分析路线:触发ANR的过程可分为三个步骤: 埋炸弹, 拆炸弹, 引爆炸弹

相关推荐
知行合一。。。4 小时前
Python--05--面向对象(继承,多态)
android·开发语言·python
张小潇6 小时前
AOSP15 WMS/AMS系统开发 -窗口动画源码分析
android
程序员陆业聪7 小时前
Shadow核心原理:壳子Activity与代理机制的精妙设计
android
噗噗127 小时前
大型私域系统的 Webhook 回调高并发架构设计与性能优化
性能优化
plainGeekDev7 小时前
Android 开发者再不转Kotlin,真的来不及了
android·kotlin
赏金术士7 小时前
第五章:数据层—网络请求与Repository
android·kotlin·compose
初雪云8 小时前
让安卓发版再简单一点,体验一键自动化发布
android·运维·自动化
jushi89998 小时前
抖音APP抖音助手增强版 内置逗音小手 支持无水印下载/音频提取/去广告等功能
android·智能手机·音视频
plainGeekDev9 小时前
Android 专家岗 Kotlin 面试题:能答出这些,说明你对语言设计有自己的理解
android·kotlin
plainGeekDev9 小时前
Android 资深岗 Kotlin 面试题:只会用协程不够,你得懂它为什么这么设计
android·kotlin