feat: add property Launcher, Orphaned

refactor some method which are related with systemd unit

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe 2023-09-13 16:52:53 +08:00 committed by Comix
parent 23dcd13f10
commit bc7fbfb3a1
14 changed files with 168 additions and 82 deletions

View File

@ -25,5 +25,21 @@
if this instance is not managed by systemd." if this instance is not managed by systemd."
/> />
</property> </property>
<property name="Launcher" type="s" access="read">
<annotation
name="org.freedesktop.DBus.Description"
value="This property indicates which Application
launcher started this instance."
/>
</property>
<property name="Orphaned" type="b" access="read">
<annotation
name="org.freedesktop.DBus.Description"
value="This property indicates that the application
to which the instance belonged has been removed."
/>
</property>
</interface> </interface>
</node> </node>

View File

@ -19,7 +19,7 @@ IdentifyRet CGroupsIdentifier::Identify(pid_t pid)
auto UnitStr = parseCGroupsPath(AppCgroupFile); auto UnitStr = parseCGroupsPath(AppCgroupFile);
auto [appId, InstanceId] = processUnitName(UnitStr); auto [appId, launcher, InstanceId] = processUnitName(UnitStr);
return {std::move(appId), std::move(InstanceId)}; return {std::move(appId), std::move(InstanceId)};
} }

View File

@ -103,9 +103,11 @@ void ApplicationManager1Service::addInstanceToApplication(const QString &unitNam
return; return;
} }
auto pair = processUnitName(unitName); auto info = processUnitName(unitName);
auto appId = pair.first; auto appId = std::move(info.applicationID);
auto instanceId = pair.second; auto launcher = std::move(info.Launcher);
auto instanceId = std::move(info.instanceID);
if (appId.isEmpty()) { if (appId.isEmpty()) {
return; return;
} }
@ -132,7 +134,7 @@ void ApplicationManager1Service::addInstanceToApplication(const QString &unitNam
const auto &applicationPath = (*appIt)->applicationPath().path(); const auto &applicationPath = (*appIt)->applicationPath().path();
if (!(*appIt)->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) [[likely]] { if (!(*appIt)->addOneInstance(instanceId, applicationPath, systemdUnitPath.path(), launcher)) [[likely]] {
qCritical() << "add Instance failed:" << applicationPath << unitName << systemdUnitPath.path(); qCritical() << "add Instance failed:" << applicationPath << unitName << systemdUnitPath.path();
} }
} }
@ -143,9 +145,11 @@ void ApplicationManager1Service::removeInstanceFromApplication(const QString &un
return; return;
} }
auto pair = processUnitName(unitName); auto info = processUnitName(unitName);
auto appId = pair.first; auto appId = std::move(info.applicationID);
auto instanceId = pair.second; auto launcher = std::move(info.Launcher);
auto instanceId = std::move(info.instanceID);
if (appId.isEmpty()) { if (appId.isEmpty()) {
return; return;
} }
@ -163,12 +167,17 @@ void ApplicationManager1Service::removeInstanceFromApplication(const QString &un
auto instanceIt = auto instanceIt =
std::find_if(appIns.cbegin(), appIns.cend(), [&systemdUnitPath](const QSharedPointer<InstanceService> &value) { std::find_if(appIns.cbegin(), appIns.cend(), [&systemdUnitPath](const QSharedPointer<InstanceService> &value) {
return value->systemdUnitPath() == systemdUnitPath; return value->property("SystemdUnitPath") == systemdUnitPath;
}); });
if (instanceIt != appIns.cend()) [[likely]] { if (instanceIt != appIns.cend()) [[likely]] {
(*appIt)->removeOneInstance(instanceIt.key()); (*appIt)->removeOneInstance(instanceIt.key());
return;
} }
orphanedInstances->removeIf([&systemdUnitPath](const QSharedPointer<InstanceService> &ptr) {
return (ptr->property("SystemdUnitPath").value<QDBusObjectPath>() == systemdUnitPath);
});
} }
void ApplicationManager1Service::scanApplications() noexcept void ApplicationManager1Service::scanApplications() noexcept
@ -357,28 +366,28 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
} }
void ApplicationManager1Service::updateApplication(const QSharedPointer<ApplicationService> &destApp, void ApplicationManager1Service::updateApplication(const QSharedPointer<ApplicationService> &destApp,
const DesktopFile &desktopFile) noexcept DesktopFile desktopFile) noexcept
{ {
// TODO: add propertyChanged // TODO: add propertyChanged
if (auto app = m_applicationList.find(destApp->applicationPath()); app == m_applicationList.cend()) { if (auto app = m_applicationList.find(destApp->applicationPath()); app == m_applicationList.cend()) {
return; return;
} }
auto timeInfo = getFileTimeInfo(QFileInfo{desktopFile.sourceFileRef()}); auto *newEntry = new (std::nothrow) DesktopEntry{};
if (newEntry == nullptr) {
qCritical() << "new DesktopEntry failed.";
return;
}
if (destApp->desktopFileSource().modified(timeInfo.mtime)) { auto err = newEntry->parse(desktopFile);
auto *newEntry = new (std::nothrow) DesktopEntry{}; if (err != DesktopErrorCode::NoError) {
if (newEntry == nullptr) { qWarning() << "update desktop file failed:" << err << ", content wouldn't change.";
qCritical() << "new DesktopEntry failed."; return;
return; }
}
auto err = newEntry->parse(destApp->desktopFileSource()); if (destApp->m_entry != newEntry) {
if (err != DesktopErrorCode::NoError) {
qWarning() << "update desktop file failed:" << err << ", content wouldn't change.";
return;
}
destApp->resetEntry(newEntry); destApp->resetEntry(newEntry);
destApp->m_desktopSource = std::move(desktopFile);
} }
} }
@ -407,9 +416,9 @@ void ApplicationManager1Service::ReloadApplications()
return false; return false;
} }
if (destApp != m_applicationList.cend()) { if (destApp != m_applicationList.cend() and apps.contains(destApp.key())) {
apps.removeOne(destApp.key()); apps.removeOne(destApp.key());
updateApplication(destApp.value(), file); updateApplication(destApp.value(), std::move(file));
return false; return false;
} }

