Skip to content

feat: move tray plugin loading to systemd-managed tray loader services - #1750

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
yixinshark:feat/tray-plugin-systemd-services
Sep 22, 2026
Merged

deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
yixinshark:feat/tray-plugin-systemd-services

Conversation

@yixinshark

@yixinshark yixinshark commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Pms: TASK-395865

Summary

  • Register org.deepin.dde.Dock1 only after the QML DockCompositor is ready so the Type=dbus unit reflects compositor readiness
  • Remove the in-process LoadTrayPlugins supervisor in favor of dde-tray-loader systemd services
  • Track LockFront state with a non-activating asynchronous startup query, Visible signals, and queries on service owner changes. Discard stale replies and wait for service events after query errors.
  • Use desktop notification rules until the first state arrives, then retain the latest state if LockFront becomes unavailable.

Test plan

  • Built notificationserver and notifyserverapplet_tests; reconfigured and built notificationserver after removing the temporary test integration.
  • Passed 9 temporary local D-Bus regression cases covering startup, query errors, Visible/reply ordering, and service restarts. The temporary tests are not included in this PR.
  • Verify org.deepin.dde.Dock1 is acquired only after the dock compositor is ready
  • Verify tray plugins are loaded by systemd tray loader services instead of dock-spawned processes
  • Verify notification panel tracks lock screen state correctly at startup

Summary by Sourcery

Move tray plugin startup to systemd-managed services and make dock readiness and notification lock-screen state handling reliable.

Bug Fixes:

  • Make notification lock-screen state tracking resilient to delayed service startup, owner changes, signal/query ordering, and stale asynchronous replies.

Enhancements:

  • Move tray plugin loading out of the dock process and into systemd-managed tray loader services.
  • Acquire the dock D-Bus service name only after the QML compositor is ready so it accurately signals dock readiness.

Build:

  • Remove the obsolete in-process tray plugin loader sources and configuration.

Bug Fixes:

  • Make notification panel lock-screen state initialization resilient to delayed session lock service startup and service ownership changes.

Enhancements:

  • Move tray plugin loading from the dock process to systemd-managed tray loader services.
  • Delay acquisition of the dock D-Bus service name until the QML compositor is ready, allowing systemd to use it as the dock readiness signal.

Chores:

  • Remove the obsolete in-process tray plugin loading supervisor and its configuration.

@sourcery-ai

sourcery-ai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Reviewer's Guide

The dock now exposes its D-Bus object immediately but acquires org.deepin.dde.Dock1 only after DockCompositor readiness, allowing systemd-ordered tray loader services to start at the correct point. The in-process tray loader is removed, while notification lock-state initialization becomes asynchronous with signal precedence and retry handling.

Sequence diagram for systemd-managed tray loading after dock readiness

sequenceDiagram
    participant DockPanel
    participant DockCompositor
    participant SessionBus
    participant Systemd
    participant TrayLoader

    DockPanel->>DockCompositor: create
    DockCompositor-->>DockPanel: compositorReadyChanged(true)
    DockPanel->>SessionBus: registerService(org.deepin.dde.Dock1)
    SessionBus-->>Systemd: BusName acquired
    Systemd->>TrayLoader: start dde-tray-loader service
    TrayLoader->>DockCompositor: connect to dockplugin Wayland socket
Loading

Sequence diagram for asynchronous lock-screen state initialization

sequenceDiagram
    participant NotificationManager
    participant LockFront
    participant SessionBus

    NotificationManager->>SessionBus: connect Visible signal
    NotificationManager->>SessionBus: async Get Visible
    alt Visible signal arrives first
        LockFront-->>NotificationManager: Visible(bool)
        NotificationManager->>NotificationManager: onScreenLockedChanged(bool)
    else Get reply arrives first
        LockFront-->>NotificationManager: QDBusPendingReply<QDBusVariant>
        NotificationManager->>NotificationManager: onScreenLockedChanged(bool)
    else Get fails
        LockFront-->>NotificationManager: error
        NotificationManager->>NotificationManager: queryScreenLockedState()
    end
Loading

File-Level Changes

Change Details Files
Defers Dock1 D-Bus service acquisition until the QML compositor reports readiness.
  • Removes early service registration from initialization.
  • Registers the service on compositorReadyChanged and retains object export earlier for compatibility.
  • Uses the service name as the systemd readiness boundary for tray-loader ordering.
panels/dock/dockpanel.cpp
panels/dock/dockpanel.h
Replaces dock-owned tray plugin supervision with systemd-managed loader services.
  • Removes LoadTrayPlugins construction and loading calls.
  • Deletes the in-process loader implementation and its build references.
  • Removes the dock tray configuration file.
