Skip to content

refactor: unify dde-apps loading in main thread - #3456

Open
18202781743 wants to merge 1 commit into
linuxdeepin:TASK-394433from
18202781743:task-performance
Open

18202781743 wants to merge 1 commit into
linuxdeepin:TASK-394433from
18202781743:task-performance

Conversation

@18202781743

@18202781743 18202781743 commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Load the dde-apps applet once in DccManager during initialization instead of having each plugin create its own instance. This centralizes lifecycle management, avoids duplicate applet creation across plugins, and ensures applet initialization happens on the main thread natively without workarounds.

Removed redundant applet creation logic from notification AppMgr and privacy PrivacySecurityWorker, along with the BlockingQueuedConnection workaround previously needed for thread safety.

  1. Add Dde Shell dependency to CMakeLists for control center
  2. Create and load dde-apps applet in DccManager::init()
  3. Remove duplicated applet creation from AppMgr
  4. Simplify PrivacySecurityWorker to use existing applet
  5. Replace BlockingQueuedConnection with direct method call
  6. Remove obsolete thread-related comments and includes

Log: Unify dde-apps loading in main thread for control center initialization

Influence:

  1. Verify control center starts without errors
  2. Test DCC main window loads completely in main thread
  3. Check plugin functionality that depends on dde-apps (notification, privacy)
  4. Verify no duplicate applet instances are created
  5. Test applet initialization order and performance
  6. Confirm thread safety with no crashes during startup

refactor: 统一在主线程中加载dde-apps

在DccManager初始化阶段统一加载dde-apps组件,取代各插件自行创建实例的方
式。这集中了生命周期管理,避免跨插件的重复创建,并确保组件在主线程原生初
始化,无需额外线程处理。

移除了通知模块AppMgr和隐私模块PrivacySecurityWorker中重复的组件创建逻
辑,以及此前为线程安全而添加的BlockingQueuedConnection处理。

  1. 在CMakeLists中添加Dde Shell依赖
  2. 在DccManager::init()中创建并加载dde-apps组件
  3. 移除AppMgr中的重复组件创建
  4. 简化PrivacySecurityWorker使用现有组件
  5. 将BlockingQueuedConnection替换为直接方法调用
  6. 移除过时的线程相关注释和头文件

Log: 统一在主线程中加载dde-apps,优化控制中心初始化

Influence:

  1. 验证控制中心启动无报错
  2. 测试主窗口在主线程中完整加载
  3. 检查依赖dde-apps的插件功能(通知、隐私)
  4. 确认未创建重复组件实例
  5. 测试组件初始化顺序和性能
  6. 确认启动期间无线程安全问题崩溃

Summary by Sourcery

Load the dde-apps applet centrally during control center initialization to provide consistent lifecycle management and eliminate duplicate plugin initialization.

Enhancements:

  • Centralize dde-apps applet initialization in DccManager so it is loaded once during main-thread startup and shared by dependent plugins.
  • Remove redundant dde-apps creation and thread-synchronization workarounds from notification and privacy plugins.

Build:

  • Add the Dde Shell dependency required for centralized applet loading.

Load the dde-apps applet once in DccManager during initialization
instead of having each plugin create its own instance. This centralizes
lifecycle management, avoids duplicate applet creation across plugins,
and ensures applet initialization happens on the main thread natively
without workarounds.

Removed redundant applet creation logic from notification AppMgr and
privacy PrivacySecurityWorker, along with the BlockingQueuedConnection
workaround previously needed for thread safety.

1. Add Dde Shell dependency to CMakeLists for control center
2. Create and load dde-apps applet in DccManager::init()
3. Remove duplicated applet creation from AppMgr
4. Simplify PrivacySecurityWorker to use existing applet
5. Replace BlockingQueuedConnection with direct method call
6. Remove obsolete thread-related comments and includes

Log: Unify dde-apps loading in main thread for control center
initialization

Influence:
1. Verify control center starts without errors
2. Test DCC main window loads completely in main thread
3. Check plugin functionality that depends on dde-apps (notification,
privacy)
4. Verify no duplicate applet instances are created
5. Test applet initialization order and performance
6. Confirm thread safety with no crashes during startup

refactor: 统一在主线程中加载dde-apps

在DccManager初始化阶段统一加载dde-apps组件,取代各插件自行创建实例的方
式。这集中了生命周期管理,避免跨插件的重复创建,并确保组件在主线程原生初
始化,无需额外线程处理。

移除了通知模块AppMgr和隐私模块PrivacySecurityWorker中重复的组件创建逻
辑,以及此前为线程安全而添加的BlockingQueuedConnection处理。

1. 在CMakeLists中添加Dde Shell依赖
2. 在DccManager::init()中创建并加载dde-apps组件
3. 移除AppMgr中的重复组件创建
4. 简化PrivacySecurityWorker使用现有组件
5. 将BlockingQueuedConnection替换为直接方法调用
6. 移除过时的线程相关注释和头文件

Log: 统一在主线程中加载dde-apps,优化控制中心初始化

Influence:
1. 验证控制中心启动无报错
2. 测试主窗口在主线程中完整加载
3. 检查依赖dde-apps的插件功能(通知、隐私)
4. 确认未创建重复组件实例
5. 测试组件初始化顺序和性能
6. 确认启动期间无线程安全问题崩溃
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743

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

@sourcery-ai

sourcery-ai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Reviewer's Guide

The control center now loads and initializes a single dde-apps applet during DccManager initialization on the main thread, while notification and privacy plugins consume the existing proxy without creating duplicate instances or using thread workarounds.

Sequence diagram for centralized dde-apps initialization