View File

@ -39,7 +39,7 @@ public:
void removeOneApplication(const QDBusObjectPath &application) noexcept; void removeOneApplication(const QDBusObjectPath &application) noexcept;
void removeAllApplication() noexcept; void removeAllApplication() noexcept;
void updateApplication(const QSharedPointer<ApplicationService> &destApp, const DesktopFile &desktopFile) noexcept; void updateApplication(const QSharedPointer<ApplicationService> &destApp, DesktopFile desktopFile) noexcept;
JobManager1Service &jobManager() noexcept { return *m_jobManager; } JobManager1Service &jobManager() noexcept { return *m_jobManager; }

View File

@ -34,10 +34,8 @@ ApplicationService::ApplicationService(DesktopFile source,
ApplicationService::~ApplicationService() ApplicationService::~ApplicationService()
{ {
for (auto &instance : m_Instances.values()) { for (auto &instance : m_Instances.values()) {
instance->m_Application = QDBusObjectPath{"/"}; orphanedInstances->append(instance);
auto *ptr = instance.get(); instance->m_orphaned = true;
instance.reset(nullptr);
ptr->setParent(qApp); // detach all instances to qApp
} }
} }
@ -465,9 +463,12 @@ QList<QDBusObjectPath> ApplicationService::instances() const noexcept
return m_Instances.keys(); return m_Instances.keys();
} }
bool ApplicationService::addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath) bool ApplicationService::addOneInstance(const QString &instanceId,
const QString &application,
const QString &systemdUnitPath,
const QString &launcher)
{ {
auto *service = new InstanceService{instanceId, application, systemdUnitPath}; auto *service = new InstanceService{instanceId, application, systemdUnitPath, launcher};
auto *adaptor = new InstanceAdaptor(service); auto *adaptor = new InstanceAdaptor(service);
QString objectPath{m_applicationPath.path() + "/" + instanceId}; QString objectPath{m_applicationPath.path() + "/" + instanceId};

View File

@ -86,7 +86,10 @@ public:
[[nodiscard]] const QString &getLauncher() const noexcept { return m_launcher; } [[nodiscard]] const QString &getLauncher() const noexcept { return m_launcher; }
void setLauncher(const QString &launcher) noexcept { m_launcher = launcher; } void setLauncher(const QString &launcher) noexcept { m_launcher = launcher; }
bool addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath); bool addOneInstance(const QString &instanceId,
const QString &application,
const QString &systemdUnitPath,
const QString &launcher);
void recoverInstances(const QList<QDBusObjectPath> &instanceList) noexcept; void recoverInstances(const QList<QDBusObjectPath> &instanceList) noexcept;
void removeOneInstance(const QDBusObjectPath &instance) noexcept; void removeOneInstance(const QDBusObjectPath &instance) noexcept;
void removeAllInstance() noexcept; void removeAllInstance() noexcept;

View File

@ -3,22 +3,14 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
#include "dbus/instanceservice.h" #include "dbus/instanceservice.h"
#include <QCoreApplication>
InstanceService::InstanceService(QString instanceId, QString application, QString systemdUnitPath) InstanceService::InstanceService(QString instanceId, QString application, QString systemdUnitPath, QString launcher)
: m_instanceId(std::move(instanceId)) : m_Launcher(std::move(launcher))
, m_instanceId(std::move(instanceId))
, m_Application(std::move(application)) , m_Application(std::move(application))
, m_SystemdUnitPath(std::move(systemdUnitPath)) , m_SystemdUnitPath(std::move(systemdUnitPath))
{ {
} }
InstanceService::~InstanceService() = default; InstanceService::~InstanceService() = default;
QDBusObjectPath InstanceService::application() const
{
return m_Application;
}
QDBusObjectPath InstanceService::systemdUnitPath() const
{
return m_SystemdUnitPath;
}

View File

@ -18,20 +18,23 @@ public:
InstanceService &operator=(const InstanceService &) = delete; InstanceService &operator=(const InstanceService &) = delete;
InstanceService &operator=(InstanceService &&) = delete; InstanceService &operator=(InstanceService &&) = delete;
Q_PROPERTY(QDBusObjectPath Application READ application) Q_PROPERTY(QDBusObjectPath Application MEMBER m_Application)
[[nodiscard]] QDBusObjectPath application() const; Q_PROPERTY(QDBusObjectPath SystemdUnitPath MEMBER m_SystemdUnitPath)
Q_PROPERTY(QString Launcher MEMBER m_Launcher)
Q_PROPERTY(QDBusObjectPath SystemdUnitPath READ systemdUnitPath) Q_PROPERTY(bool Orphaned MEMBER m_orphaned)
[[nodiscard]] QDBusObjectPath systemdUnitPath() const;
[[nodiscard]] const QString &instanceId() const noexcept { return m_instanceId; } [[nodiscard]] const QString &instanceId() const noexcept { return m_instanceId; }
private: private:
friend class ApplicationService; friend class ApplicationService;
InstanceService(QString instanceId, QString application, QString systemdUnitPath); InstanceService(QString instanceId, QString application, QString systemdUnitPath, QString launcher);
bool m_orphaned{false};
QString m_Launcher;
QString m_instanceId; QString m_instanceId;
QDBusObjectPath m_Application; QDBusObjectPath m_Application;
QDBusObjectPath m_SystemdUnitPath; QDBusObjectPath m_SystemdUnitPath;
}; };
Q_GLOBAL_STATIC(QList<QSharedPointer<InstanceService>>, orphanedInstances)
#endif #endif

