File indexing completed on 2024-12-08 10:52:35

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     auto notification = new KNotification(QStringLiteral("applicationcrash"));
0025 
0026     // immediate exit signal. This gets disconnected should `activated` arrive first (in that case we
0027     // want to wait for the terminal app to start and not exit on further notification signals)
0028     QObject::connect(notification, &KNotification::closed, this, [this, notification] {
0029         notification->disconnect(this);
0030         qApp->exit(0);
0031     });
0032 
0033     if (!QFile::exists(dump.filename)) {
0034         notification->setTitle(QStringLiteral("The warpcore has gone missing"));
0035         notification->setText(QStringLiteral("%1 [%2] crashed but has no core file").arg(dump.exe, QString::number(dump.pid)));
0036     } else {
0037         notification->setTitle(QStringLiteral("He's dead, Jim"));
0038         notification->setText(QStringLiteral("%1 [%2]").arg(dump.exe, QString::number(dump.pid)));
0039         notification->setActions({QStringLiteral("gdb")});
0040 
0041         const auto pid = dump.pid;
0042 
0043         QObject::connect(notification, &KNotification::activated, notification, [pid, this, notification]() {
0044             notification->disconnect(this);
0045             auto job = new KTerminalLauncherJob(QStringLiteral("coredumpctl gdb %1").arg(QString::number(pid)), this);
0046             connect(job, &KJob::result, this, [job] {
0047                 if (job->error() != KJob::NoError) {
0048                     qWarning() << job->errorText();
0049                 }
0050                 qApp->exit(0);
0051             });
0052             job->start();
0053 
0054             // Just in case the launcher job bugs out also add a timer.
0055             auto startTimeout = new QTimer(this);
0056             startTimeout->setInterval(16s);
0057             connect(startTimeout, &QTimer::timeout, this, [] {
0058                 qApp->exit(0);
0059             });
0060             startTimeout->start();
0061         });
0062     }
0063 
0064     notification->setFlags(KNotification::DefaultEvent | KNotification::SkipGrouping);
0065     notification->sendEvent();
0066 
0067     // KNotification internally depends on an eventloop to communicate over dbus. We therefore start the
0068     // eventloop here. ::handle() is expected to be blocking so this has no adverse effects.
0069     // The eventloop is either exited when the notification gets closed or when the debugger has started.
0070     qApp->exec();
0071     return true;
0072 }