EN

Android ANR 系列 2 :ANR 分析套路和关键 Log 介绍

字数统计: 9.8k阅读时长: 43 min
2025/02/08
loading

本文为 Android App ANR 系列的第二篇,主要分享 ANR 分析套路和关键 Log 介绍,系列文章目录如下

  1. Android App ANR 系列 1 :理解 Android ANR 设计思想
  2. Android App ANR 系列 2 :ANR 分析套路和关键 Log 介绍
  3. Android App ANR 系列 3 :ANR 案例分享

版本说明(2026-10 核查):本文保留历史设备日志和截图;AOSP 字段解释以 android-15.0.0_r1 为核对基线,旧 ART 枚举另标 Android 11。厂商日志、阈值和字段顺序须对照设备版本,不能直接套到所有 Android 系统。下方引文来自 2015 年,保留原貌:ANR 记录归属应用不等于根因在应用,也不只涉及主线程;低发生率本身不能决定是否忽略问题。

ANR(Application Not Responding),应用程序无响应,简单一个定义,却涵盖了很多 Android 系统的设计思想

首先,ANR 属于应用程序的范畴。这不同于 SNR(System Not Respoding),SNR 反映的问题是系统进程(system_server)失去了响应能力,而 ANR 明确将问题圈定在应用程序。SNR 由 Watchdog 机制保证,具体可以查阅 Watchdog 机制以及问题分析; ANR 由消息处理机制保证,Android 在系统层实现了一套精密的机制来发现 ANR,核心原理是消息调度和超时处理

其次,ANR 机制主体实现在系统层。所有与 ANR 相关的消息,都会经过系统进程(system_server)调度,然后派发到应用进程完成对消息的实际处理,同时,系统进程设计了不同的超时限制来跟踪消息的处理。 一旦应用程序处理消息不当,超时限制就起作用了,它收集一些系统状态,譬如 CPU/IO 使用情况、进程函数调用栈,并且报告用户有进程无响应了(ANR 对话框,部分 Rom 不显示 ANR 对话框,而是直接闪退到主界面)

然后,ANR 问题本质是一个性能问题。ANR 机制实际上对应用程序主线程的限制,要求主线程在限定的时间内处理完一些最常见的操作(启动服务、处理广播、处理输入), 如果处理超时,则认为主线程已经失去了响应其他操作的能力。主线程中的耗时操作,譬如密集 CPU 运算、大量 IO、复杂界面布局等,都会降低应用程序的响应能力

最后,部分 ANR 问题是很难分析的。有时候由于系统底层的一些影响,导致消息调度失败,出现问题的场景又难以复现。 这类 ANR 问题往往需要花费大量的时间去了解系统的一些行为,超出了 ANR 机制本身的范畴。有一些 ANR 问题很难调查清楚,因为整个系统不稳定的因素很多,例如 Linux Kernel 本身的 Bug 引起的内存碎片过多、硬件损坏等。这类比较底层的原因引起的 ANR 问题往往无从查起,并且这根本不是应用程序的问题,浪费了应用开发人员很多时间,如果你从事过整个系统的开发和维护工作的话会深有体会。所以我不能保证了解了本章的所有内容后能够解决一切 ANR 问题,如果出现了很疑难的 ANR 问题,我建议最好去和做 Framework、驱动和内核的朋友聊聊,或者,如果问题只是个十万分之一的偶然现象,不影响程序的正常运行,我倒是建议不去理它

– From duanqz

ANR 分析套路

先按 ANR 类型整理证据:线上看 Android Vitals 或自研监控中的 Input dispatch、Service、Broadcast、JobScheduler 等类型、设备版本和影响范围;本地及时抓 bugreport、EventLog、main/system log。/data/anr/anr_* 的直接读取受设备权限限制,不能假定普通量产机可 adb pull。怀疑调度、Binder、锁、I/O 或渲染时,要让 Perfetto/System Trace 覆盖超时之前的时间段。

Android 11(API 30)起可查 ApplicationExitInfo,但它是历史退出记录:时间戳是进程退出时间,ANR trace 可能已被覆盖;应用从 ANR 恢复后因其他原因退出,也可能带着此前的 trace。不要把它当作所有 ANR 的实时清单,详见系列第一篇。

分析时分别检查应用逻辑与系统依赖,再追踪两者之间的等待关系。系统压力可能放大应用原有的同步等待,不能只凭某个进程 CPU 高就决定归属。

ANR 问题一般的分析步骤如下:

拿到一份 ANR trace,先问一句:这是“第一案发现场”吗?日志、CPU 采样和线程 dump 未必停在同一时刻,时间没对上,后面很容易越查越偏。

  1. 先按包名、PID、用户、设备启动周期和 am_anr reason 对齐事件,防止拿错 trace。区分业务开始、超时检测、CPU 采样、线程 dump 和日志写出的时间;am_anr 不保证是故障开始时刻,dump 也可能晚于阻塞现场。
  2. 搜索 ANR in,记录责任进程、原因、CPU 采样起止时间、各进程/线程占用、Load、PSI 和缺页计数。日志打印者可能是 system_server,不要与责任进程混淆。
  3. 把超时前后相关的启动、解锁、进程变化、慢消息、锁竞争和 Binder 信息放到同一时间线上。可以先把关键行提取到一个文件里,用 VS Code 或 Notepad++ 搜索线索:是重启后第一次解锁,还是短时间内多个应用启动?沿关键线程的等待继续找持锁者、Binder 服务端、调度或 I/O;检查证据是否覆盖整个超时窗口。
  4. 证据不足时保留未知,在可复现环境补业务日志和 trace。新增采集也会有开销,不要用事后单张堆栈补写未观察到的过程。

区分是应用的问题还是系统的问题

首先应该分析是否是应用的问题

分析应用的问题的关键是需要理清当时用户的操作是什么,应用在用户这个操作的过程中扮演了什么角色,然后再进行进一步的分析

  1. 分析应用是否关键组件中的生命周期中有耗时操作,可能平时没有暴露出来,一旦系统负载上来,就会暴露问题(建议在关键生命周期函数中加上对应的 Log,方便 Debug)。
  2. 分析是否出现极端情况,导致应用的逻辑耗时,比如大量的数据处理或者导入,同时运行线程过多等(看应用的 cpu \ io 使用情况)。
  3. 分析是否存在死锁。
  4. 分析是否是在等待 binder 返回。
  5. 分析 Trace 文件中 MainThread 和 RenderThread 是否存在异常。
  6. 分析 Trace 文件中 MainThread 跟 WorkerThread 是否存在等待关系。

