0. 使用边界
- 版本基线:以 2026-10-20 为时间点,主线讨论 Android 17 / API 37;平台机制建议按 AOSP android-17.0.0_r1 复核,内核机制按 ACK android17-6.18-2026-06_r6 复核。
- 来源分层:官方 Vitals/开发者文档用于定义指标和警戒线;社区反馈用于发现体验回归,不直接作为平台机制结论;提供的文档用于把现象落到源码锚点、版本边界和观测方法。
- 阈值使用:Play/Vitals 阈值适合做告警、发版门禁和灰度回滚线,不应替代同设备、同构建、同 workload 的 A/B 测试。
- 常见失败模式:在错误状态下测到正确现象,然后把现象优化成另一个指标。所有结论都要带设备、构建、负载、工具、样本量、分位数和对照基线。
1. 总览:官方 Vitals 与社区高频问题
Android 官方 Vitals 长期关注 ANR、崩溃、慢渲染/冻帧、卡死 WakeLock、过量唤醒、后台扫描、后台网络等质量面。社区对 Android 17 的反馈更接近"稳态迭代":一部分用户无感,一部分用户感知更快,也有小部分用户报告更慢/更卡,低 RAM 或旧机型更容易暴露后台维护和热/调度差异。
| 类别 | 典型症状 | 第一优先证据 | 最容易误判 |
|---|---|---|---|
| 渲染/Jank | 滑动卡、动画跳、点击响应慢、高刷设备更明显 | FrameTimeline/JankStats/dumpsys gfxinfo + 主线程/RenderThread/GPU/HWC | 只看 doFrame;忽略 RenderThread、fence、thermal、刷新率 |
| ANR | 输入无响应、广播/服务超时、Provider 卡住 | ANR trace + 组件计时窗口 + 线程状态 + Binder/I/O/GC/LMKD | 主线程栈停在 nativePollOnce 就判断系统误报 |
| 启动 | 冷启动慢、首帧后仍不可用、升级后变慢 | 启动分段 timeline + pm art dump + Macrobenchmark CompilationMode | 把 Splash 当优化;把热启动当冷启动;编译状态不一致 |
| 内存 | PSS 增长、OOM、后台被杀、切回重建 | meminfo 分域 + heap dump/heapprofd + ApplicationExitInfo | RSS/PSS 混用;只看 Java heap 漏 Native/Graphics |
| 功耗/热 | 发热、降频、续航差、后台频繁唤醒 | batterystats/Historian + power rail + thermal headroom + wakeup | 只看 CPU/FPS;把省电模式当固定参数 |
| 稳定性/退出 | Crash、Native abort、WebView renderer 死、进程被杀 | Crash symbol + tombstone + ApplicationExitInfo + vitals | 用单一 exit reason 下结论 |
| I/O/数据库 | SP 卡、SQLite 慢、文件/媒体路径慢、OTA 后慢 | Perfetto I/O/page fault + query plan + dbinfo + bugreport 增量 | 把 OTA/首启 dexopt、快照合并、ZRAM/mmd 归因到 App |
| Binder/IPC | 同步调用慢、TransactionTooLarge、跨进程黑屏/超时 | Binder flow + 目标线程状态 + buffer/对象图 + 线程池 | 把 Binder 说成一次拷贝所以快 |
| 网络 | 首屏慢、DNS/TLS 高、弱网重试风暴、后台偷跑 | 客户端阶段耗时 + 接入层对账 + network callback/Job reason | 把 API 窗口当硬件窗口;只看 dnsStart/dnsEnd |
| 版本/归因 | 升级后变慢、targetSdk 触发行为变化、OEM 差异 | build fingerprint + targetSdk/compat change + Mainline/ART + uname/PAGE_SIZE | 从 Android 大版本反推内核/HAL;48-72 小时内下结论 |
2. 渲染卡顿 / Jank / Frozen Frames
官方口径:慢帧通常指超过 16ms 的 UI 帧;冻帧指超过 700ms 的帧,体感接近应用卡死近一秒。高刷下预算更紧:60Hz 约 16.6ms,90Hz 约 11ms,120Hz 约 8.3ms。
- 主线程:I/O、JSON/XML 解析、图片解码、同步 Binder、数据库/SP、大对象分配、反射/注解扫描。
- 列表:RecyclerView onBindViewHolder 或 Compose item 组合中做解码、格式化、创建对象;keys/DiffUtil 不当导致整表重建;预取失效。
- 绘制:View 层级深、过度绘制、onDraw 分配对象、离屏 pass 多;Compose 重组范围过大、不稳定参数、状态读错位置。
- 系统侧:RenderThread、GPU 驱动、SurfaceFlinger、BufferQueue/fence、HWC validate/present、ARR/刷新率切换、thermal 降频。
- 分析顺序:先用 FrameTimeline/FrameTracer 判定错过的是应用 deadline 还是显示合成 deadline;再回到主线程/RenderThread/GPU/HWC 取证。
3. ANR
常用组件超时边界:Input 约 5s;前台 BroadcastReceiver 约 10s、后台约 60s;Service 主要生命周期约 20s;Android 15+ 起 startForegroundService 后未尽快 startForeground 的时限更严格。
- 主线程:网络、数据库、文件、SP apply 后的组件收尾/fsync、超大 JSON 解析、锁等待/死锁、同步 Binder 长事务。
- 组件:BroadcastReceiver.onReceive 做长工作;Service/JobService/ContentProvider 初始化或 publish 慢;前台服务启动违规。
- 跨进程:Binder 线程池耗尽、嵌套调用、锁顺序不一致、目标进程冻结/解冻等待。
- 特殊 ANR:CPU 饥饿、I/O、GC/reclaim、LMKD、cached freezer、SQLite/WAL、InputTransport finished signal 历史缺陷。
- 方法:ANR trace 只是入口;要联合 InputDispatcher WaitQueue、组件计时窗口、Binder flow、线程状态、锁、I/O、GC、lmkd/freezer。
4. 启动慢
常见质量线:cold start >5s、warm start >2s 应视为高优问题;中低端机 cold start 常要求压到 1.5--2s。实验室需用 Macrobenchmark 固定 CompilationMode,线上区分冷/温/热启动。
- 关键路径:ProcessList → Zygote/USAP → PostFork → ActivityThreadMain → attachApplication → bindApplication → Provider/Application → Activity/View/Compose → first frame。
- 高频根因:ContentProvider 早于 Application.onCreate;Jetpack Startup/广告/统计/推送 SDK 自动初始化;DI 图、数据库、序列化、路由、日志框架提前建图;首屏布局节点过多、inflate/Compose initial composition 重;大图未按显示尺寸解码。
- 编译与产物:Baseline/Startup/Cloud Profile 覆盖不足;R8 与 profile 生成变体不一致;verify/speed-profile/speed 状态漂移;16 KB 页下 .so LOAD 段/ZIP 对齐不兼容。
- 误区:Splash/KeepOnScreenCondition 只能管理感知,不应隐藏关键路径;盲目多线程/拆进程会增加锁、序列化、常驻内存和一致性成本。
5. 内存泄漏 / OOM / 低内存压力
- 分域记账:Java heap、Native heap、Graphics、Code、Stack、mmap、FD、线程、WebView renderer、AI 运行时峰值不能混成一个"内存"。
- Java 高频泄漏:静态持 Context/View;非静态内部类/匿名回调;未注销 Listener;协程/Flow 作用域未取消;单例缓存无界。
- 资源高频泄漏:Bitmap 未按显示尺寸解码;图片复用池/inBitmap/Hardware Bitmap 边界不清;Camera/Codec/GL texture;Cursor/FD 未关。
- 系统边界:PSS 按共享分摊,RSS 会重复计共享页;Private_Dirty 更适合定位写时复制增长;低内存下 lmkd、mmd/ZRAM、freezer、PSI/refault 会改变体验。
- 证据:开发期 LeakCanary;线上 ApplicationExitInfo + ProfilingManager/OOM trigger + heap dump/heapprofd;Native 用 Scudo/GWP-ASan/MTE 分层,而不是只看一个总数。
6. 耗电 / 发热 / Thermal
- 高频根因:WakeLock/Alarm/定位/蓝牙扫描/传感器未按业务生命周期关闭;后台任务重复唤醒;前台服务当免死金牌;Job/WorkManager 未看 pending/stop reason、bucket、配额。
- 性能联动:长期高 CPU/GPU 负载触发 thermal throttling;应结合 ADPF PerformanceHint、thermal headroom、Game Mode/Game State 做降级。
- 设备变量:亮度、刷新率、深色模式、网络制式、省电模式、电池健康、设备老化都会改变结果;记录请求值和生效值。
- 证据:Battery Historian/dumpsys batterystats + Perfetto power rail/thermal + 线程 wakeup/锁;用 A/B 功耗实验验证收益,而不是只看 FPS。
7. 崩溃 / Native / 进程退出
- Java Crash:未捕获异常、生命周期/配置变更错误、协程异常传播、后台启动违规;关注安全恢复与退出线程。
- Native Crash:越界、use-after-free、泄漏、线程 attach/detach 错误;需要 Build ID/symbol 与 signal handler 交接边界。
- 进程退出:OOM、低内存 kill、CPU 过量终止、ANR、force-stop、升级、WebView renderer、FD 耗尽;用 ApplicationExitInfo 与 tombstone/ANR/低内存字段互证。
- 16 KB/ABI:包含 NDK 或三方 .so 的应用要检查 ELF LOAD 段对齐、APK 内未压缩 lib 的 ZIP 对齐、mmap/页掩码常量;Android 15 起支持 16 KB,Android 16 有兼容模式,Android 17 有测试 fatal 开关。
8. I/O、存储、SQLite、媒体
- SharedPreferences:apply() 返回快不代表落盘完成;组件收尾路径仍可能阻塞主线程;多进程一致性不要靠 SP。
- SQLite/Room:主线程查询、大事务、缺索引/坏查询计划、WAL checkpoint、连接池争用是常见根因。
- 媒体/共享存储:MediaProvider/Photo Picker/FUSE/SAF/URI/FD 生命周期复杂;不要把 Provider 路径当普通文件。
- OTA/首启:dexopt、odsign、快照合并、ZRAM/mmd、文件系统、16 KB page、I/O 竞争都可能让"升级后第一次慢";应与 App 代码问题分开。
9. Binder / IPC / 跨进程
- 高频根因:主线程同步 Binder 长事务;小粒度 IPC 循环;oneway 滥发导致背压;大对象塞 Parcel 触发 TransactionTooLarge;服务线程池耗尽。
- 正确边界:Binder 不只是"一次拷贝";端到端延迟包含排队、调度、SELinux/权限、对象解析、目标服务执行和下游依赖。
- 进程冻结:cached freezer 会让线程轨迹空白;同步调用、oneway、异步缓冲区、解冻原因要分开看。
- 证据:调用方 slice + Binder flow + 目标线程状态 + 下游事务 + buffer/对象图;不要把 PostFork/USAP 路径混为普通 fork。
10. 网络
- 高频根因:DNS/TLS/TCP/QUIC 叠加在首屏关键路径;同步回调中做 HTTPDNS;弱网重试无预算;图片/Feed 一次拉全量;后台同步不区分计费网络/Data Saver。
- 口径:客户端阶段耗时要和接入层对账;网络切换要同时约束解析和 socket;QUIC/HTTP3 字段显式区分;不能只看 dnsStart/dnsEnd。
- 后台:JobScheduler/WorkManager 记录 pending reason、stop reason、standby bucket、配额;前台服务不自动豁免配额。
11. 最容易被忽略:归因与版本
- 升级后 48--72 小时:dexopt、缓存重建、索引、云端画像、后台同步会扰动结论;应区分 OTA 首启、冷启动、稳定态。
- 版本坐标:build fingerprint、API/targetSdk、compat change、Mainline/ART APEX、kernel uname -r、ABI、getconf PAGE_SIZE、厂商 ROM/调度/温控。
- 指标坐标:P50/P90/P95/P99、分位数、样本量、场景入口、剔除规则;不要只看平均值或单次 trace。
- A/B 原则:同设备、同构建、同启动类型、同 workload、同编译状态;收益要同时看耗时、内存、功耗、稳定性和长尾。
12. 通用排查 SOP
- 定义问题:选择正确类别和指标,明确起点/终点;卡顿看 deadline,启动看 TTID/TTFD,内存分域,功耗按场景。
- 固定状态:版本、targetSdk、编译模式、Profile、设备、温度、电量、网络、后台任务;记录构建指纹和 Mainline/ART 版本。
- 采集证据:线上 Vitals/APM/JankStats;实验室 Macrobenchmark;深度 Perfetto 同步抓 CPU/调度/Binder/I/O/内存/GC/渲染/功耗。
- 定位阻塞方:线程状态 + wakeup/futex/Binder/I/O/GC + 锁持有者 + thermal/freq;避免把最长 slice 直接当根因。
- 源码锚点:平台按 android-17.0.0_r1,内核按 android17-6.18-2026-06_r6;区分 AOSP 公共机制、Mainline 模块、OEM 实现。
- 修复验证:先减少关键路径工作,再改布局/编译/缓存/调度;用同状态 A/B 验证收益,并把指标加入 CI/灰度门禁。
13. 指标与警戒线参考
| 指标 | 常用参考 | 说明 |
|---|---|---|
| 慢帧 | >16ms;高刷下 90Hz≈11ms、120Hz≈8.3ms | 预算随刷新率变化,不能固定按 60fps |
| 冻帧 | >700ms | 接近"卡死近一秒",Vitals 重点关注 |
| ANR | Input≈5s;前台广播≈10s/后台≈60s;Service≈20s;FGS 启动更严格 | 组件类型不同,计时窗口不同 |
| 启动 | cold >5s、warm >2s 高优;中低端 cold 目标 1.5--2s | 工程门禁常严于 Play 底线 |
| 崩溃/ANR 质量 | Play user-perceived ANR 0.47%、crash 1.09% 等 | 适合做线上告警和发版暂停线,不替代 A/B |
| 内存 | 分域看 PSS/Private_Dirty/Native/Graphics/FD | 不要只用 RSS 或单一总数 |
| 功耗 | stuck wakelock、过量唤醒、后台扫描/网络 | 按业务场景和设备分级设定阈值 |
14. 参考来源
- Android Developers / Android Vitals:性能与电池质量指标、ANR、慢渲染、冻帧、启动、内存、功耗口径。
- Android 官方 Android 17 发布信息:Pixel 首批推送、应用内存限制、高清游戏掉帧优化等方向。
- 社区反馈:9to5Google Android 17 升级后读者投票、XDA/Reddit/厂商社区中的卡顿、耗电、升级后变慢个案;仅作体验线索。
- 《Android 技术内幕:系统机制、性能优化与工具实战》(你提供的文档):AOSP android-17.0.0_r1 与 ACK android17-6.18-2026-06_r6 的源码锚点、版本边界和工具方法。