crash handler, model guard, status temp/fan, timeout fix

- SIGSEGV/SIGABRT crash handler in ui/main.cc prints stack trace to stderr
- Fixed onroad crash: guard update_model() against empty model position data
  (was dereferencing end()-1 on empty list when modeld not running in bench)
- Status window: added device temperature and fan speed
- Interactive timeout returns to splash/onroad (not ClearPilotPanel)
- bench_cmd dump detects crash loops via UI process uptime check
- bench_cmd wait_ready timeout increased to 20s
- Restored camerad to bench ignore list (not needed for UI testing)
- Updated CLAUDE.md with crash debugging procedures

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 02:46:08 +00:00
parent 4b0d0bb708
commit 3edc1972c8
6 changed files with 82 additions and 11 deletions

View File

@@ -57,7 +57,7 @@ def ui_dump():
ctx.term()
def wait_ready(timeout=10):
def wait_ready(timeout=20):
"""Wait until the UI shows ReadyWindow, up to timeout seconds."""
start = time.time()
while time.time() - start < timeout:

View File

@@ -1,4 +1,9 @@
#include <sys/resource.h>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <execinfo.h>
#include <unistd.h>
#include <QApplication>
#include <QTranslator>
@@ -8,7 +13,27 @@
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/window.h"
// CLEARPILOT: crash handler — prints stack trace to stderr on SIGSEGV/SIGABRT
static void crash_handler(int sig) {
const char *sig_name = (sig == SIGSEGV) ? "SIGSEGV" : (sig == SIGABRT) ? "SIGABRT" : "SIGNAL";
fprintf(stderr, "\n=== CRASH: %s (signal %d) ===\n", sig_name, sig);
void *frames[64];
int count = backtrace(frames, 64);
fprintf(stderr, "Backtrace (%d frames):\n", count);
backtrace_symbols_fd(frames, count, STDERR_FILENO);
fprintf(stderr, "=== END CRASH ===\n");
fflush(stderr);
// Re-raise to get default behavior (core dump / exit)
signal(sig, SIG_DFL);
raise(sig);
}
int main(int argc, char *argv[]) {
signal(SIGSEGV, crash_handler);
signal(SIGABRT, crash_handler);
setpriority(PRIO_PROCESS, 0, -20);
qInstallMessageHandler(swagLogMessageHandler);

View File

@@ -50,10 +50,11 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
}
});
QObject::connect(device(), &Device::interactiveTimeout, [=]() {
if (main_layout->currentWidget() == settingsWindow ||
main_layout->currentWidget() == statusWindow) {
closeSettings();
// CLEARPILOT: on timeout, return to splash/onroad (not ClearPilotPanel)
if (main_layout->currentWidget() != homeWindow) {
main_layout->setCurrentWidget(homeWindow);
}
homeWindow->offroadTransition(!uiState()->scene.started);
});
// load fonts
@@ -229,6 +230,8 @@ StatusWindow::StatusWindow(QWidget *parent) : QFrame(parent) {
storage_label = makeRow("Storage");
ram_label = makeRow("Memory");
load_label = makeRow("Load");
temp_label = makeRow("Temperature");
fan_label = makeRow("Fan Speed");
ip_label = makeRow("IP Address");
wifi_label = makeRow("WiFi");
vpn_label = makeRow("VPN");
@@ -273,6 +276,24 @@ void StatusWindow::refresh() {
load_label->setText(QString("%1 %2 %3").arg(parts[0], parts[1], parts[2]));
}
// Temperature
QString temps = shellCmd("cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null | sort -rn | head -1");
if (!temps.isEmpty()) {
float temp_c = temps.toLong() / 1000.0;
temp_label->setText(QString("%1°C").arg(temp_c, 0, 'f', 1));
temp_label->setStyleSheet(temp_c > 70 ? "color: #ff4444; font-size: 38px;" :
temp_c > 55 ? "color: #ffaa00; font-size: 38px;" :
"color: white; font-size: 38px;");
}
// Fan speed
QString fan = shellCmd("cat /sys/class/hwmon/hwmon*/fan1_input 2>/dev/null | head -1");
if (fan.isEmpty()) {
// Try reading from deviceState param as fallback
fan = shellCmd("cat /dev/shm/params/d/LastFanSpeed 2>/dev/null");
}
fan_label->setText(fan.isEmpty() ? "" : fan + " RPM");
// IP + WiFi
QString ip = shellCmd("ip route get 1.1.1.1 2>/dev/null | head -1 | awk '{print $7}'");
ip_label->setText(ip.isEmpty() ? "No connection" : ip);

View File

@@ -29,6 +29,8 @@ private:
QLabel *storage_label;
QLabel *ram_label;
QLabel *load_label;
QLabel *temp_label;
QLabel *fan_label;
QLabel *ip_label;
QLabel *wifi_label;
QLabel *vpn_label;

View File

@@ -93,6 +93,9 @@ void update_model(UIState *s,
if (plan_position.getX().size() < model.getPosition().getX().size()) {
plan_position = model.getPosition();
}
// CLEARPILOT: guard against empty model data (bench mode, no modeld running)
if (plan_position.getX().size() == 0) return;
float max_distance = scene.unlimited_road_ui_length ? *(plan_position.getX().end() - 1) :
std::clamp(*(plan_position.getX().end() - 1),
MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);