分析系统的状态

  1. 检查 CPU 使用率、Load 和调度等待,定位 system_server、Audio、SurfaceFlinger 等相关进程。HeapTaskDaemon 是应用 ART 的 GC 相关线程,不是独立系统服务。
  2. 检查 I/O 延迟和 /proc/pressure/io;minor/major 是缺页计数,不是内存访问次数或 I/O 吞吐量,具体见下文。
  3. 将 dumpsys meminfo、内存 PSI、回收/换页、kswapd 和杀进程记录对齐。旧设备可能用内核 lowmemorykiller,现代 Android 常用用户态 lmkd,还要区分内核 OOM。
  4. 怀疑冻结时检查设备的 freezer 状态和解冻日志。D 表示不可中断等待,不能单独证明冻结;旧内核的 __refrigerator 栈是 freezer 线索,仍需确认触发者和时间。xxxHansManager 是厂商线索,不是 AOSP 通用标签。
  5. 怀疑系统服务异常时,跟进 Binder 服务端与持锁线程的栈及调度。高负载只能提示调查方向,必须说明它如何阻塞本次超时操作。

继续分析:应用可以解决还是系统可以解决

  1. 等待链落在系统或其他进程时,提交对应版本、时间线、栈和 trace,让负责该依赖的团队继续定位,不能把“转系统”等同于无解。
  2. 应用侧仍需评估能否移出主线程、减少持锁范围或避免同步等待;能规避不等于根因就在应用。
  3. 只有证据能连接超时操作与具体阻塞原因时再归因。缺少系统权限或现场数据,就说明尚未定位。

ANR Log 分析

Log 可由测试使用 Log 工具抓取,可由线上平台获取,也可以自己抓取:

1
adb bugreport log.zip

ANR Trace Log 所包含的内容如下

线程详细数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x72c8bbf8 self=0xb400007b0ec10800
| sysTid=5991 nice=-10 cgrp=default sched=0/0 handle=0x7b95f61500
| state=S schedstat=( 807053249 267562324 1494 ) utm=63 stm=17 core=3 HZ=100
| stack=0x7fcccd9000-0x7fcccdb000 stackSize=8192KB
| held mutexes=
native: #00 pc 00000000000c6418 /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
native: #01 pc 0000000000019a9c /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
native: #02 pc 000000000001997c /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
native: #03 pc 0000000000114310 /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce(Native method)
at android.os.MessageQueue.next(MessageQueue.java:339)
at android.os.Looper.loop(Looper.java:198)
at android.app.ActivityThread.main(ActivityThread.java:8142)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

上面 Trace 中 部分字段的含义

图是旧版说明,个别数值来自另一份样例,字段应以实际 dump 为准。按 Android 15 ART 读取时:

  • tid=1 是 ART 内部线程 ID,sysTid=5991 才是 Linux TID。prio、nice、sched 分别来自不同层次,不能互换。
  • sCount 是当前 ART suspend 计数,不是历史累计暂停次数,也不证明应用被系统冻结。图中 dsCount 的旧说明不适用于所有版本;Android 15 输出的是 ucsCount,不能据此推断曾连接调试器。
  • schedstat 三项依次是累计 CPU 运行时间(ns)、运行队列等待时间(ns)、运行时间片次数。它们不是这次 ANR 窗口内的值;ART 读取失败也可能输出 0 0 0,不要把缺失当零。
  • utm/stm 是用户态/内核态 clock ticks,按输出的 HZ 换算;本例 HZ=100。core 是最近运行的 CPU 编号,不表示永久绑核。

线程堆栈

下面是该线程对应的调用堆栈

1
2
3
4
5
6
7
8
9
10
11
native: #00 pc 00000000000c6418 /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
native: #01 pc 0000000000019a9c /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
native: #02 pc 000000000001997c /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
native: #03 pc 0000000000114310 /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce(Native method)
at android.os.MessageQueue.next(MessageQueue.java:339)
at android.os.Looper.loop(Looper.java:198)
at android.app.ActivityThread.main(ActivityThread.java:8142)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

栈同时包含 Native 和 Java 帧。这里的 nativePollOnce 表示抓栈时在等待事件;它不能证明整个超时窗口都空闲,也不能排除异步广播等其他线程上的超时。先核对 ANR 类型和抓栈时刻。

线程状态

Java 的 Thread.State、ART 状态和 Linux 调度状态是不同层次。RUNNABLE 或 ART Native 不保证线程正在占用 CPU;还要看 state=S/R/D 与调度轨迹。下面的旧枚举与 Android 11 对应;Android 15 已改为 enum class,例如 kRunnable=0,不能依赖旧数值或把旧表当完整的新版本状态表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// State stored in our C++ class Thread.
// When we refer to "a suspended state", or when function names mention "ToSuspended" or
// "FromSuspended", we mean any state other than kRunnable, i.e. any state in which the thread is
// guaranteed not to access the Java heap. The kSuspended state is merely one of these.
enum ThreadState {
// Java
// Thread.State JDWP state
kTerminated = 66, // TERMINATED TS_ZOMBIE Thread.run has returned, but Thread* still around
kRunnable, // RUNNABLE TS_RUNNING runnable
kTimedWaiting, // TIMED_WAITING TS_WAIT in Object.wait() with a timeout
kSleeping, // TIMED_WAITING TS_SLEEPING in Thread.sleep()
kBlocked, // BLOCKED TS_MONITOR blocked on a monitor
kWaiting, // WAITING TS_WAIT in Object.wait()
kWaitingForLockInflation, // WAITING TS_WAIT blocked inflating a thin-lock
kWaitingForTaskProcessor, // WAITING TS_WAIT blocked waiting for taskProcessor
kWaitingForGcToComplete, // WAITING TS_WAIT blocked waiting for GC
kWaitingForCheckPointsToRun, // WAITING TS_WAIT GC waiting for checkpoints to run
kWaitingPerformingGc, // WAITING TS_WAIT performing GC
kWaitingForDebuggerSend, // WAITING TS_WAIT blocked waiting for events to be sent
kWaitingForDebuggerToAttach, // WAITING TS_WAIT blocked waiting for debugger to attach
kWaitingInMainDebuggerLoop, // WAITING TS_WAIT blocking/reading/processing debugger events
kWaitingForDebuggerSuspension, // WAITING TS_WAIT waiting for debugger suspend all
kWaitingForJniOnLoad, // WAITING TS_WAIT waiting for execution of dlopen and JNI on load code
kWaitingForSignalCatcherOutput, // WAITING TS_WAIT waiting for signal catcher IO to complete
kWaitingInMainSignalCatcherLoop, // WAITING TS_WAIT blocking/reading/processing signals
kWaitingForDeoptimization, // WAITING TS_WAIT waiting for deoptimization suspend all
kWaitingForMethodTracingStart, // WAITING TS_WAIT waiting for method tracing to start
kWaitingForVisitObjects, // WAITING TS_WAIT waiting for visiting objects
kWaitingForGetObjectsAllocated, // WAITING TS_WAIT waiting for getting the number of allocated objects
kWaitingWeakGcRootRead, // WAITING TS_WAIT waiting on the GC to read a weak root
kWaitingForGcThreadFlip, // WAITING TS_WAIT waiting on the GC thread flip (CC collector) to finish
kNativeForAbort, // WAITING TS_WAIT checking other threads are not run on abort.
kStarting, // NEW TS_WAIT native thread started, not yet ready to run managed code
kNative, // RUNNABLE TS_RUNNING running in a JNI native method
kSuspended, // RUNNABLE TS_RUNNING suspended by GC or debugger
};