View File

@ -369,7 +369,7 @@ bool DesktopFile::modified(qint64 time) const noexcept
return time != m_mtime; return time != m_mtime;
} }
DesktopErrorCode DesktopEntry::parse(DesktopFile &file) noexcept DesktopErrorCode DesktopEntry::parse(const DesktopFile &file) noexcept
{ {
DesktopFileGuard guard{file}; DesktopFileGuard guard{file};
@ -538,6 +538,24 @@ float DesktopEntry::Value::toNumeric(bool &ok) const noexcept
return v.toFloat(&ok); return v.toFloat(&ok);
} }
bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs)
{
if (lhs.m_parsed != rhs.m_parsed) {
return false;
}
if (lhs.m_entryMap != rhs.m_entryMap) {
return false;
}
return true;
}
bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs)
{
return !(lhs == rhs);
}
QDebug operator<<(QDebug debug, const DesktopEntry::Value &v) QDebug operator<<(QDebug debug, const DesktopEntry::Value &v)
{ {
QDebugStateSaver saver{debug}; QDebugStateSaver saver{debug};

View File

@ -80,7 +80,7 @@ struct DesktopFileGuard
DesktopFileGuard &operator=(const DesktopFileGuard &) = delete; DesktopFileGuard &operator=(const DesktopFileGuard &) = delete;
DesktopFileGuard &operator=(DesktopFileGuard &&) = delete; DesktopFileGuard &operator=(DesktopFileGuard &&) = delete;
explicit DesktopFileGuard(DesktopFile &file) explicit DesktopFileGuard(const DesktopFile &file)
: fileRef(file) : fileRef(file)
{ {
} }
@ -107,7 +107,7 @@ struct DesktopFileGuard
} }
private: private:
DesktopFile &fileRef; const DesktopFile &fileRef;
}; };
class DesktopEntry class DesktopEntry
@ -135,11 +135,14 @@ public:
DesktopEntry &operator=(DesktopEntry &&) = default; DesktopEntry &operator=(DesktopEntry &&) = default;
~DesktopEntry() = default; ~DesktopEntry() = default;
[[nodiscard]] DesktopErrorCode parse(DesktopFile &file) noexcept; [[nodiscard]] DesktopErrorCode parse(const DesktopFile &file) noexcept;
[[nodiscard]] DesktopErrorCode parse(QTextStream &stream) noexcept; [[nodiscard]] DesktopErrorCode parse(QTextStream &stream) noexcept;
[[nodiscard]] std::optional<QMap<QString, Value>> group(const QString &key) const noexcept; [[nodiscard]] std::optional<QMap<QString, Value>> group(const QString &key) const noexcept;
[[nodiscard]] std::optional<Value> value(const QString &key, const QString &valueKey) const noexcept; [[nodiscard]] std::optional<Value> value(const QString &key, const QString &valueKey) const noexcept;
friend bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs);
friend bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs);
private: private:
[[nodiscard]] bool checkMainEntryValidation() const noexcept; [[nodiscard]] bool checkMainEntryValidation() const noexcept;
QMap<QString, QMap<QString, Value>> m_entryMap; QMap<QString, QMap<QString, Value>> m_entryMap;
@ -150,4 +153,8 @@ QDebug operator<<(QDebug debug, const DesktopEntry::Value &v);
QDebug operator<<(QDebug debug, const DesktopErrorCode &v); QDebug operator<<(QDebug debug, const DesktopErrorCode &v);
bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs);
bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs);
#endif #endif

