diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 1fa772a6..313bcc65 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -15,12 +15,14 @@ #include "systemdsignaldispatcher.h" #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -470,15 +472,36 @@ void ApplicationManager1Service::removeInstanceFromApplication(const QString &un if (instanceIt != appIns.cend()) { auto result = m_unitResults.take(systemdUnitPath.path()); qCDebug(DDEAM) << "removeInstance: unitPath=" << systemdUnitPath.path() << "cached result=" << result; - if (result == u"failed" || result == u"canceled" || result == u"timeout" - || result == u"signal" || result == u"core-dump" || result == u"exit-code") { - QStringList logArgs{QStringLiteral("--unit=%1").arg(unitName), - "-n", "20", "-o", "cat", "-o", "with-unit", "--no-pager"}; + + static const QSet launchFailedResults{u"start-limit-hit"_s, u"resources"_s, u"exec-condition"_s, u"protocol"_s, u"timeout"_s}; + + if (launchFailedResults.contains(result)) { + EventReporter::reportAppLaunchFailed(app->eventAppId(), + QStringLiteral("systemd result: %1").arg(result), + app->x_linglong(), + (*instanceIt)->launchType(), + (*instanceIt)->launchUniqueId()); + } else if (!result.isEmpty() && result != u"success"_s) { + QStringList logArgs{"--user", QStringLiteral("--unit=%1").arg(unitName), + "-p", "warning", "-n", "6", "-o", "cat", "-o", "with-unit", "--no-pager"}; QProcess logProc; logProc.start("journalctl", logArgs); - logProc.waitForFinished(3000); - QString logInfo = QString::fromUtf8(logProc.readAllStandardOutput()); - EventReporter::reportAppAbnormalExit(app->eventAppId(), (*instanceIt)->launchType(), unitName, logInfo, (*instanceIt)->launchUniqueId()); + QString logInfo; + if (!logProc.waitForStarted(1000)) { + qCWarning(DDEAM) << "journalctl failed to start for unit:" << unitName; + } else if (!logProc.waitForFinished(3000)) { + qCWarning(DDEAM) << "journalctl timeout for unit:" << unitName; + logProc.kill(); + } else { + logInfo = QString::fromUtf8(logProc.readAllStandardOutput()); + } + + EventReporter::reportAppAbnormalExit(app->eventAppId(), + (*instanceIt)->launchType(), + unitName, + logInfo, + app->x_linglong(), + (*instanceIt)->launchUniqueId()); } app->removeOneInstance(instanceIt.key()); diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index 2760d71c..c1eb1c6f 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -36,10 +36,16 @@ class UnitResultWatcher : public QObject public Q_SLOTS: void handlePropertyChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) { - if ((interface == QStringLiteral("org.freedesktop.systemd1.Unit") - || interface == QStringLiteral("org.freedesktop.systemd1.Service")) - && changed.contains(QStringLiteral("Result"))) { - emit resultReady(m_unitPath, changed.value(QStringLiteral("Result")).toString()); + if (interface != QStringLiteral("org.freedesktop.systemd1.Unit") + && interface != QStringLiteral("org.freedesktop.systemd1.Service")) { + return; + } + + if (auto it = changed.constFind(QStringLiteral("Result")); it != changed.constEnd()) { + auto result = it.value().toString(); + if (!result.isEmpty() && result != QStringLiteral("success")) { + emit resultReady(m_unitPath, result); + } } } diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 38302e7f..a1d01036 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -408,7 +408,6 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL }(); if (desktopEntry == nullptr) { - EventReporter::reportAppLaunchFailed(eventAppId(), EventReporter::getAppVersion(id()), "This application is not set to autostart.", launchType, launchUniqueId); safe_sendErrorReply(QDBusError::Failed, "This application is not set to autostart."); } @@ -438,7 +437,6 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL if (!Actions) { const QString msg{"application can't be executed."}; qWarning() << msg; - EventReporter::reportAppLaunchFailed(eventAppId(), EventReporter::getAppVersion(id()), msg, launchType, launchUniqueId); safe_sendErrorReply(QDBusError::Failed, msg); return {}; } @@ -447,23 +445,16 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL if (execStr.isEmpty()) { const QString msg{"maybe entry actions's format is invalid, abort launch."}; qWarning() << msg; - EventReporter::reportAppLaunchFailed(eventAppId(), EventReporter::getAppVersion(id()), msg, launchType, launchUniqueId); safe_sendErrorReply(QDBusError::Failed, msg); return {}; } } - if (execStr.contains("ll-cli")) { - if (auto args = splitExecArguments(execStr); args) { - auto runIdx = args->indexOf(u"run"_s); - if (runIdx >= 0 && runIdx + 1 < args->size()) { - setEventAppId(args->at(runIdx + 1)); - } - } + auto linglongAppId = X_linglongAppId(); + if (!linglongAppId.isEmpty()) { + setEventAppId(linglongAppId); } - EventReporter::getAppVersion(eventAppId()); - const bool isSingleton = findEntryValue(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryXDeepinSingleton), EntryValueType::Boolean) .toBool(); @@ -499,14 +490,12 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL auto cmds = generateCommand(optionsMap); auto task = processExec(execStr, fields, workingDir); if (!task) { - EventReporter::reportAppLaunchFailed(eventAppId(), EventReporter::getAppVersion(id()), "Invalid Command.", launchType, launchUniqueId); safe_sendErrorReply(QDBusError::InternalError, "Invalid Command."); return {}; } if (task.LaunchBin.isEmpty()) { qCritical() << "error command is detected, abort."; - EventReporter::reportAppLaunchFailed(eventAppId(), EventReporter::getAppVersion(id()), "error command is detected, abort.", launchType, launchUniqueId); safe_sendErrorReply(QDBusError::Failed); return {}; } @@ -521,7 +510,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL // Generate instance UUID early so splash and job lambda share the same id. auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128); - EventReporter::reportAppLaunch(eventAppId(), EventReporter::getAppVersion(eventAppId()), QDateTime::currentMSecsSinceEpoch(), launchType, launchUniqueId); + EventReporter::reportAppLaunch(eventAppId(), QDateTime::currentMSecsSinceEpoch(), x_linglong(), launchType, launchUniqueId); // Notify the compositor to show a splash screen (after validation passes). if (isAutostartLaunch) { @@ -546,7 +535,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL auto &jobManager = parent()->jobManager(); return jobManager.addJob( m_applicationPath.path(), - [this, task, instanceRandomUUID = std::move(instanceRandomUUID), cmds = std::move(cmds)]( + [this, task, instanceRandomUUID = std::move(instanceRandomUUID), cmds = std::move(cmds), launchType, launchUniqueId]( const QVariant &value) mutable -> QVariant { QStringList newCommands; const int estimatedSize = 6 + cmds.size() + task.command.size() + (value.isValid() ? 1 : 0); @@ -614,7 +603,11 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL auto exitCode = process.exitCode(); if (exitCode != 0) { qWarning() << "Launch Application Failed"; - EventReporter::reportAppLaunchFailed(eventAppId(), EventReporter::getAppVersion(eventAppId()), "app-launch-helper exited with code " + QString::number(exitCode), m_launchType, m_launchUniqueId); + EventReporter::reportAppLaunchFailed(eventAppId(), + QStringLiteral("app-launch-helper exited with code %1").arg(exitCode), + x_linglong(), + launchType, + launchUniqueId); return QDBusError::Failed; } @@ -799,6 +792,12 @@ bool ApplicationService::x_linglong() const noexcept return !val.isNull(); } +QString ApplicationService::X_linglongAppId() const noexcept +{ + auto val = findEntryValue(fromStaticRaw(DesktopFileEntryKey), u"X-linglong"_s, EntryValueType::String); + return val.isNull() ? QString{} : val.toString(); +} + QString ApplicationService::X_Deepin_Vendor() const noexcept { return findEntryValue(fromStaticRaw(DesktopFileEntryKey), u"X-Deepin-Vendor"_s, EntryValueType::String).toString(); @@ -1123,8 +1122,6 @@ bool ApplicationService::addOneInstance(const QString &instanceId, QVariant::fromValue(interfaces)); } - EventReporter::reportAppLaunchDuration(eventAppId(), EventReporter::getAppVersion(eventAppId()), QDateTime::currentMSecsSinceEpoch(), launchType, uniqueId); - return true; } diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index ce328954..e43efd9c 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -97,6 +97,8 @@ class ApplicationService : public QObject, protected QDBusContext Q_PROPERTY(bool X_linglong READ x_linglong NOTIFY x_linglongChanged) [[nodiscard]] bool x_linglong() const noexcept; + [[nodiscard]] QString X_linglongAppId() const noexcept; + Q_PROPERTY(QString X_Deepin_Vendor READ X_Deepin_Vendor) [[nodiscard]] QString X_Deepin_Vendor() const noexcept; diff --git a/src/eventreporter.cpp b/src/eventreporter.cpp index 38880340..9af4cd0a 100644 --- a/src/eventreporter.cpp +++ b/src/eventreporter.cpp @@ -21,80 +21,130 @@ QHash &versionCache() static QHash cache; return cache; } + +QHash &pakTypeCache() +{ + static QHash cache; + return cache; } -void EventReporter::reportAppLaunch(const QString &appName, const QString &appVersion, qint64 timeMs, const QString &launchType, const QString &uniqueID) +struct AppPackageInfo { + QString version; + QString pakType; +}; + +AppPackageInfo queryAppPackageInfo(const QString &appId, bool isLinglong) +{ + auto &vCache = versionCache(); + auto &pCache = pakTypeCache(); + + bool versionCached = vCache.contains(appId); + bool pakTypeCached = pCache.contains(appId); + if (versionCached && pakTypeCached) { + return {vCache.value(appId), pCache.value(appId)}; + } + + AppPackageInfo info{versionCached ? vCache.value(appId) : QString{}, + pakTypeCached ? pCache.value(appId) : QString{}}; + + qCDebug(amEventReporter) << "query package info for appId:" << appId; + + if (isLinglong) { + QProcess proc; + proc.start("ll-cli", {"info", appId}); + if (!proc.waitForStarted(1000)) { + qCWarning(amEventReporter) << "ll-cli failed to start for" << appId; + } else if (!proc.waitForFinished(1000)) { + qCWarning(amEventReporter) << "ll-cli timeout for" << appId; + proc.kill(); + } else if (proc.exitCode() == 0) { + auto doc = QJsonDocument::fromJson(proc.readAllStandardOutput()); + if (doc.isObject()) { + info.version = doc.object().value("version").toString(); + } + info.pakType = "linglong"; + } else { + qCWarning(amEventReporter) << "ll-cli query failed for" << appId << "exitCode:" << proc.exitCode(); + } + } else { + QProcess proc; + proc.start("dpkg-query", {"-W", "-f=${Version}", appId}); + if (!proc.waitForStarted(1000)) { + qCWarning(amEventReporter) << "dpkg-query failed to start for" << appId; + } else if (!proc.waitForFinished(1000)) { + qCWarning(amEventReporter) << "dpkg-query timeout for" << appId; + proc.kill(); + } else if (proc.exitCode() == 0) { + info.version = QString::fromUtf8(proc.readAllStandardOutput()).trimmed(); + info.pakType = "deb"; + } else { + qCWarning(amEventReporter) << "dpkg-query failed for" << appId << "exitCode:" << proc.exitCode(); + } + } + + if (info.pakType.isEmpty()) { + info.pakType = "unknown"; + } + + vCache.insert(appId, info.version); + pCache.insert(appId, info.pakType); + + return info; +} +} + +void EventReporter::reportAppLaunch(const QString &appName, qint64 timeMs, bool isLinglong, const QString &launchType, const QString &uniqueID) { #ifdef HAVE_DDE_API_EVENTLOGGER + auto info = queryAppPackageInfo(appName, isLinglong); DDE_EventLogger::EventLogger::instance().writeEventLog({ 1000610001, appName, QJsonObject{ {"app_name", appName}, {"launch_type", launchType}, - {"app_version", appVersion}, + {"app_version", info.version}, {"unique_id", uniqueID}, {"time", timeMs}, + {"app_package_type", info.pakType}, }, }); #else Q_UNUSED(appName) - Q_UNUSED(appVersion) Q_UNUSED(timeMs) Q_UNUSED(launchType) Q_UNUSED(uniqueID) #endif } -void EventReporter::reportAppLaunchFailed(const QString &appName, const QString &appVersion, const QString &errors, const QString &launchType, const QString &uniqueID) +void EventReporter::reportAppLaunchFailed(const QString &appName, const QString &errors, bool isLinglong, const QString &launchType, const QString &uniqueID) { #ifdef HAVE_DDE_API_EVENTLOGGER + auto info = queryAppPackageInfo(appName, isLinglong); DDE_EventLogger::EventLogger::instance().writeEventLog({ 1000610002, appName, QJsonObject{ {"app_name", appName}, {"launch_type", launchType}, - {"app_version", appVersion}, + {"app_version", info.version}, {"unique_id", uniqueID}, {"errors", errors}, + {"app_package_type", info.pakType}, }, }); #else Q_UNUSED(appName) - Q_UNUSED(appVersion) Q_UNUSED(errors) Q_UNUSED(launchType) Q_UNUSED(uniqueID) #endif } -void EventReporter::reportAppLaunchDuration(const QString &appName, const QString &appVersion, qint64 timeMs, const QString &launchType, const QString &uniqueID) -{ -#ifdef HAVE_DDE_API_EVENTLOGGER - DDE_EventLogger::EventLogger::instance().writeEventLog({ - 1000610003, - appName, - QJsonObject{ - {"app_name", appName}, - {"launch_type", launchType}, - {"app_version", appVersion}, - {"unique_id", uniqueID}, - {"time", timeMs}, - }, - }); -#else - Q_UNUSED(appName) - Q_UNUSED(appVersion) - Q_UNUSED(timeMs) - Q_UNUSED(launchType) - Q_UNUSED(uniqueID) -#endif -} - -void EventReporter::reportAppAbnormalExit(const QString &appName, const QString &launchType, const QString &exec, const QString &logInfo, const QString &uniqueID) +void EventReporter::reportAppAbnormalExit(const QString &appName, const QString &launchType, const QString &exec, const QString &logInfo, bool isLinglong, const QString &uniqueID) { #ifdef HAVE_DDE_API_EVENTLOGGER + auto info = queryAppPackageInfo(appName, isLinglong); DDE_EventLogger::EventLogger::instance().writeEventLog({ 1000600012, appName, @@ -104,6 +154,7 @@ void EventReporter::reportAppAbnormalExit(const QString &appName, const QString {"unique_id", uniqueID}, {"exec", exec}, {"log", logInfo}, + {"app_package_type", info.pakType}, }, }); #else @@ -114,37 +165,3 @@ void EventReporter::reportAppAbnormalExit(const QString &appName, const QString Q_UNUSED(uniqueID) #endif } - -QString EventReporter::getAppVersion(const QString &appId) -{ - auto &cache = versionCache(); - if (auto it = cache.constFind(appId); it != cache.constEnd()) { - return it.value(); - } - - qCDebug(amEventReporter) << "query version for appId:" << appId; - QProcess proc; - proc.start("dpkg-query", {"-W", "-f=${Version}", appId}); - proc.waitForFinished(3000); - QString version; - if (proc.exitCode() == 0) { - version = QString::fromUtf8(proc.readAllStandardOutput()).trimmed(); - } - - if (version.isEmpty() && appId.startsWith("org.")) { - proc.start("ll-cli", {"info", appId}); - proc.waitForFinished(5000); - if (proc.exitCode() == 0) { - auto doc = QJsonDocument::fromJson(proc.readAllStandardOutput()); - if (doc.isObject()) { - version = doc.object().value("version").toString(); - } - } - } - - if (!version.isEmpty()) { - cache.insert(appId, version); - } - - return version; -} diff --git a/src/eventreporter.h b/src/eventreporter.h index 20c30f84..544c4cb4 100644 --- a/src/eventreporter.h +++ b/src/eventreporter.h @@ -8,10 +8,7 @@ #include namespace EventReporter { -void reportAppLaunch(const QString &appName, const QString &appVersion, qint64 timeMs, const QString &launchType = {}, const QString &uniqueID = {}); -void reportAppLaunchFailed(const QString &appName, const QString &appVersion, const QString &errors, const QString &launchType = {}, const QString &uniqueID = {}); -void reportAppLaunchDuration(const QString &appName, const QString &appVersion, qint64 timeMs, const QString &launchType = {}, const QString &uniqueID = {}); -void reportAppAbnormalExit(const QString &appName, const QString &launchType, const QString &exec, const QString &logInfo, const QString &uniqueID = {}); - -QString getAppVersion(const QString &appId); +void reportAppLaunch(const QString &appName, qint64 timeMs, bool isLinglong, const QString &launchType = {}, const QString &uniqueID = {}); +void reportAppLaunchFailed(const QString &appName, const QString &errors, bool isLinglong, const QString &launchType = {}, const QString &uniqueID = {}); +void reportAppAbnormalExit(const QString &appName, const QString &launchType, const QString &exec, const QString &logInfo, bool isLinglong, const QString &uniqueID = {}); }