线程名后的 Blocked 是 ART 状态。图中持锁者 89 是 ART tid,应在同一 dump 中找对应线程再映射 Linux TID;一条等待关系不等于死锁,需要继续检查是否形成等待环。

正常主线程 Trace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x72c8bbf8 self=0xb400007b0ec10800
| sysTid=5991 nice=-10 cgrp=default sched=0/0 handle=0x7b95f61500
| state=S schedstat=( 807053249 267562324 1494 ) utm=63 stm=17 core=3 HZ=100
| stack=0x7fcccd9000-0x7fcccdb000 stackSize=8192KB
| held mutexes=
native: #00 pc 00000000000c6418 /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
native: #01 pc 0000000000019a9c /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
native: #02 pc 000000000001997c /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
native: #03 pc 0000000000114310 /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce(Native method)
at android.os.MessageQueue.next(MessageQueue.java:339)
at android.os.Looper.loop(Looper.java:198)
at android.app.ActivityThread.main(ActivityThread.java:8142)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

该样例仅说明抓栈时处于事件等待,不能据此排除此前的阻塞。

异常主线程 Trace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"main" prio=5 tid=1 Blocked
| group="main" sCount=1 dsCount=0 flags=1 obj=0x70f65400 self=0xe28dae00
| sysTid=22002 nice=-10 cgrp=default sched=0/0 handle=0xe9674474
| state=S schedstat=( 1943159901 290647362 1661 ) utm=159 stm=34 core=7 HZ=100
| stack=0xff041000-0xff043000 stackSize=8192KB
| held mutexes=
at com.facebook.cache.disk.DiskStorageCache.e(DiskStorageCache.java:3)
- waiting to lock <0x0e57c91f> (a java.lang.Object) held by thread 89
at com.xxx.community.util.imageloader.FrescoImageLoader.a(FrescoImageLoader.java:18)
at com.xxx.community.util.imageloader.FrescoImageLoader$2$1.run(FrescoImageLoader.java:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:254)
at android.app.ActivityThread.main(ActivityThread.java:8142)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

这里的锁等待需要继续追踪持锁线程;是否造成 ANR 取决于持续时间和等待链。

CPU 使用率分析

搜索 ANR in 后,先读 CPU 采样区间,不能统一称为“ANR 前”。下面是 2020 年旧日志及解释性注释,later 区间可能包含检测之后的诊断工作;两个区间的百分比不能直接相加。缺页注释已按 Linux 定义纠正,原统计数值保留。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
ActivityManager: ANR in com.xxx.launcher (com.xxx.launcher/.Launcher)(进程名)
ActivityManager: PID: 5991(进程 pid)
ActivityManager: Reason: Input dispatching timed out (6a6083a com.xxx.launcher/com.xxx.launcher.Launcher (server) is not responding. Waited 5001ms for FocusEvent(hasFocus=true))(原因)
ActivityManager: Parent: com.xxx.launcher/.Launcher
ActivityManager: Load: 15.29 / 5.19 / 1.87(Load 表明是 1 分钟,5 分钟,15 分钟 CPU 的负载)
ActivityManager: ----- Output from /proc/pressure/memory -----(内存压力)
ActivityManager: some avg10=1.35 avg60=0.31 avg300=0.06 total=346727
ActivityManager: full avg10=0.00 avg60=0.00 avg300=0.00 total=34803
ActivityManager: ----- End output from /proc/pressure/memory -----

// 13s 内的 cpu 使用情况
ActivityManager: CPU usage from 0ms to 13135ms later (2020-09-09 02:09:54.942 to 2020-09-09 02:10:08.077):
ActivityManager: 191%(CPU 的使用率) 1948/system_server: 72%(用户态的使用率) user + 119%(内核态的使用率) kernel / faults: 78816 minor 9 major
ActivityManager: 10% 2218/android.bg: 3.6% user + 6.6% kernel
ActivityManager: 30% 5991/com.xxx.launcher: 23% user + 6.4% kernel / faults: 118172 minor(无需从存储加载页面的缺页) 2 major(需要从存储加载页面的缺页)
ActivityManager: 16% 6174/launcher-loader: 13% user + 2.8% kernel
ActivityManager: 3.9% 5991/m.xxx.launcher: 3.1% user + 0.8% kernel
ActivityManager: 20% 6549/com.xxx.xxx: 16% user + 3.7% kernel / faults: 3541 minor
ActivityManager: 10% 6889/DBCacheManager: 8.7% user + 1.2% kernel
ActivityManager: 9.4% 6942/DefaultDispatch: 7.1% user + 2.2% kernel

// 1s 内的 各个进程各个线程的 cpu 使用情况
ActivityManager: CPU usage from 246ms to 1271ms later (2020-09-09 02:09:55.188 to 2020-09-09 02:09:56.213):
ActivityManager: 290% 1948/system_server: 114% user + 176% kernel / faults: 9353 minor
ActivityManager: 32% 5159/LockSettingsSer: 29% user + 2.9% kernel
ActivityManager: 25% 8661/AnrConsumer: 8.8% user + 16% kernel
ActivityManager: 44% 5991/com.xxx.launcher: 37% user + 7.4% kernel / faults: 5756 minor
ActivityManager: 16% 6174/launcher-loader: 13% user + 3.7% kernel
ActivityManager: 14% 5991/m.xxx.launcher: 14% user + 0% kernel
ActivityManager: 37% 6549/com.xxx.xxx: 28% user + 9.3% kernel / faults: 153 minor
ActivityManager: 37% 6942/DefaultDispatch: 28% user + 9.3% kernel
ActivityManager: 20% 5962/com.android.phone: 14% user + 5.5% kernel / faults: 1345 minor
ActivityManager: 11% 5962/m.android.phone: 7.4% user + 3.7% kernel

