diff --git a/panels/dock/taskmanager/CMakeLists.txt b/panels/dock/taskmanager/CMakeLists.txt index cc9101cce..160c7bf73 100644 --- a/panels/dock/taskmanager/CMakeLists.txt +++ b/panels/dock/taskmanager/CMakeLists.txt @@ -68,6 +68,8 @@ add_library(dock-taskmanager SHARED ${DBUS_INTERFACES} waylandwindowmonitor.h taskmanagersettings.cpp taskmanagersettings.h + processinfo.cpp + processinfo.h ) qt_generate_wayland_protocol_client_sources(dock-taskmanager diff --git a/panels/dock/taskmanager/desktopfileamparser.cpp b/panels/dock/taskmanager/desktopfileamparser.cpp index 2e9e2e95e..b91716bf5 100644 --- a/panels/dock/taskmanager/desktopfileamparser.cpp +++ b/panels/dock/taskmanager/desktopfileamparser.cpp @@ -6,6 +6,7 @@ #include "abstractwindow.h" #include "desktopfileamparser.h" #include "desktopfileabstractparser.h" +#include "processinfo.h" #include #include @@ -31,6 +32,11 @@ namespace dock { static QDBusServiceWatcher dbusWatcher(AM_DBUS_PATH, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange); +QList> DesktopFileAMParser::m_identifyWindowFuns = { + {"PidEnv", &DesktopFileAMParser::identifyWindowPidEnv}, + {"AM", &DesktopFileAMParser::identifyWindowAM}, +}; + DesktopFileAMParser::DesktopFileAMParser(QString id, QObject* parent) : DesktopfileAbstractParser(id, parent) { @@ -134,6 +140,44 @@ QString DesktopFileAMParser::id2dbusPath(const QString& id) } QString DesktopFileAMParser::identifyWindow(QPointer window) +{ + for (auto iter = m_identifyWindowFuns.begin(); iter != m_identifyWindowFuns.end(); iter++) { + QString name = iter->first; + IdentifyFunc func = iter->second; + qInfo() << "identifyWindow: try " << name; + QString appId = func(window); + if (!appId.isEmpty()) { + return appId; + } + } + + return ""; +} + +QString DesktopFileAMParser::identifyWindowPidEnv(QPointer window) +{ + ProcessInfo process(window->pid()); + QString launchedDesktopFile = process.getEnv("GIO_LAUNCHED_DESKTOP_FILE"); + QString launchedDesktopFilePidStr = process.getEnv("GIO_LAUNCHED_DESKTOP_FILE_PID"); + if (launchedDesktopFile.isEmpty()) { + return ""; + } + + int launchedDesktopFilePid = launchedDesktopFilePidStr.toInt(); + int ppid = process.getPpid(); + if (launchedDesktopFilePid != ppid && !isLinglongApp(process)) { + return ""; + } + + if (!isApplicationDesktop(launchedDesktopFile)) { + return ""; + } + + QFileInfo fileinfo(launchedDesktopFile); + return fileinfo.completeBaseName(); +} + +QString DesktopFileAMParser::identifyWindowAM(QPointer window) { if (!m_amIsAvaliable) m_amIsAvaliable = QDBusConnection::sessionBus(). interface()->isServiceRegistered(AM_DBUS_PATH); @@ -160,6 +204,34 @@ QString DesktopFileAMParser::identifyWindow(QPointer window) return QString(); } +bool DesktopFileAMParser::isApplicationDesktop(const QString &path) { + for (auto dir : QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)) { + if (path.startsWith(dir + QDir::separator())) { + return true; + } + } + + return false; +} + +bool DesktopFileAMParser::isLinglongApp(ProcessInfo &process) +{ + for (ProcessInfo p(process.getPpid()); p.getPid() != 0; p = ProcessInfo(p.getPpid())) { + auto cmdline = p.getCmdLine(); + if (cmdline.isEmpty()){ + qWarning() << "Failed to get command line of" << p.getPid() << " SKIP it."; + continue; + } + if (p.getCmdLine()[0].indexOf("ll-box") != -1) { + qDebug() << "process ID" << process.getPid() << "is in linglong container," + << "ll-box PID" << p.getPid(); + return true; + } + } + + return false; +} + QString DesktopFileAMParser::identifyType() { return QStringLiteral("amAPP"); diff --git a/panels/dock/taskmanager/desktopfileamparser.h b/panels/dock/taskmanager/desktopfileamparser.h index ae3af72b3..e45b7b670 100644 --- a/panels/dock/taskmanager/desktopfileamparser.h +++ b/panels/dock/taskmanager/desktopfileamparser.h @@ -14,6 +14,9 @@ namespace dock { class AbstractWindow; +class ProcessInfo; + +typedef std::function)> IdentifyFunc; class DesktopFileAMParser : public DesktopfileAbstractParser { @@ -42,6 +45,10 @@ class DesktopFileAMParser : public DesktopfileAbstractParser DesktopFileAMParser(QString id, QObject *parent = nullptr); static QString identifyWindow(QPointer window); + static QString identifyWindowPidEnv(QPointer window); + static QString identifyWindowAM(QPointer window); + static bool isApplicationDesktop(const QString &path); + static bool isLinglongApp(ProcessInfo &process); private: QString id2dbusPath(const QString& id); @@ -58,6 +65,7 @@ private Q_SLOTS: private: inline static bool m_amIsAvaliable; + static QList> m_identifyWindowFuns; QString m_name; QString m_icon; diff --git a/panels/dock/taskmanager/processinfo.cpp b/panels/dock/taskmanager/processinfo.cpp new file mode 100644 index 000000000..1e5bb52ac --- /dev/null +++ b/panels/dock/taskmanager/processinfo.cpp @@ -0,0 +1,220 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "processinfo.h" + +#include +#include +#include + +#include +#include +#include + + +DS_BEGIN_NAMESPACE +namespace dock { +ProcessInfo::ProcessInfo(int pid) + : m_pid(pid) + , m_ppid(0) + +{ + if (pid == 0) + return; + m_exe = getExe(); + m_cwd = getCwd(); + m_cmdLine = getCmdLine(); + getStatus(); + // 部分root进程在/proc文件系统查找不到exe、cwd、cmdline信息 + if (m_exe.isEmpty() || m_cwd.isEmpty() || m_cmdLine.size() == 0) { + m_isValid = false; + return; + } + + // args + qInfo() << "ProcessInfo: exe=" << m_exe << " cwd=" << m_cwd << " cmdLine=" << (m_cmdLine[0].isEmpty() ? " " : m_cmdLine[0]); + auto verifyExe = [](QString exe, QString cwd, QString firstArg){ + if (firstArg.size() == 0) return false; + + QFileInfo info(firstArg); + if (info.completeBaseName() == firstArg) return true; + + if (!QDir::isAbsolutePath(firstArg)) + firstArg = cwd + firstArg; + + return exe == firstArg; + }; + + if (!m_cmdLine[0].isEmpty()) { + if (!verifyExe(m_exe, m_cwd, m_cmdLine[0])) { + auto parts = m_cmdLine[0].split(' '); + // try again + if (verifyExe(m_exe, m_cwd, parts[0])) { + m_args.append(parts.mid(1, parts.size() - 1)); + m_args.append(m_cmdLine.mid(1, m_cmdLine.size() - 1)); + } + } else { + m_args.append(m_cmdLine.mid(1, m_cmdLine.size() - 1)); + } + } +} + +ProcessInfo::ProcessInfo(QStringList cmd) + : m_hasPid(false) + , m_isValid(true) +{ + if (cmd.size() == 0) { + m_isValid = false; + return; + } + + m_cmdLine = cmd; + m_exe = cmd[0]; + m_args.append(cmd.mid(1, cmd.size() - 1)); +} + +ProcessInfo::~ProcessInfo() +{ +} + +QString ProcessInfo::getEnv(const QString &key) +{ + if (m_environ.size() == 0) getEnviron(); + return m_environ[key]; +} + +Status ProcessInfo::getStatus() +{ + if (!m_status.empty()){ + return m_status; + } + + QString statusFile = getFile("status"); + + std::ifstream fs(statusFile.toStdString()); + if (!fs.is_open()) { + return m_status; + } + + std::string tmp = ""; + while (std::getline(fs, tmp)) { + auto pos = tmp.find_first_of(':'); + if (pos == std::string::npos) { + continue; + } + + QString value; + if (pos + 1 < tmp.length()) { + value = QString::fromStdString(tmp.substr(pos + 1)); + } + + m_status[QString::fromStdString(tmp.substr(0, pos))] = value; + } + + return m_status; +} + +QStringList ProcessInfo::getCmdLine() +{ + if (m_cmdLine.size() == 0) { + QString cmdlineFile = getFile("cmdline"); + m_cmdLine = readFile(cmdlineFile); + } + + return m_cmdLine; +} + +QStringList ProcessInfo::getArgs() +{ + return m_args; +} + +int ProcessInfo::getPid() +{ + + return m_pid; +} + +int ProcessInfo::getPpid() +{ + if (m_ppid == 0) { + if (m_status.find("PPid") != m_status.end()) { + m_ppid = std::stoi(m_status["PPid"].toStdString()); + } + } + return m_ppid; +} + +bool ProcessInfo::initWithPid() +{ + return m_hasPid; +} + +bool ProcessInfo::isValid() +{ + return m_isValid; +} + +QString ProcessInfo::getExe() +{ + if (m_exe.isEmpty()) { + QString cmdLineFile = getFile("exe"); + QFileInfo path(cmdLineFile); + m_exe = path.canonicalFilePath(); + } + + return m_exe; +} + +bool ProcessInfo::isExist() +{ + QString procDir = "/proc/" + QString::number(m_pid); + return QFile::exists(procDir); +} + +QStringList ProcessInfo::readFile(const QString &filePath) +{ + QStringList ret; + std::ifstream fs(filePath.toStdString()); + if (!fs.is_open()) { + return ret; + } + + std::string tmp; + while (std::getline(fs, tmp, '\0')) { + ret.append(QString::fromStdString(tmp)); + } + return ret; +} + +QString ProcessInfo::getFile(const QString &file) +{ + return QString("/proc/").append(QString::number(m_pid).append('/').append(file)); +} + +QString ProcessInfo::getCwd() +{ + if (m_cwd.isEmpty()) { + QString cwdFile = getFile("cwd"); + QFileInfo path(cwdFile); + m_cwd = path.canonicalFilePath(); + } + return m_cwd; +} + +QMap ProcessInfo::getEnviron() +{ + if (m_environ.size() == 0) { + QString envFile = getFile("environ"); + QStringList contents = readFile(envFile); + for (auto line : contents){ + int index = line.indexOf('='); + m_environ.insert(line.left(index), line.right(line.size() - index - 1)); + } + } + return m_environ; +} + +} +DS_END_NAMESPACE diff --git a/panels/dock/taskmanager/processinfo.h b/panels/dock/taskmanager/processinfo.h new file mode 100644 index 000000000..505d917d2 --- /dev/null +++ b/panels/dock/taskmanager/processinfo.h @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef PROCESSINFO_H +#define PROCESSINFO_H + +#include "dsglobal.h" + +#include +#include +#include + +DS_BEGIN_NAMESPACE +namespace dock { +typedef QMap Status; + +// 进程信息 +class ProcessInfo +{ +public: + explicit ProcessInfo(int pid); + explicit ProcessInfo(QStringList cmd); + virtual ~ProcessInfo(); + + bool isValid(); + bool initWithPid(); + + int getPid(); + int getPpid(); + + QString getExe(); + QString getCwd(); + Status getStatus(); + QString getEnv(const QString &key); + + QStringList getArgs(); + QStringList getCmdLine(); + QMap getEnviron(); + +private: + bool isExist(); + QString getJoinedExeArgs(); + QString getFile(const QString &file); + QStringList readFile(const QString &filePath); + +private: + + int m_pid; + int m_ppid; + bool m_hasPid; + bool m_isValid; + + Status m_status; + QString m_exe; + QString m_cwd; + QStringList m_args; + QStringList m_cmdLine; + QVector m_uids; + QMap m_environ; +}; +} +DS_END_NAMESPACE + +#endif // PROCESSINFO_H