1. 课程导入

Android Framework 是连接应用与 Linux 内核的“中枢层”,它既承载 Activity、Window、Package、AMS、WMS 等系统服务,又直接决定应用启动速度、滑动流畅度、内存水位与系统稳定性。很多开发者遇到卡顿、ANR、Crash、内存泄漏时,第一反应是查应用代码,但真正的根因往往藏在 Binder 调用、SystemServer 锁竞争、SurfaceFlinger 合成、LowMemoryKiller 回收策略等 Framework 环节。本课程的目标,是让你从“会看日志”进阶到“能定位链路、能修改机制、能验证收益”。

本课程围绕三条主线展开:性能(启动、流畅、内存、功耗)、稳定性(ANR、Crash、Watchdog、死锁、重启)、工程方法(抓取、建模、定位、修改、回归)。三者不是并列关系,而是“指标—现象—根因—修复—验证”的闭环。

一、核心概念:先建立 Framework 的坐标系

学习 Framework 优化,第一步不是背源码,而是建立分层坐标系。Android 系统大致分为应用层、Framework 层、Native 层与内核层。Framework 层内部又可细分为 Java 服务、JNI、Native 服务与 HAL 接口。性能问题通常表现为“上层现象”,但根因可能在下层。例如应用冷启动慢,可能是 Application 初始化耗时,也可能是 AMS 调度延迟、Binder 线程池阻塞,甚至 IO 抖动导致 dex2oat 变慢。

因此,本课程会反复使用四个核心概念:调用链、关键路径、资源竞争、观测点。调用链回答“谁调用了谁”;关键路径回答“哪一段最耗时”;资源竞争回答“谁在等谁”;观测点回答“用什么工具能看到”。只有把现象映射到调用链上的具体节点,优化才不是盲猜。

Android Framework 优化知识框架 应用层 Activity / Service Binder Client Framework Java AMS / WMS / PMS SystemServer Native 服务 SurfaceFlinger AudioFlinger 内核 / HAL 调度 / IO / 驱动 Binder Driver 性能主线 • 启动:冷/温/热启动、dex2oat • 流畅:VSync、掉帧、Jank • 内存:LMK、GC、泄漏 稳定性主线 • ANR:Input / Broadcast / Service • Crash:Java / Native / Tombstone • Watchdog / 死锁 / 重启 工程方法主线 • 抓取:Perfetto / Systrace / Log • 定位:调用链 + 关键路径 • 验证:A/B 回归 + 指标对比 实战闭环:现象 → 指标 → 调用链 → 根因 → 修改 → 回归 每一章都落到一个可复现场景、一条可观测链路、一组可对比数据

二、方法流程:从现象到根因的五步法

面对一个性能或稳定性问题,建议固定使用五步法,避免“上来就改代码”。

  1. 定义现象与指标:例如“冷启动 1.8s,目标 1.2s”“滑动 120 帧中掉 18 帧”“ANR 率 0.3%”。指标必须可量化、可复现。
  2. 抓取现场数据:使用 Perfetto、Systrace、logcat、dumpsys、traces.txt、tombstone 等,保留时间戳与进程信息。
  3. 还原调用链:把主线程、Binder 线程、RenderThread、SurfaceFlinger 的时间线对齐,找到阻塞点。
  4. 定位根因:区分是锁竞争、IO 等待、GC、CPU 抢占、Binder 超时还是逻辑错误。
  5. 修改与回归:小步修改,A/B 对比,确认指标改善且无副作用。
# 典型抓取命令示例
adb shell perfetto -o /data/misc/perfetto-traces/trace.pftrace \
  -t 10s sched freq idle am wm gfx view binder_driver

adb shell dumpsys activity processes | grep -i "ANR"
adb shell cat /data/anr/traces.txt
adb shell dumpsys SurfaceFlinger --latency com.example.app

三、案例场景:一次滑动卡顿的排查路径

假设某应用在列表滑动时出现周期性卡顿。第一步看 Perfetto,发现主线程在 ViewRootImpl.performTraversals 中耗时 32ms,超过 16.6ms 帧预算。继续展开调用链,发现 measure 阶段触发了多次 requestLayout,同时 RenderThread 在等待 GPU 完成上一帧。再查 Binder,发现 WMS 的 relayoutWindow 被 SystemServer 中的锁阻塞。最终根因是窗口层级过深导致合成压力大,叠加主线程重复布局。修复方向包括:减少嵌套层级、复用 ViewHolder、把非关键布局放到异步线程、降低透明区域重叠。这个案例说明:卡顿不是“一个点”,而是主线程、RenderThread、SurfaceFlinger、WMS 共同作用的结果。

排查时优先看“谁在等谁”。如果主线程在等 Binder,就看服务端线程;如果服务端在等锁,就看锁的持有者;如果都在等 CPU,就看调度与频率。等待关系比耗时数字更能揭示根因。

四、常见误区与复盘清单

初学者最容易陷入四个误区:一是只看应用代码,忽略系统服务;二是只看平均耗时,忽略尾延迟与抖动;三是只优化单点,破坏整体稳定性;四是修改后不做回归,导致问题转移。建议每完成一次优化,都用下表复盘。

复盘项 关键问题 输出物
现象定义 指标是否可量化、可复现? 基线数据与目标值
数据抓取 是否覆盖主线程、Binder、RenderThread? Perfetto / 日志 / traces
根因定位 是等待、竞争还是计算? 调用链与阻塞点
修改验证 A/B 是否显著?有无副作用? 对比报告与回归结论
不要在没有基线数据的情况下直接改代码。没有基线的优化无法证明收益,也无法判断是否引入新的稳定性风险。先测量,再修改,再测量。

本课程后续将沿着“启动优化、流畅度优化、内存优化、ANR 分析、Crash 与 Watchdog、Binder 与锁竞争、SystemServer 稳定性、Perfetto 实战”等主题逐步展开。每一节都会给出真实场景、可执行命令、调用链分析方法和验证思路。你需要做的,是带着一个具体问题进入每一节,用五步法把它拆开、定位、修复并回归。这样学完 30 章,你收获的不只是知识点,而是一套可复用的 Framework 优化方法论。