panels/dock/CMakeLists.txt
panels/dock/dockpanel.cpp
panels/dock/dockpanel.h
panels/dock/loadtrayplugins.cpp
panels/dock/loadtrayplugins.h
panels/dconfig/org.deepin.ds.dock.tray.json
Makes initial lock-screen state discovery asynchronous and resilient to startup ordering.
  • Subscribes to lock visibility changes before querying the current value.
  • Retries failed asynchronous property queries.
  • Prevents a stale query reply from overriding a signal received during the request.
panels/notification/server/notificationmanager.cpp
panels/notification/server/notificationmanager.h
Updates package metadata for the new service-based tray loading arrangement.
  • Adjusts Debian package control metadata and dependencies.
debian/control

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="panels/dock/dockpanel.cpp" line_range="56" />
<code_context>
     connect(this, &DockPanel::compositorReadyChanged, this, [this] {
         if (!m_compositorReady) return;
-        m_loadTrayPlugins->loadDockPlugins();
+        if (!QDBusConnection::sessionBus().registerService("org.deepin.dde.Dock1")) {
+            qCWarning(dockLog) << "Failed to register org.deepin.dde.Dock1 after compositor ready";
+        }
     });
 }
</code_context>
<issue_to_address>
**issue (bug_risk):** If registering `org.deepin.dde.Dock1` fails after the compositor becomes ready, the code only logs a warning and never retries or reports startup failure. The Type=dbus unit therefore never reaches its active state, so tray-loader services ordered after it do not start.

**Triggers:** When the session bus registration temporarily fails or the bus name is already owned.

**Suggested fix:** Retry registration until it succeeds, or terminate/escalate the startup failure so systemd can restart the dock.

```suggestion
            qFatal("Failed to register org.deepin.dde.Dock1 after compositor ready");
```
</issue_to_address>

### Comment 2
<location path="panels/notification/server/notificationmanager.cpp" line_range="723" />
<code_context>
+    m_screenLocked = true;
</code_context>
<issue_to_address>
**issue (bug_risk):** When the asynchronous `Get(Visible)` call keeps failing, `m_screenLocked` remains true forever while `queryScreenLockedState()` retries once per second. Notifications are consequently treated as locked and suppressed indefinitely instead of falling back to the unlocked state used by the previous implementation.

**Triggers:** When LockFront is absent or remains unavailable after notification manager startup.

**Suggested fix:** Choose an explicit fallback after the service is unavailable, such as setting `m_screenLocked` to false, while continuing to listen for a later lock-state signal.

