Skip to content

feat(factory): upgrade DccFactory to v2.0 with lifecycle and DBus data channel#3228

Open
caixr23 wants to merge 1 commit into
linuxdeepin:masterfrom
caixr23:dcc-v2
Open

feat(factory): upgrade DccFactory to v2.0 with lifecycle and DBus data channel#3228
caixr23 wants to merge 1 commit into
linuxdeepin:masterfrom
caixr23:dcc-v2

Conversation

@caixr23
Copy link
Copy Markdown
Contributor

@caixr23 caixr23 commented May 13, 2026

  1. Rename DccFactory to DccFactory_20, bump IID to v2.0
  2. Add registerType() for QML type registration in main thread
  3. Add active() for post-creation activation in main thread
  4. Add get/set virtual methods for DBus-triggered data access in worker thread
  5. Add DCC_FULL_FACTORY_CLASS macro with singleton create and full lifecycle delegation to classname::registerType/active/get/set
  6. Preserve v1.0 interface in dccfactoryold.h for backward compatibility
  7. Wire DBus get/set slots in ControlCenterDBusAdaptor and DccManager (async dispatch pending)
  8. Migrate DefAppModel plugin as first v2.0 adopter, move qmlRegisterType into static registerType()

Influence:

  1. Verify existing v1.0 plugins still load via old interface
  2. Verify DefAppModel QML types register correctly on startup

feat(factory): 升级 DccFactory 至 v2.0,支持生命周期管理与 DBus 数据通道

  1. 将 DccFactory 重命名为 DccFactory_20,IID 升级为 v2.0
  2. 新增 registerType() 用于在主线程中注册 QML 类型
  3. 新增 active() 用于在主线程中执行创建后激活
  4. 新增 get/set 虚函数用于在子线程中响应 DBus 数据请求
  5. 新增 DCC_FULL_FACTORY_CLASS 宏,支持单例创建及完整生命周期 委托至 classname::registerType/active/get/set
  6. 在 dccfactoryold.h 中保留 v1.0 接口以向后兼容
  7. 在 ControlCenterDBusAdaptor 和 DccManager 中接入 DBus get/set (异步分发待实现)
  8. 迁移 DefAppModel 插件作为首个 v2.0 适配示例,将 qmlRegisterType 移入静态 registerType()

Influence:

  1. 验证已有的 v1.0 插件仍能通过旧接口正常加载
  2. 验证 DefAppModel 的 QML 类型在启动时正确注册

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: caixr23

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

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Sorry @caixr23, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Comment thread include/dccfactory.h
class DccObject;

class DccFactory : public QObject
class DccFactory_20 : public QObject
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

保留DccFactory名,旧插件处理会不会冲突

Comment thread include/dccfactory.h
}; \
}

#define DCC_FULL_FACTORY_CLASS(classname) \
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

命名带版本号可以不冲突 DCC_FACTORY_V20_CLASS

Comment thread include/dccfactory.h
Q_SIGNALS:
// 模块中有设置项变化时,发出该信号
// 命名valuesChanged() 待定
void propertiesChanged(const QVariantMap &properties);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

信号命名问题,数据类型用QString(json)还是QVariantMap,get/set的类型要不要统一?
信号是否有依赖插件是否实现

…a channel

1. Rename DccFactory to DccFactory_20, bump IID to v2.0
2. Add registerType() for QML type registration in main thread
3. Add active() for post-creation activation in main thread
4. Add get/set virtual methods for DBus-triggered data access in
   worker thread
5. Add DCC_FULL_FACTORY_CLASS macro with singleton create and full
   lifecycle delegation to classname::registerType/active/get/set
6. Preserve v1.0 interface in dccfactoryold.h for backward
   compatibility
7. Wire DBus get/set slots in ControlCenterDBusAdaptor and DccManager
   (async dispatch pending)
8. Migrate DefAppModel plugin as first v2.0 adopter, move
   qmlRegisterType into static registerType()

Influence:
1. Verify existing v1.0 plugins still load via old interface
2. Verify DefAppModel QML types register correctly on startup

feat(factory): 升级 DccFactory 至 v2.0,支持生命周期管理与 DBus 数据通道

1. 将 DccFactory 重命名为 DccFactory_20,IID 升级为 v2.0
2. 新增 registerType() 用于在主线程中注册 QML 类型
3. 新增 active() 用于在主线程中执行创建后激活
4. 新增 get/set 虚函数用于在子线程中响应 DBus 数据请求
5. 新增 DCC_FULL_FACTORY_CLASS 宏,支持单例创建及完整生命周期
   委托至 classname::registerType/active/get/set
6. 在 dccfactoryold.h 中保留 v1.0 接口以向后兼容
7. 在 ControlCenterDBusAdaptor 和 DccManager 中接入 DBus get/set
   (异步分发待实现)
