dde-dock/frame/util/pluginloader.cpp
Robert 0427e19b72
chore: adapt license and copyright (#680)
Modify project to pass the REUSE check

Log: Modify project to pass the REUSE check
Task: https://pms.uniontech.com/task-view-185215.html
Change-Id: Ie954cf985f16c1a243bfc912aa7458c6e85ce9de
2022-09-06 11:36:55 +08:00

193 lines
5.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-FileCopyrightText: 2011 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "pluginloader.h"
#include "utils.h"
#include <QDir>
#include <QDebug>
#include <QLibrary>
#include <QGSettings>
#include <QProcess>
#include <QtConcurrent>
#include <QFuture>
#include <DSysInfo>
DCORE_USE_NAMESPACE
PluginLoader::PluginLoader(const QString &pluginDirPath, QObject *parent)
: QThread(parent)
, m_pluginDirPath(pluginDirPath)
{
}
void PluginLoader::run()
{
QDir pluginsDir(m_pluginDirPath);
const QStringList files = pluginsDir.entryList(QDir::Files);
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();
}
return QStringList();
};
const QStringList disable_plugins_list = getDisablePluginList();
const QString dtkCoreName = dtkCoreFileName();
QStringList plugins;
// 查找可用插件
QList<QString> filePaths;
for (QString file : files) {
if (!QLibrary::isLibrary(file))
continue;
// 社区版需要加载键盘布局,其他不需要
if (file.contains("libkeyboard-layout") && !DSysInfo::isCommunityEdition())
continue;
// 由于onboard不支持wayland下输入因此屏蔽onboard插件加载
if (file.contains("libonboard") && Utils::IS_WAYLAND_DISPLAY)
continue;
// TODO: old dock plugins is uncompatible
if (file.startsWith("libdde-dock-"))
continue;
if (disable_plugins_list.contains(file)) {
qDebug() << "disable loading plugin:" << file;
continue;
}
filePaths.push_back(pluginsDir.absoluteFilePath(file));
}
// 由于使用ldd获取.so信息比较耗时采用并行处理
QFuture<QString> f = QtConcurrent::mapped(filePaths, &PluginLoader::libUsedDtkCoreFileName);
f.waitForFinished();
const QStringList &results = f.results();
if (results.size() == filePaths.size()) {
for (int i = 0; i < results.size(); ++i) {
const QString &libUsedDtkCore = results.at(i);
// 判断当前进程加载的dtkcore库是否和当前库加载的dtkcore的库为同一个如果不同则无需加载
// 否则在加载dtkcore的时候会报错dtkcore内部判断如果加载两次会抛出错误
if (libUsedDtkCore.isEmpty() || libUsedDtkCore == dtkCoreName)
plugins << filePaths.at(i);
}
} else {
plugins.append(filePaths);
}
for (auto plugin : plugins) {
emit pluginFounded(pluginsDir.absoluteFilePath(plugin));
}
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;
}