[Bug Report] Treeland 截图后浏览器窗口永久冻结(画面定格 + 点击无响应)
Tofloor
poster avatar
oniugu
deepin
2026-10-21 22:17
Author
  1. 环境
    项 值
    发行版 Deepin 25 (25),内核 6.18.48-amd64-desktop-rolling
    合成器 treeland 0.9.1(treeland-data 0.9.1),Wayland 会话,DDE_CURRENT_COMPOSITOR=TreeLand
    截图工具 deepin-screen-recorder 6.6.39(D-Bus 服务 com.deepin.Screenshot)
    浏览器 Google Chrome 154.0.8037.57 / Microsoft Edge 154.0.4258.37(均为原生 Wayland,--ozone-platform=wayland)
    显卡 Intel Meteor Lake-P [Arc Graphics] [8086:7d55],内核驱动 i915,/dev/dri/renderD128
    屏幕 eDP-1,1699x1097(scale 2)
  2. 问题现象
    Treeland 会话下截一次图后:
    1. 被截屏覆盖到的窗口永久"卡死":画面定格不再刷新;左键点击无响应;但光标形状仍会变(悬停链接显示"小手");键盘无反应
    2. 必须重启该应用才恢复,重新截图无效
    3. 非全局问题,其他程序照常可用
    4. 不是所有窗口都中招,每次被冻住的是"任意子集"
    5. 典型受害者是 Chrome / Edge(浏览器 UI 合成在独立进程,frame callback 一断整体停摆 → 表现为"点不动"而非单纯定格)
    6. 冻结之后新开的窗口正常(新 surface 默认 live)
  3. 复现步骤
    1. Treeland (Wayland) 会话下打开 Chrome / Edge
    2. 按 PrtSc 框选一块区域,松开,确认并保存截图
    3. 浏览器窗口:画面定格、滚动/切标签无变化、左键点击无反应
      (但鼠标光标形状仍随悬停位置变化)
    4. F5 / 切标签 / 滚动 → 全部无效
    5. 关闭并重新打开浏览器 → 恢复
  4. 原因分析
    4.1 调用链
    深度截图不走标准 wlr_screencopy/ext-image-copy-capture,走 deepin 自研私有协议 treeland_capture_unstable_v1:
    客户端(main_window.cpp → initializeCapture()):
    captureContext->selectSource(
    TreelandCaptureContext::source_type_region,
    true, // freeze <-- 关键
    false, // with_cursor
    waylandWindow->surface()); // mask
    服务端(treeland src/modules/capture/capture.cpp):
    void CaptureManagerV1::onCaptureContextSelectSource() {
    m_contextInSelection = context;
    if (context->freeze())
    freezeAllCapturedSurface(true, context->mask()); // 冻结
    }
    void CaptureManagerV1::freezeAllCapturedSurface(bool freeze, WSurface *mask) {
    nodes.enqueue(m_outputRenderWindow->contentItem());
    while (!nodes.isEmpty()) {
    auto node = nodes.dequeue();
    if (auto content = qobject_cast(node)) {
    ...
    content->setLive(!freeze); // 对每一个客户端 surface 都调用
    }
    ... enqueue children ...
    }
    }
    4.2 setLive(false) 的语义(waylib)
    // updateFrameDoneConnection(): live=false → 不再发 wl_surface.frame
    if ((q->rendered || q->isVisible()) && live) { surface->notifyFrameDone(); ... }
    // updatePaintNode(): live=false → 不再拉客户端新 buffer,保留最后一帧
    if (d->live || !tp->texture()) { ... }
    ⇒ 客户端收不到 frame 回调 → 停止出帧;合成器一直显示最后一帧。Chrome/Edge 的浏览器 UI 合成在独立进程,frame callback 断掉后合成器整体停摆、主线程随之阻塞 ⇒ 表现为"点不动"。
    4.3 解冻为什么没生效(use-after-free)
    解冻只有一条路径,且 mask 取的是裸指针:
    WSurface *CaptureContextV1::mask() const { return m_handle->mask; } // 无生命周期保护

