第3章 使用 dumpsys 分析 AMS 状态:命令格式、关键字段解读、活动堆栈与进程信息

3.1 dumpsys 命令结构

dumpsys 是 Android 系统提供的诊断工具,能够直接访问系统服务内部状态。对于AMS性能调优,dumpsys activity 是分析 Activity 管理、任务栈、进程优先级和广播/服务超时的核心入口。

性能诊断第一定律:永远不要猜测问题根源。先用 dumpsys 采集现场数据,再定位具体模块。这能避免 80% 的无意义代码修改。

基础命令格式:

adb shell dumpsys activity [options]

常用 options 说明表:

选项输出内容调优场景
activities所有 ActivityRecord、任务栈最详细状态启动速度、窗口焦点、泄露分析
processes进程 pid、adj 类型/分数、LRU 顺序OOM 优化、进程保活、后台耗电
services已注册及运行中的 ServiceRecordANR 定位、服务泄漏、内存占用
o前台广播接收器、前台服务概览快速排查卡顿与高负载原因
broadcasts广播队列、历史广播、超时记录广播风暴、有序广播 ANR
all以上所有信息的汇总全量现场快照
实战筛选技巧:直接执行 adb shell dumpsys activity 输出可能高达数百行。性能调优时请优先将输出保存到本地文件,再利用 grep 定向过滤。例如:
adb shell dumpsys activity all > ams_dump.txt
  grep -E "Stack|Task|mResumed|mFocused|mLastPaused" ams_dump.txt

3.2 关键字段深度解读

以下字段直接决定系统流畅度与稳定性,调优过程中必须能够快速识别。

当前焦点与可见状态

mResumedActivity: ActivityRecord{xxxxx u0 com.example/.MainActivity}
mFocusedActivity: ActivityRecord{xxxxx u0 com.example/.MainActivity}
mLastPausedActivity: ActivityRecord{yyyyy u0 com.example/.SplashActivity}
  • mResumedActivity:当前正在与用户交互的 Activity,必须快速响应触摸事件。如果此处长期不切换,可能表明启动流程被卡住。
  • mFocusedActivity:窗口焦点归属,通常与 mResumed 一致。不一致时暗示输入法/弹窗/多窗口抢焦点。
  • mLastPausedActivity:上一个被暂停的 Activity。连续快速切换 Activity 时,此字段可以帮助识别是否发生了不必要的重建或重绘。

ActivityRecord 核心字段

ActivityRecord{xxxxx u0 com.example/.DetailActivity t123}
  intent={act=android.intent.action.VIEW dat=...}
  app=ProcessRecord{yyyyy 12345:com.example/10001}
  state=STOPPED
  visible=false
  frontOfTask=false
  procIdle=true
  • state:生命周期状态(INITIALIZING/RESUMED/PAUSED/STOPPED/DESTROYING)。调优时重点关注停在 PAUSED 或 STOPPED 状态时间过长的 Record。
  • app:指向进程 ProcessRecord。如果为 null,表明进程已死亡,属于“僵尸 Activity”,会导致内存泄漏。
  • visible:真正对用户可见。如果 visible 为 false 但 state 为 RESUMED,属于异常场景,可能导致触控和绘制问题。
  • frontOfTask:是否处于任务栈顶。调优时大多数关注的应该是 frontOfTask=true 的 Record。
调优聚焦:进程死亡后 mResumedActivity 指向一个 app=null 的 ActivityRecord 时,系统会等待 5s 超时再重新创建。这是启动卡顿的常见隐性原因。

3.3 活动堆栈层次结构

Android 通过 Stack → Task → ActivityRecord 三级管理窗口。多窗口、画中画和自由窗口模式引入多个 Stack。

层次关系图解:
AMS Dumpsys 输出内部分层结构 dumpsys activity Activity Stack (Root) TaskRecord #2c3e50 TaskRecord #2c3e50 ActivityRecord A ActivityRecord B ProcessRecord adj=0 TOP

栈类型与识别:

  • Stack #0:全屏应用栈,绝大多数场景下的主运行栈。
  • Stack #1:分屏栈(Split-screen),存在时表明系统处于多窗口模式。
  • Stack #2:自由窗口栈(Freeform),常见于 Android TV 或平板模式。
  • Stack #3:画中画栈(PIP),视频应用悬浮时出现。

3.4 进程信息与 ADJ 算法

通过 dumpsys activity processes 获取进程优先级,直接关联 LMK 杀进程与后台耗电。

ProcessRecord{yyyyy 12345:com.example.app/10001}
  ...
  setAdj=0
  setRawAdj=0
  curAdj=0
  maxAdj=0
  appId=10001
  pid=12345
  thread=android.app.IApplicationThread$Stub$Proxy@xxxxx
  lastPss=245MB
  lastCachedPss=210MB
  cached=false
  hasShownUi=true
  ...

adj 核心评级表:

  • adj=0 (TOP):当前前台应用。系统必须全力保障其性能,杀进程时最后考虑。
  • adj=200 (VISIBLE):可见但非前台(例如被部分遮挡)。仍属于重要进程。
  • adj=500 (PERCEPTIBLE):可感知进程(如播放音乐、后台定位)。
  • adj=900 (CACHED):后台缓存进程。LRU 列表最末尾的进程会优先被 LMK 杀死。
  • adj=1001 (UNKNOWN_ADJ):未正确分类的进程,属于异常状态。
调优陷阱:如果低端设备频繁出现桌面重启、应用冷启动,请检查 dumpsys 输出中 cached 进程的总数是否长期超过 LMK 水位线。adj=900 的进程堆积过多会导致严重的卡顿和内存压力。

3.5 性能调优实操案例

场景 A:Activity 启动缓慢

adb shell dumpsys activity activities | grep -E "mResumedActivity|mFocusedActivity|mLastPausedActivity"

观察到 mLastPausedActivity 在目标 Activity 启动前长期未更新,说明 PAUSE 阶段卡住。此时应进一步检查目标 Activity 的 onPause() 是否执行了耗时 IO 操作。

场景 B:内存泄漏检测

adb shell dumpsys activity activities | grep -E "app=null|ActivityRecord"

如果发现大量 ActivityRecord 的 app=null 且 state=STOPPED 或 DESTROYING,说明这些 Activity 的进程已被杀死,但 ActivityRecord 仍未从栈中移除,属于典型的泄漏路径。

场景 C:ANR 快速定位

adb shell dumpsys activity processes | grep -E "adj=|setAdj=|curAdj=|lastPss="

关注 setAdj 是否被异常限制在 0/200/500 以外,以及 lastPss 是否突然飙升。配合 dumpsys activity o 查看前台广播接收器和服务,可以迅速定位造成主线程阻塞的第三方组件。

每日调优习惯:每周对主力机型执行一次 dumpsys 全量采集,对比 cached 进程数量与 lastPss 均值,能够提前发现内存衰退趋势,避免线上爆发 OOM 或 ANR 异常。