sequenceDiagram
    participant DccManager
    participant DPluginLoader
    participant DContainment
    participant DdeAppsApplet
    participant NotificationAppMgr
    participant PrivacySecurityWorker
    participant DAppletBridge

    DccManager->>DccManager: init()
    DccManager->>DPluginLoader: rootApplet()
    DPluginLoader-->>DccManager: DContainment
    DccManager->>DContainment: createApplet(DAppletData)
    DContainment-->>DccManager: DdeAppsApplet
    DccManager->>DdeAppsApplet: load()
    DccManager->>DdeAppsApplet: init()

    NotificationAppMgr->>DAppletBridge: applet()
    DAppletBridge-->>NotificationAppMgr: existing applet proxy
    PrivacySecurityWorker->>PrivacySecurityWorker: init()
    PrivacySecurityWorker->>PrivacySecurityWorker: initApp()
    PrivacySecurityWorker->>DAppletBridge: applet()
    DAppletBridge-->>PrivacySecurityWorker: existing applet proxy
Loading

File-Level Changes

Change Details Files
Centralize dde-apps applet creation and initialization in DccManager startup.
  • Add the Dde Shell dependency and link the control center against it.
  • Create the dde-apps applet from the root containment during DccManager::init(), then load and initialize it.
  • Add failure handling for missing root containment or applet creation.
src/dde-control-center/CMakeLists.txt
src/dde-control-center/dccmanager.cpp
src/dde-control-center/dccmanager.h
Remove plugin-local dde-apps lifecycle management and rely on the shared initialized applet.
  • Delete notification AppMgr fallback creation logic and retain proxy lookup/error handling.
  • Remove privacy worker applet creation and related containment/plugin-loader dependencies.
  • Replace the blocking main-thread invocation with a direct initialization call and use the default connection for model updates.
src/plugin-notification/operation/appmgr.cpp
src/plugin-privacy/operation/privacysecurityworker.cpp

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 1 issue

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

## Individual Comments

### Comment 1
<location path="src/plugin-privacy/operation/privacysecurityworker.cpp" line_range="88" />
<code_context>
-    // TODO:由于控制中心通过子线程加载插件后,会移动插件的加载线程->主线程,
-    // 并删除原有线程->未指定父的对象所处的线程会被删除,所以使用qApp->主线程调用initApp
-    QMetaObject::invokeMethod(qApp, [this]() {
-        initApp();
-    }, Qt::BlockingQueuedConnection);
-
</code_context>
<issue_to_address>
**issue (bug_risk):** `initApp()` now runs directly in the plugin data-loading thread, while `DAppletProxy` and its `appModel` belong to the main thread where `DccManager::loadAppInfos()` created and initialized the applet. The worker therefore accesses the applet proxy/model and installs signal connections from the wrong thread, reintroducing the thread-affinity problem that the removed `BlockingQueuedConnection` avoided.

**Triggers:** When the privacy plugin is created by `DccPluginManager::LoadDataTask` before `moveThread()` moves the plugin objects.

**Suggested fix:** Keep invoking `initApp()` on the application thread, or otherwise marshal all applet/model access to the applet's owning thread.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

initApp();
}, Qt::BlockingQueuedConnection);

initApp();

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): initApp() now runs directly in the plugin data-loading thread, while DAppletProxy and its appModel belong to the main thread where DccManager::loadAppInfos() created and initialized the applet. The worker therefore accesses the applet proxy/model and installs signal connections from the wrong thread, reintroducing the thread-affinity problem that the removed BlockingQueuedConnection avoided.

Triggers: When the privacy plugin is created by DccPluginManager::LoadDataTask before moveThread() moves the plugin objects.

Suggested fix: Keep invoking initApp() on the application thread, or otherwise marshal all applet/model access to the applet's owning thread.

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

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

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 98 分,大于 70 分通过阈值。本次重构将 dde-apps 加载逻辑统一到主线程的 DccManager::loadAppInfos() 中,消除了多插件间的重复代码,移除了阻塞性跨线程调用,代码结构清晰,未发现安全漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

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

建议: 建议在 appmgr.cpp 中添加注释说明 dde-apps 已由 DccManager::loadAppInfos() 在主线程统一加载,此处仅获取已加载的 applet proxy


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. src/dde-control-center/dccmanager.cpp:849 - loadAppInfos() 方法缺少函数注释,建议添加简要说明
  2. src/dde-control-center/dccmanager.cpp:852 - 使用 qWarning() 而非 qCWarning(dccLog()),与文件其他位置日志分类不一致
  3. src/dde-control-center/dccmanager.cpp:858 - 使用 qWarning() 而非 qCWarning(dccLog()),与文件其他位置日志分类不一致

建议: 1.将 qWarning() 替换为 qCWarning(dccLog()) 保持日志分类一致性
2.为 loadAppInfos() 添加函数注释


3. 代码性能 ✅

评价: 优秀 ✅ 通过

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

建议: 性能优化合理,无需额外改进


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

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

建议: 代码安全合规,无安全风险


💡 改进建议代码示例

// dccmanager.cpp - 建议修改
void DccManager::loadAppInfos()
{
    // 在主线程统一加载 dde-apps,供各插件通过 DAppletBridge 获取
    DCC_BENCHMARK("dde-apps", "Load-dde-apps");
    auto rootApplet = qobject_cast<DS_NAMESPACE::DContainment *>(DS_NAMESPACE::DPluginLoader::instance()->rootApplet());
    if (!rootApplet) {
        qCWarning(dccLog()) << "Failed to get root applet for dde-apps";
        return;
    }

    auto applet = rootApplet->createApplet(DS_NAMESPACE::DAppletData{"org.deepin.ds.dde-apps"});
    if (!applet) {
        qCWarning(dccLog()) << "Failed to create dde-apps applet";
        return;
    }
    applet->load();
    applet->init();
}

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

This branch has not been deployed

No deployments
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.

2 participants