const auto isMaskOrSubsurface = [mask](WSurface *surface) {
if (!mask) return false;
if (surface == mask) return true;
const auto subsurfaces = mask->subsurfaces(); // <-- 读已释放内存
return std::any_of(...);
};
触发顺序:

  1. 客户端在 MainWindow 构造函数里先 ensureContext() → context 先创建
  2. 之后窗口才 realize,才产生作为 mask 的 wl_surface ⇒ mask surface 后创建
  3. 客户端断开时 libwayland 逆序销毁资源 ⇒ mask surface 先死,context 后死
  4. 销毁 context → beforeDestroy → clearContextInSelection → 解冻时 m_handle->mask 已悬垂
  5. mask->subsurfaces() 读到垃圾内存,其中若含某些真实 surface 的指针值,这些 surface 就被误判为"mask 及其 subsurface"而跳过 setLive(true) → 永久冻结
    这与观测完全吻合:只有任意子集被冻住、同一批窗口会持续被冻住(释放后内存内容通常不变)、杀掉截图助手无效(状态在合成器里)、之后新建的窗口正常。
    该问题在 treeland 0.9.1 / 0.10.0 / 0.11.0 代码一致,目前均未修复。
    4.4 为什么像"点不动"而不是"画面定格"
  • 光标形状由合成器根据客户端 wl_cursor 决定 → 与 frame callback 无关,照常变化
  • 右键菜单能弹出:右键菜单是独立 popup surface(新建 surface 默认 live),能正常渲染
  • 左键其实送达了(treeland-debug events 有 button 1 press 记录),只是浏览器合成器停摆后不再处理输入/重绘
  1. 实测数据
    (1)treeland-debug --json windows 的 frames(客户端提交帧计数)
    窗口 frames 状态
    microsoft-edge 57232 → 57232 冻死
    kitty 892041 → 893315 正常
    dde-file-manager 72 → 77 正常
    org.deepin.dde.control 3185 → 3189 正常
    google-chrome(冻结后新开) 396 → 413 正常
    (2)强制重绘全部无效(frames 恒为 57232):
    treeland-debug activate / move / minimize+activate / resize
    (3)输入事件正常送达:
    21:58:17.831 button 1 press @942.741,792.951 -> 97684042142800
    21:58:18.014 button 1 release @942.741,792.951 -> 97684042142800
    (4)Chrome 自身日志:
    ERROR:ui/compositor/compositor_animation_observer.cc:65]
    CompositorAnimationObserver is active for too long (1180.63s)
    location=GlowHoverController@.../glow_hover_controller.cc:19
    location=TabIcon@.../tab_icon.cc:128
    ⇒ Chrome 合成器连续 1180 秒没推进过一帧。
  2. 已排除的其他可能
    假设 排除依据
    GPU 进程崩溃 gpu-recent-crash-count=0,无新增 crash dump
    i915/DRM 挂死 dmesg 无 i915/DRM/GPU reset 错误
    全局输入 grab / 按键卡死 XWayland 查 seat 按键掩码:LEFT 未按下;真实点击有正常投递
    浏览器进程卡死 全部线程正常等待态,CPU 空闲
    截图进程残留窗口 杀掉 deepin-screen-recorder 现象不变;场景树无残留 CaptureSourceSelector
  3. 影响范围
    所有使用 Treeland 的 Deepin 25 用户;触发条件是任意一次深度截图;受影响窗口永久冻结,只能重启该应用恢复;浏览器受影响最严重。
  4. 规避方法
    1. 重启被冻的窗口/应用(已验证唯一有效)
    2. 改用走 xdg-desktop-portal 的截图(org.freedesktop.portal.Screenshot),该路径在合成器侧走 wlr_screencopy/ext-image-copy-capture,不做 surface 冻结(尚未实测验证)
    3. 截图时尽量让重要窗口不在选区范围内
  5. 修复建议
    treeland(优先级高)
    1. CaptureContextV1::mask() 改用 QPointer,surface 销毁时置空 —— 修掉 use-after-free
    2. isMaskOrSubsurface() 在 mask 空/失效时应降级为不排除任何 surface
    3. 解冻改为按冻结集合逐个还原,不再依赖"重新遍历场景树"与冻结时刻一致
    4. clearContextInSelection() 的守卫不应导致解冻被跳过
      deepin-screen-recorder
    5. 区域截图不需要 freeze=true(那是录屏的效果),改 freeze=false 即可绕开
    6. context 用完必须 destroy(),不要在单例 manager 里缓存复用
    7. onSourceFailed() 里 _exit(0) 属硬退出,建议改正常退出路径
  6. 附:观测工具
    treeland-debug 调试 socket 默认仅 dde 用户可访问,观测时需放开(用完请还原):
    sudo chmod 666 /tmp/org.deepin.dde.treeland.debug
    常用命令:windows(含 frames 帧计数)、--json windows、tree、scene、events 50(看事件派发给谁)、activate (强制重绘以判断是否真冻死)。
Reply Favorite View the author
All Replies
avatar
deepin流云
Super Moderator
Community OP
2026-10-22 09:57
#1

自带的截图录屏目前在treeland下还不可用,近期会更新版本,到时候再看看吧

也有社区大佬自己编译了稳定版本,你可以先尝试下:https://bbs.deepin.org.cn/post/302461

Reply View the author
avatar
huaqi
deepin
2026-10-22 12:45
#2
deepin流云:

自带的截图录屏目前在treeland下还不可用,近期会更新版本,到时候再看看吧

也有社区大佬自己编译了稳定版本,你可以先尝试下:https://bbs.deepin.org.cn/post/302461

微信的截图能用吗

Reply View the author
avatar
deepin流云
Super Moderator
Community OP
2026-10-22 13:40
#3
huaqi:

微信的截图能用吗

也不行,目前三方截图也都还用不起来

Reply View the author
avatar
mozixun
Moderator
2026-10-22 16:49
#4
deepin流云:

也不行,目前三方截图也都还用不起来

微信截图应该是可以的吧

Reply View the author
avatar
deepin流云
Super Moderator
Community OP
2026-10-22 16:52
#5
mozixun:

微信截图应该是可以的吧

我的机器截不了,崩了~你的可以吗

Reply View the author
avatar
mozixun
Moderator
2026-10-22 21:11
#6
deepin流云:

我的机器截不了,崩了~你的可以吗

你试一下用deepin增强源里的treeland,应该是可以的

我同时给xdg-desktop-portal做了录屏和截图的修复实现,只是没进主线

Reply View the author
avatar
deepin流云
Super Moderator
Community OP
2026-10-23 08:39
#7
mozixun:

你试一下用deepin增强源里的treeland,应该是可以的

我同时给xdg-desktop-portal做了录屏和截图的修复实现,只是没进主线

最近研发会重点搞截图录屏这块,应该快了

Reply View the author