按 Android 15 ProcessCpuTracker,进程/线程的用户态和内核态 CPU 时间以采样 uptime 时长为分母。多线程并行时,进程出现 191% 或 290% 并不矛盾;TOTAL 则按聚合 CPU 时间计算,分母不同。faults 是采样间的增量。应把这些统计与关键线程调度对齐,不能仅靠进程总量归因。

CPU 负载

1
ActivityManager: Load: 15.29 / 5.19 / 1.871

Load 是约 1、5、15 分钟尺度的平均活跃任务数,包含可运行任务和不可中断等待任务;不是 CPU 利用率。CPU 刚空闲时历史平均值仍可能很高。0.7、1、5 都不能作为手机通用的告警线,需要结合在线核心、调度限制和 I/O 等待判断。大小核的能力、频率和热限制不同,八核不能简单理解为单核能力乘八。Linux loadavg 定义

/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state(若内核提供)记录各频率驻留时间,不是核心忙碌时间,也不是应用 CPU 时间;统计从驱动初始化或重置开始。上游文档的 usertime 单位为 10 ms,厂商扩展须核对实现。参考 CPUFreq Stats。上面的独立摘录为 1.871,前一完整日志为 1.87,这里保留原摘录精度,不据此计算新结论。

Memory 负载

1
2
3
4
ActivityManager: ----- Output from /proc/pressure/memory -----(内存压力)
ActivityManager: some avg10=1.35 avg60=0.31 avg300=0.06 total=346727
ActivityManager: full avg10=0.00 avg60=0.00 avg300=0.00 total=34803
ActivityManager: ----- End output from /proc/pressure/memory -----

这是 /proc/pressure/memory 的 PSI 输出;已把旧文转录的 somavg10 修为 some avg10,数值未改。avg10/60/300 是对应时间尺度的平滑压力百分比;total 是累计停滞时间,单位为微秒(µs),不是毫秒。

some 表示至少有任务因该资源停滞,full 表示所有非 idle 任务同时因该资源停滞。这里度量的是资源压力,不能把百分比直接读成 CPU 使用率。Linux PSI 文档

下面用两个任务的 I/O 等待示意 some/full:

图中红色表示 I/O 阻塞;理想化的 60 秒区间里,同时阻塞占 16.66%,至少一个阻塞占 50%。这只是区间比例示意,不是内核 avg60 平滑算法的直接计算结果。阻塞可以分散在多段时间内,如下图。

旧图解延伸阅读:内核工匠。

IO 负载

1
ActivityManager:   30% 5991/com.xxx.launcher: 23% user + 6.4% kernel / faults: 118172 minor(无需从存储加载页面的缺页) 2 major(需要从存储加载页面的缺页)
  1. Minor fault:处理时不需要从存储加载页面的缺页,例如页面已在内存、但需要建立映射。它不是 CPU cache miss,也不是每次内存访问都会发生。
  2. Major fault:需要从存储加载页面的缺页。它不覆盖所有 I/O,例如普通文件读写未必产生进程 major fault。

因此 118172 minor / 2 major 是采样窗口的缺页增量,不能换算成 I/O 次数或带宽。大量 major 是进一步检查缺页延迟、I/O PSI 和关键线程等待的线索,不能单独证明本次 ANR 由存储造成。Linux /proc/pid/stat 定义

进程负载

1
ActivityManager:   30% 5991/com.xxx.launcher: 23% user + 6.4% kernel / faults: 118172 minor(无需从存储加载页面的缺页) 2 major(需要从存储加载页面的缺页)

23% user 与 6.4% kernel 分别是用户态和内核态占用。总计显示 30% 涉及格式化精度,不应要求已舍入的各项相加后逐位相等。分母和多核解释见前面的 CPU 使用情况。

CPU 异常进程

以下是排查方向,不是凭进程名即可成立的原因:

  1. system_server 高占用:找具体线程,以及本次业务等待的服务/锁。
  2. kswapd 活跃:核对内存回收、换页和关键线程是否被拖慢。
  3. logd 高占用:检查日志量和实际写日志耗时,不能推断所有进程都同步阻塞在日志输出。
  4. vold 高占用:沿存储操作和 Binder 依赖找等待。
  5. 应用自身高占用:分清主线程、工作线程,以及调度竞争;应用低 CPU 也可能因锁或 Binder 等待而 ANR。
  6. 应用线程为 D:继续读阻塞栈;冻结判断见前文,不能仅凭 D 状态归因功耗策略。
  7. CPU 行前 +/-:表示采样跟踪中的新增/移除状态,不是精确的进程创建/死亡时间戳。结合进程生命周期日志确认。

系统关键 Log 介绍

应用冻结

1
xxxHansManager : freeze uid: 10245 package: com.tencent.mm reason: LcdOff

这条厂商日志给出 UID、包名和 LcdOff 原因,只是一次冻结操作线索。需要结合进程状态、解冻时间和超时窗口判断是否有关,不能直接推出冻结有 Bug。Android 11 起的 AOSP cached apps freezer 使用 cgroup v2,不能与旧内核 __refrigerator 栈或厂商 Hans 日志视作同一实现。

ActivityManager : Slow operation

下面保留旧版 AMS 的 checkTime 示例。Android 15 的相应进程启动检查可见 ProcessList.checkSlow,超过 50 ms 后按检查点输出从 startTime 起的累计耗时;并非所有 AMS 操作都会自动接受这项检查。

1
2
3
4
5
6
7
void checkTime(long startTime, String where) {
long now = SystemClock.uptimeMillis();
if ((now-startTime) > 50) {
// If we are taking more than 50ms, log about it.
Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
}
}
1
2
3
ActivityManager: Slow operation: 138ms so far, now at startProcess: done updating battery stats
ActivityManager: Slow operation: 138ms so far, now at startProcess: building log message
ActivityManager: Slow operation: 138ms so far, now at startProcess: starting to update pids map

