File indexing completed on 2024-11-10 04:54:52
0001 /* 0002 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0003 SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org> 0004 */ 0005 0006 #include "NotifierTruck.h" 0007 0008 #include <chrono> 0009 0010 #include <QCoreApplication> 0011 #include <QFile> 0012 #include <QProcess> 0013 #include <QTimer> 0014 0015 #include <KNotification> 0016 #include <KTerminalLauncherJob> 0017 0018 #include "../coredump.h" 0019 0020 using namespace std::chrono_literals; 0021 0022 bool NotifyTruck::handle(const Coredump &dump) 0023 { 0024 if (!dump.m_rawData.value(dump.keyPickup()).isEmpty()) { 0025 // Pickups are currently not supported for notify handling. The problem is that we don't know if we already 0026 // notified on a crash or not because we have no persistent storage. To fix this we'd probably need to 0027 // rejigger things substantially and insert a pickup key into the journal that the processor can then look for. 0028 // Except then the processor needs to hold on to dumps until the entire journal is processed. All a bit awkward. 0029 return false; 0030 } 0031 0032 auto notification = new KNotification(QStringLiteral("applicationcrash")); 0033 0034 // immediate exit signal. This gets disconnected should `activated` arrive first (in that case we 0035 // want to wait for the terminal app to start and not exit on further notification signals) 0036 QObject::connect(notification, &KNotification::closed, this, [this, notification] { 0037 notification->disconnect(this); 0038 qApp->exit(0); 0039 }); 0040 0041 if (!QFile::exists(dump.filename)) { 0042 notification->setTitle(QStringLiteral("The warpcore has gone missing")); 0043 notification->setText(QStringLiteral("%1 [%2] crashed but has no core file").arg(dump.exe, QString::number(dump.pid))); 0044 } else { 0045 notification->setTitle(QStringLiteral("He's dead, Jim")); 0046 notification->setText(QStringLiteral("%1 [%2]").arg(dump.exe, QString::number(dump.pid))); 0047 auto gdbAction = notification->addAction(QStringLiteral("gdb")); 0048 0049 const auto pid = dump.pid; 0050 0051 connect(gdbAction, &KNotificationAction::activated, notification, [pid, this, notification]() { 0052 notification->disconnect(this); 0053 auto job = new KTerminalLauncherJob(QStringLiteral("coredumpctl gdb %1").arg(QString::number(pid)), this); 0054 job->setProcessEnvironment(QProcessEnvironment::systemEnvironment()); 0055 connect(job, &KJob::result, this, [job] { 0056 if (job->error() != KJob::NoError) { 0057 qWarning() << job->errorText(); 0058 } 0059 qApp->exit(0); 0060 }); 0061 job->start(); 0062 0063 // Just in case the launcher job bugs out also add a timer. 0064 auto startTimeout = new QTimer(this); 0065 startTimeout->setInterval(16s); 0066 connect(startTimeout, &QTimer::timeout, this, [] { 0067 qApp->exit(0); 0068 }); 0069 startTimeout->start(); 0070 }); 0071 } 0072 0073 notification->setFlags(KNotification::DefaultEvent | KNotification::SkipGrouping); 0074 notification->sendEvent(); 0075 0076 // KNotification internally depends on an eventloop to communicate over dbus. We therefore start the 0077 // eventloop here. ::handle() is expected to be blocking so this has no adverse effects. 0078 // The eventloop is either exited when the notification gets closed or when the debugger has started. 0079 qApp->exec(); 0080 return true; 0081 } 0082 0083 #include "moc_NotifierTruck.cpp"