From 243ae8b40858b67ec291e8c349e10e2ac0749423 Mon Sep 17 00:00:00 2001 From: Xuan-Son Nguyen Date: Mon, 13 Apr 2026 22:23:45 +0200 Subject: [PATCH] feat: show crash reason on boot (#1453) ## Summary If the system reboots from crash, display the reason and tell user to include `crash_report.txt` file. To test this, simply add an `assert(false)` somewhere inside the code. ![screenshot-74453.bmp](https://github.com/user-attachments/files/26160373/screenshot-74453.bmp) --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** --- lib/I18n/translations/english.yaml | 4 ++ src/activities/ActivityManager.cpp | 3 ++ src/activities/ActivityManager.h | 1 + src/activities/home/CrashActivity.cpp | 61 +++++++++++++++++++++++++++ src/activities/home/CrashActivity.h | 13 ++++++ src/main.cpp | 12 +++--- 6 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/activities/home/CrashActivity.cpp create mode 100644 src/activities/home/CrashActivity.h diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index a948ea5a8..af66e074c 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -294,3 +294,7 @@ STR_LINK: "[link]" STR_SCREENSHOT_BUTTON: "Take screenshot" STR_AUTO_TURN_ENABLED: "Auto Turn Enabled: " STR_AUTO_TURN_PAGES_PER_MIN: "Auto Turn (Pages Per Minute)" +STR_CRASH_TITLE: "System Crash" +STR_CRASH_DESCRIPTION: "A detailed report was saved to crash_report.txt. Please include this file in your bug report." +STR_CRASH_REASON: "Crash reason:" +STR_CRASH_NO_REASON: "(No reason was recorded)" diff --git a/src/activities/ActivityManager.cpp b/src/activities/ActivityManager.cpp index 3cf115b13..bd15abbaf 100644 --- a/src/activities/ActivityManager.cpp +++ b/src/activities/ActivityManager.cpp @@ -5,6 +5,7 @@ #include "boot_sleep/BootActivity.h" #include "boot_sleep/SleepActivity.h" #include "browser/OpdsBookBrowserActivity.h" +#include "home/CrashActivity.h" #include "home/FileBrowserActivity.h" #include "home/HomeActivity.h" #include "home/RecentBooksActivity.h" @@ -196,6 +197,8 @@ void ActivityManager::goToFullScreenMessage(std::string message, EpdFontFamily:: replaceActivity(std::make_unique(renderer, mappedInput, std::move(message), style)); } +void ActivityManager::goToCrashReport() { replaceActivity(std::make_unique(renderer, mappedInput)); } + void ActivityManager::goHome() { replaceActivity(std::make_unique(renderer, mappedInput)); } void ActivityManager::pushActivity(std::unique_ptr&& activity) { diff --git a/src/activities/ActivityManager.h b/src/activities/ActivityManager.h index bc24c42e3..bc975e919 100644 --- a/src/activities/ActivityManager.h +++ b/src/activities/ActivityManager.h @@ -86,6 +86,7 @@ class ActivityManager { void goToSleep(); void goToBoot(); void goToFullScreenMessage(std::string message, EpdFontFamily::Style style = EpdFontFamily::REGULAR); + void goToCrashReport(); void goHome(); // This will move current activity to stack instead of deleting it diff --git a/src/activities/home/CrashActivity.cpp b/src/activities/home/CrashActivity.cpp new file mode 100644 index 000000000..4f5a392b9 --- /dev/null +++ b/src/activities/home/CrashActivity.cpp @@ -0,0 +1,61 @@ +#include "CrashActivity.h" + +#include +#include +#include + +#include "components/UITheme.h" +#include "fontIds.h" + +void CrashActivity::onEnter() { + Activity::onEnter(); + + panicMessage = HalSystem::getPanicInfo(false); + if (panicMessage.empty()) { + panicMessage = tr(STR_CRASH_NO_REASON); + } + HalSystem::clearPanic(); + + requestUpdateAndWait(); +} + +void CrashActivity::loop() { + if (mappedInput.isPressed(MappedInputManager::Button::Back)) { + finish(); + } +} + +void CrashActivity::render(RenderLock&&) { + renderer.clearScreen(); + + const auto& metrics = UITheme::getInstance().getMetrics(); + const auto pageWidth = renderer.getScreenWidth(); + const auto contentWidth = pageWidth - 2 * metrics.contentSidePadding; + const auto x = metrics.contentSidePadding; + const auto lineHeight = renderer.getLineHeight(UI_10_FONT_ID); + + GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_CRASH_TITLE)); + + int y = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; + + auto descLines = renderer.wrappedText(UI_10_FONT_ID, tr(STR_CRASH_DESCRIPTION), contentWidth, 10); + for (const auto& line : descLines) { + renderer.drawText(UI_10_FONT_ID, x, y, line.c_str()); + y += lineHeight; + } + + y += metrics.verticalSpacing * 2; + renderer.drawText(UI_10_FONT_ID, x, y, tr(STR_CRASH_REASON)); + y += lineHeight + metrics.verticalSpacing; + + auto panicLines = renderer.wrappedText(UI_10_FONT_ID, panicMessage.c_str(), contentWidth, 5); + for (const auto& line : panicLines) { + renderer.drawText(UI_10_FONT_ID, x, y, line.c_str()); + y += lineHeight; + } + + const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + renderer.displayBuffer(); +} diff --git a/src/activities/home/CrashActivity.h b/src/activities/home/CrashActivity.h new file mode 100644 index 000000000..9b4641ed1 --- /dev/null +++ b/src/activities/home/CrashActivity.h @@ -0,0 +1,13 @@ +#pragma once +#include "../Activity.h" + +class CrashActivity final : public Activity { + std::string panicMessage; + + public: + explicit CrashActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) + : Activity("Crash", renderer, mappedInput) {} + void onEnter() override; + void loop() override; + void render(RenderLock&&) override; +}; diff --git a/src/main.cpp b/src/main.cpp index e77e8ba6f..e51a24333 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -253,7 +253,6 @@ void setup() { } HalSystem::checkPanic(); - HalSystem::clearPanic(); // TODO: move this to an activity when we have one to display the panic info SETTINGS.loadFromFile(); I18N.loadSettings(); @@ -290,10 +289,13 @@ void setup() { APP_STATE.loadFromFile(); RECENT_BOOKS.loadFromFile(); - // Boot to home screen if no book is open, last sleep was not from reader, back button is held, or reader activity - // crashed (indicated by readerActivityLoadCount > 0) - if (APP_STATE.openEpubPath.empty() || !APP_STATE.lastSleepFromReader || - mappedInputManager.isPressed(MappedInputManager::Button::Back) || APP_STATE.readerActivityLoadCount > 0) { + if (HalSystem::isRebootFromPanic()) { + // If we rebooted from a panic, go to crash report screen to show the panic info + activityManager.goToCrashReport(); + } else if (APP_STATE.openEpubPath.empty() || !APP_STATE.lastSleepFromReader || + mappedInputManager.isPressed(MappedInputManager::Button::Back) || APP_STATE.readerActivityLoadCount > 0) { + // Boot to home screen if no book is open, last sleep was not from reader, back button is held, or reader activity + // crashed (indicated by readerActivityLoadCount > 0) activityManager.goHome(); } else { // Clear app state to avoid getting into a boot loop if the epub doesn't load