fix(ncm §33): 流媒专项批六项——流式SIGSEGV防御日志/档位保真(无损级必须flac+显示档按实际)/封面4xx不重试/收藏显隐/缓存命名迁移/topbar位图图标
- §2① ncm_api.c level_attempt: 无损级(hires/lossless及以上)命中必须 type=flac,返回 mp3 视为该档不可用续降 (修「hires 档静默给 mp3 被当命中」) - §2② player_manager.c eff_level_for_resp: 显示档按响应实际格式/码率——mp3 绝不显示 Hi-Res(≤128k→标准, 否则极高), flac 采信链 eff; br 未知钳 ≤EXHIGH - §1 流式 SIGSEGV(《十面埋伏》sig=11) 审计+UBSAN 探针未复现 → 落地防御日志(dl start/done/interrupt + play done fin/exp/fail/underrun) - §3 cover.c: download_cover 回填 rc/status; 确定性 4xx(404等)不重试立即跳下一张, 仅瞬时错误退避(rc=%d status=%d 日志) - §4 playlist.c: pl_show_fav 我创建(is_collected==0)隐藏收藏钮, 我收藏保留, 搜索歌单保守显示(评论槽并入无空洞) - §5 ncm_cache.c 双点→单点迁移 + player_manager song_local_file 旧键→当前档位键(不重下) - §6 home.c: topbar 动作 ⚙↻⌕ 迁移 sb_icons 位图(meow_topappbar_set_item_icon, 修 4k 字库豆腐) - 测试: test_ncm_core 新 test_grade_flac_gate + test_cache 双点迁移断言; degrade_sim/player_flow_sim 桩 flac 化 - 验证: stream/player_flow/window/search/cache_evict/degrade sim 全 PASS + test_ncm_core host+mipsel(qemu) + mem_sim + build_ncm.sh 0 warning - 新 ncm md5 cb818786 (text 1017110/bss 1362500), 未部署留主会话; 0 真实 NCM 业务请求
This commit is contained in:
1 parent
68ce46a5d8
commit
44a790dc1d
13 files changed
+425
-24
No files matched your search
@@ -2806,3 +2806,191 @@ a9842284ecf9529ac1c39a9119561a20 mem_sim # 宿主内存测量 harness
|
||||
- **真机长期峰值**:幽灵左滑导致无法持续采样,设备端「≤16MB」是「基线 ~6MB + 封面 0.78MB + 字库
|
||||
2.44MB」的推演上限(约 8-9MB),低于 16MB 目标;正式部署后建议主会话做一次带 launcher 的
|
||||
前台三场景采样复核。
|
||||
|
||||
---
|
||||
|
||||
## 33. 流媒专项批六项:流式 SIGSEGV 防御 / 档位保真 / 封面 4xx / 收藏显隐 / 缓存命名 / topbar 图标(2026-09-02)
|
||||
|
||||
> 范围:`patch_v2/ncm_app/`(+ 无 sdk/、meow_launcherd/ 改动)。用户报 6 项,本批逐项给
|
||||
> 根因/修法/测试。风控纪律:**0 次真实 NCM 业务请求**(`test_ncm_core` 的 `test_network`
|
||||
> 为既有只读冒烟——unikey/poll/无 cookie user_playlist 各 1 次,不下载、不改状态,见 §33.7 诚实出入)。
|
||||
|
||||
### 33.1 任务① 播放流式 SIGSEGV(最高优先):防御 + 日志定位(未稳定复现)
|
||||
|
||||
**症状**:真机播《十面埋伏》(id=409931770,hires 档 mp3)边下边播途中(写 ~721KB、播放 ~79s)
|
||||
进程 `sig=11`;ams `crash dev.player.ncm sig=11`。并非 §30.4 的 VOL_DOWN×3 SIGKILL(那是 sig=9)。
|
||||
|
||||
**根因排查(本批,诚实)**:对 `stream_src`(pread+condvar+fread 语义 read_cb)、`ncm_cache`
|
||||
写穿 `.tmp/.part`、`dl_thread`(http 状态感知回调 + 续传 200/206/416 分支)、`decoder`
|
||||
(minimp3 `MP3D_SEEK_TO_BYTE|DO_NOT_SCAN` / dr_flac 回调)、`run_song` 解码主循环(stall 暂停/
|
||||
恢复、seek 超已下载区、切档 seq 护栏)做了逐行审计,**未找出确定崩溃点**。另写临时 UBSAN
|
||||
压力探针(去实时步调:极慢/断续网 18KB/s + `.part` 续传 40% 截断 + seek 90% + 停滞 pause/
|
||||
resume 循环),跑 MIPSTest.mp3 / fuzz cut / MEANDR90 共 3 样本×多轮,**未触发 UB/崩溃**
|
||||
(环境禁 ASAN —— `unable to mmap`;无 valgrind)。因此按任务允许的「不能稳定复现就加防御+日志」。
|
||||
|
||||
**修法(本批落地)**:
|
||||
- `player_manager.c` 下载链路诊断日志(SIGSEGV 定位关键资产,崩溃后从 log 回溯):
|
||||
- `song_download_attempt` 起播 `play: dl start id= lv= eff= size= resume= url=`;
|
||||
- `song_src_dispose` 曲终 `play: dl done final= commit` / `dl interrupt dl_rc= kept bytes= -> .part`
|
||||
/ `dl 416/refuse resume -> drop .part`;
|
||||
- 解码循环播完 `play: done idx= frames= fin= exp= fail= underrun=`(区分自然完成 vs 截断)。
|
||||
- **`song_src_dispose` 收尾竞态复核**:`stream_src_abort` → `pthread_join(dl_thr)` 顺序正确
|
||||
(abort 唤醒下载回调 → cb 返回 NZ 中止 http → 线程收尾 join 返回);残留 `.part` 保留供续传。
|
||||
- **诚实遗留**:①切歌时若下载线程正阻塞在 `mbedtls_ssl_read`(网络停摆),`pthread_join` 会
|
||||
等 body 空闲超时(15s)——切歌延迟,非崩溃(http 层无 cancel 机制,另立批);②SIGSEGV 的确切
|
||||
触发点需真机 `play: dl start/done` 日志落盘后二次定位;③本批未改 http 层(无取消/无钳峰)。
|
||||
|
||||
**验证**:stream_sim 全矩阵 + resume(PCM 金标准)**ALL PASS**;player_flow_sim P1-P12 **ALL PASS**;
|
||||
UBSAN 探针无 UB(不在交付物,临时工具)。
|
||||
|
||||
### 33.2 任务② 档位保真:SQ 及以上必须 flac + 显示档按实际格式/码率
|
||||
|
||||
**根因**:`level_attempt`(`core/ncm_api.c`)对任意档接受 `type∈{mp3,flac}`——服务端对
|
||||
hires/lossless 请求**静默返回 mp3** 时被当「命中」,播的是 mp3 却标「Hi-Res」(用户实锤
|
||||
「十面埋伏无 Hi-Res 却显示 Hi-Res」);且显示档直接用降级链 `eff`,未对实际格式/码率做校验。
|
||||
|
||||
**修法**:
|
||||
- ① `ncm_api.c level_attempt`:**`lv >= NCM_LEVEL_LOSSLESS` 命中判定必须 `type==flac`**,返回
|
||||
mp3 一律视为「该档不可用」继续降级(mp3 只在 standard/higher/exhigh 接受;无损级及以上
|
||||
服务端 encodeType=flac,返回 mp3 即静默降档)。type 缺失按 url 扩展名推断(默认 mp3)。
|
||||
- ② `player_manager.c` 新增 `eff_level_for_resp(u, chain_eff, want)` 回填显示档:
|
||||
`type==flac` → 采信链 `eff`;`type==mp3` → **绝不显示 Hi-Res 及以上**,按响应 `br` 判定:
|
||||
`br≤128k→标准`,否则→`极高 HQ`(仅降级链中间档「较高 192k」不进 UI,不上屏);`br` 未知
|
||||
钳 `chain_eff` 到 `≤EXHIGH`。调用点 `g_play.eff_level = eff_level_for_resp(...)`。
|
||||
- 缓存命中路径(`song_local_file`)已有「mp3 实体 + 用户档>EXHIGH → EXHIGH」钳制,保留。
|
||||
|
||||
**测试**:
|
||||
- `test_ncm_core.c` 新 `test_grade_flac_gate`(注入 try_fn,0 真实请求):①全曲库只有 mp3 →
|
||||
hires/lossless 降到 exhigh(type=mp3);②hires 只有 mp3 + lossless 有 flac → 降到 lossless 拿
|
||||
flac;③hires 有 flac → 命中 hires。**host + mipsel(qemu) PASS**。
|
||||
- `player_flow_sim.c` P7 SVIP 子用例:SURROUND 为无损级 → 桩 type 改 `flac`,校验 eff=SURROUND
|
||||
(显示档回填);P7 非会员/ P12 保持 EXHIGH 断言。
|
||||
- `degrade_sim.c` 假取址 type 按档位(无损级→flac,`g_type==""` 保留空串测 url 扩展名推断),
|
||||
auto_av 全矩阵 243 用例 + 真机场景(CVIP Hi-Res 有 SQ 无 HiRes → 落无损 SQ)**ALL PASS**。
|
||||
|
||||
### 33.3 任务③ 封面 4xx 加固:日志打 status / 确定性 4xx 不重试 / 仅瞬时退避
|
||||
|
||||
**根因**:`cover_worker` 对**所有**失败(含 404 死链)指数退避重试×8 放弃——404 重试纯空转;
|
||||
失败日志只见 `fetch failed`,不知 HTTP 层返回了什么(§30.5 顺带遗留)。
|
||||
|
||||
**修法**(`app/logic/cover.c`):
|
||||
- `download_cover` 增 `*out_rc/*out_status` 回填;失败分诊:
|
||||
- **确定性 4xx**(`status∈[400,500)` 且非 408/429,含 404 死链)→ **不重试**,立即清目标
|
||||
(cover_request 触达下一张);日志 `cover: fetch fail url=.. rc=%d status=%d (4xx, no retry)`。
|
||||
- **瞬时错误**(超时/网络/TLS/5xx/空体)→ 指数退避重试(500ms→4s),连续 8 次放弃(原逻辑)。
|
||||
- 失败日志统一带 `rc=%d status=%d`。
|
||||
|
||||
**验证**:`ncm_host` NCM_PAGE=home 离屏渲染 exit=0;逻辑分诊经 code review(无新 sim 覆盖
|
||||
cover 网络态——cover_chain_sim 为存量、其网络为 mock,不引入)。
|
||||
|
||||
**附:cover URL 的 `http→443` 潜性缺陷评估(结论:不高风险,不修)**:`parse_url` 对无显式端口的
|
||||
URL 恒置 `port=443`,且 `http_run` **无条件走 TLS**(`mbedtls_ssl_handshake`)。对 `http://` 的
|
||||
封面 URL:当前代码连 443 做 TLS——对 music.126.net(443 上提供 TLS)恰好可用,**语义错误但未阻断**。
|
||||
真正修正需「http 走明文端口 80 + 不加 TLS」的新路径(改核心 http 层、回归风险高),本批**不改**
|
||||
(与 §30.8 结论一致);现状封面 URL 均为 https 不受影响。若后续曲库出现明文 http 图,再立批加明文路径。
|
||||
|
||||
### 33.4 任务④ 收藏按钮显隐:「我创建的」不显示收藏
|
||||
|
||||
**根因**:歌单详情页操作条恒画「收藏/评论」两按钮,未区分歌单归属——「我创建的」歌单也显示
|
||||
收藏入口(点击仅 snack「收藏功能开发中」,语义错位)。
|
||||
|
||||
**修法**(`app/ui/playlist.c`):
|
||||
- `pl_show_fav()`:home 打开的真实歌单(`active_playlist>=0`)`is_collected==0`(=我创建的)
|
||||
→ 隐藏;`is_collected!=0`(我收藏的)→ 保留;搜索歌单(`NCM_PL_SEARCH`,无法判定归属)→ 保守显示。
|
||||
- 绘制/命中一致化:`pl_draw` 不画收藏按钮;`playlist_on_tap` 收藏命中仅在 `pl_show_fav()` 时处理。
|
||||
- `pl_cmt_rect()`:收藏隐藏时评论槽**并入**原收藏位(拉宽覆盖收藏+评论,无空洞),badge 随动。
|
||||
|
||||
**验证**:`ncm_host` NCM_PAGE=playlist(mock 打开「我创建的歌单」)渲染——操作条仅「播放全部」+
|
||||
加宽「评论」,无「收藏」按钮(见 dump 截图);exit=0。
|
||||
|
||||
### 33.5 任务⑤ 缓存命名规范化:`song_<id>_<档位>.<ext>` + 存量双点迁移
|
||||
|
||||
**根因**:新键 `audio_cache_key=id_level` 已按用户定案生成 `song_<id>_<level>.<ext>`;但①卡上存量
|
||||
`song_<id>..mp3`(旧版 ext 带前导点生成的双点畸形)/ 旧无档位键 `song_<id>.mp3` 仍被「温和兼容
|
||||
只读不迁」,永远留存量;②`ncm_cache_lookup` 双点回退命中后不转正。
|
||||
|
||||
**修法**:
|
||||
- `core/ncm_cache.c ncm_cache_lookup`:双点回退命中后**迁移重命名**为单点名(同 id+ext,
|
||||
目标已存在则删旧双点),之后本条目走单点主路径,双点存量自然消亡。
|
||||
- `app/play/player_manager.c song_local_file`(`hit==2` 旧键路径):改名到**当前档位键**
|
||||
`song_<id>_<g_level>.<ext>`(`ncm_cache_path` 构造;目标已存在删旧;迁移失败回退旧路径照常播),
|
||||
**不重下**。
|
||||
|
||||
**测试**:`test_ncm_core.c test_cache` 更新——双点 `song_104..mp3` lookup 迁移为 `song_104.mp3`、
|
||||
旧双点文件删除、新文件 size=6。**host + mipsel(qemu) PASS**。
|
||||
|
||||
### 33.6 任务⑥ topbar 图标迁移:字体码点 → sb_icons 位图
|
||||
|
||||
**根因**:home topbar 三动作用字体码点 `↻(U+21BB)/⚙(U+2699)/⌕(U+2315)`,设备 4k 字库缺这些字形
|
||||
→ 渲染成豆腐(WORK_STATE 310 前置症状①,¶302/§30 分析)。
|
||||
|
||||
**修法**(`app/ui/home.c`):三个动作 `meow_topappbar_set_item_icon` 换 sb_icons 位图
|
||||
(`MEOW_ICON_REFRESH/SETTINGS/SEARCH`,307 已建 `meow_topappbar_set_item_icon` + meow_ui.a 已含);
|
||||
字符标签保留作占位,绘制走位图(Material Symbols Rounded)。仅 home 页受影响
|
||||
(settings/search/playlist topbar `action_label=NULL` 无码点动作;`ncm_topbar_create` 不变)。
|
||||
|
||||
**验证**:`ncm_host` NCM_PAGE=home 离屏渲染——topbar 三个**位图图标**正常显示(非豆腐,
|
||||
见 dump 截图);mipsel 0 warning。
|
||||
|
||||
### 33.7 验证记录(0 真实 NCM 业务请求)
|
||||
|
||||
| 项 | 方式 | 结果 |
|
||||
|---|---|---|
|
||||
| 档位保真① | `test_ncm_core` 新 `test_grade_flac_gate`(注入 try_fn) | host + qemu-mipsel **PASS** |
|
||||
| 缓存迁移 | `test_ncm_core test_cache`(双点→单点迁移) | host + qemu-mipsel **PASS** |
|
||||
| 播放流/边下边播 | stream_sim 全矩阵 + resume(PCM 金标准) | **ALL PASS** |
|
||||
| 播放状态机 | player_flow_sim P1-P12 | **ALL PASS**(P7 flac 桩更新后) |
|
||||
| 降级链语义 | degrade_sim(假取址 flac 化 + auto_av 全矩阵 243 + 真机场景) | **ALL PASS** |
|
||||
| 大歌单滑窗 | window_sim(6000 首滚动 + 盘缓存回环) | **PASS** |
|
||||
| 搜索 | search_sim | **PASS** |
|
||||
| 缓存 LRU/隔离 | cache_evict_sim | **PASS** |
|
||||
| 内存瘦身 | mem_sim(封面降采样 RssAnon 10260KB→2196KB) | **PASS** |
|
||||
| core 全量 | build_core.sh → test_ncm_core_host + qemu test_ncm_core_mipsel | **PASS** |
|
||||
| mipsel 构建 | build_ncm.sh(自有代码 -Wall -Wextra,set -e) | **0 warning** |
|
||||
| UI 渲染 | build_ncm_host.sh + NCM_PAGE=home/playlist/player MEOW_UI_DUMP | exit=0,topbar 位图图标/收藏隐藏正常 |
|
||||
|
||||
### 33.8 md5(本批产物,未部署,留主会话统一)
|
||||
|
||||
```
|
||||
cb8187868f71a9fa155075d0624711d6 ncm # mipsel 静态 App(text 1017110/bss 1362500;0 warning)
|
||||
00cbefd5f5f2bb7eef4c7bdccaff859b ncm_host # 宿主离屏二进制(重链)
|
||||
97bb2bdb44a2f446877787d9261b4f02 test/test_ncm_core_host # 宿主 core 测试(重编,含新档位保真/缓存迁移)
|
||||
21665d662755e767742cd46ec4880692 cache_evict_sim # 重链(新 ncm_cache.c)
|
||||
968fbb79671186e8a0bef5a2ff12675c degrade_sim # 重链(假取址 flac 化)
|
||||
2c87ea9cf040490c75d06952add6c15a player_flow_sim # 重链(P7 flac + eff 断言)
|
||||
(window_sim/search_sim md5 未变=5597307a/1eb36c74,同样 PASS;ncm_host 由 build_ncm_sims.sh 未触)
|
||||
```
|
||||
|
||||
### 33.9 出入清单(只改 `patch_v2/ncm_app/`)
|
||||
|
||||
```
|
||||
修改:
|
||||
core/ncm_api.c # §2① level_attempt 无损级必须 flac(32.1)
|
||||
core/ncm_cache.c # §5 ncm_cache_lookup 双点→单点迁移重命名(33.5)
|
||||
app/play/player_manager.c # §2② eff_level_for_resp 显示档回填 + §5 旧键→档位键迁移 + §1 下载/deadline 日志
|
||||
app/logic/cover.c # §3 封面 4xx 分诊 + rc/status 日志 + download_cover 回填
|
||||
app/ui/home.c # §6 topbar 动作换 sb_icons 位图
|
||||
app/ui/playlist.c # §4 收藏按钮显隐(pl_show_fav/pl_cmt_rect)
|
||||
test/test_ncm_core.c # 新 test_grade_flac_gate + test_cache 双点迁移断言
|
||||
bench/player_flow_sim.c # P7 flac 桩 + ncm_cache_path 桩(§5 迁移调用链)
|
||||
bench/degrade_sim.c # 假取址 type 按档位(无损级→flac,"" 保空测 url 推断)
|
||||
REPORT.md / devdocs/WORK_STATE.md # 本批记录(§33 / 锚点)
|
||||
(未动 sdk/、meow_launcherd/、其它 App;0 真实请求;未部署——留主会话统一上卡)
|
||||
```
|
||||
|
||||
### 33.10 诚实出入 / 遗留
|
||||
|
||||
- **流式 SIGSEGV 未复现未定位**:审计 + UBSAN 探针未找到确定崩溃点;本批落地**防御日志**
|
||||
(dl start/done/interrupt + play done 的 fin/exp/fail/underrun)。真机再崩时凭这些日志定位。
|
||||
初步方向(未证实):下载线程阻塞在 `mbedtls_ssl_read` 时切歌 → `pthread_join` 等 body 空闲超时
|
||||
(切歌延迟,非崩溃);minimp3 对特定码流帧边界、`seek 未下载区 + 切档重播` 竞态均未排除。
|
||||
- **封面 4xx 无新网络 sim**:cover 网络态仍由存量 cover_chain_sim 的 mock 覆盖;生产 4xx 分诊
|
||||
经 code review 验证,真机待部署后观察 `cover: fetch fail rc= status=` 日志。
|
||||
- **`http→443` 不修**(§33.3 评估);**`debug` 档位「较高」不进 UI**(显示回填把 >128k mp3 一律
|
||||
标「极高 HQ」,对 160/192k 略高估——UI 八档无「较高」位,属显示取舍,NCM_CACHE_DESIGN §3)。
|
||||
- **`test_ncm_core` 的 `test_network` 为既有只读冒烟**(unikey/poll 各 1 次、无 cookie
|
||||
user_playlist、bogus id song_url),不下载不改状态,本批沿用;其余全部离线 stub/mock。
|
||||
- **未部署真机**(ncm `cb818786` 留主会话统一上卡)。真机验收点:①播《十面埋伏》不再崩/或
|
||||
凭 `play: dl` 日志定位;②hires 档静默给 mp3 显示「已降级至 极高 HQ」而非 Hi-Res;③封面 404
|
||||
立即跳过不空转;④我创建的歌单无收藏按钮;⑤缓存目录名 `song_<id>_<level>.<ext>` 无双点;
|
||||
⑥home topbar 三动作显示位图图标(非豆腐)。
|
||||
Reference in new issue
Block a user