Skip to content

MusicPlayer v2.22.19 (code 60)

Latest

Choose a tag to compare

@HelloEarth520 HelloEarth520 released this 18 Sep 13:21
· 1 commit to main since this release

MusicPlayer v2.22.19

  • 版本号:versionName 2.22.19 / versionCode 60
  • 日期:2026-09-18
  • 本版主题:前台 CPU 占用优化——修复「炫彩流光文字」动画导致的每帧全视口重绘(实测 −26.5%)

需求背景

本版针对前台播放场景的 CPU / 内存占用做专项排查与优化。

真机(arm64-v8a)采样结论:

状态 CPU 占用
前台亮屏(暂停) 173.4%
前台亮屏(播放) 176.2%
后台(HOME) 14.8%
锁屏 5.7%
  • 前台高占用与是否播放无关(差 2.8 点),说明不是音频解码开销。
  • dumpsys gfxinfo:稳定 121fps、无掉帧;每帧 CPU 侧约 22ms(高刷屏每帧预算 8.3ms)、GPU 仅 3ms
    → 瓶颈在 CPU 侧渲染管线。
  • 内存无泄漏:连续切歌 16 次 PSS 471→551→515MB(回落),导入 1387 首仅 +12MB,线程 75→77。

归因过程(关键:第一次判断是错的)

第一轮判断(v2.22.18,已证伪)

按"毛玻璃很贵"的直觉,把整屏模糊从 #bg-veil 的 backdrop-filter 迁到壁纸层 filter,
并下调各处模糊半径、加 contain: layout paint。实测只降约 7%,与预期严重不符。

第二轮:CDP 逐项 A/B 归因(决定性)

经 adb forward 接 WebView 的 webview_devtools_remote_<pid>,用 Runtime.evaluate
注入覆盖 CSS,在同一进程、同一首歌、同一次会话里逐项开关。
共 5 轮、47 个对照场景(工具:_perf/cdp_attr.mjs,Node 22 原生 WebSocket,零第三方依赖)。

场景 CPU 均值 Δ 判读
基线 163.7% 0 —
停 19 个列表项标题的 fx-flow 136.4% −31.5 唯一显著项
↳ 复测(重复性) 136.6% −31.3 复现性 ±0.2
停跑马灯环 ring-run 170.5% +7.5 无成本
停歌词流逝 lyric-flow 169.5% +1.6 无成本
停顶栏 / 栏头 / 数值类 164.6~166.6% −1.3~−3.3 噪声
关全部 transition 163.3% +3.1 无成本
关全部 backdrop-filter 153.2% −10.5 约 −6%,非主因
关 filter / 壁纸模糊 165.5% +1.8 无成本
关阴影 161.7% −2.0 噪声

根因:播放列表 19 个曲目标题用 background-clip:text + 动画 background-position
实现「炫彩流动文字」(@keyframes fx-flow)。该动画不可合成到 GPU 合成线程,
每一帧都要在主线程重新栅格化文字渐变色。

非线性发现:顶栏 / 栏头 / 数值三项各自单停只值 1.3~3.3 点,但连同列表项标题一起停掉却 −54.2 点
("关全部动画"上限 −83.5)。说明成本主体是「这一帧到底有没有跨视口重绘」——
只要视口内任意一处持续变化,整条管线(主线程样式/布局/绘制 + 合成 + 所有 backdrop-filter
区域重新快照并模糊)就每帧全量运转;此时增删单个元素的边际成本很小。

