Files
MeowOS-For-R3P2/patch_v2/ncm_app/app/logic/retry_ctl.h
T
AskaEth 35a636ef42 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(旧代码每轮泄漏线程栈)。
2026-11-05 13:00:24 +08:00

43 lines
2.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 */