fix(ncm): 离线重试改单调钟节奏闸,断网不再每个 tick 重试(M10)

根因(真机日志 19000100_000000_7534.log):meow_ui_time_ms() 在设备上返回坏值——
低 32 位是「开机秒数×1000」(无毫秒),高 32 位每次调用随机(REPORT §42)。
旧守卫 `!g_home_thr_on && (!g_offline_retry_ms || now - g_offline_retry_ms >= 30000)`
因此恒真:worker 一收工,下一个 tick 立刻再重试;真机 74s 内 10 次
(间隔 5-7s 只是失败请求本身的连接超时)。第二条链是 else 分支清零重试时刻,
online/offline 一抖动就再试。

修复:
- 新增 app/logic/retry_ctl.{h,c}:节奏闸只做差值,时钟由调用方给可信单调钟
  (home.c 改传 core 的 ncm_monotonic_ms());回退不下溢(重定基准、不重试);
  busy 单飞;在线/离线抖动不重置基准;首次进离线立即探测一次,之后严格 ≥30s。
- home_tick 不再使用入参 now(真机坏值无效化);新增 home_retry_reset()。
- 静默重试不再走完整 home_reload:新增 home_reload_ex(silent) 不预读盘
  (旧实现每轮在 UI 线程同步读 playlists.bin)、home_apply_ex(keep_scroll)
  保留滚动位置、worker 记 g_home_changed 决定是否需要重绘——旧实现每轮
  home_apply() 复位滚动+整帧重绘,是「歌单列表滑动特别卡」的直接来源。
- worker 线程 pthread_detach(旧代码每轮泄漏线程栈)。
This commit is contained in:
AskaEth committed 2026-11-05 13:00:24 +08:00
1 parent aa225a1973
commit 35a636ef42
4 files changed
+149 -27

No files matched your search

+42
View File
@@ -0,0 +1,42 @@
/* logic/retry_ctl.h — 离线自动重试节奏闸(M10:断网重试风暴的修复点)。
*
* 背景(真机 19000100_000000_7534.log + launcher meow_20261105_122541.log):
* M9 的 30s 守卫写成 `if (!thr_on && (!last || now - last >= 30000))`,节奏完全依赖
* meow_ui_time_ms() 的 64 位差值。真机实测该值「低 32 位 = 整秒×1000(无毫秒)、高 32 位是垃圾」
* (见 REPORT §42),于是 now-last 几乎恒为巨大正数 → 每个 UI tick 都判「该重试」,
* 断网时把「30s 一次」退化成「每个 tick 一次」的重试风暴。
*
* 本模块把节奏判定收敛成三条硬约束(纯逻辑、零依赖,宿主编译可直接驱动):
* 1) 时钟由调用方供给**可信单调钟**(home.c 传 core 的 ncm_monotonic_ms(),不再用 SDK 的
* meow_ui_time_ms());本模块只做差值,不取时间。
* 2) 时钟回退(now < last)绝不下溢成「巨大已超时」:按「刚试过」处理并重定基准,
* 下一次尝试仍需重新等满 interval。
* 3) 单飞:busy(上一个 worker 未收工)期间任何时钟跳变都不发新尝试。
* 在线/离线抖动不重置基准 —— 抖动无法加速重试(旧实现 else 分支清零 g_offline_retry_ms,
* 状态一抖就立刻再试,是风暴的第二条触发链)。
*/
#ifndef NCM_RETRY_CTL_H
#define NCM_RETRY_CTL_H
#include <stdint.h>
typedef struct {
int64_t last_ms; /* 上次发起尝试的单调毫秒时刻(have_last=0 时无意义) */
int have_last; /* 1=至少尝试过一次 */
} ncm_retry_ctl;
void ncm_retry_ctl_init(ncm_retry_ctl *c);
/* 每个 UI tick 调一次。返回 1=现在应当发起一次重试(内部已记账:调用方随即起 worker)。
* offline=当前是否离线;busy=是否已有 worker 在跑(单飞);now_ms=单调毫秒;
* interval_ms=两次尝试的最小间隔(M10 定 30000)。
*
* 语义:
* - offline=0:返回 0,且**不动**基准(在线期间与状态抖动都不重置节奏)。
* - busy=1:返回 0。
* - 首次观察到离线:返回 1(进离线先立即探测一次,恢复后由会话门切回在线)。
* - 之后:仅当 now-last >= interval 才返回 1;now<last(时钟回退)→ 重置基准、返回 0。 */
int ncm_retry_ctl_poll(ncm_retry_ctl *c, int offline, int busy, int64_t now_ms,
int64_t interval_ms);
#endif /* NCM_RETRY_CTL_H */