mirror of
https://github.com/google/pebble
synced 2026-10-14 15:44:12 +02:00
Import of the watch repository from Pebble
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include "advanced_logging.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "comm/ble/gatt_service_changed.h"
|
||||
#include "drivers/pmic.h"
|
||||
#include "kernel/core_dump.h"
|
||||
#include "kernel/event_loop.h"
|
||||
#include "kernel/pbl_malloc.h"
|
||||
#include "popups/crashed_ui.h"
|
||||
#include "services/common/analytics/analytics.h"
|
||||
#include "system/logging.h"
|
||||
#include "system/reboot_reason.h"
|
||||
|
||||
static void log_reboot_reason_cb(void *reason) {
|
||||
AnalyticsEventCrash *crash_report = (AnalyticsEventCrash *)reason;
|
||||
analytics_event_crash(crash_report->crash_code, crash_report->link_register);
|
||||
kernel_free(crash_report);
|
||||
}
|
||||
|
||||
static RebootReasonCode s_last_reboot_reason_code = RebootReasonCode_Unknown;
|
||||
RebootReasonCode reboot_reason_get_last_reboot_reason(void) {
|
||||
return s_last_reboot_reason_code;
|
||||
}
|
||||
|
||||
void debug_reboot_reason_print(McuRebootReason mcu_reboot_reason) {
|
||||
RebootReason reason;
|
||||
reboot_reason_get(&reason);
|
||||
bool show_reset_alert = !reason.restarted_safely;
|
||||
s_last_reboot_reason_code = reason.code;
|
||||
|
||||
// We're out of flash space, scrape a few bytes back!
|
||||
static const char* rebooted_due_to = " rebooted due to ";
|
||||
|
||||
const char* restarted_safely_string = "Safely";
|
||||
if (!reason.restarted_safely) {
|
||||
restarted_safely_string = "Dangerously";
|
||||
}
|
||||
|
||||
// Keep hourly logging to keep track of hours without crashes.
|
||||
analytics_set(ANALYTICS_DEVICE_METRIC_SYSTEM_CRASH_CODE,
|
||||
0xDEAD0000 | reason.code, AnalyticsClient_System);
|
||||
uint32_t lr = reason.extra;
|
||||
|
||||
// Leave this NULL to do your own printing.
|
||||
const char *reason_string = NULL;
|
||||
switch (reason.code) {
|
||||
// Normal stuff
|
||||
case RebootReasonCode_Unknown:
|
||||
reason_string = "We don't know why we %s rebooted.";
|
||||
lr = mcu_reboot_reason.reset_mask;
|
||||
break;
|
||||
case RebootReasonCode_LowBattery:
|
||||
reason_string = "%s%sLowBattery";
|
||||
break;
|
||||
case RebootReasonCode_SoftwareUpdate:
|
||||
gatt_service_changed_server_handle_fw_update();
|
||||
reason_string = "%s%sSoftwareUpdate";
|
||||
break;
|
||||
case RebootReasonCode_ResetButtonsHeld:
|
||||
// Since we forced the reset, it isn't unexpected
|
||||
show_reset_alert = false;
|
||||
reason_string = "%s%sResetButtonsHeld";
|
||||
break;
|
||||
case RebootReasonCode_ShutdownMenuItem:
|
||||
reason_string = "%s%sLowBattery";
|
||||
break;
|
||||
case RebootReasonCode_FactoryResetReset:
|
||||
reason_string = "%s%sFactoryResetReset";
|
||||
break;
|
||||
case RebootReasonCode_FactoryResetShutdown:
|
||||
reason_string = "%s%sFactoryResetShutdown";
|
||||
break;
|
||||
case RebootReasonCode_MfgShutdown:
|
||||
reason_string = "%s%sMfgShutdown";
|
||||
break;
|
||||
case RebootReasonCode_Serial:
|
||||
reason_string = "%s%sSerial";
|
||||
break;
|
||||
case RebootReasonCode_RemoteReset:
|
||||
reason_string = "%s%sa Remote Reset";
|
||||
break;
|
||||
case RebootReasonCode_ForcedCoreDump:
|
||||
reason_string = "%s%sa Forced Coredump";
|
||||
break;
|
||||
case RebootReasonCode_PrfIdle:
|
||||
reason_string = "%s%sIdle PRF";
|
||||
break;
|
||||
// Error occurred
|
||||
case RebootReasonCode_Assert:
|
||||
show_reset_alert = true;
|
||||
reason_string = "%s%sAssert: LR %#"PRIxPTR;
|
||||
break;
|
||||
case RebootReasonCode_HardFault:
|
||||
show_reset_alert = true;
|
||||
reason_string = "%s%sHardFault: LR %#"PRIxPTR;
|
||||
break;
|
||||
case RebootReasonCode_LauncherPanic:
|
||||
show_reset_alert = true;
|
||||
reason_string = "%s%sLauncherPanic: code 0x%"PRIx32;
|
||||
break;
|
||||
case RebootReasonCode_ClockFailure:
|
||||
reason_string = "%s%sClock Failure";
|
||||
break;
|
||||
case RebootReasonCode_WorkerHardFault:
|
||||
show_reset_alert = true;
|
||||
reason_string = "%s%sWorker HardFault";
|
||||
break;
|
||||
case RebootReasonCode_OutOfMemory:
|
||||
show_reset_alert = true;
|
||||
reason_string = "%s%sOOM";
|
||||
break;
|
||||
case RebootReasonCode_BtCoredump:
|
||||
show_reset_alert = true;
|
||||
reason_string = "%s%sBT Coredump";
|
||||
break;
|
||||
default:
|
||||
reason_string = "%s%sUnrecognized Reason";
|
||||
break;
|
||||
// Error occurred
|
||||
case RebootReasonCode_Watchdog:
|
||||
show_reset_alert = true;
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "%s%sWatchdog: Bits 0x%" PRIx8 ", Mask 0x%" PRIx8,
|
||||
restarted_safely_string, rebooted_due_to, reason.data8[0], reason.data8[1]);
|
||||
|
||||
if (reason.watchdog.stuck_task_pc != 0) {
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "Stuck task PC: 0x%" PRIx32 ", LR: 0x%" PRIx32,
|
||||
reason.watchdog.stuck_task_pc, reason.watchdog.stuck_task_lr);
|
||||
|
||||
if (reason.watchdog.stuck_task_callback) {
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "Stuck callback: 0x%" PRIx32,
|
||||
reason.watchdog.stuck_task_callback);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RebootReasonCode_StackOverflow:
|
||||
show_reset_alert = true;
|
||||
PebbleTask task = (PebbleTask) reason.data8[0];
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "%s%sStackOverflow: Task #%d (%s)", restarted_safely_string,
|
||||
rebooted_due_to, task, pebble_task_get_name(task));
|
||||
break;
|
||||
case RebootReasonCode_EventQueueFull:
|
||||
show_reset_alert = true;
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "%s%sEvent Queue Full", restarted_safely_string, rebooted_due_to);
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "Task: <%s> LR: 0x%"PRIx32" Current: 0x%"PRIx32" Dropped: 0x%"PRIx32,
|
||||
pebble_task_get_name(reason.event_queue.destination_task),
|
||||
reason.event_queue.push_lr,
|
||||
reason.event_queue.current_event,
|
||||
reason.event_queue.dropped_event);
|
||||
break;
|
||||
}
|
||||
// Generic reason string
|
||||
if (reason_string) {
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, reason_string, restarted_safely_string, rebooted_due_to,
|
||||
reason.extra);
|
||||
}
|
||||
|
||||
analytics_set(ANALYTICS_DEVICE_METRIC_SYSTEM_CRASH_LR, lr, AnalyticsClient_System);
|
||||
|
||||
// We need to wait for the logging service to initialize.
|
||||
AnalyticsEventCrash *crash_report = kernel_malloc_check(sizeof(AnalyticsEventCrash));
|
||||
*crash_report = (AnalyticsEventCrash) {
|
||||
.crash_code = reason.code,
|
||||
.link_register = lr
|
||||
};
|
||||
launcher_task_add_callback(log_reboot_reason_cb, crash_report);
|
||||
|
||||
if (is_unread_coredump_available()) {
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "Unread coredump file is present!");
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "MCU reset reason mask: 0x%x", (int)mcu_reboot_reason.reset_mask);
|
||||
#if CAPABILITY_HAS_PMIC
|
||||
uint32_t pmic_reset_reason = pmic_get_last_reset_reason();
|
||||
if (pmic_reset_reason != 0) {
|
||||
DEBUG_LOG(LOG_LEVEL_INFO, "PMIC reset reason mask: 0x%x", (int)pmic_reset_reason);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_PEBBLE_JUST_RESET_ALERT
|
||||
// Trigger an alert display so that the user knows the watch rebooted due to a crash. This event
|
||||
// will be caught and handled by the launcher.c event loop.
|
||||
if (show_reset_alert) {
|
||||
crashed_ui_show_pebble_reset();
|
||||
}
|
||||
#endif
|
||||
|
||||
reboot_reason_clear();
|
||||
}
|
||||
Reference in New Issue
Block a user