三行 138ms so far 可以来自同一次操作的连续检查点,不是三个步骤各耗时 138 ms。频繁出现值得与调度、锁和 I/O 对齐,但它本身不证明 ANR 根因。

Looper : Slow dispatch

1
Looper  : Slow dispatch took 418ms main h=android.app.ActivityThread$H c=android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA@e68bdc4 m=0

418ms 是这次 dispatchMessage 的 uptime 耗时(结束减开始),包含执行、等待和被抢占,不等于 CPU 运行时间。h/c/m 分别帮助定位 Handler、callback、what。只有相应慢日志配置启用且达到阈值才输出,不是固定 500 ms 的全局规则。Android 15 Looper

Looper : Slow delivery

1
Looper  : Slow delivery took 361ms android.ui h=com.android.server.am.ActivityManagerService$UiHandler c=null m=53

361ms 是开始分发时间减 msg.when,表示超过计划执行时间多久,不是消息从创建/入队到执行的总时长。延迟投递的消息本来就有未来的执行时间;需继续找它到期后为何没被及时分发。

Looper:Slow Looper

1
W/Looper: Slow Looper main: Activity com.androidperformance.memoryfix/.MainActivity is 439ms late (wall=0ms running=0ms ClientTransaction{ callbacks=[android.app.servertransaction.TopResumedActivityChangeItem] }) because of 3 msg, msg 2 took 268ms (seq=2 running=207ms runnable=15ms late=1ms h=android.app.ActivityThread$H w=110), msg 3 took 171ms (seq=3 running=140ms runnable=5ms io=1ms late=268ms h=android.app.ActivityThread$H w=159)

这是厂商扩展格式。late/wall/running/runnable/io 和消息历史如何统计,应查该 ROM 的实现,不能直接当作 AOSP Looper 的稳定接口。样例可提示前序消息占用,但没有完整 trace 时不要把这些字段拼成确定的根因。

onTrimMemory

1
ClockTag AlarmClockApplication: onTrimMemory: 80

80 是旧的 TRIM_MEMORY_COMPLETE 等级,不是 80 MB 或 80%。官方 API 文档说明:Android 14(API 34)起不再通知该等级,常量在 API 35 废弃。因此这条旧日志可帮助读历史现场,不能作为新系统必然出现的低内存告警,也不证明随后一定被杀。

dvm_lock_sample

1
dvm_lock_sample:[system_server,1,Binder_9,1500,ActivityManagerService.java,6403,-,1448,0]

这是旧式九字段样例:进程名、敏感线程标志、等待线程名、等待毫秒数、等待方文件/行号、持锁方文件/行号、采样百分比。- 只表示文件名相同,不证明锁对象就是 AMS 本体;应按对应系统源码找两处位置。最后的 0 与常见非零采样条件不一致,原始设备实现不明,保留数值,不补猜采样策略。

它不是“等待一超过 500 ms 就实时输出”。ART 在获得锁后记录已完成的竞争,阈值由运行时配置控制,阈值以下也可概率采样;Android 15 格式还含方法名,不能用旧九字段位置硬解新日志。Monitor、LogContentionEvent

binder_sample

1
6628  6628 I binder_sample: [android.view.accessibility.IAccessibilityManager,6,2010,com.xxx.community,100]

这条旧日志的 PID/TID 都为 6628,说明记录线程是主线程。按 EventLogTags,列表含接口描述符、transaction code、耗时(ms)、blocking package、采样百分比。样例为 IAccessibilityManager、code 6、2010 ms、com.xxx.community、100%。保留字段定义不代表所有版本都开启这项采集,也没有通用的 500 ms 阈值。

transaction code 必须查同版本生成的 Stub/Proxy 或 AIDL。下面是旧 Android API 30 源码视图,FIRST_CALL_TRANSACTION + 5 对应 6,在该版本映射到 addAccessibilityInteractionConnection;不要把这个编号跨版本当固定方法名。耗时也不等于服务端纯 CPU 时间。

Long monitor contention

1
16809 14216 W system_server: Long monitor contention with owner InputDispatcher (17039) at android.content.res.Configuration com.android.server.wm.ActivityTaskManagerService.getGlobalConfigurationForPid(int)(ActivityTaskManagerService.java:1066) waiters=0 in boolean com.android.server.wm.WindowProcessController.hasActivities() for 141ms

art/runtime/monitor.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::string Monitor::PrettyContentionInfo(const std::string& owner_name,
pid_t owner_tid,
ArtMethod* owners_method,
uint32_t owners_dex_pc,
size_t num_waiters) {
Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
const char* owners_filename;
int32_t owners_line_number = 0;
if (owners_method != nullptr) {
TranslateLocation(owners_method, owners_dex_pc, &owners_filename, &owners_line_number);
}
std::ostringstream oss;
oss << "monitor contention with owner " << owner_name << " (" << owner_tid << ")";
if (owners_method != nullptr) {
oss << " at " << owners_method->PrettyMethod();
oss << "(" << owners_filename << ":" << owners_line_number << ")";
}
oss << " waiters=" << num_waiters;
return oss.str();
}

日志写出线程是 TID 14216,记录的持锁者是 InputDispatcher (17039)。141ms 是锁等待耗时,不是持锁者的 CPU 时间;waiters=0 是记录点的计数,不能解释为从未有人等待。上面保留旧版格式化代码,字段应按相同 ART 版本核对;Android 15 Monitor 在竞争结束后记录等待信息。

Binder Thread

1
E IPCThreadState: binder thread pool (31 threads) starved for 120 ms

这表示该进程的 libbinder 线程池出现饱和线索,31 是此处配置值,不是所有进程的通用上限。Android 15 IPCThreadState 在执行线程数达到上限时开始计时,降到上限以下后,若超过 100 ms 则打印。它不表示所有 Binder 通信都停止,也不能单独证明死锁;继续查看池内线程的锁、同步调用与耗时。

am_kill

1
am_kill : [0,18555,com.sina.weibo.image,945,remove task]

这是旧的五字段样例:用户 0、PID 18555、进程名、OomAdj 945、原因 remove task;已去掉旧文末尾多出的转录字符 1。Android 15 EventLogTags 还增加了 RSS 字段,解析器须匹配版本。以下五张图是旧实现的 kill 路径/原因索引,保留作历史查阅,不是当前版本所有杀进程路径的完整清单。

force-stop

异常杀进程

主动杀进程

调度杀进程

其他杀进程

由框架相应 kill 路径产生的 am_kill 与所有进程死亡不是一回事。Process.killProcess(pid)、shell 发信号或 LMK/lmkd 的行为未必经过该路径,但仍可能有其他日志;发信号受 UID、权限和 SELinux 等限制,不能杀任意 PID。