View File

@ -233,11 +233,13 @@ inline QString getDBusInterface(const QMetaType &meta)
if (name == "APPObjectManagerAdaptor" or name == "AMObjectManagerAdaptor") { if (name == "APPObjectManagerAdaptor" or name == "AMObjectManagerAdaptor") {
return ObjectManagerInterface; return ObjectManagerInterface;
} }
// const auto *infoObject = meta.metaObject();
// if (auto infoIndex = infoObject->indexOfClassInfo("D-Bus Interface"); infoIndex != -1) { if (name == "ApplicationManager1Service")
// return infoObject->classInfo(infoIndex).value(); // const auto *infoObject = meta.metaObject();
// } // if (auto infoIndex = infoObject->indexOfClassInfo("D-Bus Interface"); infoIndex != -1) {
qWarning() << "couldn't found interface:" << name; // return infoObject->classInfo(infoIndex).value();
// }
qWarning() << "couldn't found interface:" << name;
return ""; return "";
} }
@ -425,31 +427,48 @@ inline bool isApplication(const QDBusObjectPath &path)
return path.path().split('/').last().startsWith("app"); return path.path().split('/').last().startsWith("app");
} }
inline QPair<QString, QString> processUnitName(const QString &unitName) struct unitInfo
{
QString applicationID;
QString Launcher;
QString instanceID;
};
inline unitInfo processUnitName(const QString &unitName)
{ {
QString instanceId; QString instanceId;
QString launcher;
QString applicationId; QString applicationId;
if (unitName.endsWith(".service")) { decltype(auto) appPrefix = u8"app-";
auto lastDotIndex = unitName.lastIndexOf('.'); auto unit = unitName.sliced(sizeof(appPrefix) - 1);
auto app = unitName.sliced(0, lastDotIndex); // remove suffix
if (unit.endsWith(".service")) {
auto lastDotIndex = unit.lastIndexOf('.');
auto app = unit.sliced(0, lastDotIndex); // remove suffix
if (app.contains('@')) { if (app.contains('@')) {
auto atIndex = app.indexOf('@'); auto atIndex = app.indexOf('@');
instanceId = app.sliced(atIndex + 1); instanceId = app.sliced(atIndex + 1);
app.remove(atIndex, instanceId.length() + 1); app.remove(atIndex, instanceId.length() + 1);
} }
auto rest = app.split('-', Qt::SkipEmptyParts);
applicationId = app.split('-').last(); // drop launcher if it exists. if (rest.size() == 2) {
} else if (unitName.endsWith(".scope")) { launcher = rest.takeFirst();
auto lastDotIndex = unitName.lastIndexOf('.'); }
auto app = unitName.sliced(0, lastDotIndex); applicationId = rest.takeFirst();
} else if (unit.endsWith(".scope")) {
auto lastDotIndex = unit.lastIndexOf('.');
auto app = unit.sliced(0, lastDotIndex);
auto components = app.split('-'); auto components = app.split('-');
instanceId = components.takeLast(); instanceId = components.takeLast();
applicationId = components.takeLast(); applicationId = components.takeLast();
if (!components.isEmpty()) {
launcher = components.takeLast();
}
} else { } else {
qDebug() << "it's not service or scope:" << unitName << "ignore"; qDebug() << "it's not service or scope:" << unit << "ignore";
return {}; return {};
} }
@ -457,7 +476,7 @@ inline QPair<QString, QString> processUnitName(const QString &unitName)
instanceId = QUuid::createUuid().toString(QUuid::Id128); instanceId = QUuid::createUuid().toString(QUuid::Id128);
} }
return qMakePair(unescapeApplicationId(applicationId), std::move(instanceId)); return {unescapeApplicationId(applicationId), std::move(launcher), std::move(instanceId)};
} }
template <typename T> template <typename T>