实现

  • www/style.css:6 处 fx-flow 动画的时间函数 linear → steps(240, end):

    /* 改前 */  animation: fx-flow var(--fx-speed, 10s) linear infinite;
    /* 改后 */  animation: fx-flow var(--fx-speed, 10s) steps(240, end) infinite;

    渐变更新率由约 121 次/秒降到约 8 次/秒(--fx-speed 默认 10s 时约 24 次/秒)。
    动画外观不变:位移速度仍约 70px/s,每步仅约 1% 背景宽(235px 标题约 7px),
    柔和渐变下肉眼无差别。语法注意:steps() 与 linear 互斥,不能同写(否则整条声明失效)。

  • www/player.js:v2.22.18 的性能改造保留(壁纸模糊迁移、coverTick 30fps 闸门 + 页面隐藏门控、
    通知推送四要素去重、EQ 渐变对象按高度量化缓存),并修正其中已证伪的注释。

  • web-demo/style.css、web-demo/demo.js:同步同一套改造。

  • 清理:www/_perf_bak_20260918/(会被 cap copy 打进 APK)已移出到项目根。

  • android/app/build.gradle:versionCode 59 → 60,versionName 2.22.18 → 2.22.19。

  • www/index.html:设置页版本号 v2.22.19。

验证

修复前预演(CDP A/B)

场景 CPU Δ
基线 164.5% 0
全部 fx-flow 元素加 steps(240, end) 121.3% −43.2(−26%)
仅列表项标题完全停掉(对照) 137.6% −26.9

量化后的成本已与"完全删掉动画"持平 —— 拿到全部收益、零视觉损失。

修复后实测(真机,同方法)

场景 v2.22.18 v2.22.19 变化
前台亮屏播放(基线) 164.5% 120.9% −26.5%
↳ 基线复测 167.9% 133.6% −20.4%
关全部动画(下限对照) 79.5% 98.0% / 86.5% 差距收窄至约 23 点

与预演预测的 −26% 吻合。网页侧核对计算值确认修复生效:

TIMING_FN: {"titleName":"fx-flow","titleTF":"steps(240)","titleDur":"30s",
            "clockName":"fx-flow","clockTF":"steps(240)"}

构建与归档

  • cap copy → assembleDebug BUILD SUCCESSFUL(18s + 13s 两次,JDK 21)。
  • 装机:adb install -r -d → Success;dumpsys package 确认 versionCode=60 / versionName=2.22.19。
  • 归档:python _release/archive_release.py 2.22.19 60
    (source 快照 32.6MB + APK 本版/回滚基线 + source zip + website zip)。
  • webdemo 包:python _release/pack_webdemo.py 2.22.19 60(本版新增工具)。
  • 回滚基线:APK/app-v2.22.18-code59.apk(亦在 <归档>/_apk_backup/)。

装机记录

  • 覆盖安装成功,用户数据保留。
  • 冷启动正常,无 FATAL / AndroidRuntime 异常;播放正常。
  • 修复后新会话实测前台 CPU 稳定在 100~119%。

测量局限(如实说明)

  1. 帧率不可锁:部分厂商 ROM 忽略 settings put system peak_refresh_rate,设备稳定在约 121fps。
    若能在 60Hz 下运行,CPU 占用预计近似减半——这是一条尚未利用的优化路径,但系统层无可用接口。
  2. 存在状态依赖:同一组覆盖条件在两次独立测量中最大差 38 点(67.9% vs 106.0%),
    疑与温度、调度、播放进度有关。故只采纳多轮重复一致的项;单次极端值不予采信。
  3. CPU 口径:为「相对单核」百分比,8 核满载为 800%;含进程内所有线程。
  4. GPU 归因有限:dumpsys gfxinfo 的 GPU 耗时(约 3ms)未完整覆盖 WebView 自身渲染管线。

构建备忘

同 v2.22.13:cap copy android → JAVA_HOME=<JDK 21> +
ANDROID_HOME=<ANDROID_SDK> + NODE_OPTIONS="--use-system-ca" → gradlew assembleDebug。

归因工具复现方式:

ADB=<adb路径>
PID=$("$ADB" shell pidof com.musicplayer.app | tr -d '\r')
"$ADB" forward tcp:9222 localabstract:webview_devtools_remote_$PID
NODE_OPTIONS="--use-system-ca" node _perf/cdp_attr.mjs com.musicplayer.app "$PID" run