From 942e22f275ff32041a0946c16f215e3f6d3bc592 Mon Sep 17 00:00:00 2001 From: MCredstoner2004 Date: Fri, 1 Jul 2022 13:41:36 -0500 Subject: [PATCH] Write `ApplicationErrorArg` `ErrorApplet`s to log These applets are used by applications to display a custom error message to the user. Both the error message and the detailed error message are printed to the error log. Co-authored-by: lynxnb --- app/CMakeLists.txt | 1 + .../cpp/skyline/applet/applet_creator.cpp | 9 ++- .../cpp/skyline/applet/controller_applet.cpp | 9 ++- .../cpp/skyline/applet/controller_applet.h | 14 +--- .../main/cpp/skyline/applet/error_applet.cpp | 55 +++++++++++++++ .../main/cpp/skyline/applet/error_applet.h | 70 +++++++++++++++++++ .../skyline/applet/player_select_applet.cpp | 2 +- .../applet/swkbd/software_keyboard_applet.cpp | 5 +- .../applet/swkbd/software_keyboard_applet.h | 4 +- .../applet/swkbd/software_keyboard_config.cpp | 4 +- .../cpp/skyline/services/am/applet/IApplet.h | 57 ++++++++++++++- 11 files changed, 200 insertions(+), 30 deletions(-) create mode 100644 app/src/main/cpp/skyline/applet/error_applet.cpp create mode 100644 app/src/main/cpp/skyline/applet/error_applet.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index fb313dd4..9101d5c0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -262,6 +262,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/btm/IBtmUserCore.cpp ${source_DIR}/skyline/applet/applet_creator.cpp ${source_DIR}/skyline/applet/controller_applet.cpp + ${source_DIR}/skyline/applet/error_applet.cpp ${source_DIR}/skyline/applet/player_select_applet.cpp ${source_DIR}/skyline/applet/swkbd/software_keyboard_applet.cpp ${source_DIR}/skyline/applet/swkbd/software_keyboard_config.cpp diff --git a/app/src/main/cpp/skyline/applet/applet_creator.cpp b/app/src/main/cpp/skyline/applet/applet_creator.cpp index 02478604..07a15fd0 100644 --- a/app/src/main/cpp/skyline/applet/applet_creator.cpp +++ b/app/src/main/cpp/skyline/applet/applet_creator.cpp @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include "controller_applet.h" -#include "player_select_applet.h" #include "applet_creator.h" +#include "controller_applet.h" +#include "error_applet.h" +#include "player_select_applet.h" #include "swkbd/software_keyboard_applet.h" namespace skyline::applet { @@ -20,8 +21,10 @@ namespace skyline::applet { return std::make_shared(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode); case AppletId::LibraryAppletSwkbd: return std::make_shared(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode); + case AppletId::LibraryAppletError: + return std::make_shared(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode); default: - throw exception("Unimplemented Applet: 0x{:X} ({})", static_cast(appletId), ToString(appletId)); + throw exception{"Unimplemented Applet: 0x{:X} ({})", static_cast(appletId), ToString(appletId)}; } } } diff --git a/app/src/main/cpp/skyline/applet/controller_applet.cpp b/app/src/main/cpp/skyline/applet/controller_applet.cpp index ee9865f5..21edffe3 100644 --- a/app/src/main/cpp/skyline/applet/controller_applet.cpp +++ b/app/src/main/cpp/skyline/applet/controller_applet.cpp @@ -15,7 +15,7 @@ namespace skyline::applet { std::shared_ptr onNormalDataPushFromApplet, std::shared_ptr onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode) - : IApplet(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode) {} + : IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {} void ControllerApplet::HandleShowControllerSupport(input::NpadStyleSet styleSet, ControllerAppletVersion version, span arg) { // Generic macro due to both versions of arguments sharing the same fields but having different layouts @@ -82,7 +82,7 @@ namespace skyline::applet { } } - std::scoped_lock lock{inputDataMutex}; + std::scoped_lock lock{normalInputDataMutex}; switch (argPrivate.mode) { case ControllerSupportMode::ShowControllerSupport: HandleShowControllerSupport(argPrivate.styleSet, appletVersion, normalInputData.front()->GetSpan()); @@ -100,15 +100,14 @@ namespace skyline::applet { // Notify the guest that we've finished running onAppletStateChanged->Signal(); return {}; - }; + } Result ControllerApplet::GetResult() { return {}; } void ControllerApplet::PushNormalDataToApplet(std::shared_ptr data) { - std::scoped_lock lock{inputDataMutex}; - normalInputData.emplace(std::move(data)); + PushNormalInput(data); } void ControllerApplet::PushInteractiveDataToApplet(std::shared_ptr data) {} diff --git a/app/src/main/cpp/skyline/applet/controller_applet.h b/app/src/main/cpp/skyline/applet/controller_applet.h index 208a180e..c2c1d29b 100644 --- a/app/src/main/cpp/skyline/applet/controller_applet.h +++ b/app/src/main/cpp/skyline/applet/controller_applet.h @@ -2,6 +2,7 @@ // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) #pragma once + #include #include #include @@ -10,7 +11,7 @@ namespace skyline::applet { /** * @brief The Controller applet is responsible for notifiying the user of a games controller requirements and for allowing user management og controllers */ - class ControllerApplet : public service::am::IApplet { + class ControllerApplet : public service::am::IApplet, service::am::EnableNormalQueue { private: /** * @brief The version of the controller applet interface that an application supports @@ -98,17 +99,6 @@ namespace skyline::applet { }; static_assert(sizeof(ControllerSupportResultInfo) == 0xC); - std::mutex inputDataMutex; - std::queue> normalInputData; - - template - T PopNormalInput() { - std::scoped_lock lock{inputDataMutex}; - auto data{normalInputData.front()->GetSpan().as()}; - normalInputData.pop(); - return static_cast(data); - } - /** * @brief Handles the 'ShowControllerSupport' mode of the controller applet */ diff --git a/app/src/main/cpp/skyline/applet/error_applet.cpp b/app/src/main/cpp/skyline/applet/error_applet.cpp new file mode 100644 index 00000000..e02f15d1 --- /dev/null +++ b/app/src/main/cpp/skyline/applet/error_applet.cpp @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "error_applet.h" +#include "services/am/storage/ObjIStorage.h" + +namespace skyline::applet { + ErrorApplet::ErrorApplet(const DeviceState &state, + service::ServiceManager &manager, + std::shared_ptr onAppletStateChanged, + std::shared_ptr onNormalDataPushFromApplet, + std::shared_ptr onInteractiveDataPushFromApplet, + service::applet::LibraryAppletMode appletMode) + : IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {} + + Result ErrorApplet::Start() { + auto commonArg{PopNormalInput()}; + + errorStorage = PopNormalInput(); + auto errorCommonHeader{errorStorage->GetSpan().as()}; + Logger::Debug("ErrorApplet: version: 0x{:X}, type: 0x{:X}", commonArg.apiVersion, errorCommonHeader.type); + + switch (errorCommonHeader.type) { + case ErrorType::ApplicationErrorArg: + HandleApplicationErrorArg(); + break; + default: + throw exception("ErrorApplet type 0x{:X} is not implemented", errorCommonHeader.type); + } + + // Notify the guest that we've finished running + onAppletStateChanged->Signal(); + + return {}; + } + + void ErrorApplet::HandleApplicationErrorArg() { + auto applicationErrorStorage{errorStorage->GetSpan().as()}; + + if (applicationErrorStorage.fullscreenMessage[0] == '\0') + Logger::ErrorNoPrefix("Application Error: {}", applicationErrorStorage.dialogMessage.data()); + else + Logger::ErrorNoPrefix("Application Error: {}\nFull message: {}", applicationErrorStorage.dialogMessage.data(), applicationErrorStorage.fullscreenMessage.data()); + } + + Result ErrorApplet::GetResult() { + return {}; + } + + void ErrorApplet::PushNormalDataToApplet(std::shared_ptr data) { + PushNormalInput(data); + } + + void ErrorApplet::PushInteractiveDataToApplet(std::shared_ptr data) {} +} diff --git a/app/src/main/cpp/skyline/applet/error_applet.h b/app/src/main/cpp/skyline/applet/error_applet.h new file mode 100644 index 00000000..5c676184 --- /dev/null +++ b/app/src/main/cpp/skyline/applet/error_applet.h @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Copyright © 2020 Ryujinx Team and Contributors (https://github.com/ryujinx/) + +#pragma once + +#include +#include "common/language.h" + +namespace skyline::applet { + /** + * @brief The Error Applet is utilized by the guest to display an error to the user, this class prints the supplied error to the logger + * @url https://switchbrew.org/wiki/Error_Applet + * @url https://switchbrew.org/wiki/Error_applet + */ + class ErrorApplet : public service::am::IApplet, service::am::EnableNormalQueue { + private: + + #pragma pack(push, 1) + + enum class ErrorType : u8 { + ErrorCommonArg = 0, + SystemErrorArg = 1, + ApplicationErrorArg = 2, + ErrorEulaArg = 3, + ErrorPctlArg = 4, + ErrorRecordArg = 5, + SystemUpdateEulaArg = 8 + }; + + /** + * @url https://switchbrew.org/wiki/Error_Applet#ErrorCommonHeader + */ + struct ErrorCommonHeader { + ErrorType type; + u8 jump; + u8 _pad_[0x3]; + u8 contextFlag; + u8 resultFlag; + u8 contextFlag2; + }; + static_assert(sizeof(ErrorCommonHeader) == 0x8); + + struct ApplicationErrorArg { + ErrorCommonHeader commonHeader; + u32 errorNumber; + LanguageCode languageCode; + std::array dialogMessage; + std::array fullscreenMessage; //!< The message displayed when the user clicks on "Details", when not set this disables displaying Details + }; + static_assert(sizeof(ApplicationErrorArg) == 0x1014); + + #pragma pack(pop) + + std::shared_ptr errorStorage; + + void HandleApplicationErrorArg(); + + public: + ErrorApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr onAppletStateChanged, std::shared_ptr onNormalDataPushFromApplet, std::shared_ptr onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode); + + Result Start() override; + + Result GetResult() override; + + void PushNormalDataToApplet(std::shared_ptr data) override; + + void PushInteractiveDataToApplet(std::shared_ptr data) override; + }; +} diff --git a/app/src/main/cpp/skyline/applet/player_select_applet.cpp b/app/src/main/cpp/skyline/applet/player_select_applet.cpp index 23e0b923..2ef4b056 100644 --- a/app/src/main/cpp/skyline/applet/player_select_applet.cpp +++ b/app/src/main/cpp/skyline/applet/player_select_applet.cpp @@ -11,7 +11,7 @@ namespace skyline::applet { std::shared_ptr onNormalDataPushFromApplet, std::shared_ptr onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode) - : IApplet(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode) {} + : IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {} Result PlayerSelectApplet::Start() { // Return default user diff --git a/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.cpp b/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.cpp index 1713157a..4e1a02d0 100644 --- a/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.cpp +++ b/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.cpp @@ -74,7 +74,7 @@ namespace skyline::applet::swkbd { } Result SoftwareKeyboardApplet::Start() { - std::scoped_lock lock{inputDataMutex}; + std::scoped_lock lock{normalInputDataMutex}; auto commonArgs{normalInputData.front()->GetSpan().as()}; normalInputData.pop(); @@ -135,8 +135,7 @@ namespace skyline::applet::swkbd { } void SoftwareKeyboardApplet::PushNormalDataToApplet(std::shared_ptr data) { - std::scoped_lock lock{inputDataMutex}; - normalInputData.emplace(data); + PushNormalInput(data); } void SoftwareKeyboardApplet::PushInteractiveDataToApplet(std::shared_ptr data) { diff --git a/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.h b/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.h index 4982200f..1c34a5b4 100644 --- a/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.h +++ b/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_applet.h @@ -15,7 +15,7 @@ namespace skyline::applet::swkbd { * @url https://switchbrew.org/wiki/Software_Keyboard * @brief An implementation for the Software Keyboard (swkbd) Applet which handles translating guest applet transactions to the appropriate host behavior */ - class SoftwareKeyboardApplet : public service::am::IApplet { + class SoftwareKeyboardApplet : public service::am::IApplet, service::am::EnableNormalQueue { private: /** * @url https://switchbrew.org/wiki/Software_Keyboard#CloseResult @@ -73,8 +73,6 @@ namespace skyline::applet::swkbd { #pragma pack(pop) - std::mutex inputDataMutex; - std::queue> normalInputData; KeyboardConfigVB config{}; bool validationPending{}; std::u16string currentText{}; diff --git a/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_config.cpp b/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_config.cpp index 6b035866..9e1b0538 100644 --- a/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_config.cpp +++ b/app/src/main/cpp/skyline/applet/swkbd/software_keyboard_config.cpp @@ -7,7 +7,7 @@ namespace skyline::applet::swkbd { KeyboardConfigVB::KeyboardConfigVB() = default; - KeyboardConfigVB::KeyboardConfigVB(const KeyboardConfigV7 &v7config) : commonConfig(v7config.commonConfig), separateTextPos(v7config.separateTextPos) {} + KeyboardConfigVB::KeyboardConfigVB(const KeyboardConfigV7 &v7config) : commonConfig{v7config.commonConfig}, separateTextPos{v7config.separateTextPos} {} - KeyboardConfigVB::KeyboardConfigVB(const KeyboardConfigV0 &v0config) : commonConfig(v0config.commonConfig) {} + KeyboardConfigVB::KeyboardConfigVB(const KeyboardConfigV0 &v0config) : commonConfig{v0config.commonConfig} {} } diff --git a/app/src/main/cpp/skyline/services/am/applet/IApplet.h b/app/src/main/cpp/skyline/services/am/applet/IApplet.h index fbe80e56..3cbfaf5c 100644 --- a/app/src/main/cpp/skyline/services/am/applet/IApplet.h +++ b/app/src/main/cpp/skyline/services/am/applet/IApplet.h @@ -8,7 +8,6 @@ #include #include - namespace skyline::service::am { /** * @brief The base class all Applets have to inherit from @@ -70,4 +69,60 @@ namespace skyline::service::am { */ std::shared_ptr PopInteractiveAndClear(); }; + + /** + * @brief Utility class for applets that need to queue the normal data sent to them + */ + class EnableNormalQueue { + protected: + std::mutex normalInputDataMutex; + std::queue> normalInputData; + + std::shared_ptr PopNormalInput() { + std::scoped_lock lock{normalInputDataMutex}; + auto data{normalInputData.front()}; + normalInputData.pop(); + return data; + } + + template + T PopNormalInput() { + std::scoped_lock lock{normalInputDataMutex}; + auto data{normalInputData.front()->GetSpan().as()}; + normalInputData.pop(); + return data; + } + + void PushNormalInput(std::shared_ptr data) { + normalInputData.emplace(data); + } + }; + + /** + * @brief Utility class for applets that need to queue the interactive data sent to them + */ + class EnableInteractiveQueue { + protected: + std::mutex interactiveInputDataMutex; + std::queue> interactiveInputData; + + std::shared_ptr PopInteractiveInput() { + std::scoped_lock lock{interactiveInputDataMutex}; + auto data{interactiveInputData.front()}; + interactiveInputData.pop(); + return data; + } + + template + T PopInteractiveInput() { + std::scoped_lock lock{interactiveInputDataMutex}; + auto data{interactiveInputData.front()->GetSpan().as()}; + interactiveInputData.pop(); + return data; + } + + void PushInteractiveInput(std::shared_ptr data) { + interactiveInputData.emplace(data); + } + }; }