缺少 am_kill 也可能是日志覆盖或采集不全。要结合死亡、退出和内核记录,不能从“没这条日志”反推出一定由某种方式杀死。

am_proc_died

1
am_proc_died: [0,13210,com.xxx.gallery3d,935,19]

按 Android 15 EventLogTags,字段是用户、PID、进程名、OomAdj、ProcState。这里的 935/19 不是死亡原因;该事件表示系统观察到进程死亡,还要关联 am_kill、crash、lmkd 或退出记录。

am_anr

1
am_anr : [0,8769,com.android.updater,952680005,Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (has extras) }]

字段依次是用户、PID、进程名、ApplicationInfo flags 和 reason。本例用户 0、PID 8769、com.android.updater,reason 指向 BOOT_COMPLETED 广播。952680005 不是超时时长;Intent 的 flg=0x9000010 与前面的应用 flags 也不是同一字段,且未设置 0x10000000(FLAG_RECEIVER_FOREGROUND)。应按实际版本、广播标志及接收路径判断超时规则,不凭十六进制看起来大就套短期限。日志时间是事件记录时间,不等于广播开始时间。

Lowmemorykiller

1
2
lowmemorykiller: Kill 'com.heytap.themestore' (15545), uid 10136, oom_adj 995 to free 105068kB
lowmemorykiller: Reclaimed 105068kB at oom_adj 606

这是旧设备的内核 lowmemorykiller 格式,不代表现代 lmkd 总会在 kernel log 打印。首行列出进程名、PID 15545、UID 10136、标作 oom_adj 的 995 和预计回收量 105068 kB。995 不能按旧 Linux oom_adj 的 -17~15 范围解码;需核对厂商实现是否使用 oom_score_adj 量纲。

第二行没有 PID,不能仅靠相邻两行就认定同一受害进程,或把 606 无条件解释为 min_adj。日志中的预计/报告回收量也不保证等于系统最终净释放的物理内存。现代低内存调查可参考 AOSP lmkd。

Blocked msg

