| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/forensics/feedback/reboot_log/annotations.h" |
| |
| #include "fuchsia/feedback/cpp/fidl.h" |
| #include "src/developer/forensics/utils/time.h" |
| |
| namespace forensics::feedback { |
| namespace { |
| |
| std::string GetSpontaneousRebootReason(const SpontaneousRebootReason spontaneous_reboot_reason) { |
| switch (spontaneous_reboot_reason) { |
| case SpontaneousRebootReason::kSpontaneous: |
| return "spontaneous"; |
| case SpontaneousRebootReason::kBriefPowerLoss: |
| return "brief loss of power"; |
| case SpontaneousRebootReason::kHardReset: |
| return "hard reset"; |
| } |
| } |
| |
| } // namespace |
| |
| std::string LastRebootReasonAnnotation(const FinalShutdownInfo& final_shutdown_info, |
| const SpontaneousRebootReason spontaneous_reboot_reason) { |
| using FuchsiaRebootReason = fuchsia::feedback::RebootReason; |
| |
| // Define a generic value to use in case conversion fails or the converted value fails to match a |
| // good value. |
| std::string generic_value = "unknown"; |
| if (const std::optional<bool> graceful_opt = final_shutdown_info.OptionallyGraceful(); |
| graceful_opt.has_value()) { |
| generic_value = (graceful_opt.value()) ? "graceful" : "ungraceful"; |
| } |
| |
| const auto reboot_reason = final_shutdown_info.ToFidlRebootReason(); |
| if (!reboot_reason) { |
| return generic_value; |
| } |
| |
| switch (reboot_reason.value()) { |
| case FuchsiaRebootReason::COLD: |
| return "cold"; |
| case FuchsiaRebootReason::BRIEF_POWER_LOSS: |
| return GetSpontaneousRebootReason(spontaneous_reboot_reason); |
| case FuchsiaRebootReason::BROWNOUT: |
| return "brownout"; |
| case FuchsiaRebootReason::KERNEL_PANIC: |
| return "kernel panic"; |
| case FuchsiaRebootReason::SYSTEM_OUT_OF_MEMORY: |
| return "system out of memory"; |
| case FuchsiaRebootReason::HARDWARE_WATCHDOG_TIMEOUT: |
| return "hardware watchdog timeout"; |
| case FuchsiaRebootReason::SOFTWARE_WATCHDOG_TIMEOUT: |
| return "software watchdog timeout"; |
| case FuchsiaRebootReason::USER_REQUEST: |
| return "user request"; |
| case FuchsiaRebootReason::SYSTEM_UPDATE: |
| return "system update"; |
| case FuchsiaRebootReason::RETRY_SYSTEM_UPDATE: |
| return "retry system update"; |
| case FuchsiaRebootReason::ZBI_SWAP: |
| return "ZBI swap"; |
| case FuchsiaRebootReason::HIGH_TEMPERATURE: |
| return "device too hot"; |
| case FuchsiaRebootReason::SESSION_FAILURE: |
| return "fatal session failure"; |
| case FuchsiaRebootReason::SYSMGR_FAILURE: |
| return "fatal sysmgr failure"; |
| case FuchsiaRebootReason::CRITICAL_COMPONENT_FAILURE: |
| return "fatal critical component failure"; |
| case FuchsiaRebootReason::FACTORY_DATA_RESET: |
| return "factory data reset"; |
| case FuchsiaRebootReason::ROOT_JOB_TERMINATION: |
| return "root job termination"; |
| case FuchsiaRebootReason::NETSTACK_MIGRATION: |
| return "netstack migration"; |
| case FuchsiaRebootReason::ANDROID_UNEXPECTED_REASON: |
| return "android unexpected reason"; |
| case FuchsiaRebootReason::ANDROID_NO_REASON: |
| return "android no reason"; |
| case FuchsiaRebootReason::ANDROID_RESCUE_PARTY: |
| return "android rescue party"; |
| case FuchsiaRebootReason::ANDROID_CRITICAL_PROCESS_FAILURE: |
| return "android critical process failure"; |
| case FuchsiaRebootReason::DEVELOPER_REQUEST: |
| return "developer request"; |
| default: |
| return generic_value; |
| } |
| } |
| |
| ErrorOrString LastRebootUptimeAnnotation(const RebootLog& reboot_log) { |
| if (reboot_log.Uptime().has_value()) { |
| const auto uptime = FormatDuration(*reboot_log.Uptime()); |
| if (uptime.has_value()) { |
| return ErrorOrString(*uptime); |
| } |
| } |
| |
| return ErrorOrString(Error::kMissingValue); |
| } |
| |
| ErrorOrString LastRebootRuntimeAnnotation(const RebootLog& reboot_log) { |
| if (reboot_log.Runtime().has_value()) { |
| const auto runtime = FormatDuration(*reboot_log.Runtime()); |
| if (runtime.has_value()) { |
| return ErrorOrString(*runtime); |
| } |
| } |
| |
| return ErrorOrString(Error::kMissingValue); |
| } |
| |
| ErrorOrString LastRebootTotalSuspendedTimeAnnotation(const RebootLog& reboot_log) { |
| if (reboot_log.Uptime().has_value() && reboot_log.Runtime().has_value()) { |
| const std::optional<std::string> suspended_time = |
| FormatDuration(*reboot_log.Uptime() - *reboot_log.Runtime()); |
| if (suspended_time.has_value()) { |
| return ErrorOrString(*suspended_time); |
| } |
| } |
| |
| return ErrorOrString(Error::kMissingValue); |
| } |
| |
| ErrorOrString LastShutdownGracefulActionAnnotation(const FinalShutdownInfo& final_shutdown_info) { |
| const std::optional<GracefulShutdownAction> action = |
| final_shutdown_info.ToGracefulShutdownAction(); |
| if (!action.has_value()) { |
| return ErrorOrString(Error::kMissingValue); |
| } |
| |
| switch (*action) { |
| case GracefulShutdownAction::kPoweroff: |
| return ErrorOrString("poweroff"); |
| case GracefulShutdownAction::kReboot: |
| return ErrorOrString("reboot"); |
| case GracefulShutdownAction::kRebootToRecovery: |
| return ErrorOrString("reboot to recovery"); |
| case GracefulShutdownAction::kRebootToBootloader: |
| return ErrorOrString("reboot to bootloader"); |
| case GracefulShutdownAction::kNotSupported: |
| case GracefulShutdownAction::kNotParseable: |
| return ErrorOrString(Error::kBadValue); |
| } |
| } |
| |
| } // namespace forensics::feedback |