fix: 插件加载的时候过滤掉和当前进程使用的dtkcore版本不同的插件

在加载插件之前,拿到当前进程使用的dtkCore,然后依次判断每个插件依赖的dtkCore是否和当前的dtkCore一致,如果出现不一致的情况,则不加载

Log: 增加对不同版本插件的限制
Task: https://pms.uniontech.com/zentao/task-view-81282.html
Change-Id: I7ffc7d94f33adc4edcb8191622c5f7448d70ab32
This commit is contained in:
Dong Hualin 2021-08-02 17:00:24 +08:00
parent 32894dd413
commit b543d92151
3 changed files with 120 additions and 9 deletions

View File

@ -52,7 +52,7 @@ AbstractPluginsController::AbstractPluginsController(QObject *parent)
AbstractPluginsController::~AbstractPluginsController()
{
for (auto inter: m_pluginsMap.keys()) {
for (auto inter : m_pluginsMap.keys()) {
m_pluginsMap.remove(inter);
delete m_pluginsMap.value(inter).value("pluginloader");
delete inter;
@ -150,7 +150,7 @@ PluginsItemInterface *AbstractPluginsController::pluginInterAt(const QString &it
}
PluginsItemInterface *AbstractPluginsController::pluginInterAt(QObject *destItem)
{
{
QMapIterator<PluginsItemInterface *, QMap<QString, QObject *>> it(m_pluginsMap);
while (it.hasNext()) {
it.next();
@ -165,7 +165,7 @@ PluginsItemInterface *AbstractPluginsController::pluginInterAt(QObject *destItem
void AbstractPluginsController::startLoader(PluginLoader *loader)
{
connect(loader, &PluginLoader::finished, loader, &PluginLoader::deleteLater, Qt::QueuedConnection);
connect(loader, &PluginLoader::pluginFounded, this, [ = ](const QString &pluginFile){
connect(loader, &PluginLoader::pluginFounded, this, [ = ](const QString &pluginFile) {
QPair<QString, PluginsItemInterface *> pair;
pair.first = pluginFile;
pair.second = nullptr;
@ -222,7 +222,7 @@ void AbstractPluginsController::loadPlugin(const QString &pluginFile)
}
if (!pluginIsValid) {
for (auto &pair: m_pluginLoadMap.keys()) {
for (auto &pair : m_pluginLoadMap.keys()) {
if (pair.first == pluginFile) {
m_pluginLoadMap.remove(pair);
}
@ -233,8 +233,8 @@ void AbstractPluginsController::loadPlugin(const QString &pluginFile)
}
if (interface->pluginName() == "multitasking") {
if (qEnvironmentVariable("XDG_SESSION_TYPE").contains("wayland") or Dtk::Core::DSysInfo::deepinType() == Dtk::Core::DSysInfo::DeepinServer){
for (auto &pair: m_pluginLoadMap.keys()) {
if (qEnvironmentVariable("XDG_SESSION_TYPE").contains("wayland") or Dtk::Core::DSysInfo::deepinType() == Dtk::Core::DSysInfo::DeepinServer) {
for (auto &pair : m_pluginLoadMap.keys()) {
if (pair.first == pluginFile) {
m_pluginLoadMap.remove(pair);
}

View File

@ -37,7 +37,7 @@ void PluginLoader::run()
QDir pluginsDir(m_pluginDirPath);
const QStringList files = pluginsDir.entryList(QDir::Files);
auto getDisablePluginList = [ = ]{
auto getDisablePluginList = [ = ] {
if (QGSettings::isSchemaInstalled("com.deepin.dde.dock.disableplugins")) {
QGSettings gsetting("com.deepin.dde.dock.disableplugins", "/com/deepin/dde/dock/disableplugins/");
return gsetting.get("disable-plugins-list").toStringList();
@ -47,11 +47,12 @@ void PluginLoader::run()
const QStringList disable_plugins_list = getDisablePluginList();
const QString dtkCoreName = dtkCoreFileName();
QStringList plugins;
// 查找可用插件
for (QString file : files)
{
for (QString file : files) {
if (!QLibrary::isLibrary(file))
continue;
@ -63,6 +64,12 @@ void PluginLoader::run()
qDebug() << "disable loading plugin:" << file;
continue;
}
// 判断当前进程加载的dtkcore库是否和当前库加载的dtkcore的库为同一个如果不同则无需加载
// 否则在加载dtkcore的时候会报错dtkcore内部判断如果加载两次会抛出错误
QString libUsedDtkCore = libUsedDtkCoreFileName(pluginsDir.absoluteFilePath(file));
if (!libUsedDtkCore.isEmpty() && libUsedDtkCore != dtkCoreName)
continue;
plugins << file;
}
for (auto plugin : plugins) {
@ -71,3 +78,103 @@ void PluginLoader::run()
emit finished();
}
/**
* @brief 使dtkcore库的文件名
* @return 使dtkCore库的文件名
*/
QString PluginLoader::dtkCoreFileName()
{
QFile f("/proc/self/maps");
if (!f.open(QIODevice::ReadOnly))
return QString();
const QByteArray &data = f.readAll();
QTextStream ts(data);
while (Q_UNLIKELY(!ts.atEnd())) {
const QString line = ts.readLine();
const QStringList &maps = line.split(' ', QString::SplitBehavior::SkipEmptyParts);
if (Q_UNLIKELY(maps.size() < 6))
continue;
QFileInfo info(maps.value(5));
QString infoAbPath = info.absoluteFilePath();
if (info.fileName().contains("dtkcore")) {
infoAbPath = realFileName(infoAbPath);
if (infoAbPath.contains("/")) {
int pathIndex = infoAbPath.lastIndexOf("/");
infoAbPath = infoAbPath.mid(pathIndex + 1).trimmed();
}
f.close();
return infoAbPath;
}
}
f.close();
return QString();
}
/**
* @brief so库使用的dtkcore库文件名
* @param dtkcore库的so库文件名
* @return 使dtkcore库文件名
*/
QString PluginLoader::libUsedDtkCoreFileName(const QString &fileName)
{
QString lddCommand = QString("ldd -r %1").arg(fileName);
FILE *fp = popen(lddCommand.toLocal8Bit().data(), "r");
if (fp) {
char buf[2000] = {0};
while (fgets(buf, sizeof(buf), fp)) {
QString rowResult = buf;
rowResult = rowResult.trimmed();
if (rowResult.contains("dtkcore")) {
QStringList coreSplits = rowResult.split("=>");
if (coreSplits.size() < 2)
continue;
pclose(fp);
QString dtkCorePath = coreSplits[1];
// 删除后面的括号的内容
int addrIndex = dtkCorePath.indexOf("(0x");
dtkCorePath = realFileName(dtkCorePath.left(addrIndex).trimmed());
if (dtkCorePath.contains("/")) {
int pathIndex = dtkCorePath.lastIndexOf("/");
dtkCorePath = dtkCorePath.mid(pathIndex + 1).trimmed();
}
return dtkCorePath;
}
}
pclose(fp);
}
return QString();
}
/**
* @brief
* @param
* @return
*/
QString PluginLoader::realFileName(QString fileName)
{
QString command = QString("ls %1 -al").arg(fileName);
FILE *fp = popen(command.toLocal8Bit().data(), "r");
if (fp) {
char buf[2000] = {0};
if (fgets(buf, sizeof(buf), fp)) {
QString rowInfo = buf;
if (rowInfo.contains("->")) {
pclose(fp);
QStringList fileInfos = rowInfo.split("->");
QString srcFileName = fileInfos[1];
srcFileName = srcFileName.trimmed();
return srcFileName;
}
}
pclose(fp);
}
return fileName;
}

View File

@ -38,6 +38,10 @@ signals:
protected:
void run();
QString dtkCoreFileName();
QString libUsedDtkCoreFileName(const QString &fileName);
QString realFileName(QString fileName); // 获取软连接的真实文件的路径
private:
QString m_pluginDirPath;
};