Skip to content

Commit f4d11e7

Browse files
committed
refactor: move plugin factory preparation before module loading
1. Extracted plugin factory preparation logic from LoadPluginTask::doLoadSo() into new method preparePluginFactory() 2. Modified LoadPluginTask::doLoadSo() to LoadPluginTask::createData() that uses pre-prepared factory 3. Added factory pointer to PluginData structure to store prepared factory instance 4. Moved factory preparation to occur before loadModule() in plugin loading sequence 5. Simplified createData() method to focus only on object creation from factory 6. Added proper cleanup of factory pointer in PluginManager destructor This refactoring separates factory preparation from object creation, allowing factory initialization to happen earlier in the plugin loading process. The change improves code organization by separating concerns: factory loading/validation vs. object instantiation. This prepares for potential optimizations where factory preparation could be done in parallel or at different stages of application startup. Influence: 1. Verify plugin loading still works correctly for all control center modules 2. Test plugin loading with both valid and invalid .so files 3. Verify error handling when factory preparation fails 4. Test memory management and cleanup of factory instances 5. Ensure plugin status updates are still emitted correctly 6. Verify thread safety during factory preparation and object creation 7. Test with plugins that have parent/child relationships in their created objects refactor: 将插件工厂准备逻辑前移到模块加载之前执行 1. 从 LoadPluginTask::doLoadSo() 中提取插件工厂准备逻辑到新的 preparePluginFactory() 方法 2. 将 LoadPluginTask::doLoadSo() 重命名为 LoadPluginTask::createData(), 使用预先准备的工厂 3. 在 PluginData 结构中添加工厂指针以存储准备好的工厂实例 4. 将工厂准备移动到插件加载序列中的 loadModule() 之前执行 5. 简化 createData() 方法,专注于从工厂创建对象 6. 在 PluginManager 析构函数中添加工厂指针的适当清理 此次重构将工厂准备与对象创建分离,允许工厂初始化在插件加载过程的更早阶段 进行。这一改动通过分离关注点(工厂加载/验证 vs. 对象实例化)改善了代码组 织。这为潜在的优化做好了准备,工厂准备可以并行进行或在应用程序启动的不同 阶段执行。 Influence: 1. 验证所有控制中心模块的插件加载是否仍然正常工作 2. 测试使用有效和无效 .so 文件的插件加载 3. 验证工厂准备失败时的错误处理 4. 测试工厂实例的内存管理和清理 5. 确保插件状态更新仍然正确发出 6. 验证工厂准备和对象创建期间的线程安全性 7. 测试具有父子关系的插件对象的创建
1 parent 2b4569d commit f4d11e7

2 files changed

Lines changed: 70 additions & 49 deletions

File tree

src/dde-control-center/pluginmanager.cpp

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct PluginData
7575
QString name;
7676
QString path;
7777
uint type;
78+
DccFactory *factory;
7879

7980
DccObject *module;
8081
DccObject *mainObj;
@@ -87,6 +88,7 @@ struct PluginData
8788
: name(_name)
8889
, path(_path)
8990
, type(T_Unknown)
91+
, factory(nullptr)
9092
, module(nullptr)
9193
, mainObj(nullptr)
9294
, soObj(nullptr)
@@ -111,7 +113,7 @@ class LoadPluginTask : public QRunnable
111113

112114
protected:
113115
void run() override;
114-
void doLoadSo();
116+
void createData();
115117

116118
protected:
117119
PluginManager *m_pManager;
@@ -121,62 +123,33 @@ class LoadPluginTask : public QRunnable
121123
void LoadPluginTask::run()
122124
{
123125
m_data->thread = QThread::currentThread();
124-
doLoadSo();
126+
createData();
125127
m_data->thread = nullptr;
126128
}
127129

