From 684b13bfed1203ed42d69692db4cc597fb563d95 Mon Sep 17 00:00:00 2001 From: Aptivi Date: Tue, 17 Dec 2024 11:41:02 +0300 Subject: [PATCH] imp - bkp - Better exception handling in init/rese... ...t --- Instead of failing the whole process, try to fail individual processes when resetting or initializing components so that the rest of the kernel gets initialized or reset, even if there is a failure. However, users will get notified of errors when initialization or resetting experiences an error at the end. - Backportable for 0.1.1.x - Backportable for 0.1.0.x --- Type: imp Breaking: False Doc Required: False Backport Required: True Part: 1/1 --- .../Kernel/Starting/KernelInitializers.cs | 705 ++++++++++++++---- 1 file changed, 571 insertions(+), 134 deletions(-) diff --git a/public/Nitrocid/Kernel/Starting/KernelInitializers.cs b/public/Nitrocid/Kernel/Starting/KernelInitializers.cs index 4c205c5f3..8da632939 100644 --- a/public/Nitrocid/Kernel/Starting/KernelInitializers.cs +++ b/public/Nitrocid/Kernel/Starting/KernelInitializers.cs @@ -59,6 +59,9 @@ using Nitrocid.Network.SpeedDial; using Nitrocid.Network.Connections; using Terminaux.Base.Extensions; +using System.Collections.Generic; +using System.Text; +using Nitrocid.Kernel.Exceptions; namespace Nitrocid.Kernel.Starting { @@ -112,6 +115,7 @@ internal static void InitializeCritical() internal static void InitializeEssential() { + List exceptions = []; try { // Load alternative buffer (only supported on Linux, because Windows doesn't seem to respect CursorVisible = false on alt buffers) @@ -146,56 +150,144 @@ internal static void InitializeEssential() JournalManager.JournalPath = Getting.GetNumberedFileName(Path.GetDirectoryName(PathsManagement.GetKernelPath(KernelPathType.Journaling)), PathsManagement.GetKernelPath(KernelPathType.Journaling)); // Initialize custom languages - if (KernelEntry.TalkativePreboot) - SplashReport.ReportProgress(Translate.DoTranslation("Loading custom languages...")); - LanguageManager.InstallCustomLanguages(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded custom languages."); + try + { + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgress(Translate.DoTranslation("Loading custom languages...")); + LanguageManager.InstallCustomLanguages(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded custom languages."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load custom languages"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load custom languages") + $": {exc.Message}"); + } // Initialize addons - if (KernelEntry.TalkativePreboot) - SplashReport.ReportProgress(Translate.DoTranslation("Loading important kernel addons...")); - AddonTools.ProcessAddons(ModLoadPriority.Important); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded important kernel addons."); + try + { + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgress(Translate.DoTranslation("Loading important kernel addons...")); + AddonTools.ProcessAddons(ModLoadPriority.Important); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded important kernel addons."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load important kernel addons"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load important kernel addons") + $": {exc.Message}"); + } // Stop the splash prior to loading config if (KernelEntry.PrebootSplash) SplashManager.CloseSplash(SplashContext.Preboot); // Create config file and then read it - if (KernelEntry.TalkativePreboot) - SplashReport.ReportProgress(Translate.DoTranslation("Loading configuration...")); - if (!KernelEntry.SafeMode) - Config.InitializeConfig(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded configuration."); + try + { + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgress(Translate.DoTranslation("Loading configuration...")); + if (!KernelEntry.SafeMode) + Config.InitializeConfig(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded configuration."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load important kernel addons"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load important kernel addons") + $": {exc.Message}"); + } // Read privacy consents - PrivacyConsentTools.LoadConsents(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded privacy consents."); + try + { + PrivacyConsentTools.LoadConsents(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded privacy consents."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load privacy consents"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load privacy consents") + $": {exc.Message}"); + } // Load background ColorTools.LoadBack(); DebugWriter.WriteDebug(DebugLevel.I, "Loaded background."); // Load splash - SplashManager.OpenSplash(SplashContext.StartingUp); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded splash."); + try + { + SplashManager.OpenSplash(SplashContext.StartingUp); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded splash."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load splash"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load splash") + $": {exc.Message}"); + } // Initialize important mods if (Config.MainConfig.StartKernelMods) { - if (KernelEntry.TalkativePreboot) - SplashReport.ReportProgress(Translate.DoTranslation("Loading important mods...")); - ModManager.StartMods(ModLoadPriority.Important); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded important mods."); + try + { + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgress(Translate.DoTranslation("Loading important mods...")); + ModManager.StartMods(ModLoadPriority.Important); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded important mods."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load important mods"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load important mods") + $": {exc.Message}"); + } } // Populate debug devices - RemoteDebugTools.LoadAllDevices(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded remote debug devices."); + try + { + RemoteDebugTools.LoadAllDevices(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded remote debug devices."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load remote debug devices"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load remote debug devices") + $": {exc.Message}"); + } // Show first-time color calibration for first-time run if (KernelEntry.FirstTime) ConsoleTools.ShowColorRampAndSet(); + + // Check for errors + if (exceptions.Count > 0) + throw new KernelException(KernelExceptionType.Environment, Translate.DoTranslation("There were errors when trying to initialize essential components.")); } catch (Exception ex) { @@ -204,7 +296,8 @@ internal static void InitializeEssential() DebugWriter.WriteDebugStackTrace(ex); InfoBoxModalColor.WriteInfoBoxModal( Translate.DoTranslation("The kernel failed to initialize some of the essential components. The kernel will not work properly at this point.") + "\n\n" + - Translate.DoTranslation("Error information:") + $" {ex.Message}" + Translate.DoTranslation("Error information:") + $" {ex.Message}\n\n" + + PopulateExceptionText(exceptions) ); SplashManager.EndSplashOut(SplashContext.StartingUp); } @@ -226,50 +319,175 @@ internal static void InitializeWelcomeMessages() internal static void InitializeOptional() { + List exceptions = []; try { - // Initialize notifications - if (!NotificationManager.NotifThread.IsAlive) - NotificationManager.NotifThread.Start(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded notification thread."); - - // Install cancellation handler - CancellationHandlers.InstallHandler(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded cancellation handler."); - - // Initialize aliases - AliasManager.InitAliases(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded aliases."); - - // Initialize speed dial - SpeedDialTools.LoadAll(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded speed dial entries."); - - // Load system env vars and convert them - UESHVariables.ConvertSystemEnvironmentVariables(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded environment variables."); - - // Initialize alarm listener - AlarmListener.StartListener(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded alarm listener."); - - // Finalize addons - AddonTools.ProcessAddons(ModLoadPriority.Optional); - AddonTools.FinalizeAddons(); - DebugWriter.WriteDebug(DebugLevel.I, "Finalized addons."); - - // If the two files are not found, create two MOTD files with current config and load them. - MotdParse.ReadMotd(); - MalParse.ReadMal(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded MOTD and MAL."); - - // Load shell command histories - ShellManager.LoadHistories(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded shell command histories."); - - // Load extension handlers - ExtensionHandlerTools.LoadAllHandlers(); - DebugWriter.WriteDebug(DebugLevel.I, "Loaded extension handlers."); + try + { + // Initialize notifications + if (!NotificationManager.NotifThread.IsAlive) + NotificationManager.NotifThread.Start(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded notification thread."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load notification thread"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load notification thread") + $": {exc.Message}"); + } + + try + { + // Install cancellation handler + CancellationHandlers.InstallHandler(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded cancellation handler."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load cancellation handler"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load cancellation handler") + $": {exc.Message}"); + } + + try + { + // Initialize aliases + AliasManager.InitAliases(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded aliases."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load aliases"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load aliases") + $": {exc.Message}"); + } + + try + { + // Initialize speed dial + SpeedDialTools.LoadAll(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded speed dial entries."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load speed dial entries"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load speed dial entries") + $": {exc.Message}"); + } + + try + { + // Load system env vars and convert them + UESHVariables.ConvertSystemEnvironmentVariables(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded environment variables."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load environment variables"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load environment variables") + $": {exc.Message}"); + } + + try + { + // Initialize alarm listener + AlarmListener.StartListener(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded alarm listener."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load alarm listener"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load alarm listener") + $": {exc.Message}"); + } + + try + { + // Finalize addons + AddonTools.ProcessAddons(ModLoadPriority.Optional); + AddonTools.FinalizeAddons(); + DebugWriter.WriteDebug(DebugLevel.I, "Finalized addons."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to finalize addons"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load finalize addons") + $": {exc.Message}"); + } + + try + { + // If the two files are not found, create two MOTD files with current config and load them. + MotdParse.ReadMotd(); + MalParse.ReadMal(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded MOTD and MAL."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load MOTD and MAL"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load MOTD and MAL") + $": {exc.Message}"); + } + + try + { + // Load shell command histories + ShellManager.LoadHistories(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded shell command histories."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load shell command histories"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load shell command histories") + $": {exc.Message}"); + } + + try + { + // Load extension handlers + ExtensionHandlerTools.LoadAllHandlers(); + DebugWriter.WriteDebug(DebugLevel.I, "Loaded extension handlers."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to load extension handlers"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + if (KernelEntry.TalkativePreboot) + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to load extension handlers") + $": {exc.Message}"); + } + + // Check for errors + if (exceptions.Count > 0) + throw new KernelException(KernelExceptionType.Environment, Translate.DoTranslation("There were errors when trying to initialize optional components.")); } catch (Exception ex) { @@ -278,7 +496,8 @@ internal static void InitializeOptional() DebugWriter.WriteDebugStackTrace(ex); InfoBoxModalColor.WriteInfoBoxModal( Translate.DoTranslation("The kernel failed to initialize some of the optional components. If it's trying to read a configuration file, make sure that it's formatted correctly.") + "\n\n" + - Translate.DoTranslation("Error information:") + $" {ex.Message}" + Translate.DoTranslation("Error information:") + $" {ex.Message}\n\n" + + PopulateExceptionText(exceptions) ); SplashManager.EndSplashOut(SplashContext.StartingUp); } @@ -287,94 +506,286 @@ internal static void InitializeOptional() internal static void ResetEverything() { var context = !PowerManager.KernelShutdown ? SplashContext.Rebooting : SplashContext.ShuttingDown; + List exceptions = []; try { - // Reset every variable below - SplashReport._Progress = 0; - SplashReport._ProgressText = ""; - SplashReport._KernelBooted = false; - DebugWriter.WriteDebug(DebugLevel.I, "General variables reset"); - SplashReport.ReportProgress(Translate.DoTranslation("General variables reset")); - - // Save shell command histories - ShellManager.SaveHistories(); - DebugWriter.WriteDebug(DebugLevel.I, "Saved shell command histories."); - SplashReport.ReportProgress(Translate.DoTranslation("Saved shell command histories.")); - - // Save privacy consents - PrivacyConsentTools.SaveConsents(); - DebugWriter.WriteDebug(DebugLevel.I, "Saved privacy consents."); - - // Disconnect all hosts from remote debugger - RemoteDebugger.StopRDebugThread(); - DebugWriter.WriteDebug(DebugLevel.I, "Remote debugger stopped"); - - // Reset languages - SplashManager.BeginSplashOut(context); - LanguageManager.SetLangDry(Config.MainConfig.CurrentLanguage); - LanguageManager.currentUserLanguage = LanguageManager.Languages[Config.MainConfig.CurrentLanguage]; - SplashManager.EndSplashOut(context); + try + { + // Reset every variable below + SplashReport._Progress = 0; + SplashReport._ProgressText = ""; + SplashReport._KernelBooted = false; + DebugWriter.WriteDebug(DebugLevel.I, "General variables reset"); + SplashReport.ReportProgress(Translate.DoTranslation("General variables reset")); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to reset general variables"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to reset general variables") + $": {exc.Message}"); + } - // Save extension handlers - ExtensionHandlerTools.SaveAllHandlers(); - DebugWriter.WriteDebug(DebugLevel.I, "Extension handlers saved"); + try + { + // Save shell command histories + ShellManager.SaveHistories(); + DebugWriter.WriteDebug(DebugLevel.I, "Saved shell command histories."); + SplashReport.ReportProgress(Translate.DoTranslation("Saved shell command histories.")); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to save shell command histories"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to save shell command histories") + $": {exc.Message}"); + } - // Stop alarm listener - AlarmListener.StopListener(); - DebugWriter.WriteDebug(DebugLevel.I, "Stopped alarm listener."); + try + { + // Save privacy consents + PrivacyConsentTools.SaveConsents(); + DebugWriter.WriteDebug(DebugLevel.I, "Saved privacy consents."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to save privacy consents"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to save privacy consents") + $": {exc.Message}"); + } - // Save all settings - Config.CreateConfig(); - DebugWriter.WriteDebug(DebugLevel.I, "Config saved"); - SplashReport.ReportProgress(Translate.DoTranslation("Config saved.")); + try + { + // Disconnect all hosts from remote debugger + RemoteDebugger.StopRDebugThread(); + DebugWriter.WriteDebug(DebugLevel.I, "Remote debugger stopped"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop remote debugger"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop remote debugger") + $": {exc.Message}"); + } - // Stop all mods - ModManager.StopMods(); - DebugWriter.WriteDebug(DebugLevel.I, "Mods stopped"); + try + { + // Reset languages + SplashManager.BeginSplashOut(context); + LanguageManager.SetLangDry(Config.MainConfig.CurrentLanguage); + LanguageManager.currentUserLanguage = LanguageManager.Languages[Config.MainConfig.CurrentLanguage]; + SplashManager.EndSplashOut(context); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to reset languages"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to reset languages") + $": {exc.Message}"); + } - // Stop all addons and their registered components - AddonTools.UnloadAddons(); - ScreensaverManager.AddonSavers.Clear(); - DebugWriter.WriteDebug(DebugLevel.I, "Addons and their registered components stopped"); - SplashReport.ReportProgress(Translate.DoTranslation("Extra kernel functions and their registered components stopped.")); + try + { + // Save extension handlers + ExtensionHandlerTools.SaveAllHandlers(); + DebugWriter.WriteDebug(DebugLevel.I, "Extension handlers saved"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to save extension handlers"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to save extension handlers") + $": {exc.Message}"); + } - // Stop RPC - RemoteProcedure.StopRPC(); - DebugWriter.WriteDebug(DebugLevel.I, "RPC stopped"); + try + { + // Stop alarm listener + AlarmListener.StopListener(); + DebugWriter.WriteDebug(DebugLevel.I, "Stopped alarm listener."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop alarm listener"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop alarm listener") + $": {exc.Message}"); + } - // Disconnect all connections - NetworkConnectionTools.CloseAllConnections(); - DebugWriter.WriteDebug(DebugLevel.I, "Closed all connections"); + try + { + // Save all settings + Config.CreateConfig(); + DebugWriter.WriteDebug(DebugLevel.I, "Config saved"); + SplashReport.ReportProgress(Translate.DoTranslation("Config saved.")); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to save configuration"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to save configuration") + $": {exc.Message}"); + } + + try + { + // Stop all mods + ModManager.StopMods(); + DebugWriter.WriteDebug(DebugLevel.I, "Mods stopped"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop mods"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop mods") + $": {exc.Message}"); + } + + try + { + // Stop all addons and their registered components + AddonTools.UnloadAddons(); + ScreensaverManager.AddonSavers.Clear(); + DebugWriter.WriteDebug(DebugLevel.I, "Addons and their registered components stopped"); + SplashReport.ReportProgress(Translate.DoTranslation("Extra kernel functions and their registered components stopped.")); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop addons"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop addons") + $": {exc.Message}"); + } + + try + { + // Stop RPC + RemoteProcedure.StopRPC(); + DebugWriter.WriteDebug(DebugLevel.I, "RPC stopped"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop RPC"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop RPC") + $": {exc.Message}"); + } + + try + { + // Disconnect all connections + NetworkConnectionTools.CloseAllConnections(); + DebugWriter.WriteDebug(DebugLevel.I, "Closed all connections"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to close all connections"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to close all connections") + $": {exc.Message}"); + } // Disable safe mode KernelEntry.SafeMode = false; DebugWriter.WriteDebug(DebugLevel.I, "Safe mode disabled"); - // Stop screensaver timeout - ScreensaverManager.StopTimeout(); - DebugWriter.WriteDebug(DebugLevel.I, "Screensaver timeout stopped"); + try + { + // Stop screensaver timeout + ScreensaverManager.StopTimeout(); + DebugWriter.WriteDebug(DebugLevel.I, "Screensaver timeout stopped"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop screensaver timeout"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop screensaver timeout") + $": {exc.Message}"); + } - // Reset the boot log - SplashReport.logBuffer.Clear(); - DebugWriter.WriteDebug(DebugLevel.I, "Boot log buffer reset"); + try + { + // Reset the boot log + SplashReport.logBuffer.Clear(); + DebugWriter.WriteDebug(DebugLevel.I, "Boot log buffer reset"); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to reset boot log buffer"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to reset boot log buffer") + $": {exc.Message}"); + } - // Stop cursor handler - ConsolePointerHandler.StopHandler(); - DebugWriter.WriteDebug(DebugLevel.I, "Stopped the cursor handler."); + try + { + // Stop cursor handler + ConsolePointerHandler.StopHandler(); + DebugWriter.WriteDebug(DebugLevel.I, "Stopped the cursor handler."); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop the cursor handler"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop the cursor handler") + $": {exc.Message}"); + } // Disable Debugger if (KernelEntry.DebugMode) { - DebugWriter.WriteDebug(DebugLevel.I, "Shutting down debugger"); - KernelEntry.DebugMode = false; - DebugWriter.DebugStreamWriter?.Close(); - DebugWriter.DebugStreamWriter?.Dispose(); - DebugWriter.isDisposed = true; - DebugWriter.debugLines = 0; + try + { + DebugWriter.WriteDebug(DebugLevel.I, "Shutting down debugger"); + KernelEntry.DebugMode = false; + DebugWriter.DebugStreamWriter?.Close(); + DebugWriter.DebugStreamWriter?.Dispose(); + DebugWriter.isDisposed = true; + DebugWriter.debugLines = 0; + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop the debugger"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop the debugger") + $": {exc.Message}"); + } } - // Clear all active threads as we're rebooting - ThreadManager.StopAllThreads(); + try + { + // Clear all active threads as we're rebooting + ThreadManager.StopAllThreads(); + } + catch (Exception exc) + { + exceptions.Add(exc); + DebugWriter.WriteDebug(DebugLevel.E, "Failed to stop all kernel threads"); + DebugWriter.WriteDebug(DebugLevel.E, exc.Message); + DebugWriter.WriteDebugStackTrace(exc); + SplashReport.ReportProgressError(Translate.DoTranslation("Failed to stop all kernel threads") + $": {exc.Message}"); + } + + // Check for errors + if (exceptions.Count > 0) + throw new KernelException(KernelExceptionType.Environment, Translate.DoTranslation("There were errors when trying to reset components.")); } catch (Exception ex) { @@ -385,7 +796,8 @@ internal static void ResetEverything() DebugWriter.WriteDebugStackTrace(ex); InfoBoxModalColor.WriteInfoBoxModal( Translate.DoTranslation("The kernel failed to reset all the configuration to their initial states. Some of the components might have not unloaded correctly. If you're experiencing problems after the reboot, this might be the cause. Please shut down the kernel once rebooted.") + "\n\n" + - Translate.DoTranslation("Error information:") + $" {ex.Message}" + Translate.DoTranslation("Error information:") + $" {ex.Message}\n\n" + + PopulateExceptionText(exceptions) ); SplashManager.EndSplashOut(context); } @@ -420,5 +832,30 @@ internal static void ResetEverything() KernelEntry.QuietKernel = false; } } + + private static string PopulateExceptionText(List exceptions) + { + var exceptionsBuilder = new StringBuilder("\n\n"); + for (int i = 0; i < exceptions.Count; i++) + { + Exception exception = exceptions[i]; + + // Write the exception header + string exceptionHeader = $"{Translate.DoTranslation("Exception")} {i}/{exceptions.Count}"; + exceptionsBuilder.AppendLine(exceptionHeader); + exceptionsBuilder.AppendLine(new string('=', ConsoleChar.EstimateCellWidth(exceptionHeader))); + + // Now, write the exception itself + exceptionsBuilder.AppendLine($"{exception.GetType().Name}: {exception.Message}"); + if (KernelEntry.DebugMode) + exceptionsBuilder.AppendLine(exception.StackTrace); + + if (i < exceptions.Count - 1) + exceptionsBuilder.AppendLine("\n\n"); + } + if (exceptions.Count == 0) + exceptionsBuilder.AppendLine(Translate.DoTranslation("Consult the kernel debug logs for more info.")); + return exceptionsBuilder.ToString(); + } } }