View File

@ -42,12 +42,32 @@ void PropertiesForwarder::PropertyChanged()
return; return;
} }
auto sig = mo->property(sigIndex + 1); auto sig = mo->method(sigIndex);
const auto *propName = sig.name(); auto signature = sig.methodSignature();
auto value = sig.read(sender);
QByteArray propName;
for (auto i = mo->propertyOffset(); i < mo->propertyCount(); ++i) {
auto prop = mo->property(i);
if (!prop.hasNotifySignal()) {
continue;
}
if (prop.notifySignal().methodSignature() == signature) {
propName = prop.name();
}
}
if (propName.isEmpty()) {
qDebug() << "can't find corresponding property:" << signature;
return;
}
auto propIndex = mo->indexOfProperty(propName.constData());
auto prop = mo->property(propIndex);
auto value = prop.read(sender);
auto childs = sender->children();
auto msg = QDBusMessage::createSignal(m_path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); auto msg = QDBusMessage::createSignal(m_path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
msg << QString{ApplicationInterface}; msg << QString{ApplicationInterface};
msg << QVariantMap{{QString{propName}, value}}; msg << QVariantMap{{QString{propName}, value}};
msg << QStringList{}; msg << QStringList{};

View File

@ -33,20 +33,18 @@ bool SystemdSignalDispatcher::connectToSignals() noexcept
void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath) void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath)
{ {
decltype(auto) appPrefix = u8"app-"; if (!unitName.startsWith("app-")) {
if (!unitName.startsWith(appPrefix)) {
return; return;
} }
emit SystemdUnitNew(unitName.sliced(sizeof(appPrefix) - 1), systemdUnitPath); emit SystemdUnitNew(unitName, systemdUnitPath);
} }
void SystemdSignalDispatcher::onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath) void SystemdSignalDispatcher::onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath)
{ {
decltype(auto) appPrefix = u8"app-"; if (!unitName.startsWith("app-")) {
if (!unitName.startsWith(appPrefix)) {
return; return;
} }
emit SystemdUnitRemoved(unitName.sliced(sizeof(appPrefix) - 1), systemdUnitPath); emit SystemdUnitRemoved(unitName, systemdUnitPath);
} }

View File

@ -38,8 +38,8 @@ public:
auto ptr = std::make_unique<QFile>(QString{"/usr/share/applications/test-Application.desktop"}); auto ptr = std::make_unique<QFile>(QString{"/usr/share/applications/test-Application.desktop"});
DesktopFile file{std::move(ptr), "test-Application", 0, 0}; DesktopFile file{std::move(ptr), "test-Application", 0, 0};
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file), nullptr, tmp); QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file), nullptr, tmp);
QSharedPointer<InstanceService> instance = QSharedPointer<InstanceService> instance = QSharedPointer<InstanceService>::create(
QSharedPointer<InstanceService>::create(InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}); InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}, QString{"DDE"});
app->m_Instances.insert(InstancePath, instance); app->m_Instances.insert(InstancePath, instance);
m_am->m_applicationList.insert(ApplicationPath, app); m_am->m_applicationList.insert(ApplicationPath, app);
} }