这是内部/厂商增补日志,旧文的 1.5 s 是该采集实现的慢消息门槛,不是 AOSP 通用 ANR 超时。cost=32436 ms 是消息处理耗时,不等于 CPU 时间;Current msg List 是当时待处理队列,不是已经执行完的消息列表。when 的负数表示相对预定执行时间的差值,不能直接当每条消息的 CPU 耗时。what=110/114/121 等编号需按对应版本 ActivityThread.H 查义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
E ANR_LOG : >>> msg's executing time is too long
E ANR_LOG : Blocked msg = { when=-32s683ms what=110 target=android.app.ActivityThread$H obj=AppBindData{appInfo=ApplicationInfo{bd8d51e com.android.contacts}} } , cost = 32436 ms
E ANR_LOG : >>>Current msg List is:
E ANR_LOG : Current msg <1> = { when=-32s672ms what=140 target=android.app.ActivityThread$H arg1=5 }
E ANR_LOG : Current msg <2> = { when=-32s671ms what=114 target=android.app.ActivityThread$H obj=CreateServiceData{token=android.os.BinderProxy@f7611ff className=com.android.contacts.xxxAppServicesManagerClient packageName=com.android.contacts intent=null} }
E ANR_LOG : Current msg <3> = { when=-32s671ms what=121 target=android.app.ActivityThread$H obj=BindServiceData{token=android.os.BinderProxy@f7611ff intent=Intent { cmp=com.android.contacts/.xxxAppServicesManagerClient }} }
E ANR_LOG : Current msg <4> = { when=-31s658ms what=1 target=android.os.AsyncTask$InternalHandler obj=android.os.AsyncTask$AsyncTaskResult@75e517c }
E ANR_LOG : Current msg <5> = { when=-29s750ms what=140 target=android.app.ActivityThread$H arg1=10 }
E ANR_LOG : Current msg <6> = { when=-29s103ms what=118 target=android.app.ActivityThread$H obj={1.0 460mcc3mnc [zh_CN] ldltr sw360dp w360dp h622dp 480dpi nrml long port finger -keyb/v/h -nav/h appBounds=Rect(0, 0 - 1080, 1920) s.10mThemeChanged = 0mThemeChangedFlags = 0mFlipFont = 0}
E ANR_LOG : Current msg <7> = { when=-28s370ms what=118 target=android.app.ActivityThread$H obj={1.0 460mcc11mnc [zh_CN] ldltr sw360dp w360dp h622dp 480dpi nrml long port finger -keyb/v/h -nav/h appBounds=Rect(0, 0 - 1080, 1920) s.11mThemeChanged = 0mThemeChangedFlags = 0mFlipFont = 0} }
E ANR_LOG : Current msg <8> = { when=-27s821ms what=122 target=android.app.ActivityThread$H obj=BindServiceData{token=android.os.BinderProxy@f7611ff intent=Intent { cmp=com.android.contacts/.xxxAppServicesManagerClient }} }
E ANR_LOG : Current msg <9> = { when=-27s821ms what=116 target=android.app.ActivityThread$H obj=android.os.BinderProxy@f7611ff }
E ANR_LOG : Current msg <10> = { when=-27s654ms what=114 target=android.app.ActivityThread$H obj=CreateServiceData{token=android.os.BinderProxy@e23cf1b className=com.android.contacts.xxxAppServicesManagerClient packageName=com.android.contacts intent=null} }
E ANR_LOG : >>>CURRENT MSG DUMP OVER<<<

通用场景 Log 介绍

灭屏 Log

关键是 power_screen_broadcast_done、screen_toggled 和 power_screen_state

1
2
3
4
5
6
7
8
9
10
11
12
1810  2470 I intercept_power: [ACTION_DOWN,1,0]
1810 2470 I intercept_power: [ACTION_UP,0,0]
1810 2470 I power_sleep_requested: 0

1810 1810 I power_screen_state: [0,2,0,0,1254]
1810 1810 I screen_toggled: 0 // 0 代表灭屏,1 代表亮屏
1810 1810 I power_screen_broadcast_send: 1
1810 1825 I wm_set_keyguard_shown: [1,0,0,setKeyguardShown] // (keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)

2768 2768 I sysui_status_bar_state: [1,1,0,0,0,1]

1810 1810 I power_screen_broadcast_done: [0,611,1] // 0 代表灭屏,611 是广播耗时(ms)

以上是旧日志序列。power_screen_broadcast_done 的三项是 on、广播耗时(ms)、wakelockCount;611 是广播流程耗时,不是屏幕面板熄灭延迟。power_screen_broadcast_send: 1 的 1 是 wakelockCount,不是亮屏标志。Android 15 Notifier

亮屏 Log

关键是 power_screen_broadcast_done、screen_toggled 和 power_screen_state

其中
power_screen_state

  1. offOrOn|1|5
  2. becauseOfUser|1|5
  3. totalTouchDownTime|2|3
  4. touchCycles|1|1
  5. latency|1|3
1
2
3
4
5
6
1810  2470 I intercept_power: [ACTION_DOWN,1,0]
1810 2470 I intercept_power: [ACTION_UP,1,0]
1810 1810 I screen_toggled: 1 // 1 代表亮屏
1810 1810 I power_screen_broadcast_send: 1
1810 1810 I power_screen_state: [1,0,0,0,319]
1810 1810 I power_screen_broadcast_done: [1,633,1] // 1 代表亮屏,633 是广播耗时(ms)

同理,633 ms 是亮屏广播耗时,不是从按键到屏幕可见的总延迟。上面的 |1|5 等是 EventLog 字段类型/单位元数据,不是日志中的实际数值。厂商 power_screen_state 的 reason/latency 还要核对写入点,不能把该旧序列视为每台设备必有的日志。

解锁完整 Log

wm_set_keyguard_shown 的值

  1. (keyguardShowing|1) :Keyguard 是否在显示
  2. (aodShowing|1) :aodShowing 是否在显示
  3. (keyguardGoingAway|1) :Keyguard 消失
  4. (Reason|3) :原因
1
2
3
4
5
6
7
8
9
10
 1810  5711 I wm_set_keyguard_shown: [1,0,1,keyguardGoingAway]
// 桌面 Resume
1810 5711 I wm_set_resumed_activity: [0,com.xxx.launcher/.Launcher,resumeTopActivityInnerLocked]
1810 5711 I wm_resume_activity: [0,93093883,63,com.xxx.launcher/.Launcher]
20615 20615 I wm_on_restart_called: [93093883,com.xxx.launcher.Launcher,performRestartActivity]
20615 20615 I wm_on_start_called: [93093883,com.xxx.launcher.Launcher,handleStartActivity]
20615 20615 I wm_on_resume_called: [93093883,com.xxx.launcher.Launcher,RESUME_ACTIVITY]
20615 20615 I wm_on_top_resumed_gained_called: [93093883,com.xxx.launcher.Launcher,topWhenResuming]

1810 5711 I wm_set_keyguard_shown: [0,0,1,setKeyguardShown] // keyguard 不显示,aod 不显示,keyguardGoingAway,原因是调用了 setKeyguardShown,不代表桌面已显示

这是旧四字段格式。Android 15 的 wm_set_keyguard_shown 已包含 DisplayId、keyguardShowing、aodShowing、keyguardGoingAway、occluded、Reason 六项,不能按旧位置解析。setKeyguardShown 是调用原因,不证明桌面已呈现或可交互;还要对齐窗口、绘制和输入证据。WindowManager EventLogTags

通知栏下拉完整 Log

1
2
3
4
5
6
2768  2768 I sysui_multi_action: [757,803,799,panel_open,802,1]
2768 2768 I sysui_multi_action: [757,1328,758,4,1326,29,1327,0,1329,0]
1810 3004 I notification_visibility: [-1|android|55|null|1000,1,457483196,457483196,0,4]
1810 3004 I notification_visibility: [0|com.android.systemui|10005|null|10132,1,97168545,97168545,0,2]
1810 3004 I notification_visibility: [0|com.android.systemui|2147483647|ranker_group|10132|ranker_group,1,97168236,97168236,0,1]
1810 3004 I notification_visibility: [-1|com.android.systemui|10006|null|10132,1,82586063,82586063,0,0]

sysui_multi_action 的数字是版本相关的 Metrics 编码,应查对应定义。notification_visibility 的顺序为 key、visible、lifespan、freshness、exposure、rank;这些时长字段不是事故的绝对时间戳。visible=1 提示通知可见,不能单独还原一次完整手势。

通知栏折叠完整 Log

1
2
3
4
5
2768  2768 I sysui_multi_action: [757,111,758,2]
1810 5473 I notification_visibility: [-1|android|55|null|1000,0,457546516,457546516,0,4]
1810 5473 I notification_visibility: [0|com.android.systemui|10005|null|10132,0,97231865,97231865,0,2]
1810 5473 I notification_visibility: [0|com.android.systemui|2147483647|ranker_group|10132|ranker_group,0,97231557,97231557,0,1]
1810 5473 I notification_visibility: [-1|com.android.systemui|10006|null|10132,0,82649384,82649384,0,0]

这里 notification_visibility 的 visible 变为 0。日志开关和版本会影响可见内容;没有这几行不能证明用户没展开/收起通知栏。

应用启动完整 Log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 创建 Task
1810 5473 I wm_task_created: [100,-1]
1810 5473 I wm_stack_created: 100
1810 5473 I wm_create_task: [0,100]

// 创建 Activity
1810 5473 I wm_create_activity: [0,231348670,100,com.androidperformance.memoryfix/.MainActivity,android.intent.action.MAIN,NULL,NULL,270532608]

// 桌面走 pause 流程
1810 5473 I wm_pause_activity: [0,93093883,com.xxx.launcher/.Launcher,userLeaving=true]
0615 20615 I wm_on_top_resumed_lost_called: [93093883,com.xxx.launcher.Launcher,topStateChangedWhenResumed]
0615 20615 I wm_on_paused_called: [93093883,com.xxx.launcher.Launcher,performPause]
1810 3720 I wm_add_to_stopping: [0,93093883,com.xxx.launcher/.Launcher,makeInvisible]

//启动 Activity
1810 2045 I am_proc_start: [0,18803,10263,com.androidperformance.memoryfix,pre-top-activity,{com.androidperformance.memoryfix/com.androidperformance.memoryfix.MainActivity}]
1810 3428 I am_proc_bound: [0,18803,com.androidperformance.memoryfix]
1810 3428 I wm_restart_activity: [0,231348670,100,com.androidperformance.memoryfix/.MainActivity]
1810 3428 I wm_set_resumed_activity: [0,com.androidperformance.memoryfix/.MainActivity,minimalResumeActivityLocked]
8803 18803 I wm_on_create_called: [231348670,com.androidperformance.memoryfix.MainActivity,performCreate]
8803 18803 I wm_on_start_called: [231348670,com.androidperformance.memoryfix.MainActivity,handleStartActivity]
8803 18803 I wm_on_resume_called: [231348670,com.androidperformance.memoryfix.MainActivity,RESUME_ACTIVITY]
8803 18803 I wm_on_top_resumed_gained_called: [231348670,com.androidperformance.memoryfix.MainActivity,topStateChangedWhenResumed]
1810 2034 I wm_activity_launch_time: [0,231348670,com.androidperformance.memoryfix/.MainActivity,471]

// 桌面走 stop 流程
1810 1978 I wm_stop_activity: [0,93093883,com.xxx.launcher/.Launcher]
0615 20615 I wm_on_stop_called: [93093883,com.xxx.launcher.Launcher,STOP_ACTIVITY_ITEM]

原摘录有 0615 20615、8803 18803 等疑似缺失首位的 PID 文本,未取得原文件,不补造数字;定位进程需结合 am_proc_start 和完整现场。wm_activity_launch_time 的 471 ms 是该版本启动统计点,不保证包含完全绘制或可交互的全部阶段。

Window Focus 相关的流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 从桌面启动 App,focus 变化 :Launcher => null => App
WindowManager: Changing focus from Window{b0416d7 u0 com.xxx.launcher/com.xxx.launcher.Launcher} to null,diplayid=0
WindowManager: Changing focus from null to Window{10f5145 u0 com.android.settings/com.android.settings.Settings},diplayid=0

// 从 App 返回桌面,focus 变化 :App => null => Launcher
WindowManager: Changing focus from Window{10f5145 u0 com.android.settings/com.android.settings.Settings} to null,diplayid=0
WindowManager: Changing focus from null to Window{b0416d7 u0 com.xxx.launcher/com.xxx.launcher.Launcher},diplayid=0

// 从 App 界面进入锁屏:focus 变化 :App => null => 锁屏
WindowManager: Changing focus from Window{10f5145 u0 com.android.settings/com.android.settings.Settings} to null,diplayid=0
WindowManager: Changing focus from null to Window{82e5f30 u0 NotificationShade},diplayid=0

// 从锁屏界面解锁进入 App,focus 变化 :锁屏 => App
WindowManager: Changing focus from Window{82e5f30 u0 NotificationShade} to Window{10f5145 u0 com.android.settings/com.android.settings.Settings},diplayid=0

短暂 Launcher → null → App 可以是普通窗口切换。要判断 NoFocusedWindow ANR,需结合等待焦点事件、有无 focused application、无焦点持续时间及对应超时规则,不能看到 null 就归因。焦点日志还受调试开关影响,细节见系列第一篇。

ANR 相关资料分享

  1. 西瓜视频稳定性治理体系建设一:Tailor 原理及实践
  2. 西瓜视频稳定性治理体系建设二:Raphael 原理及实践
  3. 西瓜视频稳定性治理体系建设三:Sliver 原理及实践
  4. 西瓜卡顿 & ANR 优化治理及监控体系建设
  5. 今日头条 ANR 优化实践系列 - 设计原理及影响因素
  6. 今日头条 ANR 优化实践系列 - 监控工具与分析思路
  7. 今日头条 ANR 优化实践系列分享 - 实例剖析集锦
  8. 今日头条 ANR 优化实践系列 - Barrier 导致主线程假死
  9. 今日头条 ANR 优化实践系列 - 告别 SharedPreference 等待
  10. Android ANR|原理解析及常见案例

参考资料

  1. https://duanqz.github.io/2015-10-12-ANR-Analysis#1-%E6%A6%82%E8%A7%88
  2. https://duanqz.github.io/2015-10-12-ANR-Analysis
  3. http://gityuan.com/2016/12/02/app-not-response/
  4. http://gityuan.com/2017/01/01/input-anr/
  5. https://xiaozhuanlan.com/topic/5097486132

关于我 && 博客

下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!

  1. 博主个人介绍 :里面有个人的微信和微信群链接。
  2. 本博客内容导航 :个人博客内容的一个导航。
  3. 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
  4. Android性能优化知识星球 : 历史介绍(已停止运营)

一个人可以走的更快 , 一群人可以走的更远

CATALOG
  1. 1. ANR 分析套路
  2. 2. ANR 问题一般的分析步骤如下:
    1. 2.1. 区分是应用的问题还是系统的问题
      1. 2.1.1. 首先应该分析是否是应用的问题
      2. 2.1.2. 分析系统的状态
    2. 2.2. 继续分析:应用可以解决还是系统可以解决
  3. 3. ANR Log 分析
    1. 3.1. 线程详细数据
    2. 3.2. 线程堆栈
    3. 3.3. 线程状态
      1. 3.3.1. 正常主线程 Trace
      2. 3.3.2. 异常主线程 Trace
    4. 3.4. CPU 使用率分析
    5. 3.5. CPU 负载
    6. 3.6. Memory 负载
    7. 3.7. IO 负载
    8. 3.8. 进程负载
    9. 3.9. CPU 异常进程
  4. 4. 系统关键 Log 介绍
    1. 4.1. 应用冻结
    2. 4.2. ActivityManager : Slow operation
    3. 4.3. Looper : Slow dispatch
    4. 4.4. Looper : Slow delivery
    5. 4.5. Looper:Slow Looper
    6. 4.6. onTrimMemory
    7. 4.7. dvm_lock_sample
    8. 4.8. binder_sample
    9. 4.9. Long monitor contention
    10. 4.10. Binder Thread
    11. 4.11. am_kill
      1. 4.11.1. force-stop
      2. 4.11.2. 异常杀进程
      3. 4.11.3. 主动杀进程
      4. 4.11.4. 调度杀进程
      5. 4.11.5. 其他杀进程
    12. 4.12. am_proc_died
    13. 4.13. am_anr
    14. 4.14. Lowmemorykiller
    15. 4.15. Blocked msg
  5. 5. 通用场景 Log 介绍
    1. 5.1. 灭屏 Log
    2. 5.2. 亮屏 Log
    3. 5.3. 解锁完整 Log
    4. 5.4. 通知栏下拉完整 Log
    5. 5.5. 通知栏折叠完整 Log
    6. 5.6. 应用启动完整 Log
    7. 5.7. Window Focus 相关的流程
  6. 6. ANR 相关资料分享
  7. 7. 参考资料
  8. 8. 关于我 && 博客