Files
泡芙 3a240395aa fix(rdp): RDP 关闭超时与编辑器分离任务的生命周期治理
排查文档记录的结论是:RDP 关闭超时时会把整个 adapter 连同 COM 资源一起
Box::leak,SSH 文件编辑器的分离加载/保存任务持有窗口强引用,两者都会让
已关闭的会话残留内存。本次按文档建议分三档落地,并刻意保持关闭/释放语义
不变——先建立可观测性,再改所有权。

第 1 档:低频诊断,不改任何语义

- 新增 windows_rdp_host::lifecycle_stats:进程级原子计数,明确区分
  created / destroyed / quarantined,覆盖 hosts_*、wrong_thread_drops、
  overlays_* 与 adapters_retired / retired_destroyed / retired_leaked_at_exit,
  并派生 live_hosts() / live_overlays() / quarantined_adapters()。
- close 超时、overlay abandon、wrong-thread drop 的日志补
  close_mode / retry_count / elapsed_ms / last_stage / last_error 关联字段。
- C++ 侧原先 DestroyWindow(host_window) 调用后不看结果,现挪进新的
  destroy_host_window() noexcept:先取 GetWindowThreadProcessId(窗口销毁
  之后 Win32 已不再报线程 id),SetLastError 后调用,再回读 GetLastError()
  与 IsWindow()。失败行始终打印,成功行受 NAVOP_REMOTE_DESKTOP_DIAGNOSTICS
  约束。刻意不做重试:失败只可能是跨线程调用或句柄已失效,而重试存在句柄
  被复用后二次释放的风险。

第 2 档:编辑器分离任务改用弱引用

- reload_tab / save_tab 的分离任务由 cx.entity().clone() 改为 downgrade()。
  根因就在这里:慢的 SFTP 往返会把已关闭的窗口连同其全部 tab 一起钉住。
- save 语义保持不变:写操作照常执行完毕,只有 UI 更新退化为 no-op。
- 新增 impl Drop for RemoteFileEditorWindow。窗口被移除时仍开着的 tab 不走
  close_clean_tab,视图与 tab 计数必须在这里归还,否则计数会永久漂移。
- 结果被丢弃时打 log_task_result_discarded,用于区分「任务干净排空」与
  「任务仍挂在后台」。

第 3 档:Box::leak 兜底改为 owner 线程 retirement 队列

- 三处 deadline 分支(close 超时、初始化清理超时、drain 的 poll_view_owner)
  不再 Box::leak,改为交给 windows_native_retirement:owner 线程按
  RETIREMENT_RETRY_INTERVAL=1s 重试 force_close,沿用已有的 borrow-free
  三段式(Phase B 释放借用之后才泵 COM 消息,避免重入 App 借用),
  RETIREMENT_MAX_AGE=60s 有界宽限到期、或 on_app_quit 时才兜底 leak 并计数。
- WindowsNativeCloseOperation::into_leaked_adapter 更名 into_adapter,语义
  仍是无 COM 调用的所有权移交,只是不再隐含「泄漏」。
- 队列本身(RetirementPolicy / Retired / RetirementQueue)是纯数据且跨平台
  单测覆盖,只有 GPUI/native 接线是 Windows 专属。

验证:

- cargo test -p windows_rdp_host:153 lib + 39 contract passed / 0 failed
- cargo test -p remote_desktop_view --features windows-native-rdp:
  280 passed / 0 failed
- cargo test -p remote_file_editor:62 passed / 0 failed
- 同步更新三处源文本契约测试:删去 Box::leak / into_leaked_adapter 断言,
  新增「三处 deadline 路径都不得再出现 Box::leak」「retirement driver 不得
  在 update_global 借用内 spawn」「销毁必须观测 DestroyWindow 结果」等不变量

未验证:真实 RDP 会话卡住 COM 回调、真实 SFTP 断连等真机路径仍是
#[ignore] + NAVOP_LIVE_* 环境变量用例,需要真实服务器。另有报告的 RDP
终端卡死(#118)根因仍未定位,本次未触碰该链路。
2026-09-13 22:48:42 +08:00
..