128-
void LoadPluginTask::doLoadSo()
130+
void LoadPluginTask::createData()
129131
{
130-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataBegin, "load plugin begin");
131-
// {main.qml}
132-
const QString soPath = m_data->path + "/" + m_data->name + ".so";
132+
Q_EMIT m_pManager->updatePluginStatus(m_data, DataBegin, "create data begin");
133133
QElapsedTimer timer;
134134
timer.start();
135135
QObject *dataObj = nullptr;
136136
DccObject *soObj = nullptr;
137-
if (QFile::exists(soPath)) {
138-
if (m_pManager->isDeleting()) {
139-
return;
140-
}
141-
QPluginLoader loader(soPath);
137+
if (m_pManager->isDeleting()) {
138+
return;
139+
}
140+
if (!m_data->factory) {
141+
Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": create data skipped");
142+
return;
143+
} else {
142144
Q_EMIT m_pManager->updatePluginStatus(m_data, DataLoad, QString());
143-
loader.load();
144-
if (m_pManager->isDeleting()) {
145-
return;
145+
dataObj = m_data->factory->create();
146+
if (dataObj && dataObj->parent()) {
147+
dataObj->setParent(nullptr);
146148
}
147-
if (!loader.isLoaded()) {
148-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataErr, "Load the plugin failed." + loader.errorString());
149-
} else {
150-
const auto &meta = loader.metaData();
151-
do {
152-
const auto iid = meta["IID"].toString();
153-
if (iid.isEmpty() || iid != QString(qobject_interface_iid<DccFactory *>())) {
154-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataErr, "Error iid:" + iid);
155-
break;
156-
}
157-
158-
if (!loader.instance()) {
159-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataErr, "instance() failed." + loader.errorString());
160-
break;
161-
}
162-
DccFactory *factory = qobject_cast<DccFactory *>(loader.instance());
163-
if (!factory) {
164-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataErr, "The plugin isn't a DccFactory." + soPath);
165-
loader.unload();
166-
break;
167-
}
168-
dataObj = factory->create();
169-
if (dataObj && dataObj->parent()) {
170-
dataObj->setParent(nullptr);
171-
}
172-
soObj = factory->dccObject();
173-
if (soObj && soObj->parent()) {
174-
soObj->setParent(nullptr);
175-
}
176-
} while (false);
149+
soObj = m_data->factory->dccObject();
150+
if (soObj && soObj->parent()) {
151+
soObj->setParent(nullptr);
177152
}
178-
} else {
179-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataErr, "File does not exist:" + soPath);
180153
}
181154
if (dataObj) {
182155
m_data->data = dataObj;
@@ -192,7 +165,7 @@ void LoadPluginTask::doLoadSo()
192165
m_data->soObj->moveToThread(m_pManager->thread());
193166
m_data->soObj->setParent(m_pManager->parent());
194167
}
195-
Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": load plugin finished. elapsed time :" + QString::number(timer.elapsed()));
168+
Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": create data finished. elapsed time :" + QString::number(timer.elapsed()));
196169
}
197170

198171
PluginManager::PluginManager(DccManager *parent)
@@ -224,6 +197,7 @@ PluginManager::~PluginManager()
224197
delete data->data;
225198
data->data = nullptr;
226199
}
200+
data->factory = nullptr;
227201
delete data;
228202
}
229203
m_plugins.clear();
@@ -305,6 +279,49 @@ bool PluginManager::updatePluginType(PluginData *plugin)
305279
return false;
306280
}
307281

282+
bool PluginManager::preparePluginFactory(PluginData *plugin)
283+
{
284+
if (!plugin || plugin->factory) {
285+
return plugin && plugin->factory;
286+
}
287+
288+
const QString soPath = plugin->path + "/" + plugin->name + ".so";
289+
if (!QFile::exists(soPath)) {
290+
return true;
291+
}
292+
293+
QPluginLoader loader(soPath);
294+
if (!loader.load()) {
295+
qCWarning(dccLog()) << plugin->name << ": prepare factory load failed" << loader.errorString();
296+
return false;
297+
}
298+
299+
const auto &meta = loader.metaData();
300+
const auto iid = meta["IID"].toString();
301+
if (iid.isEmpty() || iid != QString(qobject_interface_iid<DccFactory *>())) {
302+
qCWarning(dccLog()) << plugin->name << ": prepare factory iid error" << iid;
303+
loader.unload();
304+
return false;
305+
}
306+
307+
QObject *instance = loader.instance();
308+
if (!instance) {
309+
qCWarning(dccLog()) << plugin->name << ": prepare factory instance failed" << loader.errorString();
310+
loader.unload();
311+
return false;
312+
}
313+
314+
DccFactory *factory = qobject_cast<DccFactory *>(instance);
315+
if (!factory) {
316+
qCWarning(dccLog()) << plugin->name << ": prepare factory cast failed";
317+
loader.unload();
318+
return false;
319+
}
320+
321+
plugin->factory = factory;
322+
return true;
323+
}
324+
308325
QThreadPool *PluginManager::threadPool()
309326
{
310327
if (!m_threadPool) {
@@ -341,6 +358,10 @@ void PluginManager::loadPlugin(PluginData *plugin)
341358
threadPool()->start(new LoadPluginTask(plugin, this));
342359
}
343360
} else if ((plugin->status & (MetaDataEnd | ModuleLoad)) == MetaDataEnd) {
361+
if (!preparePluginFactory(plugin)) {
362+
Q_EMIT updatePluginStatus(plugin, DataErr | PluginEnd, ": factory preparation failed, plugin skipped");
363+
return;
364+
}
344365
DccManager::installTranslator(plugin->name);
345366
loadModule(plugin);
346367
} else {

src/dde-control-center/pluginmanager.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44
#pragma once
@@ -8,7 +8,6 @@
88
#include <QStringList>
99
#include <QVector>
1010

11-
class QPluginLoader;
1211
class QQmlComponent;
1312
class QThreadPool;
1413

@@ -42,6 +41,7 @@ public Q_SLOTS:
4241
private:
4342
bool compareVersion(const QString &targetVersion, const QString &baseVersion);
4443
bool updatePluginType(PluginData *plugin);
44+
bool preparePluginFactory(PluginData *plugin);
4545
QThreadPool *threadPool();
4646

4747
private Q_SLOTS:

0 commit comments

Comments
 (0)