8. 迁移 DefAppModel 插件作为首个 v2.0 适配示例,将
   qmlRegisterType 移入静态 registerType()

Influence:
1. 验证已有的 v1.0 插件仍能通过旧接口正常加载
2. 验证 DefAppModel 的 QML 类型在启动时正确注册
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX,我已经仔细审查了你提供的Git Diff。这次代码变更主要是将控制中心的插件工厂接口从 v1.0 升级到了 v2.0,增加了生命周期管理(registerType, active)和数据读写接口(get, set),并引入了DBus的异步调用机制。

整体设计思路清晰,但在语法逻辑、代码质量、性能和安全性方面存在一些需要改进的隐患。以下是我的详细审查意见:

一、 语法与逻辑问题

  1. DCC_FULL_FACTORY_CLASS 宏中的单例模式存在严重的逻辑缺陷

    • 问题:在 create 方法中,使用了 if (!m_object) 来判断是否创建对象,实现类似单例的效果。但是,create 的签名是 QObject *create(QObject *parent = nullptr),如果第二次调用 create 传入了不同的 parent,由于 m_object 已存在,传入的 parent 会被直接忽略。更严重的是,active(), get(), set() 都强依赖于 m_object 不为空,但它们都是 virtual 函数,可以被外部直接调用。如果在 create 之前调用了这几个函数,将会发生空指针解引用(Null Pointer Dereference),导致程序崩溃。
    • 建议
      • active(), get(), set() 中增加对 m_object 的空指针保护(如 Q_ASSERT(m_object) 或安全返回)。
      • 考虑将对象的创建移到 registerType()active() 中,或者明确在文档/注释中规定 create 必须最先调用且只调用一次。
  2. DCC_FULL_FACTORY_CLASS 宏中的信号连接可能失效

    • 问题:在宏的 create 方法中:connect(m_object, &classname::propertiesChanged, this, &classname##DccFactory::propertiesChanged);。这里要求 classname 必须包含 void propertiesChanged(const QVariantMap &) 信号。如果子类没有严格定义该信号,或者签名不完全匹配,编译将会报错。此外,如果以后插件作者想在 classname 中自定义该信号的触发逻辑,宏的强绑定会限制灵活性。
    • 建议:确保所有使用 DCC_FULL_FACTORY_CLASS 的类都继承包含此信号的接口,或者提供更灵活的信号转发机制。
  3. DccManager::set 的返回值与异步逻辑矛盾

    • 问题:在 dccmanager.cpp 中,set 函数返回类型为 void,且内部调用了 setDelayedReply(true) 表示异步回复。但是在 controlcenterdbusadaptor.cpp 中,Set 函数声明了 void Set(...) 且注释写着“错误以DBus的错误返回”。如果 DBus 需要返回错误,必须通过 QDBusMessage::createErrorReply() 来发送,当前的 void 返回值和注释没有体现如何传递具体的错误信息。
    • 建议:统一错误处理机制。如果是异步,应在注释中明确说明如何通过 message 发送错误回复;如果是同步,建议将 DccManager::set 改为返回 QString(与 get 和底层的 DccFactory_20::set 保持一致)。
  4. dccfactoryold.h 中的版权年份错误

    • 问题:新增文件 dccfactoryold.h 的版权年份为 2026,这显然是一个笔误(当前通常是2024)。
    • 建议:修改为 2024 - 2026 或正确的起止年份。

二、 代码质量与可读性

  1. 类名命名规范问题

    • 问题:新接口类名 DccFactory_20 带有下划线和数字,不符合 C++ 常见的驼峰命名规范(如 DccFactoryV2DccFactoryV20)。虽然这是内部类,但作为导出的宏参数,会降低代码的专业感。
    • 建议:考虑重命名为 DccFactoryV2DccFactoryV20
  2. 返回值类型的 const 修饰多余

    • 问题:在 DccFactory_20DefAppModel 中,函数签名为 const QString get(...)const QString set(...)。对于按值返回的类型,加 const 修饰是没有意义的,因为返回的是临时对象(右值),不会被修改。
    • 建议:移除返回值的 const,改为 QString get(const QString &param)QString set(const QString &param)
  3. 宏的代码可读性

    • 问题DCC_FULL_FACTORY_CLASS 宏过于庞大,包含了完整的类定义和5个函数的实现,且带有信号连接,阅读和维护难度极高。
    • 建议:如果可能,考虑使用模板类来代替宏。如果必须使用宏(例如为了配合 Q_PLUGIN_METADATAQ_INTERFACES),建议在宏内部增加更详细的注释说明每个函数的职责。

三、 代码性能

  1. DCC_FULL_FACTORY_CLASS 中的对象生命周期与内存泄漏风险

    • 问题:宏中 m_object = new classname(parent);,这里将插件对象的父对象设置为 parent(即 DccFactory_20 的调用者传入的 parent)。但是,m_object 是工厂类的成员变量,工厂类本身可能并不拥有该对象的所有权。如果传入的 parentnullptr,或者 parent 的生命周期比工厂类短,可能会导致悬挂指针或内存泄漏。
    • 建议:明确 m_object 的所有权。建议将 m_object 的 parent 设置为工厂类本身(this),或者使用智能指针 QPointer<classname> m_object; 来防止悬挂指针。
  2. 字符串传参的隐式共享

    • 问题getset 接口大量使用了 const QString &param,这是好的。但在高频调用场景(如 DBus 批量获取/设置)下,QString 的解析可能成为瓶颈。
    • 建议:既然注释中提到“建议支持批量获取/设置”,建议在接口设计上直接使用 QJsonObjectQJsonArray 替代 QString,这样可以在 DBus 通信层直接使用结构化数据,避免 QString 到 JSON 的二次解析开销。

四、 代码安全

  1. 线程安全与数据竞争

    • 问题:注释中明确指出 getset 是在子线程中调用,而 active 等是在主线程中调用。在 DCC_FULL_FACTORY_CLASS 宏中,m_object 是裸指针,主线程的 active() 和子线程的 get()/set() 会并发访问同一个 m_object 对象。如果 m_object 内部有状态变更,极易引发数据竞争。
    • 建议
      • 必须在 m_object 对应的实现类内部使用读写锁(QReadWriteLock)或互斥锁(QMutex)保护共享数据。
      • 工厂类的 m_object 指针本身的读取也需要保护,建议使用 std::atomic<classname*>QPointer(注意 QPointer 不是线程安全的,赋值时仍需加锁)。
  2. DBus 接口的输入校验

    • 问题GetSet 接口直接暴露给 DBus,外部进程可以随意调用。param 参数目前没有任何校验。
    • 建议:在 DccManager::getDccManager::set 的实现中,必须对 moduleparam 进行严格的格式校验和长度限制,防止恶意 DBus 调用导致内存暴涨或解析崩溃(如畸形 JSON 导致的死循环)。

总结与修改建议示例

针对 DCC_FULL_FACTORY_CLASS 宏中暴露的最严重的空指针和命名/const问题,建议做如下修改:

// 修改类名和返回值const
class DccFactoryV2 : public QObject
{
    // ...
    virtual QString get(const QString &param) { return QString(); }
    virtual QString set(const QString &param) { return QString(); }
    // ...
};

// 宏内部增加空指针保护
#define DCC_FULL_FACTORY_CLASS(classname)                                                                          \\
    namespace {                                                                                                    \\
    class Q_DECL_EXPORT classname##DccFactory : public dccV25::DccFactoryV2                                        \\
    {                                                                                                              \\
        Q_OBJECT                                                                                                   \\
        Q_PLUGIN_METADATA(IID DccFactory_iid)                                                                      \\
        Q_INTERFACES(dccV25::DccFactoryV2);                                                                        \\
                                                                                                                   \\
    public:                                                                                                        \\
        using dccV25::DccFactoryV2::DccFactoryV2;                                                                  \\
        void registerType() override                                                                               \\
        {                                                                                                          \\
            classname::registerType();                                                                             \\
        }                                                                                                          \\
        QObject *create(QObject *parent = nullptr) override                                                        \\
        {                                                                                                          \\
            if (!m_object) {                                                                                       \\
                m_object = new classname(this); /* 明确所有权,防止内存泄漏 */                                        \\
                connect(m_object, &classname::propertiesChanged, this, &classname##DccFactory::propertiesChanged); \\
            }                                                                                                      \\
            return m_object;                                                                                       \\
        }                                                                                                          \\
        void active() override                                                                                     \\
        {                                                                                                          \\
            if (m_object) m_object->active();                                                                      \\
            else qWarning() << "active() called before create()";                                                  \\
        }                                                                                                          \\
        QString get(const QString &param) override                                                                 \\
        {                                                                                                          \\
            if (m_object) return m_object->get(param);                                                             \\
            qWarning() << "get() called before create()";                                                          \\
            return QString();                                                                                      \\
        }                                                                                                          \\
        QString set(const QString &param) override                                                                 \\
        {                                                                                                          \\
            if (m_object) return m_object->set(param);                                                             \\
            qWarning() << "set() called before create()";                                                          \\
            return QStringLiteral("Error: Object not initialized");                                                \\
        }                                                                                                          \\
                                                                                                                   \\
    private:                                                                                                       \\
        classname *m_object = nullptr;                                                                             \\
    };                                                                                                             \\
    }

希望这些审查意见对你有所帮助!如果有任何疑问,欢迎随时探讨。

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 16, 2026

TAG Bot

New tag: 6.1.86
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3238

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 20, 2026

TAG Bot

New tag: 6.1.87
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3245

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 22, 2026

TAG Bot

New tag: 6.1.88
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3251

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