// Copyright (C) 2023 The Qt Company Ltd. // Copyright (C) 2019 Luxoft Sweden AB // Copyright (C) 2018 Pelagicore AG // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #if defined(Q_OS_UNIX) # include #endif #include "dbuscontextadaptor.h" #include "applicationmanager.h" #include "applicationmanager_adaptor.h" #include "packagemanager.h" #include "dbuspolicy.h" #include "exception.h" #include "logging.h" #include "intentclient.h" #include "intentclientrequest.h" using namespace Qt::StringLiterals; //NOTE: The header for this class is autogenerated from the XML interface definition. // We are NOT using the generated cpp, but instead implement the adaptor manually. QT_USE_NAMESPACE_AM ApplicationManagerAdaptor::ApplicationManagerAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { auto am = ApplicationManager::instance(); connect(am, &ApplicationManager::countChanged, this, &ApplicationManagerAdaptor::countChanged); connect(am, &ApplicationManager::applicationAdded, this, &ApplicationManagerAdaptor::applicationAdded); connect(am, &ApplicationManager::applicationChanged, this, &ApplicationManagerAdaptor::applicationChanged); connect(am, &ApplicationManager::applicationAboutToBeRemoved, this, &ApplicationManagerAdaptor::applicationAboutToBeRemoved); connect(am, &ApplicationManager::applicationWasActivated, this, &ApplicationManagerAdaptor::applicationWasActivated); connect(am, &ApplicationManager::windowManagerCompositorReadyChanged, this, &ApplicationManagerAdaptor::windowManagerCompositorReadyChanged); // connect this signal via a lambda, since it needs a type conversion connect(am, &ApplicationManager::applicationRunStateChanged, this, [this](const QString &id, QtAM::Am::RunState runState) { emit applicationRunStateChanged(id, runState); }); } ApplicationManagerAdaptor::~ApplicationManagerAdaptor() { } int ApplicationManagerAdaptor::count() const { return ApplicationManager::instance()->count(); } bool ApplicationManagerAdaptor::dummy() const { return ApplicationManager::instance()->isDummy(); } bool ApplicationManagerAdaptor::securityChecksEnabled() const { return ApplicationManager::instance()->securityChecksEnabled(); } bool ApplicationManagerAdaptor::singleProcess() const { return ApplicationManager::instance()->isSingleProcess(); } QVariantMap ApplicationManagerAdaptor::systemProperties() const { return convertToDBusVariant(ApplicationManager::instance()->systemProperties()).toMap(); } bool ApplicationManagerAdaptor::windowManagerCompositorReady() const { return ApplicationManager::instance()->isWindowManagerCompositorReady(); } QStringList ApplicationManagerAdaptor::applicationIds() { QT_AM_AUTHENTICATE_DBUS(QStringList) return ApplicationManager::instance()->applicationIds(); } uint ApplicationManagerAdaptor::applicationRunState(const QString &id) { QT_AM_AUTHENTICATE_DBUS(uint) return ApplicationManager::instance()->applicationRunState(id); } QStringList ApplicationManagerAdaptor::capabilities(const QString &id) { QT_AM_AUTHENTICATE_DBUS(QStringList) return ApplicationManager::instance()->capabilities(id); } bool ApplicationManagerAdaptor::debugApplication(const QString &id, const QString &debugWrapper) { return debugApplication(id, debugWrapper, QString()); } bool ApplicationManagerAdaptor::debugApplication(const QString &id, const QString &debugWrapper, const QString &documentUrl) { return debugApplication(id, debugWrapper, UnixFdMap(), documentUrl); } bool ApplicationManagerAdaptor::debugApplication(const QString &id, const QString &debugWrapper, const QtAM::UnixFdMap &redirections, const QString &documentUrl) { QT_AM_AUTHENTICATE_DBUS(bool) QVector stdioRedirections = { -1, -1, -1 }; # if defined(Q_OS_UNIX) for (auto it = redirections.cbegin(); it != redirections.cend(); ++it) { QDBusUnixFileDescriptor dfd = it.value(); int fd = dfd.fileDescriptor(); const QString &which = it.key(); if (which == u"in") stdioRedirections[0] = dup(fd); else if (which == u"out") stdioRedirections[1] = dup(fd); else if (which == u"err") stdioRedirections[2] = dup(fd); } # else Q_UNUSED(redirections) # endif // defined(Q_OS_UNIX) auto am = ApplicationManager::instance(); try { return am->startApplicationInternal(id, documentUrl, QString(), debugWrapper, std::move(stdioRedirections)); } catch (const Exception &e) { qCWarning(LogSystem) << e.what(); if (auto *ctxt = DBusContextAdaptor::dbusContextFor(this)) ctxt->sendErrorReply(QDBusError::Failed, e.errorString()); return false; } } QVariantMap ApplicationManagerAdaptor::get(const QString &id) { QT_AM_AUTHENTICATE_DBUS(QVariantMap) auto map = ApplicationManager::instance()->get(id); map.remove(u"application"_s); // cannot marshall QObject * map.remove(u"applicationObject"_s); // cannot marshall QObject * return convertToDBusVariant(map).toMap(); } QString ApplicationManagerAdaptor::identifyApplication(qlonglong pid) { QT_AM_AUTHENTICATE_DBUS(QString) return ApplicationManager::instance()->identifyApplication(pid); } QStringList ApplicationManagerAdaptor::identifyAllApplications(qlonglong pid) { QT_AM_AUTHENTICATE_DBUS(QStringList) return ApplicationManager::instance()->identifyAllApplications(pid); } bool ApplicationManagerAdaptor::openUrl(const QString &url) { QT_AM_AUTHENTICATE_DBUS(bool) return ApplicationManager::instance()->openUrl(url); } bool ApplicationManagerAdaptor::startApplication(const QString &id) { return startApplication(id, QString()); } bool ApplicationManagerAdaptor::startApplication(const QString &id, const QString &documentUrl) { return startApplication(id, UnixFdMap(), documentUrl); } bool ApplicationManagerAdaptor::startApplication(const QString &id, const QtAM::UnixFdMap &redirections, const QString &documentUrl) { QT_AM_AUTHENTICATE_DBUS(bool) QVector stdioRedirections = { -1, -1, -1 }; # if defined(Q_OS_UNIX) for (auto it = redirections.cbegin(); it != redirections.cend(); ++it) { QDBusUnixFileDescriptor dfd = it.value(); int fd = dfd.fileDescriptor(); const QString &which = it.key(); if (which == u"in") stdioRedirections[0] = dup(fd); else if (which == u"out") stdioRedirections[1] = dup(fd); else if (which == u"err") stdioRedirections[2] = dup(fd); } # else Q_UNUSED(redirections) # endif // defined(Q_OS_UNIX) auto am = ApplicationManager::instance(); try { return am->startApplicationInternal(id, documentUrl, QString(), QString(), std::move(stdioRedirections)); } catch (const Exception &e) { qCWarning(LogSystem) << e.what(); if (auto *ctxt = DBusContextAdaptor::dbusContextFor(this)) ctxt->sendErrorReply(QDBusError::Failed, e.errorString()); return false; } } void ApplicationManagerAdaptor::stopAllApplications() { stopAllApplications(false); } void ApplicationManagerAdaptor::stopAllApplications(bool forceKill) { QT_AM_AUTHENTICATE_DBUS(void) ApplicationManager::instance()->stopAllApplications(forceKill); } void ApplicationManagerAdaptor::stopApplication(const QString &id) { stopApplication(id, false); } void ApplicationManagerAdaptor::stopApplication(const QString &id, bool forceKill) { QT_AM_AUTHENTICATE_DBUS(void) ApplicationManager::instance()->stopApplication(id, forceKill); } QString ApplicationManagerAdaptor::sendIntentRequestAs(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId, const QString &jsonParameters) { QT_AM_AUTHENTICATE_DBUS(QString) QDBusContext *dbusContext = DBusContextAdaptor::dbusContextFor(this); dbusContext->setDelayedReply(true); if (!PackageManager::instance()->developmentMode()) { dbusContext->sendErrorReply(QDBusError::Failed, u"Only supported if 'developmentMode' is active"_s); return { }; } if (intentId.isEmpty()) { dbusContext->sendErrorReply(QDBusError::Failed, u"intentId cannot be empty"_s); return { }; } QVariantMap parameters; if (!jsonParameters.trimmed().isEmpty()) { QJsonParseError parseError; auto jsDoc = QJsonDocument::fromJson(jsonParameters.toUtf8(), &parseError); if (jsDoc.isNull()) { dbusContext->sendErrorReply(QDBusError::Failed, u"jsonParameters is not a valid JSON document: "_s + parseError.errorString()); return { }; } parameters = jsDoc.toVariant().toMap(); } auto dbusMsg = new QDBusMessage(dbusContext->message()); auto dbusName = dbusContext->connection().name(); const QString reqAppId = requestingApplicationId.isEmpty() ? IntentClient::instance()->systemUiId() : requestingApplicationId; auto icr = IntentClient::instance()->requestToSystem(reqAppId, intentId, applicationId, parameters); icr->startTimeout(IntentClient::instance()->replyFromSystemTimeout()); // clang-code-model: this slot is always called (even on timeouts), so dbusMsg does not leak connect(icr, &IntentClientRequest::replyReceived, this, [icr, dbusMsg, dbusName]() { bool succeeded = icr->succeeded(); QDBusConnection conn(dbusName); if (succeeded) { auto jsonResult = QString::fromUtf8(QJsonDocument::fromVariant(icr->result()).toJson()); conn.send(dbusMsg->createReply(jsonResult)); } else { conn.send(dbusMsg->createErrorReply(QDBusError::Failed, icr->errorMessage())); } delete dbusMsg; icr->deleteLater(); }); return { }; } void ApplicationManagerAdaptor::broadcastIntentRequestAs(const QString &requestingApplicationId, const QString &intentId, const QString &jsonParameters) { QT_AM_AUTHENTICATE_DBUS(void) QDBusContext *dbusContext = DBusContextAdaptor::dbusContextFor(this); if (!PackageManager::instance()->developmentMode()) { dbusContext->sendErrorReply(QDBusError::Failed, u"Only supported if 'developmentMode' is active"_s); return; } if (intentId.isEmpty()) { dbusContext->sendErrorReply(QDBusError::Failed, u"intentId cannot be empty"_s); return; } QVariantMap parameters; if (!jsonParameters.trimmed().isEmpty()) { QJsonParseError parseError; auto jsDoc = QJsonDocument::fromJson(jsonParameters.toUtf8(), &parseError); if (jsDoc.isNull()) { dbusContext->sendErrorReply(QDBusError::Failed, u"jsonParameters is not a valid JSON document: "_s + parseError.errorString()); return; } parameters = jsDoc.toVariant().toMap(); } const QString reqAppId = requestingApplicationId.isEmpty() ? IntentClient::instance()->systemUiId() : requestingApplicationId; IntentClient::instance()->requestToSystem(reqAppId, intentId, u":broadcast:"_s, parameters); }