```suggestion
            qWarning(notifyLog) << "Failed to get the lock visible property:" << reply.error().message();
            m_screenLocked = false;
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread panels/dock/dockpanel.cpp
if (!m_compositorReady) return;
m_loadTrayPlugins->loadDockPlugins();
if (!QDBusConnection::sessionBus().registerService("org.deepin.dde.Dock1")) {
qCWarning(dockLog) << "Failed to register org.deepin.dde.Dock1 after compositor ready";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): If registering org.deepin.dde.Dock1 fails after the compositor becomes ready, the code only logs a warning and never retries or reports startup failure. The Type=dbus unit therefore never reaches its active state, so tray-loader services ordered after it do not start.

Triggers: When the session bus registration temporarily fails or the bus name is already owned.

Suggested fix: Retry registration until it succeeds, or terminate/escalate the startup failure so systemd can restart the dock.

Suggested change
qCWarning(dockLog) << "Failed to register org.deepin.dde.Dock1 after compositor ready";
qFatal("Failed to register org.deepin.dde.Dock1 after compositor ready");

Comment thread panels/notification/server/notificationmanager.cpp Outdated
@yixinshark
yixinshark force-pushed the feat/tray-plugin-systemd-services branch from 1bbdf21 to 3220869 Compare September 22, 2026 09:09
Register org.deepin.dde.Dock1 only after the QML DockCompositor is ready
so Type=dbus reflects compositor readiness. Replace the in-process
LoadTrayPlugins supervisor with dde-tray-loader systemd services.

Query LockFront asynchronously at startup and on service owner changes
without D-Bus auto-activation, and follow Visible signals. Discard stale
replies and rely on service events to recover from errors without polling.
Use the desktop notification policy until a state arrives, then preserve
the latest state when queries fail or the service exits.

dock 仅在 QML DockCompositor 就绪后才注册 org.deepin.dde.Dock1,使
Type=dbus 单元能反映合成器就绪状态;移除进程内的 LoadTrayPlugins 管理器,
改用 dde-tray-loader 的 systemd 服务。

启动时和服务 owner 变化后异步查询 LockFront,并监听 Visible 信号;
查询禁止 D-Bus 自动激活,以保留会话启动顺序。丢弃过期回复,查询失败后
等待服务事件恢复,不再轮询。首次获取状态前使用桌面通知策略,后续查询
失败或服务退出时保留最近一次状态。

Log: move tray plugin loading to systemd-managed tray loader services
Pms: TASK-395865
@yixinshark
yixinshark force-pushed the feat/tray-plugin-systemd-services branch from 3220869 to 49f4994 Compare September 22, 2026 09:18
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 100 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本次 PR 将托盘插件加载从进程内管理迁移至 systemd 管理的外部服务,同时将通知管理器的屏幕锁定状态查询从同步改为异步。代码变更逻辑正确,注释详尽,性能和架构均有显著改善,未发现安全漏洞。DBus 服务注册时机的调整符合 systemd Type=dbus 单元的就绪语义,异步查询模式正确处理了竞态条件。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

潜在问题:
✅ 未发现明显问题

分析建议:

  1. dockpanel.cpp: 将 org.deepin.dde.Dock1 DBus 服务注册从 init() 移至 compositorReadyChanged 回调中,确保仅在 QML DockCompositor 创建完成后才注册服务名,逻辑正确,符合 systemd Type=dbus 单元的就绪信号语义
  2. notificationmanager.cpp: 将同步 QDBusInterface::call() 替换为异步 QDBusPendingCallWatcher 模式,正确处理了 Get 回复与 Visible 信号之间的竞态条件:serviceOwnerChanged 回调会丢弃旧查询,onScreenLockedChanged 会取消挂起的查询,finished 回调通过 watcher != m_screenLockedQueryWatcher 判断是否被取代
  3. notificationmanager.cpp: setAutoStartService(false) 正确防止了在 dde-session 启动 LockFront 之前过早激活该服务
  4. loadtrayplugins.cpp/h 删除完整,CMakeLists.txt 同步移除编译引用,dockpanel.h 移除前向声明和成员变量,无悬空引用

2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

潜在问题:
✅ 未发现明显问题

分析建议:

  1. dockpanel.cpp 构造函数注释详细解释了 org.deepin.dde.Dock1 服务名作为 systemd Type=dbus 单元就绪标志的作用,以及为何必须在 QML DockCompositor 创建后才注册
  2. dockpanel.cpp init() 中的 NOTE 注释清晰说明了对象导出与服务名注册的分离关系
  3. notificationmanager.cpp 中多处内联注释解释了关键设计决策:"Discard any reply from the previous owner before starting a new query"、"dde-session starts LockFront after the dock; querying must not activate it early"、"An absent service is expected at startup"、"A Visible signal supersedes any pending query reply"
  4. queryScreenLockedState() 方法从原 initScreenLockedState() 中干净地分离出来,职责单一:initScreenLockedState() 负责设置监听器,queryScreenLockedState() 负责执行异步查询
  5. LockFrontDBusService 和 LockFrontDBusPath 提取为静态常量,提高了可维护性

3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

潜在问题:
✅ 未发现明显问题

分析建议:

  1. notificationmanager.cpp: 从同步 QDBusInterface::call() 改为异步 QDBusConnection::asyncCall(),消除了启动期间的事件循环阻塞,显著改善启动性能
  2. 移除 LoadTrayPlugins 后,托盘插件加载由 systemd 管理的外部服务承担,实现了并行启动和进程隔离,插件崩溃不再影响 dock 主进程
  3. queryScreenLockedState() 通过检查 m_screenLockedQueryWatcher 避免重复查询,减少不必要的 DBus 调用
  4. setAutoStartService(false) 避免了不必要的服务激活开销

4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

漏洞对比统计: 新增漏洞 0 个,减少漏洞 0 个,持平 0 个

安全漏洞详情:
✅ 未发现安全漏洞

分析建议:

  1. 所有 DBus 服务名、路径和接口均为硬编码常量,无用户输入参与,不存在注入风险
  2. setAutoStartService(false) 是良好的安全实践,防止了通过 DBus 查询触发非预期的服务激活
  3. 移除 LoadTrayPlugins 类减少了攻击面:旧代码使用 QProcess 执行外部程序并从环境变量和文件系统扫描中获取插件路径,新方案由 systemd 管理降低了风险
  4. DBus 错误处理完善:预期的 ServiceUnknown 和 NameHasNoOwner 错误被静默处理,非预期错误被记录到日志
  5. 内存安全:所有 QObject 派生对象均正确设置父对象,QDBusPendingCallWatcher 通过 deleteLater() 清理,无内存泄漏

📋 审查信息

项目 内容
平台 GitHub PR
PR URL #1750
PR 标题 feat: move tray plugin loading to systemd-managed tray loader services
作者 yixinshark
分析模式 全量分析
OCR 审查 代码克隆失败,OCR 未执行
SAST 扫描 无 SAST 扫描结果
变更文件数 9 个文件

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mhduiy, yixinshark

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@yixinshark

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Sep 22, 2026

Copy link
Copy Markdown

This pr force merged! (status: blocked)

@deepin-bot
deepin-bot Bot merged commit 16d7d64 into linuxdeepin:master Sep 22, 2026
7 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants