feat: add ProcessGuesser1 service
Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
parent
f796535233
commit
8f6628c5d2
9
api/dbus/org.desktopspec.ProcessGuesser1.xml
Normal file
9
api/dbus/org.desktopspec.ProcessGuesser1.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.desktopspec.ProcessGuesser1">
|
||||
<method name="GuessApplicationId">
|
||||
<arg type="h" name="pidfd" direction="in" />
|
||||
<arg type="s" name="appId" direction="out" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
@ -14,6 +14,7 @@ qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.deskto
|
||||
qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ObjectManager1.xml dbus/applicationmanager1service.h ApplicationManager1Service AMobjectmanager1adaptor AMObjectManagerAdaptor)
|
||||
qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ObjectManager1.xml dbus/applicationservice.h ApplicationService APPobjectmanager1adaptor APPObjectManagerAdaptor)
|
||||
qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.MimeManager1.xml dbus/mimemanager1service.h MimeManager1Service)
|
||||
qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ProcessGuesser1.xml dbus/processguesser1service.h ProcessGuesser1Service)
|
||||
|
||||
target_sources(dde_am_dbus PRIVATE
|
||||
${dde_am_dbus_SOURCE}
|
||||
|
@ -9,8 +9,10 @@
|
||||
#include "propertiesForwarder.h"
|
||||
#include "applicationHooks.h"
|
||||
#include "desktopfilegenerator.h"
|
||||
#include "processguesser1service.h"
|
||||
#include <QFile>
|
||||
#include <QDBusMessage>
|
||||
#include <QStringBuilder>
|
||||
#include <unistd.h>
|
||||
|
||||
ApplicationManager1Service::~ApplicationManager1Service() = default;
|
||||
@ -28,6 +30,8 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce
|
||||
qFatal("%s", connection.lastError().message().toLocal8Bit().data());
|
||||
}
|
||||
|
||||
new (std::nothrow) ProcessGuesser1Service{connection, this};
|
||||
|
||||
if (auto *tmp = new (std::nothrow) ApplicationManager1Adaptor{this}; tmp == nullptr) {
|
||||
qCritical() << "new Application Manager Adaptor failed.";
|
||||
std::terminate();
|
||||
@ -397,37 +401,15 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
|
||||
|
||||
Q_ASSERT_X(static_cast<bool>(m_identifier), "Identify", "Broken Identifier.");
|
||||
|
||||
QString fdFilePath = QString{"/proc/self/fdinfo/%1"}.arg(pidfd.fileDescriptor());
|
||||
QFile fdFile{fdFilePath};
|
||||
if (!fdFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
||||
qWarning() << "open " << fdFilePath << "failed: " << fdFile.errorString();
|
||||
return {};
|
||||
}
|
||||
auto content = fdFile.readAll();
|
||||
QTextStream stream{content};
|
||||
QString appPid;
|
||||
while (!stream.atEnd()) {
|
||||
auto line = stream.readLine();
|
||||
if (line.startsWith("Pid")) {
|
||||
appPid = line.split(":").last().trimmed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (appPid.isEmpty()) {
|
||||
qWarning() << "can't find pid which corresponding with the instance of this application.";
|
||||
return {};
|
||||
}
|
||||
bool ok;
|
||||
auto pid = appPid.toUInt(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "AppId is failed to convert to uint.";
|
||||
auto pid = getPidFromPidFd(pidfd);
|
||||
if (pid == 0) {
|
||||
sendErrorReply(QDBusError::Failed, "pid is invalid");
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto ret = m_identifier->Identify(pid);
|
||||
|
||||
if (ret.ApplicationId.isEmpty()) {
|
||||
qInfo() << "Identify failed.";
|
||||
sendErrorReply(QDBusError::Failed, "Identify failed.");
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -436,14 +418,14 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
|
||||
});
|
||||
|
||||
if (app == m_applicationList.cend()) {
|
||||
qWarning() << "can't find application:" << ret.ApplicationId;
|
||||
sendErrorReply(QDBusError::Failed, "can't find application:" % ret.ApplicationId);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto instancePath = (*app)->findInstance(ret.InstanceId);
|
||||
|
||||
if (auto path = instancePath.path(); path.isEmpty()) {
|
||||
qWarning() << "can't find instance:" << path;
|
||||
sendErrorReply(QDBusError::Failed, "can't find instance:" % path);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -457,7 +439,6 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
|
||||
void ApplicationManager1Service::updateApplication(const QSharedPointer<ApplicationService> &destApp,
|
||||
DesktopFile desktopFile) noexcept
|
||||
{
|
||||
// TODO: add propertyChanged
|
||||
if (auto app = m_applicationList.find(destApp->applicationPath()); app == m_applicationList.cend()) {
|
||||
return;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
class ApplicationService;
|
||||
|
||||
class ApplicationManager1Service final : public QObject, public QDBusContext
|
||||
class ApplicationManager1Service final : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -43,6 +43,7 @@ public:
|
||||
findApplicationsByIds(const QStringList &appIds) const noexcept;
|
||||
void updateApplication(const QSharedPointer<ApplicationService> &destApp, DesktopFile desktopFile) noexcept;
|
||||
|
||||
[[nodiscard]] const auto &Applications() const noexcept { return m_applicationList; }
|
||||
[[nodiscard]] JobManager1Service &jobManager() noexcept { return *m_jobManager; }
|
||||
[[nodiscard]] const JobManager1Service &jobManager() const noexcept { return *m_jobManager; }
|
||||
[[nodiscard]] const QStringList &applicationHooks() const noexcept { return m_hookElements; }
|
||||
|
@ -928,6 +928,12 @@ QVariant ApplicationService::findEntryValue(const QString &group,
|
||||
bool ok{false};
|
||||
|
||||
switch (type) {
|
||||
case EntryValueType::Raw: {
|
||||
auto valStr = val.toString();
|
||||
if (!valStr.isEmpty()) {
|
||||
ret = QVariant::fromValue(valStr);
|
||||
}
|
||||
} break;
|
||||
case EntryValueType::String: {
|
||||
auto valStr = toString(val);
|
||||
if (!valStr.isEmpty()) {
|
||||
|
@ -28,7 +28,7 @@
|
||||
QString getDeepinWineScaleFactor(const QString &appId) noexcept;
|
||||
double getScaleFactor() noexcept;
|
||||
|
||||
class ApplicationService : public QObject, public QDBusContext
|
||||
class ApplicationService : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -118,6 +118,10 @@ public:
|
||||
}
|
||||
void resetEntry(DesktopEntry *newEntry) noexcept;
|
||||
void detachAllInstance() noexcept;
|
||||
[[nodiscard]] QVariant findEntryValue(const QString &group,
|
||||
const QString &valueKey,
|
||||
EntryValueType type,
|
||||
const QLocale &locale = getUserLocale()) const noexcept;
|
||||
|
||||
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields) noexcept;
|
||||
[[nodiscard]] static QStringList unescapeExecArgs(const QString &str) noexcept;
|
||||
@ -168,10 +172,6 @@ private:
|
||||
DesktopFile m_desktopSource;
|
||||
QSharedPointer<DesktopEntry> m_entry{nullptr};
|
||||
QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
|
||||
[[nodiscard]] QVariant findEntryValue(const QString &group,
|
||||
const QString &valueKey,
|
||||
EntryValueType type,
|
||||
const QLocale &locale = getUserLocale()) const noexcept;
|
||||
void updateAfterLaunch(bool isLaunch) noexcept;
|
||||
static bool shouldBeShown(const std::unique_ptr<DesktopEntry> &entry) noexcept;
|
||||
[[nodiscard]] bool autostartCheck(const QString &linkPath) const noexcept;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
class ApplicationManager1Service;
|
||||
|
||||
class MimeManager1Service : public QObject, public QDBusContext
|
||||
class MimeManager1Service : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
111
src/dbus/processguesser1service.cpp
Normal file
111
src/dbus/processguesser1service.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "processguesser1adaptor.h"
|
||||
#include "applicationservice.h"
|
||||
#include "global.h"
|
||||
|
||||
ProcessGuesser1Service::ProcessGuesser1Service(QDBusConnection &connection, ApplicationManager1Service *parent) noexcept
|
||||
: QObject(parent)
|
||||
{
|
||||
if (!connection.registerService("org.desktopspec.ProcessGuesser1")) {
|
||||
qFatal("%s", connection.lastError().message().toLocal8Bit().data());
|
||||
}
|
||||
|
||||
if (auto *tmp = new (std::nothrow) ProcessGuesser1Adaptor{this}; tmp == nullptr) {
|
||||
qFatal("new Process Guesser Adaptor failed.");
|
||||
}
|
||||
|
||||
if (!registerObjectToDBus(this, "/org/desktopspec/ProcessGuesser1", "org.desktopspec.ProcessGuesser1")) {
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessGuesser1Service::checkTryExec(QString tryExec) noexcept
|
||||
{
|
||||
if (!tryExec.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo exeBin{tryExec};
|
||||
if (!exeBin.isAbsolute()) {
|
||||
tryExec = QStandardPaths::findExecutable(tryExec);
|
||||
}
|
||||
|
||||
if (!tryExec.isEmpty()) {
|
||||
exeBin.setFile(tryExec);
|
||||
if (!exeBin.exists() or !exeBin.isFile() or !exeBin.isExecutable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ProcessGuesser1Service::GuessApplicationId(const QDBusUnixFileDescriptor &pidfd) noexcept
|
||||
{
|
||||
if (!pidfd.isValid()) {
|
||||
sendErrorReply(QDBusError::InvalidArgs);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pid = getPidFromPidFd(pidfd);
|
||||
if (pid == 0) {
|
||||
sendErrorReply(QDBusError::Failed, "Pid is invalid");
|
||||
return {};
|
||||
}
|
||||
|
||||
QString exePath = QString{"/proc/%1/exe"}.arg(pid);
|
||||
QFileInfo info{exePath};
|
||||
|
||||
if (!info.exists()) {
|
||||
sendErrorReply(QDBusError::Failed, "Pid is invalid.");
|
||||
return {};
|
||||
}
|
||||
const auto &binary = info.symLinkTarget();
|
||||
|
||||
const auto &applications = myParent()->Applications();
|
||||
QString appId;
|
||||
|
||||
for (const QSharedPointer<ApplicationService> &app : applications) {
|
||||
auto exec = app->findEntryValue(DesktopFileEntryKey, "Exec", EntryValueType::Raw).toString();
|
||||
if (exec.isEmpty()) { // NOTE: Exec is not required in desktop file.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto execList = ApplicationService::unescapeExecArgs(exec);
|
||||
if (execList.isEmpty()) {
|
||||
sendErrorReply(QDBusError::InternalError);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto execBin = execList.first();
|
||||
QFileInfo execInfo{execBin};
|
||||
if (!execInfo.isAbsolute()) {
|
||||
execBin = QStandardPaths::findExecutable(execBin);
|
||||
}
|
||||
|
||||
if (!execBin.isEmpty() and execBin == binary) {
|
||||
if (!appId.isEmpty()) {
|
||||
sendErrorReply(QDBusError::Failed, "Multiple binary have been detected.");
|
||||
return {};
|
||||
}
|
||||
appId = app->id();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto tryExec = app->findEntryValue(DesktopFileEntryKey, "TryExec", EntryValueType::String).toString();
|
||||
if (!checkTryExec(tryExec)) {
|
||||
sendErrorReply(QDBusError::Failed, "Couldn't find the binary which corresponding with process.");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (appId.isEmpty()) {
|
||||
sendErrorReply(QDBusError::Failed, "Couldn't found application.");
|
||||
return {};
|
||||
}
|
||||
|
||||
return appId;
|
||||
}
|
36
src/dbus/processguesser1service.h
Normal file
36
src/dbus/processguesser1service.h
Normal file
@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef PROCESSGUESSER1SERVICE_H
|
||||
#define PROCESSGUESSER1SERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusContext>
|
||||
#include <QDBusUnixFileDescriptor>
|
||||
#include "applicationmanager1service.h"
|
||||
|
||||
class ProcessGuesser1Service : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProcessGuesser1Service(QDBusConnection &connection, ApplicationManager1Service *parent) noexcept;
|
||||
~ProcessGuesser1Service() override = default;
|
||||
ProcessGuesser1Service(const ProcessGuesser1Service &) = delete;
|
||||
ProcessGuesser1Service(ProcessGuesser1Service &&) = delete;
|
||||
ProcessGuesser1Service &operator=(const ProcessGuesser1Service &) = delete;
|
||||
ProcessGuesser1Service &operator=(ProcessGuesser1Service &&) = delete;
|
||||
ApplicationManager1Service *myParent() { return dynamic_cast<ApplicationManager1Service *>(QObject::parent()); }
|
||||
[[nodiscard]] const ApplicationManager1Service *myParent() const
|
||||
{
|
||||
return dynamic_cast<ApplicationManager1Service *>(QObject::parent());
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
QString GuessApplicationId(const QDBusUnixFileDescriptor &pidfd) noexcept;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static bool checkTryExec(QString tryExec) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
@ -17,7 +17,7 @@
|
||||
|
||||
enum class EntryContext { Unknown, EntryOuter, Entry, Done };
|
||||
|
||||
enum class EntryValueType { String, LocaleString, Boolean, IconString };
|
||||
enum class EntryValueType { String, LocaleString, Boolean, IconString, Raw };
|
||||
|
||||
struct DesktopFileGuard;
|
||||
|
||||
|
35
src/global.h
35
src/global.h
@ -16,6 +16,7 @@
|
||||
#include <QDir>
|
||||
#include <QRegularExpression>
|
||||
#include <QDBusObjectPath>
|
||||
#include <QDBusUnixFileDescriptor>
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusMessage>
|
||||
#include <unistd.h>
|
||||
@ -576,4 +577,38 @@ inline QByteArray getCurrentSessionId()
|
||||
return id.value<QDBusVariant>().variant().toByteArray();
|
||||
}
|
||||
|
||||
inline uint getPidFromPidFd(const QDBusUnixFileDescriptor &pidfd) noexcept
|
||||
{
|
||||
QString fdFilePath = QString{"/proc/self/fdinfo/%1"}.arg(pidfd.fileDescriptor());
|
||||
QFile fdFile{fdFilePath};
|
||||
if (!fdFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
||||
qWarning() << "open " << fdFilePath << "failed: " << fdFile.errorString();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto content = fdFile.readAll();
|
||||
QTextStream stream{content};
|
||||
QString appPid;
|
||||
while (!stream.atEnd()) {
|
||||
auto line = stream.readLine();
|
||||
if (line.startsWith("Pid")) {
|
||||
appPid = line.split(":").last().trimmed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (appPid.isEmpty()) {
|
||||
qWarning() << "can't find pid which corresponding with the instance of this application.";
|
||||
return 0;
|
||||
}
|
||||
bool ok{false};
|
||||
auto pid = appPid.toUInt(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "AppId is failed to convert to uint.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user