From 7de6b410305fcfcd34078e62fbe0ceedb43663f9 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 30 Dec 2023 20:51:23 -0500 Subject: service: split am into components --- src/core/CMakeLists.txt | 45 + src/core/hle/service/am/am.cpp | 2677 +------------------- src/core/hle/service/am/am.h | 454 +--- src/core/hle/service/am/am_results.h | 14 + src/core/hle/service/am/applet_ae.cpp | 258 +- .../hle/service/am/applet_common_functions.cpp | 47 + src/core/hle/service/am/applet_common_functions.h | 19 + src/core/hle/service/am/applet_message_queue.cpp | 68 + src/core/hle/service/am/applet_message_queue.h | 75 + src/core/hle/service/am/applet_oe.cpp | 100 +- src/core/hle/service/am/applets/applet_cabinet.cpp | 6 +- .../hle/service/am/applets/applet_controller.cpp | 1 + src/core/hle/service/am/applets/applet_error.cpp | 1 + .../service/am/applets/applet_general_backend.cpp | 1 + .../hle/service/am/applets/applet_mii_edit.cpp | 1 + .../service/am/applets/applet_profile_select.cpp | 1 + .../am/applets/applet_software_keyboard.cpp | 1 + .../hle/service/am/applets/applet_web_browser.cpp | 1 + src/core/hle/service/am/applets/applets.cpp | 6 +- src/core/hle/service/am/application_creator.cpp | 25 + src/core/hle/service/am/application_creator.h | 16 + src/core/hle/service/am/application_functions.cpp | 610 +++++ src/core/hle/service/am/application_functions.h | 63 + src/core/hle/service/am/application_proxy.cpp | 114 + src/core/hle/service/am/application_proxy.h | 32 + src/core/hle/service/am/audio_controller.cpp | 91 + src/core/hle/service/am/audio_controller.h | 36 + src/core/hle/service/am/common_state_getter.cpp | 288 +++ src/core/hle/service/am/common_state_getter.h | 78 + src/core/hle/service/am/debug_functions.cpp | 44 + src/core/hle/service/am/debug_functions.h | 16 + src/core/hle/service/am/display_controller.cpp | 97 + src/core/hle/service/am/display_controller.h | 24 + .../hle/service/am/global_state_controller.cpp | 34 + src/core/hle/service/am/global_state_controller.h | 16 + src/core/hle/service/am/home_menu_functions.cpp | 57 + src/core/hle/service/am/home_menu_functions.h | 25 + .../hle/service/am/library_applet_accessor.cpp | 178 ++ src/core/hle/service/am/library_applet_accessor.h | 34 + src/core/hle/service/am/library_applet_creator.cpp | 145 ++ src/core/hle/service/am/library_applet_creator.h | 22 + src/core/hle/service/am/library_applet_proxy.cpp | 142 ++ src/core/hle/service/am/library_applet_proxy.h | 35 + .../service/am/library_applet_self_accessor.cpp | 382 +++ .../hle/service/am/library_applet_self_accessor.h | 38 + src/core/hle/service/am/lock_accessor.cpp | 71 + src/core/hle/service/am/lock_accessor.h | 28 + .../hle/service/am/process_winding_controller.cpp | 73 + .../hle/service/am/process_winding_controller.h | 20 + src/core/hle/service/am/self_controller.cpp | 438 ++++ src/core/hle/service/am/self_controller.h | 72 + src/core/hle/service/am/storage.cpp | 60 + src/core/hle/service/am/storage.h | 42 + src/core/hle/service/am/storage_accessor.cpp | 82 + src/core/hle/service/am/storage_accessor.h | 24 + src/core/hle/service/am/system_applet_proxy.cpp | 135 + src/core/hle/service/am/system_applet_proxy.h | 34 + src/core/hle/service/am/window_controller.cpp | 55 + src/core/hle/service/am/window_controller.h | 21 + src/yuzu/configuration/configure_input.cpp | 1 + src/yuzu/main.cpp | 1 + 61 files changed, 4093 insertions(+), 3482 deletions(-) create mode 100644 src/core/hle/service/am/am_results.h create mode 100644 src/core/hle/service/am/applet_common_functions.cpp create mode 100644 src/core/hle/service/am/applet_common_functions.h create mode 100644 src/core/hle/service/am/applet_message_queue.cpp create mode 100644 src/core/hle/service/am/applet_message_queue.h create mode 100644 src/core/hle/service/am/application_creator.cpp create mode 100644 src/core/hle/service/am/application_creator.h create mode 100644 src/core/hle/service/am/application_functions.cpp create mode 100644 src/core/hle/service/am/application_functions.h create mode 100644 src/core/hle/service/am/application_proxy.cpp create mode 100644 src/core/hle/service/am/application_proxy.h create mode 100644 src/core/hle/service/am/audio_controller.cpp create mode 100644 src/core/hle/service/am/audio_controller.h create mode 100644 src/core/hle/service/am/common_state_getter.cpp create mode 100644 src/core/hle/service/am/common_state_getter.h create mode 100644 src/core/hle/service/am/debug_functions.cpp create mode 100644 src/core/hle/service/am/debug_functions.h create mode 100644 src/core/hle/service/am/display_controller.cpp create mode 100644 src/core/hle/service/am/display_controller.h create mode 100644 src/core/hle/service/am/global_state_controller.cpp create mode 100644 src/core/hle/service/am/global_state_controller.h create mode 100644 src/core/hle/service/am/home_menu_functions.cpp create mode 100644 src/core/hle/service/am/home_menu_functions.h create mode 100644 src/core/hle/service/am/library_applet_accessor.cpp create mode 100644 src/core/hle/service/am/library_applet_accessor.h create mode 100644 src/core/hle/service/am/library_applet_creator.cpp create mode 100644 src/core/hle/service/am/library_applet_creator.h create mode 100644 src/core/hle/service/am/library_applet_proxy.cpp create mode 100644 src/core/hle/service/am/library_applet_proxy.h create mode 100644 src/core/hle/service/am/library_applet_self_accessor.cpp create mode 100644 src/core/hle/service/am/library_applet_self_accessor.h create mode 100644 src/core/hle/service/am/lock_accessor.cpp create mode 100644 src/core/hle/service/am/lock_accessor.h create mode 100644 src/core/hle/service/am/process_winding_controller.cpp create mode 100644 src/core/hle/service/am/process_winding_controller.h create mode 100644 src/core/hle/service/am/self_controller.cpp create mode 100644 src/core/hle/service/am/self_controller.h create mode 100644 src/core/hle/service/am/storage.cpp create mode 100644 src/core/hle/service/am/storage.h create mode 100644 src/core/hle/service/am/storage_accessor.cpp create mode 100644 src/core/hle/service/am/storage_accessor.h create mode 100644 src/core/hle/service/am/system_applet_proxy.cpp create mode 100644 src/core/hle/service/am/system_applet_proxy.h create mode 100644 src/core/hle/service/am/window_controller.cpp create mode 100644 src/core/hle/service/am/window_controller.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ea6b2c285..3a2ba9ed4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -392,6 +392,7 @@ add_library(core STATIC hle/service/acc/profile_manager.h hle/service/am/am.cpp hle/service/am/am.h + hle/service/am/am_results.h hle/service/am/applet_ae.cpp hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp @@ -417,12 +418,56 @@ add_library(core STATIC hle/service/am/applets/applet_web_browser_types.h hle/service/am/applets/applets.cpp hle/service/am/applets/applets.h + hle/service/am/applet_common_functions.cpp + hle/service/am/applet_common_functions.h + hle/service/am/applet_message_queue.cpp + hle/service/am/applet_message_queue.h + hle/service/am/application_creator.cpp + hle/service/am/application_creator.h + hle/service/am/application_functions.cpp + hle/service/am/application_functions.h + hle/service/am/application_proxy.cpp + hle/service/am/application_proxy.h + hle/service/am/audio_controller.cpp + hle/service/am/audio_controller.h + hle/service/am/common_state_getter.cpp + hle/service/am/common_state_getter.h + hle/service/am/debug_functions.cpp + hle/service/am/debug_functions.h + hle/service/am/display_controller.cpp + hle/service/am/display_controller.h + hle/service/am/global_state_controller.cpp + hle/service/am/global_state_controller.h + hle/service/am/home_menu_functions.cpp + hle/service/am/home_menu_functions.h hle/service/am/idle.cpp hle/service/am/idle.h + hle/service/am/library_applet_accessor.cpp + hle/service/am/library_applet_accessor.h + hle/service/am/library_applet_creator.cpp + hle/service/am/library_applet_creator.h + hle/service/am/library_applet_proxy.cpp + hle/service/am/library_applet_proxy.h + hle/service/am/library_applet_self_accessor.cpp + hle/service/am/library_applet_self_accessor.h + hle/service/am/lock_accessor.cpp + hle/service/am/lock_accessor.h hle/service/am/omm.cpp hle/service/am/omm.h + hle/service/am/process_winding_controller.cpp + hle/service/am/process_winding_controller.h + hle/service/am/self_controller.cpp + hle/service/am/self_controller.h + hle/service/am/system_applet_proxy.cpp + hle/service/am/system_applet_proxy.h hle/service/am/spsm.cpp hle/service/am/spsm.h + hle/service/am/storage_accessor.cpp + hle/service/am/storage_accessor.h + hle/service/am/storage.cpp + hle/service/am/storage.h + hle/service/am/window_controller.cpp + hle/service/am/window_controller.h hle/service/aoc/aoc_u.cpp hle/service/aoc/aoc_u.h hle/service/apm/apm.cpp diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 38f67adcd..46bc4f703 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1,2541 +1,17 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include -#include -#include "common/settings.h" -#include "common/settings_enums.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/file_sys/control_metadata.h" -#include "core/file_sys/patch_manager.h" -#include "core/file_sys/registered_cache.h" -#include "core/file_sys/savedata_factory.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_transfer_memory.h" -#include "core/hle/result.h" -#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" -#include "core/hle/service/am/applets/applet_cabinet.h" -#include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/am/applets/applet_mii_edit_types.h" -#include "core/hle/service/am/applets/applet_profile_select.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" -#include "core/hle/service/am/applets/applet_web_browser.h" -#include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" #include "core/hle/service/am/spsm.h" -#include "core/hle/service/apm/apm_controller.h" -#include "core/hle/service/apm/apm_interface.h" -#include "core/hle/service/bcat/backend/backend.h" -#include "core/hle/service/caps/caps_su.h" -#include "core/hle/service/caps/caps_types.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/save_data_controller.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/ns/ns.h" -#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" -#include "core/hle/service/nvnflinger/nvnflinger.h" -#include "core/hle/service/pm/pm.h" #include "core/hle/service/server_manager.h" -#include "core/hle/service/sm/sm.h" -#include "core/hle/service/vi/vi.h" -#include "core/hle/service/vi/vi_results.h" -#include "core/memory.h" -#include "hid_core/hid_types.h" -#include "hid_core/resources/npad/npad.h" namespace Service::AM { -constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; -constexpr Result ResultNoMessages{ErrorModule::AM, 3}; -constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; - -enum class LaunchParameterKind : u32 { - UserChannel = 1, - AccountPreselectedUser = 2, -}; - -constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; - -struct LaunchParameterAccountPreselectedUser { - u32_le magic; - u32_le is_account_selected; - Common::UUID current_user; - INSERT_PADDING_BYTES(0x70); -}; -static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); - -IWindowController::IWindowController(Core::System& system_) - : ServiceFramework{system_, "IWindowController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "CreateWindow"}, - {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, - {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"}, - {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, - {11, nullptr, "ReleaseForegroundRights"}, - {12, nullptr, "RejectToChangeIntoBackground"}, - {20, nullptr, "SetAppletWindowVisibility"}, - {21, nullptr, "SetAppletGpuTimeSlice"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IWindowController::~IWindowController() = default; - -void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { - const u64 process_id = system.ApplicationProcess()->GetProcessId(); - - LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(process_id); -} - -void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { - const u64 process_id = 0; - - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(process_id); -} - -void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IAudioController::IAudioController(Core::System& system_) - : ServiceFramework{system_, "IAudioController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, - {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"}, - {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"}, - {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"}, - {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IAudioController::~IAudioController() = default; - -void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const float main_applet_volume_tmp = rp.Pop(); - const float library_applet_volume_tmp = rp.Pop(); - - LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}", - main_applet_volume_tmp, library_applet_volume_tmp); - - // Ensure the volume values remain within the 0-100% range - main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume); - library_applet_volume = - std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(main_applet_volume); -} - -void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(library_applet_volume); -} - -void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) { - struct Parameters { - float volume; - s64 fade_time_ns; - }; - static_assert(sizeof(Parameters) == 16); - - IPC::RequestParser rp{ctx}; - const auto parameters = rp.PopRaw(); - - LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume, - parameters.fade_time_ns); - - main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume); - fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns}; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const float transparent_volume_rate_tmp = rp.Pop(); - - LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp); - - // Clamp volume range to 0-100%. - transparent_volume_rate = - std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IDisplayController::IDisplayController(Core::System& system_) - : ServiceFramework{system_, "IDisplayController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetLastForegroundCaptureImage"}, - {1, nullptr, "UpdateLastForegroundCaptureImage"}, - {2, nullptr, "GetLastApplicationCaptureImage"}, - {3, nullptr, "GetCallerAppletCaptureImage"}, - {4, nullptr, "UpdateCallerAppletCaptureImage"}, - {5, nullptr, "GetLastForegroundCaptureImageEx"}, - {6, nullptr, "GetLastApplicationCaptureImageEx"}, - {7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"}, - {8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"}, - {9, nullptr, "CopyBetweenCaptureBuffers"}, - {10, nullptr, "AcquireLastApplicationCaptureBuffer"}, - {11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, - {12, nullptr, "AcquireLastForegroundCaptureBuffer"}, - {13, nullptr, "ReleaseLastForegroundCaptureBuffer"}, - {14, nullptr, "AcquireCallerAppletCaptureBuffer"}, - {15, nullptr, "ReleaseCallerAppletCaptureBuffer"}, - {16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, - {17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, - {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, - {20, nullptr, "ClearCaptureBuffer"}, - {21, nullptr, "ClearAppletTransitionBuffer"}, - {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, - {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, - {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"}, - {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"}, - {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"}, - {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"}, - {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IDisplayController::~IDisplayController() = default; - -void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1u); - rb.Push(0); -} - -void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1U); - rb.Push(0); -} - -void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1U); - rb.Push(0); -} - -void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IDebugFunctions::IDebugFunctions(Core::System& system_) - : ServiceFramework{system_, "IDebugFunctions"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, - {1, nullptr, "OpenMainApplication"}, - {10, nullptr, "PerformSystemButtonPressing"}, - {20, nullptr, "InvalidateTransitionLayer"}, - {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, - {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"}, - {40, nullptr, "GetAppletResourceUsageInfo"}, - {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"}, - {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"}, - {100, nullptr, "SetCpuBoostModeForApplet"}, - {101, nullptr, "CancelCpuBoostModeForApplet"}, - {110, nullptr, "PushToAppletBoundChannelForDebug"}, - {111, nullptr, "TryPopFromAppletBoundChannelForDebug"}, - {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"}, - {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"}, - {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"}, - {130, nullptr, "FriendInvitationSetApplicationParameter"}, - {131, nullptr, "FriendInvitationClearApplicationParameter"}, - {132, nullptr, "FriendInvitationPushApplicationParameter"}, - {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"}, - {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"}, - {300, nullptr, "TerminateAllRunningApplicationsForDebug"}, - {900, nullptr, "GetGrcProcessLaunchedSystemEvent"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IDebugFunctions::~IDebugFunctions() = default; - -ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) - : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, - service_context{system, "ISelfController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ISelfController::Exit, "Exit"}, - {1, &ISelfController::LockExit, "LockExit"}, - {2, &ISelfController::UnlockExit, "UnlockExit"}, - {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, - {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"}, - {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, - {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, - {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, - {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"}, - {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, - {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, - {15, nullptr, "SetScreenShotAppletIdentityInfo"}, - {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, - {17, nullptr, "SetControllerFirmwareUpdateSection"}, - {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, - {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, - {20, nullptr, "SetDesirableKeyboardLayout"}, - {21, nullptr, "GetScreenShotProgramId"}, - {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, - {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"}, - {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"}, - {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"}, - {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, - {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, - {46, nullptr, "SetRecordingLayerCompositionEnabled"}, - {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, - {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, - {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, - {61, nullptr, "SetMediaPlaybackState"}, - {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, - {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, - {64, nullptr, "SetInputDetectionSourceSet"}, - {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"}, - {66, nullptr, "GetCurrentIlluminance"}, - {67, nullptr, "IsIlluminanceAvailable"}, - {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"}, - {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, - {70, nullptr, "ReportMultimediaError"}, - {71, nullptr, "GetCurrentIlluminanceEx"}, - {72, nullptr, "SetInputDetectionPolicy"}, - {80, nullptr, "SetWirelessPriorityMode"}, - {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, - {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, - {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, - {110, nullptr, "SetApplicationAlbumUserData"}, - {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, - {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, - {1000, nullptr, "GetDebugStorageChannel"}, - }; - // clang-format on - - RegisterHandlers(functions); - - launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); - - // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is - // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple - // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not - // suspended if the event has previously been created by a call to - // GetAccumulatedSuspendedTickChangedEvent. - - accumulated_suspended_tick_changed_event = - service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); - accumulated_suspended_tick_changed_event->Signal(); -} - -ISelfController::~ISelfController() { - service_context.CloseEvent(launchable_event); - service_context.CloseEvent(accumulated_suspended_tick_changed_event); -} - -void ISelfController::Exit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - - system.Exit(); -} - -void ISelfController::LockExit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - system.SetExitLocked(true); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::UnlockExit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - system.SetExitLocked(false); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - - if (system.GetExitRequested()) { - system.Exit(); - } -} - -void ISelfController::EnterFatalSection(HLERequestContext& ctx) { - ++num_fatal_sections_entered; - LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - // Entry and exit of fatal sections must be balanced. - if (num_fatal_sections_entered == 0) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(Result{ErrorModule::AM, 512}); - return; - } - - --num_fatal_sections_entered; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - launchable_event->Signal(); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(launchable_event->GetReadableEvent()); -} - -void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto permission = rp.PopEnum(); - LOG_DEBUG(Service_AM, "called, permission={}", permission); - - screenshot_permission = permission; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - bool flag = rp.Pop(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - bool flag = rp.Pop(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. - IPC::RequestParser rp{ctx}; - - struct FocusHandlingModeParams { - u8 unknown0; - u8 unknown1; - u8 unknown2; - }; - const auto flags = rp.PopRaw(); - - LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", - flags.unknown0, flags.unknown1, flags.unknown2); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. - IPC::RequestParser rp{ctx}; - - bool enabled = rp.Pop(); - LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // TODO(Subv): Find out how AM determines the display to use, for now just - // create the layer in the Default display. - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto layer_id = nvnflinger.CreateLayer(*display_id); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(*layer_id); -} - -void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(this->EnsureBufferSharingEnabled()); -} - -void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(this->EnsureBufferSharingEnabled()); - rb.Push(system_shared_buffer_id); - rb.Push(system_shared_layer_id); -} - -void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(this->EnsureBufferSharingEnabled()); - rb.Push(system_shared_buffer_id); -} - -Result ISelfController::EnsureBufferSharingEnabled() { - if (buffer_sharing_enabled) { - return ResultSuccess; - } - - if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) { - return VI::ResultOperationFailed; - } - - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto result = nvnflinger.GetSystemBufferManager().Initialize( - &system_shared_buffer_id, &system_shared_layer_id, *display_id); - - if (result.IsSuccess()) { - buffer_sharing_enabled = true; - } - - return result; -} - -void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // TODO(Subv): Find out how AM determines the display to use, for now just - // create the layer in the Default display. - // This calls nn::vi::CreateRecordingLayer() which creates another layer. - // Currently we do not support more than 1 layer per display, output 1 layer id for now. - // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse - // side effects. - // TODO: Support multiple layers - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto layer_id = nvnflinger.CreateLayer(*display_id); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(*layer_id); -} - -void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - idle_time_detection_extension = rp.Pop(); - LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", - idle_time_detection_extension); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(idle_time_detection_extension); -} - -void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - is_auto_sleep_disabled = rp.Pop(); - - // On the system itself, if the previous state of is_auto_sleep_disabled - // differed from the current value passed in, it'd signify the internal - // window manager to update (and also increment some statistics like update counts) - // - // It'd also indicate this change to an idle handling context. - // - // However, given we're emulating this behavior, most of this can be ignored - // and it's sufficient to simply set the member variable for querying via - // IsAutoSleepDisabled(). - - LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(is_auto_sleep_disabled); -} - -void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - // This command returns the total number of system ticks since ISelfController creation - // where the game was suspended. Since Yuzu doesn't implement game suspension, this command - // can just always return 0 ticks. - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); -} - -void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - // This service call sets an internal flag whether a notification is shown when an image is - // captured. Currently we do not support capturing images via the capture button, so this can be - // stubbed for now. - const bool album_image_taken_notification_enabled = rp.Pop(); - - LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", - album_image_taken_notification_enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto report_option = rp.PopEnum(); - - LOG_INFO(Service_AM, "called, report_option={}", report_option); - - const auto screenshot_service = - system.ServiceManager().GetService( - "caps:su"); - - if (screenshot_service) { - screenshot_service->CaptureAndSaveScreenshot(report_option); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto is_record_volume_muted = rp.Pop(); - - LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -AppletMessageQueue::AppletMessageQueue(Core::System& system) - : service_context{system, "AppletMessageQueue"} { - on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); - on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged"); -} - -AppletMessageQueue::~AppletMessageQueue() { - service_context.CloseEvent(on_new_message); - service_context.CloseEvent(on_operation_mode_changed); -} - -Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { - return on_new_message->GetReadableEvent(); -} - -Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { - return on_operation_mode_changed->GetReadableEvent(); -} - -void AppletMessageQueue::PushMessage(AppletMessage msg) { - messages.push(msg); - on_new_message->Signal(); -} - -AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { - if (messages.empty()) { - on_new_message->Clear(); - return AppletMessage::None; - } - auto msg = messages.front(); - messages.pop(); - if (messages.empty()) { - on_new_message->Clear(); - } - return msg; -} - -std::size_t AppletMessageQueue::GetMessageCount() const { - return messages.size(); -} - -void AppletMessageQueue::RequestExit() { - PushMessage(AppletMessage::Exit); -} - -void AppletMessageQueue::RequestResume() { - PushMessage(AppletMessage::Resume); -} - -void AppletMessageQueue::FocusStateChanged() { - PushMessage(AppletMessage::FocusStateChanged); -} - -void AppletMessageQueue::OperationModeChanged() { - PushMessage(AppletMessage::OperationModeChanged); - PushMessage(AppletMessage::PerformanceModeChanged); - on_operation_mode_changed->Signal(); -} - -ILockAccessor::ILockAccessor(Core::System& system_) - : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, &ILockAccessor::TryLock, "TryLock"}, - {2, &ILockAccessor::Unlock, "Unlock"}, - {3, &ILockAccessor::GetEvent, "GetEvent"}, - {4,&ILockAccessor::IsLocked, "IsLocked"}, - }; - // clang-format on - - RegisterHandlers(functions); - - lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); -} - -ILockAccessor::~ILockAccessor() { - service_context.CloseEvent(lock_event); -}; - -void ILockAccessor::TryLock(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto return_handle = rp.Pop(); - - LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle); - - // TODO: When return_handle is true this function should return the lock handle - - is_locked = true; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(is_locked); -} - -void ILockAccessor::Unlock(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - is_locked = false; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ILockAccessor::GetEvent(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - lock_event->Signal(); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(lock_event->GetReadableEvent()); -} - -void ILockAccessor::IsLocked(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - rb.Push(is_locked); -} - -ICommonStateGetter::ICommonStateGetter(Core::System& system_, - std::shared_ptr msg_queue_) - : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, - service_context{system_, "ICommonStateGetter"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, - {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, - {2, nullptr, "GetThisAppletKind"}, - {3, nullptr, "AllowToEnterSleep"}, - {4, nullptr, "DisallowToEnterSleep"}, - {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, - {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, - {7, nullptr, "GetCradleStatus"}, - {8, &ICommonStateGetter::GetBootMode, "GetBootMode"}, - {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, - {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"}, - {11, nullptr, "ReleaseSleepLock"}, - {12, nullptr, "ReleaseSleepLockTransiently"}, - {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"}, - {14, nullptr, "GetWakeupCount"}, - {20, nullptr, "PushToGeneralChannel"}, - {30, nullptr, "GetHomeButtonReaderLockAccessor"}, - {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, - {32, nullptr, "GetWriterLockAccessorEx"}, - {40, nullptr, "GetCradleFwVersion"}, - {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, - {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, - {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, - {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, - {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, - {55, nullptr, "IsInControllerFirmwareUpdateSection"}, - {59, nullptr, "SetVrPositionForDebug"}, - {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, - {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, - {62, nullptr, "GetHdcpAuthenticationState"}, - {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, - {64, nullptr, "SetTvPowerStateMatchingMode"}, - {65, nullptr, "GetApplicationIdByContentActionName"}, - {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, - {67, nullptr, "CancelCpuBoostMode"}, - {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"}, - {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, - {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, - {91, nullptr, "GetCurrentPerformanceConfiguration"}, - {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, - {110, nullptr, "OpenMyGpuErrorHandler"}, - {120, nullptr, "GetAppletLaunchedHistory"}, - {200, nullptr, "GetOperationModeSystemInfo"}, - {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"}, - {400, nullptr, "ActivateMigrationService"}, - {401, nullptr, "DeactivateMigrationService"}, - {500, nullptr, "DisableSleepTillShutdown"}, - {501, nullptr, "SuppressDisablingSleepTemporarily"}, - {502, nullptr, "IsSleepEnabled"}, - {503, nullptr, "IsDisablingSleepSuppressed"}, - {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, - }; - // clang-format on - - RegisterHandlers(functions); - - sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); - - // Configure applets to be in foreground state - msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); - msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); -} - -ICommonStateGetter::~ICommonStateGetter() { - service_context.CloseEvent(sleep_lock_event); -}; - -void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(Service::PM::SystemBootMode::Normal)); // Normal boot mode -} - -void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); -} - -void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - const auto message = msg_queue->PopMessage(); - IPC::ResponseBuilder rb{ctx, 3}; - - if (message == AppletMessageQueue::AppletMessage::None) { - LOG_ERROR(Service_AM, "Message queue is empty"); - rb.Push(AM::ResultNoMessages); - rb.PushEnum(message); - return; - } - - rb.Push(ResultSuccess); - rb.PushEnum(message); -} - -void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(FocusState::InFocus)); -} - -void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // Sleep lock is acquired immediately. - sleep_lock_event->Signal(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown = rp.Pop(); - - LOG_INFO(Service_AM, "called, unknown={}", unknown); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); -} - -void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); -} - -void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(vr_mode_state); -} - -void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - vr_mode_state = rp.Pop(); - - LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto is_lcd_backlight_off_enabled = rp.Pop(); - - LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}", - is_lcd_backlight_off_enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); -} - -void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - - if (Settings::IsDockedMode()) { - rb.Push(static_cast(Service::VI::DisplayResolution::DockedWidth)); - rb.Push(static_cast(Service::VI::DisplayResolution::DockedHeight)); - } else { - rb.Push(static_cast(Service::VI::DisplayResolution::UndockedWidth)); - rb.Push(static_cast(Service::VI::DisplayResolution::UndockedHeight)); - } -} - -void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS"); - - const auto& sm = system.ServiceManager(); - const auto apm_sys = sm.GetService("apm:sys"); - ASSERT(apm_sys != nullptr); - - apm_sys->SetCpuBoostMode(ctx); -} - -void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto system_button{rp.PopEnum()}; - - LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(SysPlatformRegion::Global); -} - -void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled( - HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IStorageImpl::~IStorageImpl() = default; - -class StorageDataImpl final : public IStorageImpl { -public: - explicit StorageDataImpl(std::vector&& buffer_) : buffer{std::move(buffer_)} {} - - std::vector& GetData() override { - return buffer; - } - - const std::vector& GetData() const override { - return buffer; - } - - std::size_t GetSize() const override { - return buffer.size(); - } - -private: - std::vector buffer; -}; - -IStorage::IStorage(Core::System& system_, std::vector&& buffer) - : ServiceFramework{system_, "IStorage"}, impl{std::make_shared( - std::move(buffer))} { - Register(); -} - -void IStorage::Register() { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorage::Open, "Open"}, - {1, nullptr, "OpenTransferStorage"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IStorage::~IStorage() = default; - -void IStorage::Open(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, *this); -} - -void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { - const bool use_docked_mode{Settings::IsDockedMode()}; - LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); -} - -void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode()); -} - -class ILibraryAppletAccessor final : public ServiceFramework { -public: - explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr applet_) - : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, - {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, - {10, &ILibraryAppletAccessor::Start, "Start"}, - {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"}, - {25, nullptr, "Terminate"}, - {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, - {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, - {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"}, - {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, - {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, - {102, nullptr, "PushExtraStorage"}, - {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, - {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, - {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, - {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, - {110, nullptr, "NeedsToExitProcess"}, - {120, nullptr, "GetLibraryAppletInfo"}, - {150, nullptr, "RequestForAppletToGetForeground"}, - {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetAppletStateChangedEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); - } - - void IsCompleted(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(applet->TransactionComplete()); - } - - void GetResult(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(applet->GetStatus()); - } - - void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Start(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - ASSERT(applet != nullptr); - - applet->Initialize(); - applet->Execute(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void RequestExit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - ASSERT(applet != nullptr); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(applet->RequestExit()); - } - - void PushInData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface().lock()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void PopOutData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - auto storage = applet->GetBroker().PopNormalDataToGame(); - if (storage == nullptr) { - LOG_DEBUG(Service_AM, - "storage is a nullptr. There is no data in the current normal channel"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(std::move(storage)); - } - - void PushInteractiveInData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface().lock()); - - ASSERT(applet->IsInitialized()); - applet->ExecuteInteractive(); - applet->Execute(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void PopInteractiveOutData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - auto storage = applet->GetBroker().PopInteractiveDataToGame(); - if (storage == nullptr) { - LOG_DEBUG(Service_AM, - "storage is a nullptr. There is no data in the current interactive channel"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(std::move(storage)); - } - - void GetPopOutDataEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); - } - - void GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); - } - - void GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is - // actually used anywhere - constexpr u64 handle = 0xdeadbeef; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(handle); - } - - std::shared_ptr applet; -}; - -IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) - : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorageAccessor::GetSize, "GetSize"}, - {10, &IStorageAccessor::Write, "Write"}, - {11, &IStorageAccessor::Read, "Read"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IStorageAccessor::~IStorageAccessor() = default; - -void IStorageAccessor::GetSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - - rb.Push(ResultSuccess); - rb.Push(static_cast(backing.GetSize())); -} - -void IStorageAccessor::Write(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const u64 offset{rp.Pop()}; - const auto data{ctx.ReadBuffer()}; - const std::size_t size{std::min(data.size(), backing.GetSize() - offset)}; - - LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - - if (offset > backing.GetSize()) { - LOG_ERROR(Service_AM, - "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", - backing.GetSize(), size, offset); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultInvalidOffset); - return; - } - - std::memcpy(backing.GetData().data() + offset, data.data(), size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IStorageAccessor::Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const u64 offset{rp.Pop()}; - const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; - - LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - - if (offset > backing.GetSize()) { - LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", - backing.GetSize(), size, offset); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultInvalidOffset); - return; - } - - ctx.WriteBuffer(backing.GetData().data() + offset, size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletCreator"} { - static const FunctionInfo functions[] = { - {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, - {1, nullptr, "TerminateAllLibraryApplets"}, - {2, nullptr, "AreAnyLibraryAppletsLeft"}, - {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, - {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, - {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, - }; - RegisterHandlers(functions); -} - -ILibraryAppletCreator::~ILibraryAppletCreator() = default; - -void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto applet_id = rp.PopRaw(); - const auto applet_mode = rp.PopRaw(); - - LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, - applet_mode); - - const auto& applet_manager{system.GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, applet_mode); - - if (applet == nullptr) { - LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, applet); -} - -void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const s64 size{rp.Pop()}; - - LOG_DEBUG(Service_AM, "called, size={}", size); - - if (size <= 0) { - LOG_ERROR(Service_AM, "size is less than or equal to 0"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - std::vector buffer(size); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(buffer)); -} - -void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - struct Parameters { - u8 permissions; - s64 size; - }; - - const auto parameters{rp.PopRaw()}; - const auto handle{ctx.GetCopyHandle(0)}; - - LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, - parameters.size, handle); - - if (parameters.size <= 0) { - LOG_ERROR(Service_AM, "size is less than or equal to 0"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - auto transfer_mem = ctx.GetObjectFromHandle(handle); - - if (transfer_mem.IsNull()) { - LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - std::vector memory(transfer_mem->GetSize()); - ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(memory)); -} - -void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const s64 size{rp.Pop()}; - const auto handle{ctx.GetCopyHandle(0)}; - - LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); - - if (size <= 0) { - LOG_ERROR(Service_AM, "size is less than or equal to 0"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - auto transfer_mem = ctx.GetObjectFromHandle(handle); - - if (transfer_mem.IsNull()) { - LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - std::vector memory(transfer_mem->GetSize()); - ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(memory)); -} - -ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, - {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, - {2, nullptr, "PopInteractiveInData"}, - {3, nullptr, "PushInteractiveOutData"}, - {5, nullptr, "GetPopInDataEvent"}, - {6, nullptr, "GetPopInteractiveInDataEvent"}, - {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, - {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, - {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, - {13, nullptr, "CanUseApplicationCore"}, - {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, - {15, nullptr, "GetMainAppletApplicationControlProperty"}, - {16, nullptr, "GetMainAppletStorageId"}, - {17, nullptr, "GetCallerAppletIdentityInfoStack"}, - {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, - {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, - {20, nullptr, "PopExtraStorage"}, - {25, nullptr, "GetPopExtraStorageEvent"}, - {30, nullptr, "UnpopInData"}, - {31, nullptr, "UnpopExtraStorage"}, - {40, nullptr, "GetIndirectLayerProducerHandle"}, - {50, nullptr, "ReportVisibleError"}, - {51, nullptr, "ReportVisibleErrorWithErrorContext"}, - {60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, - {70, nullptr, "GetCurrentApplicationId"}, - {80, nullptr, "RequestExitToSelf"}, - {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, - {100, nullptr, "CreateGameMovieTrimmer"}, - {101, nullptr, "ReserveResourceForMovieOperation"}, - {102, nullptr, "UnreserveResourceForMovieOperation"}, - {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"}, - {120, nullptr, "GetLaunchStorageInfoForDebug"}, - {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, - {140, nullptr, "SetApplicationMemoryReservation"}, - {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, - }; - // clang-format on - RegisterHandlers(functions); - - switch (system.GetAppletManager().GetCurrentAppletId()) { - case Applets::AppletId::Cabinet: - PushInShowCabinetData(); - break; - case Applets::AppletId::MiiEdit: - PushInShowMiiEditData(); - break; - case Applets::AppletId::PhotoViewer: - PushInShowAlbum(); - break; - case Applets::AppletId::SoftwareKeyboard: - PushInShowSoftwareKeyboard(); - break; - case Applets::AppletId::Controller: - PushInShowController(); - break; - default: - break; - } -} - -ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; -void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - if (queue_data.empty()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultNoDataInChannel); - return; - } - - auto data = queue_data.front(); - queue_data.pop_front(); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(data)); -} - -void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - system.Exit(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { - struct LibraryAppletInfo { - Applets::AppletId applet_id; - Applets::LibraryAppletMode library_applet_mode; - }; - - LOG_WARNING(Service_AM, "(STUBBED) called"); - - const LibraryAppletInfo applet_info{ - .applet_id = system.GetAppletManager().GetCurrentAppletId(), - .library_applet_mode = Applets::LibraryAppletMode::AllForeground, - }; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushRaw(applet_info); -} - -void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { - struct AppletIdentityInfo { - Applets::AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; - }; - static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); - - LOG_WARNING(Service_AM, "(STUBBED) called"); - - const AppletIdentityInfo applet_info{ - .applet_id = Applets::AppletId::QLaunch, - .application_id = 0x0100000000001000ull, - }; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(applet_info); -} - -void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { - struct AppletIdentityInfo { - Applets::AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; - }; - static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); - LOG_WARNING(Service_AM, "(STUBBED) called"); - - const AppletIdentityInfo applet_info{ - .applet_id = Applets::AppletId::QLaunch, - .application_id = 0x0100000000001000ull, - }; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(applet_info); -} - -void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { - const Service::Account::ProfileManager manager{}; - bool is_empty{true}; - s32 user_count{-1}; - - LOG_INFO(Service_AM, "called"); - - if (manager.GetUserCount() > 0) { - is_empty = false; - user_count = static_cast(manager.GetUserCount()); - ctx.WriteBuffer(manager.GetAllUsers()); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(is_empty); - rb.Push(user_count); -} - -void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void ILibraryAppletSelfAccessor::PushInShowAlbum() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = 1, - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector argument_data(sizeof(arguments)); - std::vector settings_data{2}; - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(settings_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowController() { - const Applets::CommonArguments common_args = { - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast(Applets::ControllerAppletVersion::Version8), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - Applets::ControllerSupportArgNew user_args = { - .header = {.player_count_min = 1, - .player_count_max = 4, - .enable_take_over_connection = true, - .enable_left_justify = false, - .enable_permit_joy_dual = true, - .enable_single_mode = false, - .enable_identification_color = false}, - .identification_colors = {}, - .enable_explain_text = false, - .explain_text = {}, - }; - - Applets::ControllerSupportArgPrivate private_args = { - .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), - .arg_size = sizeof(Applets::ControllerSupportArgNew), - .is_home_menu = true, - .flag_1 = true, - .mode = Applets::ControllerSupportMode::ShowControllerSupport, - .caller = Applets::ControllerSupportCaller:: - Application, // switchbrew: Always zero except with - // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, - // which sets this to the input param - .style_set = Core::HID::NpadStyleSet::None, - .joy_hold_type = 0, - }; - std::vector common_args_data(sizeof(common_args)); - std::vector private_args_data(sizeof(private_args)); - std::vector user_args_data(sizeof(user_args)); - - std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); - std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); - std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); - - queue_data.emplace_back(std::move(common_args_data)); - queue_data.emplace_back(std::move(private_args_data)); - queue_data.emplace_back(std::move(user_args_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowCabinetData() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast(Applets::CabinetAppletVersion::Version1), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - const Applets::StartParamForAmiiboSettings amiibo_settings{ - .param_1 = 0, - .applet_mode = system.GetAppletManager().GetCabinetMode(), - .flags = Applets::CabinetFlags::None, - .amiibo_settings_1 = 0, - .device_handle = 0, - .tag_info{}, - .register_info{}, - .amiibo_settings_3{}, - }; - - std::vector argument_data(sizeof(arguments)); - std::vector settings_data(sizeof(amiibo_settings)); - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(settings_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { - struct MiiEditV3 { - Applets::MiiEditAppletInputCommon common; - Applets::MiiEditAppletInputV3 input; - }; - static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); - - MiiEditV3 mii_arguments{ - .common = - { - .version = Applets::MiiEditAppletVersion::Version3, - .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, - }, - .input{}, - }; - - std::vector argument_data(sizeof(mii_arguments)); - std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); - - queue_data.emplace_back(std::move(argument_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast(Applets::SwkbdAppletVersion::Version524301), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector initial_string(0); - - const Applets::SwkbdConfigCommon swkbd_config{ - .type = Applets::SwkbdType::Qwerty, - .ok_text{}, - .left_optional_symbol_key{}, - .right_optional_symbol_key{}, - .use_prediction = false, - .key_disable_flags{}, - .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, - .header_text{}, - .sub_text{}, - .guide_text{}, - .max_text_length = 500, - .min_text_length = 0, - .password_mode = Applets::SwkbdPasswordMode::Disabled, - .text_draw_type = Applets::SwkbdTextDrawType::Box, - .enable_return_button = true, - .use_utf8 = false, - .use_blur_background = true, - .initial_string_offset{}, - .initial_string_length = static_cast(initial_string.size()), - .user_dictionary_offset{}, - .user_dictionary_entries{}, - .use_text_check = false, - }; - - Applets::SwkbdConfigNew swkbd_config_new{}; - - std::vector argument_data(sizeof(arguments)); - std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); - std::vector work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); - - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); - std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, - sizeof(Applets::SwkbdConfigNew)); - std::memcpy(work_buffer.data(), initial_string.data(), - swkbd_config.initial_string_length * sizeof(char16_t)); - - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(swkbd_data)); - queue_data.emplace_back(std::move(work_buffer)); -} - -IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) - : ServiceFramework{system_, "IAppletCommonFunctions"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "SetTerminateResult"}, - {10, nullptr, "ReadThemeStorage"}, - {11, nullptr, "WriteThemeStorage"}, - {20, nullptr, "PushToAppletBoundChannel"}, - {21, nullptr, "TryPopFromAppletBoundChannel"}, - {40, nullptr, "GetDisplayLogicalResolution"}, - {42, nullptr, "SetDisplayMagnification"}, - {50, nullptr, "SetHomeButtonDoubleClickEnabled"}, - {51, nullptr, "GetHomeButtonDoubleClickEnabled"}, - {52, nullptr, "IsHomeButtonShortPressedBlocked"}, - {60, nullptr, "IsVrModeCurtainRequired"}, - {61, nullptr, "IsSleepRequiredByHighTemperature"}, - {62, nullptr, "IsSleepRequiredByLowBattery"}, - {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"}, - {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"}, - {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"}, - {90, nullptr, "OpenNamedChannelAsParent"}, - {91, nullptr, "OpenNamedChannelAsChild"}, - {100, nullptr, "SetApplicationCoreUsageMode"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IAppletCommonFunctions::~IAppletCommonFunctions() = default; - -void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IApplicationFunctions::IApplicationFunctions(Core::System& system_) - : ServiceFramework{system_, "IApplicationFunctions"}, service_context{system, - "IApplicationFunctions"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, - {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, - {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, - {12, nullptr, "CreateApplicationAndRequestToStart"}, - {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, - {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, - {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, - {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, - {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, - {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, - {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, - {24, nullptr, "GetLaunchStorageInfoForDebug"}, - {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, - {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, - {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"}, - {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"}, - {29, nullptr, "GetCacheStorageMax"}, - {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, - {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, - {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, - {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, - {34, nullptr, "SelectApplicationLicense"}, - {35, nullptr, "GetDeviceSaveDataSizeMax"}, - {36, nullptr, "GetLimitedApplicationLicense"}, - {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, - {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, - {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, - {60, nullptr, "SetMediaPlaybackStateForApplication"}, - {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"}, - {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, - {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, - {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, - {70, nullptr, "RequestToShutdown"}, - {71, nullptr, "RequestToReboot"}, - {72, nullptr, "RequestToSleep"}, - {80, nullptr, "ExitAndRequestToShowThanksMessage"}, - {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, - {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, - {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, - {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, - {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, - {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, - {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, - {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, - {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, - {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, - {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, - {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, - {131, nullptr, "SetDelayTimeToAbortOnGpuError"}, - {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, - {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, - {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"}, - {151, nullptr, "TryPopFromNotificationStorageChannel"}, - {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"}, - {170, nullptr, "SetHdcpAuthenticationActivated"}, - {180, nullptr, "GetLaunchRequiredVersion"}, - {181, nullptr, "UpgradeLaunchRequiredVersion"}, - {190, nullptr, "SendServerMaintenanceOverlayNotification"}, - {200, nullptr, "GetLastApplicationExitReason"}, - {500, nullptr, "StartContinuousRecordingFlushForDebug"}, - {1000, nullptr, "CreateMovieMaker"}, - {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"}, - }; - // clang-format on - - RegisterHandlers(functions); - - gpu_error_detected_event = - service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); - friend_invitation_storage_channel_event = - service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); - notification_storage_channel_event = - service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); - health_warning_disappeared_system_event = - service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); -} - -IApplicationFunctions::~IApplicationFunctions() { - service_context.CloseEvent(gpu_error_detected_event); - service_context.CloseEvent(friend_invitation_storage_channel_event); - service_context.CloseEvent(notification_storage_channel_event); - service_context.CloseEvent(health_warning_disappeared_system_event); -} - -void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto is_visible = rp.Pop(); - - LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto kind = rp.PopEnum(); - - LOG_INFO(Service_AM, "called, kind={:08X}", kind); - - if (kind == LaunchParameterKind::UserChannel) { - auto channel = system.GetUserChannel(); - if (channel.empty()) { - LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - auto data = channel.back(); - channel.pop_back(); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(data)); - } else if (kind == LaunchParameterKind::AccountPreselectedUser && - !launch_popped_account_preselect) { - // TODO: Verify this is hw-accurate - LaunchParameterAccountPreselectedUser params{}; - - params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; - params.is_account_selected = 1; - - Account::ProfileManager profile_manager{}; - const auto uuid = profile_manager.GetUser(static_cast(Settings::values.current_user)); - ASSERT(uuid.has_value() && uuid->IsValid()); - params.current_user = *uuid; - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - - std::vector buffer(sizeof(LaunchParameterAccountPreselectedUser)); - std::memcpy(buffer.data(), ¶ms, buffer.size()); - - rb.PushIpcInterface(system, std::move(buffer)); - launch_popped_account_preselect = true; - } else { - LOG_ERROR(Service_AM, "Unknown launch parameter kind."); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - } -} - -void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - u128 user_id = rp.PopRaw(); - - LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); - - FileSys::SaveDataAttribute attribute{}; - attribute.title_id = system.GetApplicationProcessProgramID(); - attribute.user_id = user_id; - attribute.type = FileSys::SaveDataType::SaveData; - - FileSys::VirtualDir save_data{}; - const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( - &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(res); - rb.Push(0); -} - -void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { - // Takes an input u32 Result, no output. - // For example, in some cases official apps use this with error 0x2A2 then - // uses svcBreak. - - IPC::RequestParser rp{ctx}; - u32 result = rp.Pop(); - LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - std::array version_string{}; - - const auto res = [this] { - const auto title_id = system.GetApplicationProcessProgramID(); - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), - system.GetFileSystemController(), - system.GetContentProvider()}; - return pm_update.GetControlMetadata(); - }(); - - if (res.first != nullptr) { - const auto& version = res.first->GetVersionString(); - std::copy(version.begin(), version.end(), version_string.begin()); - } else { - static constexpr char default_version[]{"1.0.0"}; - std::memcpy(version_string.data(), default_version, sizeof(default_version)); - } - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(version_string); -} - -void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { - // TODO(bunnei): This should be configurable - LOG_DEBUG(Service_AM, "called"); - - // Get supported languages from NACP, if possible - // Default to 0 (all languages supported) - u32 supported_languages = 0; - - const auto res = [this] { - const auto title_id = system.GetApplicationProcessProgramID(); - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), - system.GetFileSystemController(), - system.GetContentProvider()}; - return pm_update.GetControlMetadata(); - }(); - - if (res.first != nullptr) { - supported_languages = res.first->GetSupportedLanguages(); - } - - // Call IApplicationManagerInterface implementation. - auto& service_manager = system.ServiceManager(); - auto ns_am2 = service_manager.GetService("ns:am2"); - auto app_man = ns_am2->GetApplicationManagerInterface(); - - // Get desired application language - u8 desired_language{}; - const auto res_lang = - app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages); - if (res_lang != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res_lang); - return; - } - - // Convert to settings language code. - u64 language_code{}; - const auto res_code = - app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language); - if (res_code != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res_code); - return; - } - - LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(language_code); -} - -void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - constexpr bool gameplay_recording_supported = false; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(gameplay_recording_supported); -} - -void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); // Unknown, seems to be ignored by official processes -} - -void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - - // Returns a 128-bit UUID - rb.Push(0); - rb.Push(0); -} - -void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { - struct Parameters { - FileSys::SaveDataType type; - u128 user_id; - u64 new_normal_size; - u64 new_journal_size; - }; - static_assert(sizeof(Parameters) == 40); - - IPC::RequestParser rp{ctx}; - const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw(); - - LOG_DEBUG(Service_AM, - "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " - "new_journal={:016X}", - static_cast(type), user_id[1], user_id[0], new_normal_size, new_journal_size); - - system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( - type, system.GetApplicationProcessProgramID(), user_id, - {new_normal_size, new_journal_size}); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - - // The following value is used upon failure to help the system recover. - // Since we always succeed, this should be 0. - rb.Push(0); -} - -void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { - struct Parameters { - FileSys::SaveDataType type; - u128 user_id; - }; - static_assert(sizeof(Parameters) == 24); - - IPC::RequestParser rp{ctx}; - const auto [type, user_id] = rp.PopRaw(); - - LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], - user_id[0]); - - const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( - type, system.GetApplicationProcessProgramID(), user_id); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.Push(size.normal); - rb.Push(size.journal); -} - -void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) { - struct InputParameters { - u16 index; - s64 size; - s64 journal_size; - }; - static_assert(sizeof(InputParameters) == 24); - - struct OutputParameters { - u32 storage_target; - u64 required_size; - }; - static_assert(sizeof(OutputParameters) == 16); - - IPC::RequestParser rp{ctx}; - const auto params = rp.PopRaw(); - - LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}", - params.index, params.size, params.journal_size); - - const OutputParameters resp{ - .storage_target = 1, - .required_size = 0, - }; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(resp); -} - -void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - constexpr u64 size_max_normal = 0xFFFFFFF; - constexpr u64 size_max_journal = 0xFFFFFFF; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.Push(size_max_normal); - rb.Push(size_max_journal); -} - -void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::RequestParser rp{ctx}; - [[maybe_unused]] const auto unk_1 = rp.Pop(); - [[maybe_unused]] const auto unk_2 = rp.Pop(); - const auto program_index = rp.Pop(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - - system.ExecuteProgram(program_index); -} - -void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - system.GetUserChannel().clear(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - const auto storage = rp.PopIpcInterface().lock(); - if (storage) { - system.GetUserChannel().push_back(storage->GetData()); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(previous_program_index); -} - -void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); -} - -void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); -} - -void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); -} - -void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); -} - -void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); -} - -void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { auto message_queue = std::make_shared(system); auto server_manager = std::make_unique(system); @@ -2550,155 +26,4 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { ServerManager::RunServer(std::move(server_manager)); } -IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) - : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system, - "IHomeMenuFunctions"} { - // clang-format off - static const FunctionInfo functions[] = { - {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, - {11, nullptr, "LockForeground"}, - {12, nullptr, "UnlockForeground"}, - {20, nullptr, "PopFromGeneralChannel"}, - {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, - {30, nullptr, "GetHomeButtonWriterLockAccessor"}, - {31, nullptr, "GetWriterLockAccessorEx"}, - {40, nullptr, "IsSleepEnabled"}, - {41, nullptr, "IsRebootEnabled"}, - {50, nullptr, "LaunchSystemApplet"}, - {51, nullptr, "LaunchStarter"}, - {100, nullptr, "PopRequestLaunchApplicationForDebug"}, - {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, - {200, nullptr, "LaunchDevMenu"}, - {1000, nullptr, "SetLastApplicationExitReason"}, - }; - // clang-format on - - RegisterHandlers(functions); - - pop_from_general_channel_event = - service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent"); -} - -IHomeMenuFunctions::~IHomeMenuFunctions() { - service_context.CloseEvent(pop_from_general_channel_event); -} - -void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); -} - -IGlobalStateController::IGlobalStateController(Core::System& system_) - : ServiceFramework{system_, "IGlobalStateController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestToEnterSleep"}, - {1, nullptr, "EnterSleep"}, - {2, nullptr, "StartSleepSequence"}, - {3, nullptr, "StartShutdownSequence"}, - {4, nullptr, "StartRebootSequence"}, - {9, nullptr, "IsAutoPowerDownRequested"}, - {10, nullptr, "LoadAndApplyIdlePolicySettings"}, - {11, nullptr, "NotifyCecSettingsChanged"}, - {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, - {13, nullptr, "UpdateDefaultDisplayResolution"}, - {14, nullptr, "ShouldSleepOnBoot"}, - {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, - {30, nullptr, "OpenCradleFirmwareUpdater"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IGlobalStateController::~IGlobalStateController() = default; - -IApplicationCreator::IApplicationCreator(Core::System& system_) - : ServiceFramework{system_, "IApplicationCreator"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "CreateApplication"}, - {1, nullptr, "PopLaunchRequestedApplication"}, - {10, nullptr, "CreateSystemApplication"}, - {100, nullptr, "PopFloatingApplicationForDevelopment"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IApplicationCreator::~IApplicationCreator() = default; - -IProcessWindingController::IProcessWindingController(Core::System& system_) - : ServiceFramework{system_, "IProcessWindingController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, - {11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"}, - {21, nullptr, "PushContext"}, - {22, nullptr, "PopContext"}, - {23, nullptr, "CancelWindingReservation"}, - {30, nullptr, "WindAndDoReserved"}, - {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"}, - {41, nullptr, "ReserveToStartAndWait"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IProcessWindingController::~IProcessWindingController() = default; - -void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - struct AppletProcessLaunchReason { - u8 flag; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(AppletProcessLaunchReason) == 0x4, - "AppletProcessLaunchReason is an invalid size"); - - AppletProcessLaunchReason reason{ - .flag = 0, - }; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw(reason); -} - -void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { - const auto applet_id = system.GetAppletManager().GetCurrentAppletId(); - const auto applet_mode = Applets::LibraryAppletMode::AllForeground; - - LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, - applet_mode); - - const auto& applet_manager{system.GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, applet_mode); - - if (applet == nullptr) { - LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, applet); -} - } // namespace Service::AM diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 905a71b9f..4a2d797bd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -1,20 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include -#include -#include - -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/service.h" - -namespace Kernel { -class KernelCore; -class KReadableEvent; -class KTransferMemory; -} // namespace Kernel +namespace Core { +class System; +} namespace Service::Nvnflinger { class Nvnflinger; @@ -22,443 +13,6 @@ class Nvnflinger; namespace Service::AM { -class AppletMessageQueue { -public: - // This is nn::am::AppletMessage - enum class AppletMessage : u32 { - None = 0, - ChangeIntoForeground = 1, - ChangeIntoBackground = 2, - Exit = 4, - ApplicationExited = 6, - FocusStateChanged = 15, - Resume = 16, - DetectShortPressingHomeButton = 20, - DetectLongPressingHomeButton = 21, - DetectShortPressingPowerButton = 22, - DetectMiddlePressingPowerButton = 23, - DetectLongPressingPowerButton = 24, - RequestToPrepareSleep = 25, - FinishedSleepSequence = 26, - SleepRequiredByHighTemperature = 27, - SleepRequiredByLowBattery = 28, - AutoPowerDown = 29, - OperationModeChanged = 30, - PerformanceModeChanged = 31, - DetectReceivingCecSystemStandby = 32, - SdCardRemoved = 33, - LaunchApplicationRequested = 50, - RequestToDisplay = 51, - ShowApplicationLogo = 55, - HideApplicationLogo = 56, - ForceHideApplicationLogo = 57, - FloatingApplicationDetected = 60, - DetectShortPressingCaptureButton = 90, - AlbumScreenShotTaken = 92, - AlbumRecordingSaved = 93, - }; - - explicit AppletMessageQueue(Core::System& system); - ~AppletMessageQueue(); - - Kernel::KReadableEvent& GetMessageReceiveEvent(); - Kernel::KReadableEvent& GetOperationModeChangedEvent(); - void PushMessage(AppletMessage msg); - AppletMessage PopMessage(); - std::size_t GetMessageCount() const; - void RequestExit(); - void RequestResume(); - void FocusStateChanged(); - void OperationModeChanged(); - -private: - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* on_new_message; - Kernel::KEvent* on_operation_mode_changed; - - std::queue messages; -}; - -class IWindowController final : public ServiceFramework { -public: - explicit IWindowController(Core::System& system_); - ~IWindowController() override; - -private: - void GetAppletResourceUserId(HLERequestContext& ctx); - void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); - void AcquireForegroundRights(HLERequestContext& ctx); -}; - -class IAudioController final : public ServiceFramework { -public: - explicit IAudioController(Core::System& system_); - ~IAudioController() override; - -private: - void SetExpectedMasterVolume(HLERequestContext& ctx); - void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx); - void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx); - void ChangeMainAppletMasterVolume(HLERequestContext& ctx); - void SetTransparentAudioRate(HLERequestContext& ctx); - - static constexpr float min_allowed_volume = 0.0f; - static constexpr float max_allowed_volume = 1.0f; - - float main_applet_volume{0.25f}; - float library_applet_volume{max_allowed_volume}; - float transparent_volume_rate{min_allowed_volume}; - - // Volume transition fade time in nanoseconds. - // e.g. If the main applet volume was 0% and was changed to 50% - // with a fade of 50ns, then over the course of 50ns, - // the volume will gradually fade up to 50% - std::chrono::nanoseconds fade_time_ns{0}; -}; - -class IDisplayController final : public ServiceFramework { -public: - explicit IDisplayController(Core::System& system_); - ~IDisplayController() override; - -private: - void GetCallerAppletCaptureImageEx(HLERequestContext& ctx); - void TakeScreenShotOfOwnLayer(HLERequestContext& ctx); - void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); - void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); - void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); - void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); -}; - -class IDebugFunctions final : public ServiceFramework { -public: - explicit IDebugFunctions(Core::System& system_); - ~IDebugFunctions() override; -}; - -class ISelfController final : public ServiceFramework { -public: - explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); - ~ISelfController() override; - -private: - void Exit(HLERequestContext& ctx); - void LockExit(HLERequestContext& ctx); - void UnlockExit(HLERequestContext& ctx); - void EnterFatalSection(HLERequestContext& ctx); - void LeaveFatalSection(HLERequestContext& ctx); - void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx); - void SetScreenShotPermission(HLERequestContext& ctx); - void SetOperationModeChangedNotification(HLERequestContext& ctx); - void SetPerformanceModeChangedNotification(HLERequestContext& ctx); - void SetFocusHandlingMode(HLERequestContext& ctx); - void SetRestartMessageEnabled(HLERequestContext& ctx); - void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx); - void SetAlbumImageOrientation(HLERequestContext& ctx); - void IsSystemBufferSharingEnabled(HLERequestContext& ctx); - void GetSystemSharedBufferHandle(HLERequestContext& ctx); - void GetSystemSharedLayerHandle(HLERequestContext& ctx); - void CreateManagedDisplayLayer(HLERequestContext& ctx); - void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); - void SetHandlesRequestToDisplay(HLERequestContext& ctx); - void ApproveToDisplay(HLERequestContext& ctx); - void SetIdleTimeDetectionExtension(HLERequestContext& ctx); - void GetIdleTimeDetectionExtension(HLERequestContext& ctx); - void ReportUserIsActive(HLERequestContext& ctx); - void SetAutoSleepDisabled(HLERequestContext& ctx); - void IsAutoSleepDisabled(HLERequestContext& ctx); - void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx); - void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx); - void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx); - void SaveCurrentScreenshot(HLERequestContext& ctx); - void SetRecordVolumeMuted(HLERequestContext& ctx); - - Result EnsureBufferSharingEnabled(); - - enum class ScreenshotPermission : u32 { - Inherit = 0, - Enable = 1, - Disable = 2, - }; - - Nvnflinger::Nvnflinger& nvnflinger; - - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* launchable_event; - Kernel::KEvent* accumulated_suspended_tick_changed_event; - - u32 idle_time_detection_extension = 0; - u64 num_fatal_sections_entered = 0; - u64 system_shared_buffer_id = 0; - u64 system_shared_layer_id = 0; - bool is_auto_sleep_disabled = false; - bool buffer_sharing_enabled = false; - ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; -}; - -class ILockAccessor final : public ServiceFramework { -public: - explicit ILockAccessor(Core::System& system_); - ~ILockAccessor() override; - -private: - void TryLock(HLERequestContext& ctx); - void Unlock(HLERequestContext& ctx); - void GetEvent(HLERequestContext& ctx); - void IsLocked(HLERequestContext& ctx); - - bool is_locked{}; - - Kernel::KEvent* lock_event; - KernelHelpers::ServiceContext service_context; -}; - -class ICommonStateGetter final : public ServiceFramework { -public: - explicit ICommonStateGetter(Core::System& system_, - std::shared_ptr msg_queue_); - ~ICommonStateGetter() override; - -private: - // This is nn::oe::FocusState - enum class FocusState : u8 { - InFocus = 1, - NotInFocus = 2, - Background = 3, - }; - - // This is nn::oe::OperationMode - enum class OperationMode : u8 { - Handheld = 0, - Docked = 1, - }; - - // This is nn::am::service::SystemButtonType - enum class SystemButtonType { - None, - HomeButtonShortPressing, - HomeButtonLongPressing, - PowerButtonShortPressing, - PowerButtonLongPressing, - ShutdownSystem, - CaptureButtonShortPressing, - CaptureButtonLongPressing, - }; - - enum class SysPlatformRegion : s32 { - Global = 1, - Terra = 2, - }; - - void GetEventHandle(HLERequestContext& ctx); - void ReceiveMessage(HLERequestContext& ctx); - void GetCurrentFocusState(HLERequestContext& ctx); - void RequestToAcquireSleepLock(HLERequestContext& ctx); - void GetAcquiredSleepLockEvent(HLERequestContext& ctx); - void GetReaderLockAccessorEx(HLERequestContext& ctx); - void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); - void GetOperationMode(HLERequestContext& ctx); - void GetPerformanceMode(HLERequestContext& ctx); - void GetBootMode(HLERequestContext& ctx); - void IsVrModeEnabled(HLERequestContext& ctx); - void SetVrModeEnabled(HLERequestContext& ctx); - void SetLcdBacklighOffEnabled(HLERequestContext& ctx); - void BeginVrModeEx(HLERequestContext& ctx); - void EndVrModeEx(HLERequestContext& ctx); - void GetDefaultDisplayResolution(HLERequestContext& ctx); - void SetCpuBoostMode(HLERequestContext& ctx); - void GetBuiltInDisplayType(HLERequestContext& ctx); - void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); - void GetSettingsPlatformRegion(HLERequestContext& ctx); - void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); - - std::shared_ptr msg_queue; - bool vr_mode_state{}; - Kernel::KEvent* sleep_lock_event; - KernelHelpers::ServiceContext service_context; -}; - -class IStorageImpl { -public: - virtual ~IStorageImpl(); - virtual std::vector& GetData() = 0; - virtual const std::vector& GetData() const = 0; - virtual std::size_t GetSize() const = 0; -}; - -class IStorage final : public ServiceFramework { -public: - explicit IStorage(Core::System& system_, std::vector&& buffer); - ~IStorage() override; - - std::vector& GetData() { - return impl->GetData(); - } - - const std::vector& GetData() const { - return impl->GetData(); - } - - std::size_t GetSize() const { - return impl->GetSize(); - } - -private: - void Register(); - void Open(HLERequestContext& ctx); - - std::shared_ptr impl; -}; - -class IStorageAccessor final : public ServiceFramework { -public: - explicit IStorageAccessor(Core::System& system_, IStorage& backing_); - ~IStorageAccessor() override; - -private: - void GetSize(HLERequestContext& ctx); - void Write(HLERequestContext& ctx); - void Read(HLERequestContext& ctx); - - IStorage& backing; -}; - -class ILibraryAppletCreator final : public ServiceFramework { -public: - explicit ILibraryAppletCreator(Core::System& system_); - ~ILibraryAppletCreator() override; - -private: - void CreateLibraryApplet(HLERequestContext& ctx); - void CreateStorage(HLERequestContext& ctx); - void CreateTransferMemoryStorage(HLERequestContext& ctx); - void CreateHandleStorage(HLERequestContext& ctx); -}; - -class ILibraryAppletSelfAccessor final : public ServiceFramework { -public: - explicit ILibraryAppletSelfAccessor(Core::System& system_); - ~ILibraryAppletSelfAccessor() override; - -private: - void PopInData(HLERequestContext& ctx); - void PushOutData(HLERequestContext& ctx); - void GetLibraryAppletInfo(HLERequestContext& ctx); - void GetMainAppletIdentityInfo(HLERequestContext& ctx); - void ExitProcessAndReturn(HLERequestContext& ctx); - void GetCallerAppletIdentityInfo(HLERequestContext& ctx); - void GetDesirableKeyboardLayout(HLERequestContext& ctx); - void GetMainAppletAvailableUsers(HLERequestContext& ctx); - void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); - - void PushInShowAlbum(); - void PushInShowCabinetData(); - void PushInShowMiiEditData(); - void PushInShowSoftwareKeyboard(); - void PushInShowController(); - - std::deque> queue_data; -}; - -class IAppletCommonFunctions final : public ServiceFramework { -public: - explicit IAppletCommonFunctions(Core::System& system_); - ~IAppletCommonFunctions() override; - -private: - void SetCpuBoostRequestPriority(HLERequestContext& ctx); -}; - -class IApplicationFunctions final : public ServiceFramework { -public: - explicit IApplicationFunctions(Core::System& system_); - ~IApplicationFunctions() override; - -private: - void PopLaunchParameter(HLERequestContext& ctx); - void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx); - void EnsureSaveData(HLERequestContext& ctx); - void SetTerminateResult(HLERequestContext& ctx); - void GetDisplayVersion(HLERequestContext& ctx); - void GetDesiredLanguage(HLERequestContext& ctx); - void IsGamePlayRecordingSupported(HLERequestContext& ctx); - void InitializeGamePlayRecording(HLERequestContext& ctx); - void SetGamePlayRecordingState(HLERequestContext& ctx); - void NotifyRunning(HLERequestContext& ctx); - void GetPseudoDeviceId(HLERequestContext& ctx); - void ExtendSaveData(HLERequestContext& ctx); - void GetSaveDataSize(HLERequestContext& ctx); - void CreateCacheStorage(HLERequestContext& ctx); - void GetSaveDataSizeMax(HLERequestContext& ctx); - void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); - void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); - void BeginBlockingHomeButton(HLERequestContext& ctx); - void EndBlockingHomeButton(HLERequestContext& ctx); - void EnableApplicationCrashReport(HLERequestContext& ctx); - void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx); - void SetApplicationCopyrightImage(HLERequestContext& ctx); - void SetApplicationCopyrightVisibility(HLERequestContext& ctx); - void QueryApplicationPlayStatistics(HLERequestContext& ctx); - void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx); - void ExecuteProgram(HLERequestContext& ctx); - void ClearUserChannel(HLERequestContext& ctx); - void UnpopToUserChannel(HLERequestContext& ctx); - void GetPreviousProgramIndex(HLERequestContext& ctx); - void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx); - void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx); - void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx); - void GetNotificationStorageChannelEvent(HLERequestContext& ctx); - void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); - void PrepareForJit(HLERequestContext& ctx); - - KernelHelpers::ServiceContext service_context; - - bool launch_popped_account_preselect = false; - s32 previous_program_index{-1}; - Kernel::KEvent* gpu_error_detected_event; - Kernel::KEvent* friend_invitation_storage_channel_event; - Kernel::KEvent* notification_storage_channel_event; - Kernel::KEvent* health_warning_disappeared_system_event; -}; - -class IHomeMenuFunctions final : public ServiceFramework { -public: - explicit IHomeMenuFunctions(Core::System& system_); - ~IHomeMenuFunctions() override; - -private: - void RequestToGetForeground(HLERequestContext& ctx); - void GetPopFromGeneralChannelEvent(HLERequestContext& ctx); - - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* pop_from_general_channel_event; -}; - -class IGlobalStateController final : public ServiceFramework { -public: - explicit IGlobalStateController(Core::System& system_); - ~IGlobalStateController() override; -}; - -class IApplicationCreator final : public ServiceFramework { -public: - explicit IApplicationCreator(Core::System& system_); - ~IApplicationCreator() override; -}; - -class IProcessWindingController final : public ServiceFramework { -public: - explicit IProcessWindingController(Core::System& system_); - ~IProcessWindingController() override; - -private: - void GetLaunchReason(HLERequestContext& ctx); - void OpenCallingLibraryApplet(HLERequestContext& ctx); -}; - void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); } // namespace Service::AM diff --git a/src/core/hle/service/am/am_results.h b/src/core/hle/service/am/am_results.h new file mode 100644 index 000000000..528b334ad --- /dev/null +++ b/src/core/hle/service/am/am_results.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Service::AM { + +constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; +constexpr Result ResultNoMessages{ErrorModule::AM, 3}; +constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index e30e6478a..bd9e5f505 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -1,263 +1,13 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/library_applet_proxy.h" +#include "core/hle/service/am/system_applet_proxy.h" #include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/nvnflinger/nvnflinger.h" namespace Service::AM { -class ILibraryAppletProxy final : public ServiceFramework { -public: - explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletProxy"}, - nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, - {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, - {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, - {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, - {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, - {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, - {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, - {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, - {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, - {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, - {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, - {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, msg_queue); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nvnflinger); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetProcessWindingController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; -}; - -class ISystemAppletProxy final : public ServiceFramework { -public: - explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "ISystemAppletProxy"}, - nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, - {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, - {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"}, - {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"}, - {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"}, - {10, nullptr, "GetProcessWindingController"}, - {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, - {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, - {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, - {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, - {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, - {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, msg_queue); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nvnflinger); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetApplicationCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; -}; - void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -284,8 +34,8 @@ void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, std::shared_ptr msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{ - std::move(msg_queue_)} { + : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { // clang-format off static const FunctionInfo functions[] = { {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, diff --git a/src/core/hle/service/am/applet_common_functions.cpp b/src/core/hle/service/am/applet_common_functions.cpp new file mode 100644 index 000000000..81c01a48b --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.cpp @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) + : ServiceFramework{system_, "IAppletCommonFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "SetTerminateResult"}, + {10, nullptr, "ReadThemeStorage"}, + {11, nullptr, "WriteThemeStorage"}, + {20, nullptr, "PushToAppletBoundChannel"}, + {21, nullptr, "TryPopFromAppletBoundChannel"}, + {40, nullptr, "GetDisplayLogicalResolution"}, + {42, nullptr, "SetDisplayMagnification"}, + {50, nullptr, "SetHomeButtonDoubleClickEnabled"}, + {51, nullptr, "GetHomeButtonDoubleClickEnabled"}, + {52, nullptr, "IsHomeButtonShortPressedBlocked"}, + {60, nullptr, "IsVrModeCurtainRequired"}, + {61, nullptr, "IsSleepRequiredByHighTemperature"}, + {62, nullptr, "IsSleepRequiredByLowBattery"}, + {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"}, + {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"}, + {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"}, + {90, nullptr, "OpenNamedChannelAsParent"}, + {91, nullptr, "OpenNamedChannelAsChild"}, + {100, nullptr, "SetApplicationCoreUsageMode"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAppletCommonFunctions::~IAppletCommonFunctions() = default; + +void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_common_functions.h b/src/core/hle/service/am/applet_common_functions.h new file mode 100644 index 000000000..be87b3820 --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IAppletCommonFunctions final : public ServiceFramework { +public: + explicit IAppletCommonFunctions(Core::System& system_); + ~IAppletCommonFunctions() override; + +private: + void SetCpuBoostRequestPriority(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_message_queue.cpp b/src/core/hle/service/am/applet_message_queue.cpp new file mode 100644 index 000000000..e4931031d --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +AppletMessageQueue::AppletMessageQueue(Core::System& system) + : service_context{system, "AppletMessageQueue"} { + on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); + on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged"); +} + +AppletMessageQueue::~AppletMessageQueue() { + service_context.CloseEvent(on_new_message); + service_context.CloseEvent(on_operation_mode_changed); +} + +Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { + return on_new_message->GetReadableEvent(); +} + +Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { + return on_operation_mode_changed->GetReadableEvent(); +} + +void AppletMessageQueue::PushMessage(AppletMessage msg) { + messages.push(msg); + on_new_message->Signal(); +} + +AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { + if (messages.empty()) { + on_new_message->Clear(); + return AppletMessage::None; + } + auto msg = messages.front(); + messages.pop(); + if (messages.empty()) { + on_new_message->Clear(); + } + return msg; +} + +std::size_t AppletMessageQueue::GetMessageCount() const { + return messages.size(); +} + +void AppletMessageQueue::RequestExit() { + PushMessage(AppletMessage::Exit); +} + +void AppletMessageQueue::RequestResume() { + PushMessage(AppletMessage::Resume); +} + +void AppletMessageQueue::FocusStateChanged() { + PushMessage(AppletMessage::FocusStateChanged); +} + +void AppletMessageQueue::OperationModeChanged() { + PushMessage(AppletMessage::OperationModeChanged); + PushMessage(AppletMessage::PerformanceModeChanged); + on_operation_mode_changed->Signal(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_message_queue.h b/src/core/hle/service/am/applet_message_queue.h new file mode 100644 index 000000000..60145aae9 --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.h @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KReadableEvent; +} // namespace Kernel + +namespace Service::AM { + +class AppletMessageQueue { +public: + // This is nn::am::AppletMessage + enum class AppletMessage : u32 { + None = 0, + ChangeIntoForeground = 1, + ChangeIntoBackground = 2, + Exit = 4, + ApplicationExited = 6, + FocusStateChanged = 15, + Resume = 16, + DetectShortPressingHomeButton = 20, + DetectLongPressingHomeButton = 21, + DetectShortPressingPowerButton = 22, + DetectMiddlePressingPowerButton = 23, + DetectLongPressingPowerButton = 24, + RequestToPrepareSleep = 25, + FinishedSleepSequence = 26, + SleepRequiredByHighTemperature = 27, + SleepRequiredByLowBattery = 28, + AutoPowerDown = 29, + OperationModeChanged = 30, + PerformanceModeChanged = 31, + DetectReceivingCecSystemStandby = 32, + SdCardRemoved = 33, + LaunchApplicationRequested = 50, + RequestToDisplay = 51, + ShowApplicationLogo = 55, + HideApplicationLogo = 56, + ForceHideApplicationLogo = 57, + FloatingApplicationDetected = 60, + DetectShortPressingCaptureButton = 90, + AlbumScreenShotTaken = 92, + AlbumRecordingSaved = 93, + }; + + explicit AppletMessageQueue(Core::System& system); + ~AppletMessageQueue(); + + Kernel::KReadableEvent& GetMessageReceiveEvent(); + Kernel::KReadableEvent& GetOperationModeChangedEvent(); + void PushMessage(AppletMessage msg); + AppletMessage PopMessage(); + std::size_t GetMessageCount() const; + void RequestExit(); + void RequestResume(); + void FocusStateChanged(); + void OperationModeChanged(); + +private: + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* on_new_message; + Kernel::KEvent* on_operation_mode_changed; + + std::queue messages; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index d6c565d85..f373d1136 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -1,107 +1,13 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/logging/log.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/application_proxy.h" #include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/nvnflinger/nvnflinger.h" namespace Service::AM { -class IApplicationProxy final : public ServiceFramework { -public: - explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "IApplicationProxy"}, - nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, - {1, &IApplicationProxy::GetSelfController, "GetSelfController"}, - {2, &IApplicationProxy::GetWindowController, "GetWindowController"}, - {3, &IApplicationProxy::GetAudioController, "GetAudioController"}, - {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"}, - {10, nullptr, "GetProcessWindingController"}, - {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, - {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, - {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nvnflinger); - } - - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, msg_queue); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - void GetApplicationFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; -}; - void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -112,8 +18,8 @@ void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, std::shared_ptr msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{ - std::move(msg_queue_)} { + : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { static const FunctionInfo functions[] = { {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index c2ff444a6..1b756fbd7 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -9,6 +9,7 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/nfc/common/device.h" #include "hid_core/hid_core.h" @@ -17,9 +18,8 @@ namespace Service::AM::Applets { Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ - system_, - "CabinetApplet"} { + : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, + service_context{system_, "CabinetApplet"} { availability_change_event = service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 0e4d9cc39..bc8de6b60 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -12,6 +12,7 @@ #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" +#include "core/hle/service/am/storage.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index 084bc138c..96126832c 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -10,6 +10,7 @@ #include "core/frontend/applets/error.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_error.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c0032f652..c010c78e2 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -9,6 +9,7 @@ #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_general_backend.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp index e83e931c5..1576b45c4 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp @@ -7,6 +7,7 @@ #include "core/frontend/applets/mii_edit.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_mii_edit.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/mii/mii.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp index 89cb323e9..f32db6842 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/applets/applet_profile_select.cpp @@ -10,6 +10,7 @@ #include "core/hle/service/acc/errors.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_profile_select.h" +#include "core/hle/service/am/storage.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp index 4145bb84f..a6a07cef3 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp @@ -6,6 +6,7 @@ #include "core/frontend/applets/software_keyboard.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_software_keyboard.h" +#include "core/hle/service/am/storage.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 19057ad7b..871737b3e 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -20,6 +20,7 @@ #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_web_browser.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/iplatform_service_manager.h" #include "core/loader/loader.h" diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 89d5434af..6a47f4b7a 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_controller.h" @@ -26,13 +27,14 @@ #include "core/hle/service/am/applets/applet_software_keyboard.h" #include "core/hle/service/am/applets/applet_web_browser.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/sm/sm.h" namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) - : system{system_}, applet_mode{applet_mode_}, service_context{system, - "ILibraryAppletAccessor"} { + : system{system_}, applet_mode{applet_mode_}, + service_context{system, "ILibraryAppletAccessor"} { state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent"); pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent"); pop_interactive_out_data_event = diff --git a/src/core/hle/service/am/application_creator.cpp b/src/core/hle/service/am/application_creator.cpp new file mode 100644 index 000000000..79ea045a3 --- /dev/null +++ b/src/core/hle/service/am/application_creator.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/application_creator.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IApplicationCreator::IApplicationCreator(Core::System& system_) + : ServiceFramework{system_, "IApplicationCreator"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateApplication"}, + {1, nullptr, "PopLaunchRequestedApplication"}, + {10, nullptr, "CreateSystemApplication"}, + {100, nullptr, "PopFloatingApplicationForDevelopment"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IApplicationCreator::~IApplicationCreator() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_creator.h b/src/core/hle/service/am/application_creator.h new file mode 100644 index 000000000..375a3c476 --- /dev/null +++ b/src/core/hle/service/am/application_creator.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IApplicationCreator final : public ServiceFramework { +public: + explicit IApplicationCreator(Core::System& system_); + ~IApplicationCreator() override; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_functions.cpp b/src/core/hle/service/am/application_functions.cpp new file mode 100644 index 000000000..fef45c732 --- /dev/null +++ b/src/core/hle/service/am/application_functions.cpp @@ -0,0 +1,610 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "common/uuid.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/savedata_factory.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/application_functions.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/save_data_controller.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM { + +enum class LaunchParameterKind : u32 { + UserChannel = 1, + AccountPreselectedUser = 2, +}; + +constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; + +struct LaunchParameterAccountPreselectedUser { + u32_le magic; + u32_le is_account_selected; + Common::UUID current_user; + INSERT_PADDING_BYTES(0x70); +}; +static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); + +IApplicationFunctions::IApplicationFunctions(Core::System& system_) + : ServiceFramework{system_, "IApplicationFunctions"}, + service_context{system, "IApplicationFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, + {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, + {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, + {12, nullptr, "CreateApplicationAndRequestToStart"}, + {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, + {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, + {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, + {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, + {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, + {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, + {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, + {24, nullptr, "GetLaunchStorageInfoForDebug"}, + {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, + {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, + {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"}, + {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"}, + {29, nullptr, "GetCacheStorageMax"}, + {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, + {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, + {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, + {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, + {34, nullptr, "SelectApplicationLicense"}, + {35, nullptr, "GetDeviceSaveDataSizeMax"}, + {36, nullptr, "GetLimitedApplicationLicense"}, + {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, + {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, + {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, + {60, nullptr, "SetMediaPlaybackStateForApplication"}, + {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"}, + {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, + {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, + {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, + {70, nullptr, "RequestToShutdown"}, + {71, nullptr, "RequestToReboot"}, + {72, nullptr, "RequestToSleep"}, + {80, nullptr, "ExitAndRequestToShowThanksMessage"}, + {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, + {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, + {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, + {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, + {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, + {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, + {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, + {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, + {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, + {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, + {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, + {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, + {131, nullptr, "SetDelayTimeToAbortOnGpuError"}, + {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, + {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, + {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"}, + {151, nullptr, "TryPopFromNotificationStorageChannel"}, + {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"}, + {170, nullptr, "SetHdcpAuthenticationActivated"}, + {180, nullptr, "GetLaunchRequiredVersion"}, + {181, nullptr, "UpgradeLaunchRequiredVersion"}, + {190, nullptr, "SendServerMaintenanceOverlayNotification"}, + {200, nullptr, "GetLastApplicationExitReason"}, + {500, nullptr, "StartContinuousRecordingFlushForDebug"}, + {1000, nullptr, "CreateMovieMaker"}, + {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"}, + }; + // clang-format on + + RegisterHandlers(functions); + + gpu_error_detected_event = + service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); + friend_invitation_storage_channel_event = + service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); + notification_storage_channel_event = + service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); + health_warning_disappeared_system_event = + service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); +} + +IApplicationFunctions::~IApplicationFunctions() { + service_context.CloseEvent(gpu_error_detected_event); + service_context.CloseEvent(friend_invitation_storage_channel_event); + service_context.CloseEvent(notification_storage_channel_event); + service_context.CloseEvent(health_warning_disappeared_system_event); +} + +void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_visible = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto kind = rp.PopEnum(); + + LOG_INFO(Service_AM, "called, kind={:08X}", kind); + + if (kind == LaunchParameterKind::UserChannel) { + auto channel = system.GetUserChannel(); + if (channel.empty()) { + LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + auto data = channel.back(); + channel.pop_back(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, std::move(data)); + } else if (kind == LaunchParameterKind::AccountPreselectedUser && + !launch_popped_account_preselect) { + // TODO: Verify this is hw-accurate + LaunchParameterAccountPreselectedUser params{}; + + params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; + params.is_account_selected = 1; + + Account::ProfileManager profile_manager{}; + const auto uuid = profile_manager.GetUser(static_cast(Settings::values.current_user)); + ASSERT(uuid.has_value() && uuid->IsValid()); + params.current_user = *uuid; + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + + std::vector buffer(sizeof(LaunchParameterAccountPreselectedUser)); + std::memcpy(buffer.data(), ¶ms, buffer.size()); + + rb.PushIpcInterface(system, std::move(buffer)); + launch_popped_account_preselect = true; + } else { + LOG_ERROR(Service_AM, "Unknown launch parameter kind."); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + } +} + +void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u128 user_id = rp.PopRaw(); + + LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); + + FileSys::SaveDataAttribute attribute{}; + attribute.title_id = system.GetApplicationProcessProgramID(); + attribute.user_id = user_id; + attribute.type = FileSys::SaveDataType::SaveData; + + FileSys::VirtualDir save_data{}; + const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( + &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(0); +} + +void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { + // Takes an input u32 Result, no output. + // For example, in some cases official apps use this with error 0x2A2 then + // uses svcBreak. + + IPC::RequestParser rp{ctx}; + u32 result = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::array version_string{}; + + const auto res = [this] { + const auto title_id = system.GetApplicationProcessProgramID(); + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + const auto& version = res.first->GetVersionString(); + std::copy(version.begin(), version.end(), version_string.begin()); + } else { + static constexpr char default_version[]{"1.0.0"}; + std::memcpy(version_string.data(), default_version, sizeof(default_version)); + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(version_string); +} + +void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { + // TODO(bunnei): This should be configurable + LOG_DEBUG(Service_AM, "called"); + + // Get supported languages from NACP, if possible + // Default to 0 (all languages supported) + u32 supported_languages = 0; + + const auto res = [this] { + const auto title_id = system.GetApplicationProcessProgramID(); + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + u8 desired_language{}; + const auto res_lang = + app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages); + if (res_lang != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_lang); + return; + } + + // Convert to settings language code. + u64 language_code{}; + const auto res_code = + app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language); + if (res_code != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_code); + return; + } + + LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(language_code); +} + +void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + constexpr bool gameplay_recording_supported = false; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(gameplay_recording_supported); +} + +void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); // Unknown, seems to be ignored by official processes +} + +void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + + // Returns a 128-bit UUID + rb.Push(0); + rb.Push(0); +} + +void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + u64 new_normal_size; + u64 new_journal_size; + }; + static_assert(sizeof(Parameters) == 40); + + IPC::RequestParser rp{ctx}; + const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw(); + + LOG_DEBUG(Service_AM, + "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " + "new_journal={:016X}", + static_cast(type), user_id[1], user_id[0], new_normal_size, new_journal_size); + + system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( + type, system.GetApplicationProcessProgramID(), user_id, + {new_normal_size, new_journal_size}); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + + // The following value is used upon failure to help the system recover. + // Since we always succeed, this should be 0. + rb.Push(0); +} + +void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + }; + static_assert(sizeof(Parameters) == 24); + + IPC::RequestParser rp{ctx}; + const auto [type, user_id] = rp.PopRaw(); + + LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], + user_id[0]); + + const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( + type, system.GetApplicationProcessProgramID(), user_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.Push(size.normal); + rb.Push(size.journal); +} + +void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) { + struct InputParameters { + u16 index; + s64 size; + s64 journal_size; + }; + static_assert(sizeof(InputParameters) == 24); + + struct OutputParameters { + u32 storage_target; + u64 required_size; + }; + static_assert(sizeof(OutputParameters) == 16); + + IPC::RequestParser rp{ctx}; + const auto params = rp.PopRaw(); + + LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}", + params.index, params.size, params.journal_size); + + const OutputParameters resp{ + .storage_target = 1, + .required_size = 0, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(resp); +} + +void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + constexpr u64 size_max_normal = 0xFFFFFFF; + constexpr u64 size_max_journal = 0xFFFFFFF; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.Push(size_max_normal); + rb.Push(size_max_journal); +} + +void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + [[maybe_unused]] const auto unk_1 = rp.Pop(); + [[maybe_unused]] const auto unk_2 = rp.Pop(); + const auto program_index = rp.Pop(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + system.ExecuteProgram(program_index); +} + +void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.GetUserChannel().clear(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + const auto storage = rp.PopIpcInterface().lock(); + if (storage) { + system.GetUserChannel().push_back(storage->GetData()); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(previous_program_index); +} + +void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); +} + +void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); +} + +void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); +} + +void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); +} + +void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); +} + +void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_functions.h b/src/core/hle/service/am/application_functions.h new file mode 100644 index 000000000..22aab1c8f --- /dev/null +++ b/src/core/hle/service/am/application_functions.h @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IApplicationFunctions final : public ServiceFramework { +public: + explicit IApplicationFunctions(Core::System& system_); + ~IApplicationFunctions() override; + +private: + void PopLaunchParameter(HLERequestContext& ctx); + void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx); + void EnsureSaveData(HLERequestContext& ctx); + void SetTerminateResult(HLERequestContext& ctx); + void GetDisplayVersion(HLERequestContext& ctx); + void GetDesiredLanguage(HLERequestContext& ctx); + void IsGamePlayRecordingSupported(HLERequestContext& ctx); + void InitializeGamePlayRecording(HLERequestContext& ctx); + void SetGamePlayRecordingState(HLERequestContext& ctx); + void NotifyRunning(HLERequestContext& ctx); + void GetPseudoDeviceId(HLERequestContext& ctx); + void ExtendSaveData(HLERequestContext& ctx); + void GetSaveDataSize(HLERequestContext& ctx); + void CreateCacheStorage(HLERequestContext& ctx); + void GetSaveDataSizeMax(HLERequestContext& ctx); + void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); + void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); + void BeginBlockingHomeButton(HLERequestContext& ctx); + void EndBlockingHomeButton(HLERequestContext& ctx); + void EnableApplicationCrashReport(HLERequestContext& ctx); + void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx); + void SetApplicationCopyrightImage(HLERequestContext& ctx); + void SetApplicationCopyrightVisibility(HLERequestContext& ctx); + void QueryApplicationPlayStatistics(HLERequestContext& ctx); + void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx); + void ExecuteProgram(HLERequestContext& ctx); + void ClearUserChannel(HLERequestContext& ctx); + void UnpopToUserChannel(HLERequestContext& ctx); + void GetPreviousProgramIndex(HLERequestContext& ctx); + void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx); + void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx); + void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx); + void GetNotificationStorageChannelEvent(HLERequestContext& ctx); + void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); + void PrepareForJit(HLERequestContext& ctx); + + KernelHelpers::ServiceContext service_context; + + bool launch_popped_account_preselect = false; + s32 previous_program_index{-1}; + Kernel::KEvent* gpu_error_detected_event; + Kernel::KEvent* friend_invitation_storage_channel_event; + Kernel::KEvent* notification_storage_channel_event; + Kernel::KEvent* health_warning_disappeared_system_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_proxy.cpp b/src/core/hle/service/am/application_proxy.cpp new file mode 100644 index 000000000..e9cd0aa71 --- /dev/null +++ b/src/core/hle/service/am/application_proxy.cpp @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/am/application_functions.h" +#include "core/hle/service/am/application_proxy.h" +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr msg_queue_, + Core::System& system_) + : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &IApplicationProxy::GetSelfController, "GetSelfController"}, + {2, &IApplicationProxy::GetWindowController, "GetWindowController"}, + {3, &IApplicationProxy::GetAudioController, "GetAudioController"}, + {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"}, + {10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"}, + {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, + {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void IApplicationProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, nvnflinger); +} + +void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, msg_queue); +} + +void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_proxy.h b/src/core/hle/service/am/application_proxy.h new file mode 100644 index 000000000..4f620242b --- /dev/null +++ b/src/core/hle/service/am/application_proxy.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IApplicationProxy final : public ServiceFramework { +public: + explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr msg_queue_, + Core::System& system_); + +private: + void GetAudioController(HLERequestContext& ctx); + void GetDisplayController(HLERequestContext& ctx); + void GetProcessWindingController(HLERequestContext& ctx); + void GetDebugFunctions(HLERequestContext& ctx); + void GetWindowController(HLERequestContext& ctx); + void GetSelfController(HLERequestContext& ctx); + void GetCommonStateGetter(HLERequestContext& ctx); + void GetLibraryAppletCreator(HLERequestContext& ctx); + void GetApplicationFunctions(HLERequestContext& ctx); + + Nvnflinger::Nvnflinger& nvnflinger; + std::shared_ptr msg_queue; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/audio_controller.cpp b/src/core/hle/service/am/audio_controller.cpp new file mode 100644 index 000000000..ae75db174 --- /dev/null +++ b/src/core/hle/service/am/audio_controller.cpp @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IAudioController::IAudioController(Core::System& system_) + : ServiceFramework{system_, "IAudioController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, + {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"}, + {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"}, + {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"}, + {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAudioController::~IAudioController() = default; + +void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const float main_applet_volume_tmp = rp.Pop(); + const float library_applet_volume_tmp = rp.Pop(); + + LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}", + main_applet_volume_tmp, library_applet_volume_tmp); + + // Ensure the volume values remain within the 0-100% range + main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume); + library_applet_volume = + std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(main_applet_volume); +} + +void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(library_applet_volume); +} + +void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) { + struct Parameters { + float volume; + s64 fade_time_ns; + }; + static_assert(sizeof(Parameters) == 16); + + IPC::RequestParser rp{ctx}; + const auto parameters = rp.PopRaw(); + + LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume, + parameters.fade_time_ns); + + main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume); + fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns}; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const float transparent_volume_rate_tmp = rp.Pop(); + + LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp); + + // Clamp volume range to 0-100%. + transparent_volume_rate = + std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/audio_controller.h b/src/core/hle/service/am/audio_controller.h new file mode 100644 index 000000000..a47e3bad8 --- /dev/null +++ b/src/core/hle/service/am/audio_controller.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IAudioController final : public ServiceFramework { +public: + explicit IAudioController(Core::System& system_); + ~IAudioController() override; + +private: + void SetExpectedMasterVolume(HLERequestContext& ctx); + void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx); + void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx); + void ChangeMainAppletMasterVolume(HLERequestContext& ctx); + void SetTransparentAudioRate(HLERequestContext& ctx); + + static constexpr float min_allowed_volume = 0.0f; + static constexpr float max_allowed_volume = 1.0f; + + float main_applet_volume{0.25f}; + float library_applet_volume{max_allowed_volume}; + float transparent_volume_rate{min_allowed_volume}; + + // Volume transition fade time in nanoseconds. + // e.g. If the main applet volume was 0% and was changed to 50% + // with a fade of 50ns, then over the course of 50ns, + // the volume will gradually fade up to 50% + std::chrono::nanoseconds fade_time_ns{0}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/common_state_getter.cpp b/src/core/hle/service/am/common_state_getter.cpp new file mode 100644 index 000000000..0b54b769d --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.cpp @@ -0,0 +1,288 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/lock_accessor.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/apm/apm_interface.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/pm/pm.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/vi/vi.h" + +namespace Service::AM { + +ICommonStateGetter::ICommonStateGetter(Core::System& system_, + std::shared_ptr msg_queue_) + : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, + service_context{system_, "ICommonStateGetter"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, + {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, + {2, nullptr, "GetThisAppletKind"}, + {3, nullptr, "AllowToEnterSleep"}, + {4, nullptr, "DisallowToEnterSleep"}, + {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, + {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, + {7, nullptr, "GetCradleStatus"}, + {8, &ICommonStateGetter::GetBootMode, "GetBootMode"}, + {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, + {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"}, + {11, nullptr, "ReleaseSleepLock"}, + {12, nullptr, "ReleaseSleepLockTransiently"}, + {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"}, + {14, nullptr, "GetWakeupCount"}, + {20, nullptr, "PushToGeneralChannel"}, + {30, nullptr, "GetHomeButtonReaderLockAccessor"}, + {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, + {32, nullptr, "GetWriterLockAccessorEx"}, + {40, nullptr, "GetCradleFwVersion"}, + {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, + {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, + {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, + {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, + {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, + {55, nullptr, "IsInControllerFirmwareUpdateSection"}, + {59, nullptr, "SetVrPositionForDebug"}, + {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, + {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, + {62, nullptr, "GetHdcpAuthenticationState"}, + {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, + {64, nullptr, "SetTvPowerStateMatchingMode"}, + {65, nullptr, "GetApplicationIdByContentActionName"}, + {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, + {67, nullptr, "CancelCpuBoostMode"}, + {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"}, + {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, + {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, + {91, nullptr, "GetCurrentPerformanceConfiguration"}, + {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, + {110, nullptr, "OpenMyGpuErrorHandler"}, + {120, nullptr, "GetAppletLaunchedHistory"}, + {200, nullptr, "GetOperationModeSystemInfo"}, + {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"}, + {400, nullptr, "ActivateMigrationService"}, + {401, nullptr, "DeactivateMigrationService"}, + {500, nullptr, "DisableSleepTillShutdown"}, + {501, nullptr, "SuppressDisablingSleepTemporarily"}, + {502, nullptr, "IsSleepEnabled"}, + {503, nullptr, "IsDisablingSleepSuppressed"}, + {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, + }; + // clang-format on + + RegisterHandlers(functions); + + sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); + + // Configure applets to be in foreground state + msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); +} + +ICommonStateGetter::~ICommonStateGetter() { + service_context.CloseEvent(sleep_lock_event); +}; + +void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(Service::PM::SystemBootMode::Normal)); // Normal boot mode +} + +void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); +} + +void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + const auto message = msg_queue->PopMessage(); + IPC::ResponseBuilder rb{ctx, 3}; + + if (message == AppletMessageQueue::AppletMessage::None) { + LOG_ERROR(Service_AM, "Message queue is empty"); + rb.Push(AM::ResultNoMessages); + rb.PushEnum(message); + return; + } + + rb.Push(ResultSuccess); + rb.PushEnum(message); +} + +void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(FocusState::InFocus)); +} + +void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { + const bool use_docked_mode{Settings::IsDockedMode()}; + LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); +} + +void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode()); +} + +void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // Sleep lock is acquired immediately. + sleep_lock_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown = rp.Pop(); + + LOG_INFO(Service_AM, "called, unknown={}", unknown); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); +} + +void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(vr_mode_state); +} + +void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + vr_mode_state = rp.Pop(); + + LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_lcd_backlight_off_enabled = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}", + is_lcd_backlight_off_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); +} + +void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + + if (Settings::IsDockedMode()) { + rb.Push(static_cast(Service::VI::DisplayResolution::DockedWidth)); + rb.Push(static_cast(Service::VI::DisplayResolution::DockedHeight)); + } else { + rb.Push(static_cast(Service::VI::DisplayResolution::UndockedWidth)); + rb.Push(static_cast(Service::VI::DisplayResolution::UndockedHeight)); + } +} + +void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS"); + + const auto& sm = system.ServiceManager(); + const auto apm_sys = sm.GetService("apm:sys"); + ASSERT(apm_sys != nullptr); + + apm_sys->SetCpuBoostMode(ctx); +} + +void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto system_button{rp.PopEnum()}; + + LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(SysPlatformRegion::Global); +} + +void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled( + HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/common_state_getter.h b/src/core/hle/service/am/common_state_getter.h new file mode 100644 index 000000000..11d66f10a --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.h @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +#include "core/hle/service/am/applet_message_queue.h" + +namespace Service::AM { + +class ICommonStateGetter final : public ServiceFramework { +public: + explicit ICommonStateGetter(Core::System& system_, + std::shared_ptr msg_queue_); + ~ICommonStateGetter() override; + +private: + // This is nn::oe::FocusState + enum class FocusState : u8 { + InFocus = 1, + NotInFocus = 2, + Background = 3, + }; + + // This is nn::oe::OperationMode + enum class OperationMode : u8 { + Handheld = 0, + Docked = 1, + }; + + // This is nn::am::service::SystemButtonType + enum class SystemButtonType { + None, + HomeButtonShortPressing, + HomeButtonLongPressing, + PowerButtonShortPressing, + PowerButtonLongPressing, + ShutdownSystem, + CaptureButtonShortPressing, + CaptureButtonLongPressing, + }; + + enum class SysPlatformRegion : s32 { + Global = 1, + Terra = 2, + }; + + void GetEventHandle(HLERequestContext& ctx); + void ReceiveMessage(HLERequestContext& ctx); + void GetCurrentFocusState(HLERequestContext& ctx); + void RequestToAcquireSleepLock(HLERequestContext& ctx); + void GetAcquiredSleepLockEvent(HLERequestContext& ctx); + void GetReaderLockAccessorEx(HLERequestContext& ctx); + void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); + void GetOperationMode(HLERequestContext& ctx); + void GetPerformanceMode(HLERequestContext& ctx); + void GetBootMode(HLERequestContext& ctx); + void IsVrModeEnabled(HLERequestContext& ctx); + void SetVrModeEnabled(HLERequestContext& ctx); + void SetLcdBacklighOffEnabled(HLERequestContext& ctx); + void BeginVrModeEx(HLERequestContext& ctx); + void EndVrModeEx(HLERequestContext& ctx); + void GetDefaultDisplayResolution(HLERequestContext& ctx); + void SetCpuBoostMode(HLERequestContext& ctx); + void GetBuiltInDisplayType(HLERequestContext& ctx); + void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); + void GetSettingsPlatformRegion(HLERequestContext& ctx); + void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); + + std::shared_ptr msg_queue; + bool vr_mode_state{}; + Kernel::KEvent* sleep_lock_event; + KernelHelpers::ServiceContext service_context; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/debug_functions.cpp b/src/core/hle/service/am/debug_functions.cpp new file mode 100644 index 000000000..f80b970f2 --- /dev/null +++ b/src/core/hle/service/am/debug_functions.cpp @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IDebugFunctions::IDebugFunctions(Core::System& system_) + : ServiceFramework{system_, "IDebugFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, + {1, nullptr, "OpenMainApplication"}, + {10, nullptr, "PerformSystemButtonPressing"}, + {20, nullptr, "InvalidateTransitionLayer"}, + {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, + {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"}, + {40, nullptr, "GetAppletResourceUsageInfo"}, + {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"}, + {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"}, + {100, nullptr, "SetCpuBoostModeForApplet"}, + {101, nullptr, "CancelCpuBoostModeForApplet"}, + {110, nullptr, "PushToAppletBoundChannelForDebug"}, + {111, nullptr, "TryPopFromAppletBoundChannelForDebug"}, + {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"}, + {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"}, + {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"}, + {130, nullptr, "FriendInvitationSetApplicationParameter"}, + {131, nullptr, "FriendInvitationClearApplicationParameter"}, + {132, nullptr, "FriendInvitationPushApplicationParameter"}, + {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"}, + {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"}, + {300, nullptr, "TerminateAllRunningApplicationsForDebug"}, + {900, nullptr, "GetGrcProcessLaunchedSystemEvent"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDebugFunctions::~IDebugFunctions() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/debug_functions.h b/src/core/hle/service/am/debug_functions.h new file mode 100644 index 000000000..d55968743 --- /dev/null +++ b/src/core/hle/service/am/debug_functions.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IDebugFunctions final : public ServiceFramework { +public: + explicit IDebugFunctions(Core::System& system_); + ~IDebugFunctions() override; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/display_controller.cpp b/src/core/hle/service/am/display_controller.cpp new file mode 100644 index 000000000..d4d3d60e7 --- /dev/null +++ b/src/core/hle/service/am/display_controller.cpp @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IDisplayController::IDisplayController(Core::System& system_) + : ServiceFramework{system_, "IDisplayController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetLastForegroundCaptureImage"}, + {1, nullptr, "UpdateLastForegroundCaptureImage"}, + {2, nullptr, "GetLastApplicationCaptureImage"}, + {3, nullptr, "GetCallerAppletCaptureImage"}, + {4, nullptr, "UpdateCallerAppletCaptureImage"}, + {5, nullptr, "GetLastForegroundCaptureImageEx"}, + {6, nullptr, "GetLastApplicationCaptureImageEx"}, + {7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"}, + {8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"}, + {9, nullptr, "CopyBetweenCaptureBuffers"}, + {10, nullptr, "AcquireLastApplicationCaptureBuffer"}, + {11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, + {12, nullptr, "AcquireLastForegroundCaptureBuffer"}, + {13, nullptr, "ReleaseLastForegroundCaptureBuffer"}, + {14, nullptr, "AcquireCallerAppletCaptureBuffer"}, + {15, nullptr, "ReleaseCallerAppletCaptureBuffer"}, + {16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, + {17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, + {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, + {20, nullptr, "ClearCaptureBuffer"}, + {21, nullptr, "ClearAppletTransitionBuffer"}, + {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, + {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"}, + {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"}, + {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"}, + {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"}, + {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDisplayController::~IDisplayController() = default; + +void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(1u); + rb.Push(1); +} + +void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(1U); + rb.Push(1); +} + +void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(1U); + rb.Push(1); +} + +void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/display_controller.h b/src/core/hle/service/am/display_controller.h new file mode 100644 index 000000000..32f819294 --- /dev/null +++ b/src/core/hle/service/am/display_controller.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IDisplayController final : public ServiceFramework { +public: + explicit IDisplayController(Core::System& system_); + ~IDisplayController() override; + +private: + void GetCallerAppletCaptureImageEx(HLERequestContext& ctx); + void TakeScreenShotOfOwnLayer(HLERequestContext& ctx); + void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); + void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/global_state_controller.cpp b/src/core/hle/service/am/global_state_controller.cpp new file mode 100644 index 000000000..ed0eb7108 --- /dev/null +++ b/src/core/hle/service/am/global_state_controller.cpp @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/global_state_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IGlobalStateController::IGlobalStateController(Core::System& system_) + : ServiceFramework{system_, "IGlobalStateController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RequestToEnterSleep"}, + {1, nullptr, "EnterSleep"}, + {2, nullptr, "StartSleepSequence"}, + {3, nullptr, "StartShutdownSequence"}, + {4, nullptr, "StartRebootSequence"}, + {9, nullptr, "IsAutoPowerDownRequested"}, + {10, nullptr, "LoadAndApplyIdlePolicySettings"}, + {11, nullptr, "NotifyCecSettingsChanged"}, + {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, + {13, nullptr, "UpdateDefaultDisplayResolution"}, + {14, nullptr, "ShouldSleepOnBoot"}, + {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, + {30, nullptr, "OpenCradleFirmwareUpdater"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IGlobalStateController::~IGlobalStateController() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/global_state_controller.h b/src/core/hle/service/am/global_state_controller.h new file mode 100644 index 000000000..7125464a1 --- /dev/null +++ b/src/core/hle/service/am/global_state_controller.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IGlobalStateController final : public ServiceFramework { +public: + explicit IGlobalStateController(Core::System& system_); + ~IGlobalStateController() override; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/home_menu_functions.cpp b/src/core/hle/service/am/home_menu_functions.cpp new file mode 100644 index 000000000..640e9fbb7 --- /dev/null +++ b/src/core/hle/service/am/home_menu_functions.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/home_menu_functions.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) + : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system, + "IHomeMenuFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, + {11, nullptr, "LockForeground"}, + {12, nullptr, "UnlockForeground"}, + {20, nullptr, "PopFromGeneralChannel"}, + {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, + {30, nullptr, "GetHomeButtonWriterLockAccessor"}, + {31, nullptr, "GetWriterLockAccessorEx"}, + {40, nullptr, "IsSleepEnabled"}, + {41, nullptr, "IsRebootEnabled"}, + {50, nullptr, "LaunchSystemApplet"}, + {51, nullptr, "LaunchStarter"}, + {100, nullptr, "PopRequestLaunchApplicationForDebug"}, + {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, + {200, nullptr, "LaunchDevMenu"}, + {1000, nullptr, "SetLastApplicationExitReason"}, + }; + // clang-format on + + RegisterHandlers(functions); + + pop_from_general_channel_event = + service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent"); +} + +IHomeMenuFunctions::~IHomeMenuFunctions() { + service_context.CloseEvent(pop_from_general_channel_event); +} + +void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/home_menu_functions.h b/src/core/hle/service/am/home_menu_functions.h new file mode 100644 index 000000000..e082d5d73 --- /dev/null +++ b/src/core/hle/service/am/home_menu_functions.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IHomeMenuFunctions final : public ServiceFramework { +public: + explicit IHomeMenuFunctions(Core::System& system_); + ~IHomeMenuFunctions() override; + +private: + void RequestToGetForeground(HLERequestContext& ctx); + void GetPopFromGeneralChannelEvent(HLERequestContext& ctx); + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* pop_from_general_channel_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_accessor.cpp b/src/core/hle/service/am/library_applet_accessor.cpp new file mode 100644 index 000000000..1cccdfcf2 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -0,0 +1,178 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/library_applet_accessor.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr applet_) + : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, + {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, + {10, &ILibraryAppletAccessor::Start, "Start"}, + {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"}, + {25, nullptr, "Terminate"}, + {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, + {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, + {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"}, + {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, + {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, + {102, nullptr, "PushExtraStorage"}, + {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, + {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, + {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, + {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, + {110, nullptr, "NeedsToExitProcess"}, + {120, nullptr, "GetLibraryAppletInfo"}, + {150, nullptr, "RequestForAppletToGetForeground"}, + {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); +} + +void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(applet->TransactionComplete()); +} + +void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->GetStatus()); +} + +void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + + applet->Initialize(); + applet->Execute(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->RequestExit()); +} + +void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + auto storage = applet->GetBroker().PopNormalDataToGame(); + if (storage == nullptr) { + LOG_DEBUG(Service_AM, + "storage is a nullptr. There is no data in the current normal channel"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(std::move(storage)); +} + +void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface().lock()); + + ASSERT(applet->IsInitialized()); + applet->ExecuteInteractive(); + applet->Execute(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + auto storage = applet->GetBroker().PopInteractiveDataToGame(); + if (storage == nullptr) { + LOG_DEBUG(Service_AM, + "storage is a nullptr. There is no data in the current interactive channel"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(std::move(storage)); +} + +void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); +} + +void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); +} + +void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is + // actually used anywhere + constexpr u64 handle = 0xdeadbeef; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(handle); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_accessor.h b/src/core/hle/service/am/library_applet_accessor.h new file mode 100644 index 000000000..698467233 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.h @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletAccessor final : public ServiceFramework { +public: + explicit ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr applet_); + +private: + void GetAppletStateChangedEvent(HLERequestContext& ctx); + void IsCompleted(HLERequestContext& ctx); + void GetResult(HLERequestContext& ctx); + void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx); + void Start(HLERequestContext& ctx); + void RequestExit(HLERequestContext& ctx); + void PushInData(HLERequestContext& ctx); + void PopOutData(HLERequestContext& ctx); + void PushInteractiveInData(HLERequestContext& ctx); + void PopInteractiveOutData(HLERequestContext& ctx); + void GetPopOutDataEvent(HLERequestContext& ctx); + void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); + void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); + + std::shared_ptr applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp new file mode 100644 index 000000000..c33f50a40 --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -0,0 +1,145 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/library_applet_accessor.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletCreator"} { + static const FunctionInfo functions[] = { + {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, + {1, nullptr, "TerminateAllLibraryApplets"}, + {2, nullptr, "AreAnyLibraryAppletsLeft"}, + {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, + {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, + {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, + }; + RegisterHandlers(functions); +} + +ILibraryAppletCreator::~ILibraryAppletCreator() = default; + +void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto applet_id = rp.PopRaw(); + const auto applet_mode = rp.PopRaw(); + + LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, + applet_mode); + + const auto& applet_manager{system.GetAppletManager()}; + const auto applet = applet_manager.GetApplet(applet_id, applet_mode); + + if (applet == nullptr) { + LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, applet); +} + +void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 size{rp.Pop()}; + + LOG_DEBUG(Service_AM, "called, size={}", size); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + std::vector buffer(size); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, std::move(buffer)); +} + +void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + struct Parameters { + u8 permissions; + s64 size; + }; + + const auto parameters{rp.PopRaw()}; + const auto handle{ctx.GetCopyHandle(0)}; + + LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, + parameters.size, handle); + + if (parameters.size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + auto transfer_mem = ctx.GetObjectFromHandle(handle); + + if (transfer_mem.IsNull()) { + LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + std::vector memory(transfer_mem->GetSize()); + ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, std::move(memory)); +} + +void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 size{rp.Pop()}; + const auto handle{ctx.GetCopyHandle(0)}; + + LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + auto transfer_mem = ctx.GetObjectFromHandle(handle); + + if (transfer_mem.IsNull()) { + LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + std::vector memory(transfer_mem->GetSize()); + ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, std::move(memory)); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.h b/src/core/hle/service/am/library_applet_creator.h new file mode 100644 index 000000000..97f236fbc --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletCreator final : public ServiceFramework { +public: + explicit ILibraryAppletCreator(Core::System& system_); + ~ILibraryAppletCreator() override; + +private: + void CreateLibraryApplet(HLERequestContext& ctx); + void CreateStorage(HLERequestContext& ctx); + void CreateTransferMemoryStorage(HLERequestContext& ctx); + void CreateHandleStorage(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_proxy.cpp b/src/core/hle/service/am/library_applet_proxy.cpp new file mode 100644 index 000000000..047fc40f4 --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.cpp @@ -0,0 +1,142 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/am/global_state_controller.h" +#include "core/hle/service/am/home_menu_functions.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_proxy.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr msg_queue_, + Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, + {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, + {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, + {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, + {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, + {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, + {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, + {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, + {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, + {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, msg_queue); +} + +void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, nvnflinger); +} + +void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_proxy.h b/src/core/hle/service/am/library_applet_proxy.h new file mode 100644 index 000000000..cd9e6d02b --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletProxy final : public ServiceFramework { +public: + explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr msg_queue_, + Core::System& system_); + +private: + void GetCommonStateGetter(HLERequestContext& ctx); + void GetSelfController(HLERequestContext& ctx); + void GetWindowController(HLERequestContext& ctx); + void GetAudioController(HLERequestContext& ctx); + void GetDisplayController(HLERequestContext& ctx); + void GetProcessWindingController(HLERequestContext& ctx); + void GetLibraryAppletCreator(HLERequestContext& ctx); + void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx); + void GetAppletCommonFunctions(HLERequestContext& ctx); + void GetHomeMenuFunctions(HLERequestContext& ctx); + void GetGlobalStateController(HLERequestContext& ctx); + void GetDebugFunctions(HLERequestContext& ctx); + + Nvnflinger::Nvnflinger& nvnflinger; + std::shared_ptr msg_queue; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp new file mode 100644 index 000000000..0a12afbbd --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -0,0 +1,382 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core_timing.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/am/applets/applet_controller.h" +#include "core/hle/service/am/applets/applet_mii_edit_types.h" +#include "core/hle/service/am/applets/applet_software_keyboard_types.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" +#include "hid_core/hid_types.h" + +namespace Service::AM { + +ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, + {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, + {2, nullptr, "PopInteractiveInData"}, + {3, nullptr, "PushInteractiveOutData"}, + {5, nullptr, "GetPopInDataEvent"}, + {6, nullptr, "GetPopInteractiveInDataEvent"}, + {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, + {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, + {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, + {13, nullptr, "CanUseApplicationCore"}, + {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, + {15, nullptr, "GetMainAppletApplicationControlProperty"}, + {16, nullptr, "GetMainAppletStorageId"}, + {17, nullptr, "GetCallerAppletIdentityInfoStack"}, + {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, + {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, + {20, nullptr, "PopExtraStorage"}, + {25, nullptr, "GetPopExtraStorageEvent"}, + {30, nullptr, "UnpopInData"}, + {31, nullptr, "UnpopExtraStorage"}, + {40, nullptr, "GetIndirectLayerProducerHandle"}, + {50, nullptr, "ReportVisibleError"}, + {51, nullptr, "ReportVisibleErrorWithErrorContext"}, + {60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, + {70, nullptr, "GetCurrentApplicationId"}, + {80, nullptr, "RequestExitToSelf"}, + {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, + {100, nullptr, "CreateGameMovieTrimmer"}, + {101, nullptr, "ReserveResourceForMovieOperation"}, + {102, nullptr, "UnreserveResourceForMovieOperation"}, + {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"}, + {120, nullptr, "GetLaunchStorageInfoForDebug"}, + {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, + {140, nullptr, "SetApplicationMemoryReservation"}, + {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, + }; + // clang-format on + RegisterHandlers(functions); + + switch (system.GetAppletManager().GetCurrentAppletId()) { + case Applets::AppletId::Cabinet: + PushInShowCabinetData(); + break; + case Applets::AppletId::MiiEdit: + PushInShowMiiEditData(); + break; + case Applets::AppletId::PhotoViewer: + PushInShowAlbum(); + break; + case Applets::AppletId::SoftwareKeyboard: + PushInShowSoftwareKeyboard(); + break; + case Applets::AppletId::Controller: + PushInShowController(); + break; + default: + break; + } +} + +ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; + +void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + if (queue_data.empty()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + auto data = queue_data.front(); + queue_data.pop_front(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, std::move(data)); +} + +void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + system.Exit(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { + struct LibraryAppletInfo { + Applets::AppletId applet_id; + Applets::LibraryAppletMode library_applet_mode; + }; + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const LibraryAppletInfo applet_info{ + .applet_id = system.GetAppletManager().GetCurrentAppletId(), + .library_applet_mode = Applets::LibraryAppletMode::AllForeground, + }; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { + struct AppletIdentityInfo { + Applets::AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; + }; + static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const AppletIdentityInfo applet_info{ + .applet_id = Applets::AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { + struct AppletIdentityInfo { + Applets::AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; + }; + static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const AppletIdentityInfo applet_info{ + .applet_id = Applets::AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { + const Service::Account::ProfileManager manager{}; + bool is_empty{true}; + s32 user_count{-1}; + + LOG_INFO(Service_AM, "called"); + + if (manager.GetUserCount() > 0) { + is_empty = false; + user_count = static_cast(manager.GetUserCount()); + ctx.WriteBuffer(manager.GetAllUsers()); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(is_empty); + rb.Push(user_count); +} + +void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void ILibraryAppletSelfAccessor::PushInShowAlbum() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = 1, + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector argument_data(sizeof(arguments)); + std::vector settings_data{2}; + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(settings_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowController() { + const Applets::CommonArguments common_args = { + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast(Applets::ControllerAppletVersion::Version8), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + Applets::ControllerSupportArgNew user_args = { + .header = {.player_count_min = 1, + .player_count_max = 4, + .enable_take_over_connection = true, + .enable_left_justify = false, + .enable_permit_joy_dual = true, + .enable_single_mode = false, + .enable_identification_color = false}, + .identification_colors = {}, + .enable_explain_text = false, + .explain_text = {}, + }; + + Applets::ControllerSupportArgPrivate private_args = { + .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), + .arg_size = sizeof(Applets::ControllerSupportArgNew), + .is_home_menu = true, + .flag_1 = true, + .mode = Applets::ControllerSupportMode::ShowControllerSupport, + .caller = Applets::ControllerSupportCaller:: + Application, // switchbrew: Always zero except with + // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, + // which sets this to the input param + .style_set = Core::HID::NpadStyleSet::None, + .joy_hold_type = 0, + }; + std::vector common_args_data(sizeof(common_args)); + std::vector private_args_data(sizeof(private_args)); + std::vector user_args_data(sizeof(user_args)); + + std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); + std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); + std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); + + queue_data.emplace_back(std::move(common_args_data)); + queue_data.emplace_back(std::move(private_args_data)); + queue_data.emplace_back(std::move(user_args_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowCabinetData() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast(Applets::CabinetAppletVersion::Version1), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + const Applets::StartParamForAmiiboSettings amiibo_settings{ + .param_1 = 0, + .applet_mode = system.GetAppletManager().GetCabinetMode(), + .flags = Applets::CabinetFlags::None, + .amiibo_settings_1 = 0, + .device_handle = 0, + .tag_info{}, + .register_info{}, + .amiibo_settings_3{}, + }; + + std::vector argument_data(sizeof(arguments)); + std::vector settings_data(sizeof(amiibo_settings)); + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(settings_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { + struct MiiEditV3 { + Applets::MiiEditAppletInputCommon common; + Applets::MiiEditAppletInputV3 input; + }; + static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); + + MiiEditV3 mii_arguments{ + .common = + { + .version = Applets::MiiEditAppletVersion::Version3, + .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, + }, + .input{}, + }; + + std::vector argument_data(sizeof(mii_arguments)); + std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); + + queue_data.emplace_back(std::move(argument_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast(Applets::SwkbdAppletVersion::Version524301), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector initial_string(0); + + const Applets::SwkbdConfigCommon swkbd_config{ + .type = Applets::SwkbdType::Qwerty, + .ok_text{}, + .left_optional_symbol_key{}, + .right_optional_symbol_key{}, + .use_prediction = false, + .key_disable_flags{}, + .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .header_text{}, + .sub_text{}, + .guide_text{}, + .max_text_length = 500, + .min_text_length = 0, + .password_mode = Applets::SwkbdPasswordMode::Disabled, + .text_draw_type = Applets::SwkbdTextDrawType::Box, + .enable_return_button = true, + .use_utf8 = false, + .use_blur_background = true, + .initial_string_offset{}, + .initial_string_length = static_cast(initial_string.size()), + .user_dictionary_offset{}, + .user_dictionary_entries{}, + .use_text_check = false, + }; + + Applets::SwkbdConfigNew swkbd_config_new{}; + + std::vector argument_data(sizeof(arguments)); + std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); + std::vector work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); + + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); + std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, + sizeof(Applets::SwkbdConfigNew)); + std::memcpy(work_buffer.data(), initial_string.data(), + swkbd_config.initial_string_length * sizeof(char16_t)); + + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(swkbd_data)); + queue_data.emplace_back(std::move(work_buffer)); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.h b/src/core/hle/service/am/library_applet_self_accessor.h new file mode 100644 index 000000000..45b325b77 --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletSelfAccessor final : public ServiceFramework { +public: + explicit ILibraryAppletSelfAccessor(Core::System& system_); + ~ILibraryAppletSelfAccessor() override; + +private: + void PopInData(HLERequestContext& ctx); + void PushOutData(HLERequestContext& ctx); + void GetLibraryAppletInfo(HLERequestContext& ctx); + void GetMainAppletIdentityInfo(HLERequestContext& ctx); + void ExitProcessAndReturn(HLERequestContext& ctx); + void GetCallerAppletIdentityInfo(HLERequestContext& ctx); + void GetDesirableKeyboardLayout(HLERequestContext& ctx); + void GetMainAppletAvailableUsers(HLERequestContext& ctx); + void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); + + void PushInShowAlbum(); + void PushInShowCabinetData(); + void PushInShowMiiEditData(); + void PushInShowSoftwareKeyboard(); + void PushInShowController(); + + std::deque> queue_data; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/lock_accessor.cpp b/src/core/hle/service/am/lock_accessor.cpp new file mode 100644 index 000000000..d0bd8d95e --- /dev/null +++ b/src/core/hle/service/am/lock_accessor.cpp @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/lock_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILockAccessor::ILockAccessor(Core::System& system_) + : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} { + // clang-format off + static const FunctionInfo functions[] = { + {1, &ILockAccessor::TryLock, "TryLock"}, + {2, &ILockAccessor::Unlock, "Unlock"}, + {3, &ILockAccessor::GetEvent, "GetEvent"}, + {4,&ILockAccessor::IsLocked, "IsLocked"}, + }; + // clang-format on + + RegisterHandlers(functions); + + lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); +} + +ILockAccessor::~ILockAccessor() { + service_context.CloseEvent(lock_event); +}; + +void ILockAccessor::TryLock(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto return_handle = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle); + + // TODO: When return_handle is true this function should return the lock handle + + is_locked = true; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_locked); +} + +void ILockAccessor::Unlock(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + is_locked = false; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILockAccessor::GetEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + lock_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(lock_event->GetReadableEvent()); +} + +void ILockAccessor::IsLocked(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + rb.Push(is_locked); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/lock_accessor.h b/src/core/hle/service/am/lock_accessor.h new file mode 100644 index 000000000..626f60e07 --- /dev/null +++ b/src/core/hle/service/am/lock_accessor.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILockAccessor final : public ServiceFramework { +public: + explicit ILockAccessor(Core::System& system_); + ~ILockAccessor() override; + +private: + void TryLock(HLERequestContext& ctx); + void Unlock(HLERequestContext& ctx); + void GetEvent(HLERequestContext& ctx); + void IsLocked(HLERequestContext& ctx); + + bool is_locked{}; + + Kernel::KEvent* lock_event; + KernelHelpers::ServiceContext service_context; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp new file mode 100644 index 000000000..7b3ab157f --- /dev/null +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/library_applet_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IProcessWindingController::IProcessWindingController(Core::System& system_) + : ServiceFramework{system_, "IProcessWindingController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, + {11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"}, + {21, nullptr, "PushContext"}, + {22, nullptr, "PopContext"}, + {23, nullptr, "CancelWindingReservation"}, + {30, nullptr, "WindAndDoReserved"}, + {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"}, + {41, nullptr, "ReserveToStartAndWait"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IProcessWindingController::~IProcessWindingController() = default; + +void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + struct AppletProcessLaunchReason { + u8 flag; + INSERT_PADDING_BYTES(3); + }; + static_assert(sizeof(AppletProcessLaunchReason) == 0x4, + "AppletProcessLaunchReason is an invalid size"); + + AppletProcessLaunchReason reason{ + .flag = 0, + }; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(reason); +} + +void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { + const auto applet_id = system.GetAppletManager().GetCurrentAppletId(); + const auto applet_mode = Applets::LibraryAppletMode::AllForeground; + + LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, + applet_mode); + + const auto& applet_manager{system.GetAppletManager()}; + const auto applet = applet_manager.GetApplet(applet_id, applet_mode); + + if (applet == nullptr) { + LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, applet); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.h b/src/core/hle/service/am/process_winding_controller.h new file mode 100644 index 000000000..9b9704201 --- /dev/null +++ b/src/core/hle/service/am/process_winding_controller.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IProcessWindingController final : public ServiceFramework { +public: + explicit IProcessWindingController(Core::System& system_); + ~IProcessWindingController() override; + +private: + void GetLaunchReason(HLERequestContext& ctx); + void OpenCallingLibraryApplet(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp new file mode 100644 index 000000000..0f495c871 --- /dev/null +++ b/src/core/hle/service/am/self_controller.cpp @@ -0,0 +1,438 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/vi/vi_results.h" + +namespace Service::AM { + +ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, + service_context{system, "ISelfController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISelfController::Exit, "Exit"}, + {1, &ISelfController::LockExit, "LockExit"}, + {2, &ISelfController::UnlockExit, "UnlockExit"}, + {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, + {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"}, + {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, + {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, + {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, + {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"}, + {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, + {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, + {15, nullptr, "SetScreenShotAppletIdentityInfo"}, + {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, + {17, nullptr, "SetControllerFirmwareUpdateSection"}, + {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, + {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, + {20, nullptr, "SetDesirableKeyboardLayout"}, + {21, nullptr, "GetScreenShotProgramId"}, + {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, + {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"}, + {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"}, + {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"}, + {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, + {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, + {46, nullptr, "SetRecordingLayerCompositionEnabled"}, + {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, + {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, + {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, + {61, nullptr, "SetMediaPlaybackState"}, + {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, + {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, + {64, nullptr, "SetInputDetectionSourceSet"}, + {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"}, + {66, nullptr, "GetCurrentIlluminance"}, + {67, nullptr, "IsIlluminanceAvailable"}, + {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"}, + {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, + {70, nullptr, "ReportMultimediaError"}, + {71, nullptr, "GetCurrentIlluminanceEx"}, + {72, nullptr, "SetInputDetectionPolicy"}, + {80, nullptr, "SetWirelessPriorityMode"}, + {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, + {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, + {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, + {110, nullptr, "SetApplicationAlbumUserData"}, + {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, + {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, + {1000, nullptr, "GetDebugStorageChannel"}, + }; + // clang-format on + + RegisterHandlers(functions); + + launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); + + // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is + // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple + // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not + // suspended if the event has previously been created by a call to + // GetAccumulatedSuspendedTickChangedEvent. + + accumulated_suspended_tick_changed_event = + service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); + accumulated_suspended_tick_changed_event->Signal(); +} + +ISelfController::~ISelfController() { + service_context.CloseEvent(launchable_event); + service_context.CloseEvent(accumulated_suspended_tick_changed_event); +} + +void ISelfController::Exit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + system.Exit(); +} + +void ISelfController::LockExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLocked(true); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::UnlockExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLocked(false); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + if (system.GetExitRequested()) { + system.Exit(); + } +} + +void ISelfController::EnterFatalSection(HLERequestContext& ctx) { + ++num_fatal_sections_entered; + LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + // Entry and exit of fatal sections must be balanced. + if (num_fatal_sections_entered == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Result{ErrorModule::AM, 512}); + return; + } + + --num_fatal_sections_entered; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + launchable_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(launchable_event->GetReadableEvent()); +} + +void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto permission = rp.PopEnum(); + LOG_DEBUG(Service_AM, "called, permission={}", permission); + + screenshot_permission = permission; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + bool flag = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + bool flag = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous + // u8, these are bool flags. No output. + IPC::RequestParser rp{ctx}; + + struct FocusHandlingModeParams { + u8 unknown0; + u8 unknown1; + u8 unknown2; + }; + const auto flags = rp.PopRaw(); + + LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", + flags.unknown0, flags.unknown1, flags.unknown2); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous + // u8, these are bool flags. No output. + IPC::RequestParser rp{ctx}; + + bool enabled = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO(Subv): Find out how AM determines the display to use, for now just + // create the layer in the Default display. + const auto display_id = nvnflinger.OpenDisplay("Default"); + const auto layer_id = nvnflinger.CreateLayer(*display_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(*layer_id); +} + +void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); +} + +void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); + rb.Push(system_shared_buffer_id); + rb.Push(system_shared_layer_id); +} + +void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); + rb.Push(system_shared_buffer_id); +} + +Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { + if (buffer_sharing_enabled) { + return ResultSuccess; + } + + if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) { + return VI::ResultOperationFailed; + } + + const auto display_id = nvnflinger.OpenDisplay("Default"); + const auto result = nvnflinger.GetSystemBufferManager().Initialize( + &system_shared_buffer_id, &system_shared_layer_id, *display_id); + + if (result.IsSuccess()) { + buffer_sharing_enabled = true; + } + + return result; +} + +void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO(Subv): Find out how AM determines the display to use, for now just + // create the layer in the Default display. + // This calls nn::vi::CreateRecordingLayer() which creates another layer. + // Currently we do not support more than 1 layer per display, output 1 layer id for now. + // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse + // side effects. + // TODO: Support multiple layers + const auto display_id = nvnflinger.OpenDisplay("Default"); + const auto layer_id = nvnflinger.CreateLayer(*display_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(*layer_id); +} + +void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + idle_time_detection_extension = rp.Pop(); + LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", + idle_time_detection_extension); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(idle_time_detection_extension); +} + +void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + is_auto_sleep_disabled = rp.Pop(); + + // On the system itself, if the previous state of is_auto_sleep_disabled + // differed from the current value passed in, it'd signify the internal + // window manager to update (and also increment some statistics like update counts) + // + // It'd also indicate this change to an idle handling context. + // + // However, given we're emulating this behavior, most of this can be ignored + // and it's sufficient to simply set the member variable for querying via + // IsAutoSleepDisabled(). + + LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_auto_sleep_disabled); +} + +void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + // This command returns the total number of system ticks since ISelfController creation + // where the game was suspended. Since Yuzu doesn't implement game suspension, this command + // can just always return 0 ticks. + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); +} + +void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + // This service call sets an internal flag whether a notification is shown when an image is + // captured. Currently we do not support capturing images via the capture button, so this can be + // stubbed for now. + const bool album_image_taken_notification_enabled = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", + album_image_taken_notification_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto report_option = rp.PopEnum(); + + LOG_INFO(Service_AM, "called, report_option={}", report_option); + + const auto screenshot_service = + system.ServiceManager().GetService( + "caps:su"); + + if (screenshot_service) { + screenshot_service->CaptureAndSaveScreenshot(report_option); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto is_record_volume_muted = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/self_controller.h b/src/core/hle/service/am/self_controller.h new file mode 100644 index 000000000..f157bb826 --- /dev/null +++ b/src/core/hle/service/am/self_controller.h @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ISelfController final : public ServiceFramework { +public: + explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); + ~ISelfController() override; + +private: + void Exit(HLERequestContext& ctx); + void LockExit(HLERequestContext& ctx); + void UnlockExit(HLERequestContext& ctx); + void EnterFatalSection(HLERequestContext& ctx); + void LeaveFatalSection(HLERequestContext& ctx); + void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx); + void SetScreenShotPermission(HLERequestContext& ctx); + void SetOperationModeChangedNotification(HLERequestContext& ctx); + void SetPerformanceModeChangedNotification(HLERequestContext& ctx); + void SetFocusHandlingMode(HLERequestContext& ctx); + void SetRestartMessageEnabled(HLERequestContext& ctx); + void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx); + void SetAlbumImageOrientation(HLERequestContext& ctx); + void IsSystemBufferSharingEnabled(HLERequestContext& ctx); + void GetSystemSharedBufferHandle(HLERequestContext& ctx); + void GetSystemSharedLayerHandle(HLERequestContext& ctx); + void CreateManagedDisplayLayer(HLERequestContext& ctx); + void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); + void SetHandlesRequestToDisplay(HLERequestContext& ctx); + void ApproveToDisplay(HLERequestContext& ctx); + void SetIdleTimeDetectionExtension(HLERequestContext& ctx); + void GetIdleTimeDetectionExtension(HLERequestContext& ctx); + void ReportUserIsActive(HLERequestContext& ctx); + void SetAutoSleepDisabled(HLERequestContext& ctx); + void IsAutoSleepDisabled(HLERequestContext& ctx); + void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx); + void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx); + void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx); + void SaveCurrentScreenshot(HLERequestContext& ctx); + void SetRecordVolumeMuted(HLERequestContext& ctx); + + Result EnsureBufferSharingEnabled(Kernel::KProcess* process); + + enum class ScreenshotPermission : u32 { + Inherit = 0, + Enable = 1, + Disable = 2, + }; + + Nvnflinger::Nvnflinger& nvnflinger; + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* launchable_event; + Kernel::KEvent* accumulated_suspended_tick_changed_event; + + u32 idle_time_detection_extension = 0; + u64 num_fatal_sections_entered = 0; + u64 system_shared_buffer_id = 0; + u64 system_shared_layer_id = 0; + bool is_auto_sleep_disabled = false; + bool buffer_sharing_enabled = false; + ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage.cpp b/src/core/hle/service/am/storage.cpp new file mode 100644 index 000000000..9a86c867a --- /dev/null +++ b/src/core/hle/service/am/storage.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/storage.h" +#include "core/hle/service/am/storage_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IStorageImpl::~IStorageImpl() = default; + +class StorageDataImpl final : public IStorageImpl { +public: + explicit StorageDataImpl(std::vector&& buffer_) : buffer{std::move(buffer_)} {} + + std::vector& GetData() override { + return buffer; + } + + const std::vector& GetData() const override { + return buffer; + } + + std::size_t GetSize() const override { + return buffer.size(); + } + +private: + std::vector buffer; +}; + +IStorage::IStorage(Core::System& system_, std::vector&& buffer) + : ServiceFramework{system_, "IStorage"}, + impl{std::make_shared(std::move(buffer))} { + Register(); +} + +void IStorage::Register() { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IStorage::Open, "Open"}, + {1, nullptr, "OpenTransferStorage"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IStorage::~IStorage() = default; + +void IStorage::Open(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, *this); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage.h b/src/core/hle/service/am/storage.h new file mode 100644 index 000000000..d47a8d89f --- /dev/null +++ b/src/core/hle/service/am/storage.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IStorageImpl { +public: + virtual ~IStorageImpl(); + virtual std::vector& GetData() = 0; + virtual const std::vector& GetData() const = 0; + virtual std::size_t GetSize() const = 0; +}; + +class IStorage final : public ServiceFramework { +public: + explicit IStorage(Core::System& system_, std::vector&& buffer); + ~IStorage() override; + + std::vector& GetData() { + return impl->GetData(); + } + + const std::vector& GetData() const { + return impl->GetData(); + } + + std::size_t GetSize() const { + return impl->GetSize(); + } + +private: + void Register(); + void Open(HLERequestContext& ctx); + + std::shared_ptr impl; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage_accessor.cpp b/src/core/hle/service/am/storage_accessor.cpp new file mode 100644 index 000000000..7d8c82de3 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.cpp @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/storage_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) + : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IStorageAccessor::GetSize, "GetSize"}, + {10, &IStorageAccessor::Write, "Write"}, + {11, &IStorageAccessor::Read, "Read"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IStorageAccessor::~IStorageAccessor() = default; + +void IStorageAccessor::GetSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(ResultSuccess); + rb.Push(static_cast(backing.GetSize())); +} + +void IStorageAccessor::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const u64 offset{rp.Pop()}; + const auto data{ctx.ReadBuffer()}; + const std::size_t size{std::min(data.size(), backing.GetSize() - offset)}; + + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + + if (offset > backing.GetSize()) { + LOG_ERROR(Service_AM, + "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", + backing.GetSize(), size, offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidOffset); + return; + } + + std::memcpy(backing.GetData().data() + offset, data.data(), size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IStorageAccessor::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const u64 offset{rp.Pop()}; + const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; + + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + + if (offset > backing.GetSize()) { + LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", + backing.GetSize(), size, offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidOffset); + return; + } + + ctx.WriteBuffer(backing.GetData().data() + offset, size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage_accessor.h b/src/core/hle/service/am/storage_accessor.h new file mode 100644 index 000000000..8648bfc13 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/storage.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IStorageAccessor final : public ServiceFramework { +public: + explicit IStorageAccessor(Core::System& system_, IStorage& backing_); + ~IStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Read(HLERequestContext& ctx); + + IStorage& backing; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/system_applet_proxy.cpp b/src/core/hle/service/am/system_applet_proxy.cpp new file mode 100644 index 000000000..d51a2c8db --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.cpp @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/am/application_creator.h" +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/am/global_state_controller.h" +#include "core/hle/service/am/home_menu_functions.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/am/system_applet_proxy.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr msg_queue_, + Core::System& system_) + : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, + {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"}, + {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"}, + {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"}, + {10, nullptr, "GetProcessWindingController"}, + {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, + {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, + {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, + {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, + {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, msg_queue); +} + +void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, nvnflinger); +} + +void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetApplicationCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/system_applet_proxy.h b/src/core/hle/service/am/system_applet_proxy.h new file mode 100644 index 000000000..b8855b1d6 --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.h @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ISystemAppletProxy final : public ServiceFramework { +public: + explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr msg_queue_, + Core::System& system_); + +private: + void GetCommonStateGetter(HLERequestContext& ctx); + void GetSelfController(HLERequestContext& ctx); + void GetWindowController(HLERequestContext& ctx); + void GetAudioController(HLERequestContext& ctx); + void GetDisplayController(HLERequestContext& ctx); + void GetLibraryAppletCreator(HLERequestContext& ctx); + void GetHomeMenuFunctions(HLERequestContext& ctx); + void GetGlobalStateController(HLERequestContext& ctx); + void GetApplicationCreator(HLERequestContext& ctx); + void GetAppletCommonFunctions(HLERequestContext& ctx); + void GetDebugFunctions(HLERequestContext& ctx); + + Nvnflinger::Nvnflinger& nvnflinger; + std::shared_ptr msg_queue; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/window_controller.cpp b/src/core/hle/service/am/window_controller.cpp new file mode 100644 index 000000000..f2ba3c134 --- /dev/null +++ b/src/core/hle/service/am/window_controller.cpp @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IWindowController::IWindowController(Core::System& system_) + : ServiceFramework{system_, "IWindowController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateWindow"}, + {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, + {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"}, + {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, + {11, nullptr, "ReleaseForegroundRights"}, + {12, nullptr, "RejectToChangeIntoBackground"}, + {20, nullptr, "SetAppletWindowVisibility"}, + {21, nullptr, "SetAppletGpuTimeSlice"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IWindowController::~IWindowController() = default; + +void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { + const u64 process_id = system.ApplicationProcess()->GetProcessId(); + + LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(process_id); +} + +void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { + const u64 process_id = 0; + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(process_id); +} + +void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/window_controller.h b/src/core/hle/service/am/window_controller.h new file mode 100644 index 000000000..07b0e0e17 --- /dev/null +++ b/src/core/hle/service/am/window_controller.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IWindowController final : public ServiceFramework { +public: + explicit IWindowController(Core::System& system_); + ~IWindowController() override; + +private: + void GetAppletResourceUserId(HLERequestContext& ctx); + void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); + void AcquireForegroundRights(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 49ec52546..718534ba1 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/sm/sm.h" #include "hid_core/frontend/emulated_controller.h" diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 782bcbb61..f51fd3fa3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -44,6 +44,7 @@ #include "core/frontend/applets/software_keyboard.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/set/system_settings_server.h" -- cgit v1.2.3 From a7e9d7842dc78e09bfe50ba3bc471b8a75d29b96 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Jan 2024 19:22:02 -0500 Subject: am: add new datatypes for per-applet state --- src/core/CMakeLists.txt | 17 + src/core/hle/service/am/am_types.h | 171 ++++++++++ src/core/hle/service/am/applet.cpp | 63 ++++ src/core/hle/service/am/applet.h | 164 ++++++++++ src/core/hle/service/am/applet_manager.cpp | 352 +++++++++++++++++++++ src/core/hle/service/am/applet_manager.h | 59 ++++ src/core/hle/service/am/hid_registration.cpp | 29 ++ src/core/hle/service/am/hid_registration.h | 30 ++ src/core/hle/service/am/library_applet_storage.cpp | 140 ++++++++ src/core/hle/service/am/library_applet_storage.h | 36 +++ src/core/hle/service/am/managed_layer_holder.cpp | 59 ++++ src/core/hle/service/am/managed_layer_holder.h | 32 ++ src/core/hle/service/am/process.cpp | 138 ++++++++ src/core/hle/service/am/process.h | 50 +++ src/core/hle/service/am/system_buffer_manager.cpp | 49 +++ src/core/hle/service/am/system_buffer_manager.h | 44 +++ src/core/hle/service/event.cpp | 31 ++ src/core/hle/service/event.h | 31 ++ .../service/nvnflinger/fb_share_buffer_manager.cpp | 2 +- 19 files changed, 1496 insertions(+), 1 deletion(-) create mode 100644 src/core/hle/service/am/am_types.h create mode 100644 src/core/hle/service/am/applet.cpp create mode 100644 src/core/hle/service/am/applet.h create mode 100644 src/core/hle/service/am/applet_manager.cpp create mode 100644 src/core/hle/service/am/applet_manager.h create mode 100644 src/core/hle/service/am/hid_registration.cpp create mode 100644 src/core/hle/service/am/hid_registration.h create mode 100644 src/core/hle/service/am/library_applet_storage.cpp create mode 100644 src/core/hle/service/am/library_applet_storage.h create mode 100644 src/core/hle/service/am/managed_layer_holder.cpp create mode 100644 src/core/hle/service/am/managed_layer_holder.h create mode 100644 src/core/hle/service/am/process.cpp create mode 100644 src/core/hle/service/am/process.h create mode 100644 src/core/hle/service/am/system_buffer_manager.cpp create mode 100644 src/core/hle/service/am/system_buffer_manager.h create mode 100644 src/core/hle/service/event.cpp create mode 100644 src/core/hle/service/event.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3a2ba9ed4..049946426 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -393,8 +393,13 @@ add_library(core STATIC hle/service/am/am.cpp hle/service/am/am.h hle/service/am/am_results.h + hle/service/am/am_types.h + hle/service/am/applet.cpp + hle/service/am/applet.h hle/service/am/applet_ae.cpp hle/service/am/applet_ae.h + hle/service/am/applet_manager.cpp + hle/service/am/applet_manager.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h hle/service/am/applets/applet_cabinet.cpp @@ -438,6 +443,8 @@ add_library(core STATIC hle/service/am/display_controller.h hle/service/am/global_state_controller.cpp hle/service/am/global_state_controller.h + hle/service/am/hid_registration.cpp + hle/service/am/hid_registration.h hle/service/am/home_menu_functions.cpp hle/service/am/home_menu_functions.h hle/service/am/idle.cpp @@ -450,16 +457,24 @@ add_library(core STATIC hle/service/am/library_applet_proxy.h hle/service/am/library_applet_self_accessor.cpp hle/service/am/library_applet_self_accessor.h + hle/service/am/library_applet_storage.cpp + hle/service/am/library_applet_storage.h hle/service/am/lock_accessor.cpp hle/service/am/lock_accessor.h + hle/service/am/managed_layer_holder.cpp + hle/service/am/managed_layer_holder.h hle/service/am/omm.cpp hle/service/am/omm.h hle/service/am/process_winding_controller.cpp hle/service/am/process_winding_controller.h + hle/service/am/process.cpp + hle/service/am/process.h hle/service/am/self_controller.cpp hle/service/am/self_controller.h hle/service/am/system_applet_proxy.cpp hle/service/am/system_applet_proxy.h + hle/service/am/system_buffer_manager.cpp + hle/service/am/system_buffer_manager.h hle/service/am/spsm.cpp hle/service/am/spsm.h hle/service/am/storage_accessor.cpp @@ -531,6 +546,8 @@ add_library(core STATIC hle/service/es/es.h hle/service/eupld/eupld.cpp hle/service/eupld/eupld.h + hle/service/event.cpp + hle/service/event.h hle/service/fatal/fatal.cpp hle/service/fatal/fatal.h hle/service/fatal/fatal_p.cpp diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h new file mode 100644 index 000000000..d0a237a7e --- /dev/null +++ b/src/core/hle/service/am/am_types.h @@ -0,0 +1,171 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Service::AM { + +namespace Frontend { +class FrontendApplet; +} + +enum class AppletType { + Application, + LibraryApplet, + SystemApplet, +}; + +enum class GameplayRecordingState : u32 { + Disabled, + Enabled, +}; + +// This is nn::oe::FocusState +enum class FocusState : u8 { + InFocus = 1, + NotInFocus = 2, + Background = 3, +}; + +// This is nn::oe::OperationMode +enum class OperationMode : u8 { + Handheld = 0, + Docked = 1, +}; + +// This is nn::am::service::SystemButtonType +enum class SystemButtonType { + None, + HomeButtonShortPressing, + HomeButtonLongPressing, + PowerButtonShortPressing, + PowerButtonLongPressing, + ShutdownSystem, + CaptureButtonShortPressing, + CaptureButtonLongPressing, +}; + +enum class SysPlatformRegion : s32 { + Global = 1, + Terra = 2, +}; + +struct AppletProcessLaunchReason { + u8 flag; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(AppletProcessLaunchReason) == 0x4, + "AppletProcessLaunchReason is an invalid size"); + +enum class ScreenshotPermission : u32 { + Inherit = 0, + Enable = 1, + Disable = 2, +}; + +struct FocusHandlingMode { + bool unknown0; + bool unknown1; + bool unknown2; + bool unknown3; +}; + +enum class IdleTimeDetectionExtension : u32 { + Disabled = 0, + Extended = 1, + ExtendedUnsafe = 2, +}; + +enum class AppletId : u32 { + None = 0x00, + Application = 0x01, + OverlayDisplay = 0x02, + QLaunch = 0x03, + Starter = 0x04, + Auth = 0x0A, + Cabinet = 0x0B, + Controller = 0x0C, + DataErase = 0x0D, + Error = 0x0E, + NetConnect = 0x0F, + ProfileSelect = 0x10, + SoftwareKeyboard = 0x11, + MiiEdit = 0x12, + Web = 0x13, + Shop = 0x14, + PhotoViewer = 0x15, + Settings = 0x16, + OfflineWeb = 0x17, + LoginShare = 0x18, + WebAuth = 0x19, + MyPage = 0x1A, +}; + +enum class AppletProgramId : u64 { + QLaunch = 0x0100000000001000ull, + Auth = 0x0100000000001001ull, + Cabinet = 0x0100000000001002ull, + Controller = 0x0100000000001003ull, + DataErase = 0x0100000000001004ull, + Error = 0x0100000000001005ull, + NetConnect = 0x0100000000001006ull, + ProfileSelect = 0x0100000000001007ull, + SoftwareKeyboard = 0x0100000000001008ull, + MiiEdit = 0x0100000000001009ull, + Web = 0x010000000000100Aull, + Shop = 0x010000000000100Bull, + OverlayDisplay = 0x010000000000100Cull, + PhotoViewer = 0x010000000000100Dull, + Settings = 0x010000000000100Eull, + OfflineWeb = 0x010000000000100Full, + LoginShare = 0x0100000000001010ull, + WebAuth = 0x0100000000001011ull, + Starter = 0x0100000000001012ull, + MyPage = 0x0100000000001013ull, + MaxProgramId = 0x0100000000001FFFull, +}; + +enum class LibraryAppletMode : u32 { + AllForeground = 0, + Background = 1, + NoUI = 2, + BackgroundIndirectDisplay = 3, + AllForegroundInitiallyHidden = 4, +}; + +enum class CommonArgumentVersion : u32 { + Version0, + Version1, + Version2, + Version3, +}; + +enum class CommonArgumentSize : u32 { + Version3 = 0x20, +}; + +enum class ThemeColor : u32 { + BasicWhite = 0, + BasicBlack = 3, +}; + +struct CommonArguments { + CommonArgumentVersion arguments_version; + CommonArgumentSize size; + u32 library_version; + ThemeColor theme_color; + bool play_startup_sound; + u64 system_tick; +}; +static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); + +using AppletResourceUserId = u64; +using ProgramId = u64; + +struct Applet; +struct AppletStorageHolder; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet.cpp b/src/core/hle/service/am/applet.cpp new file mode 100644 index 000000000..8f44fab33 --- /dev/null +++ b/src/core/hle/service/am/applet.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" + +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" + +namespace Service::AM { + +AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context) + : m_event(context) {} +AppletStorageChannel::~AppletStorageChannel() = default; + +void AppletStorageChannel::PushData(std::shared_ptr storage) { + std::scoped_lock lk{m_lock}; + + m_data.emplace_back(std::move(storage)); + m_event.Signal(); +} + +Result AppletStorageChannel::PopData(std::shared_ptr* out_storage) { + std::scoped_lock lk{m_lock}; + + SCOPE_EXIT({ + if (m_data.empty()) { + m_event.Clear(); + } + }); + + R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); + + *out_storage = std::move(m_data.front()); + m_data.pop_front(); + + R_SUCCEED(); +} + +Kernel::KReadableEvent* AppletStorageChannel::GetEvent() { + return m_event.GetHandle(); +} + +AppletStorageHolder::AppletStorageHolder(Core::System& system) + : context(system, "AppletStorageHolder"), in_data(context), interactive_in_data(context), + out_data(context), interactive_out_data(context), state_changed_event(context) {} + +AppletStorageHolder::~AppletStorageHolder() = default; + +Applet::Applet(Core::System& system, std::unique_ptr process_) + : context(system, "Applet"), message_queue(system), process(std::move(process_)), + hid_registration(system, *process), gpu_error_detected_event(context), + friend_invitation_storage_channel_event(context), notification_storage_channel_event(context), + health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context), + pop_from_general_channel_event(context), library_applet_launchable_event(context), + accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) { + + aruid = process->GetProcessId(); + program_id = process->GetProgramId(); +} + +Applet::~Applet() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h new file mode 100644 index 000000000..9650a2615 --- /dev/null +++ b/src/core/hle/service/am/applet.h @@ -0,0 +1,164 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/math_util.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/event.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/am/hid_registration.h" +#include "core/hle/service/am/managed_layer_holder.h" +#include "core/hle/service/am/process.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/am/system_buffer_manager.h" + +namespace Service::Nvnflinger { +class FbShareBufferManager; +class Nvnflinger; +} // namespace Service::Nvnflinger + +namespace Service::AM { + +class AppletStorageChannel { +public: + explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx); + ~AppletStorageChannel(); + + void PushData(std::shared_ptr storage); + Result PopData(std::shared_ptr* out_storage); + Kernel::KReadableEvent* GetEvent(); + +private: + std::mutex m_lock{}; + std::deque> m_data{}; + Event m_event; +}; + +struct AppletStorageHolder { + explicit AppletStorageHolder(Core::System& system); + ~AppletStorageHolder(); + + KernelHelpers::ServiceContext context; + + AppletStorageChannel in_data; + AppletStorageChannel interactive_in_data; + AppletStorageChannel out_data; + AppletStorageChannel interactive_out_data; + Event state_changed_event; +}; + +struct Applet { + explicit Applet(Core::System& system, std::unique_ptr process_); + ~Applet(); + + // Lock + std::mutex lock{}; + + // Event creation helper + KernelHelpers::ServiceContext context; + + // Applet message queue + AppletMessageQueue message_queue; + + // Process + std::unique_ptr process; + + // Creation state + AppletId applet_id{}; + AppletResourceUserId aruid{}; + AppletProcessLaunchReason launch_reason{}; + AppletType type{}; + ProgramId program_id{}; + LibraryAppletMode library_applet_mode{}; + s32 previous_program_index{-1}; + ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable}; + + // hid state + HidRegistration hid_registration; + + // vi state + SystemBufferManager system_buffer_manager{}; + ManagedLayerHolder managed_layer_holder{}; + + // Applet common functions + Result terminate_result{}; + s32 display_logical_width{}; + s32 display_logical_height{}; + Common::Rectangle display_magnification{0, 0, 1, 1}; + bool home_button_double_click_enabled{}; + bool home_button_short_pressed_blocked{}; + bool home_button_long_pressed_blocked{}; + bool vr_mode_curtain_required{}; + bool sleep_required_by_high_temperature{}; + bool sleep_required_by_low_battery{}; + s32 cpu_boost_request_priority{-1}; + bool handling_capture_button_short_pressed_message_enabled_for_applet{}; + bool handling_capture_button_long_pressed_message_enabled_for_applet{}; + u32 application_core_usage_mode{}; + + // Application functions + bool gameplay_recording_supported{}; + GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled}; + bool jit_service_launched{}; + bool is_running{}; + bool application_crash_report_enabled{}; + + // Common state + FocusState focus_state{}; + bool sleep_lock_enabled{}; + bool vr_mode_enabled{}; + bool lcd_backlight_off_enabled{}; + APM::CpuBoostMode boost_mode{}; + bool request_exit_to_library_applet_at_execute_next_program_enabled{}; + + // Channels + std::deque> user_channel_launch_parameter{}; + std::deque> preselected_user_launch_parameter{}; + + // Caller applet + std::weak_ptr caller_applet{}; + std::shared_ptr caller_applet_storage{}; + bool is_completed{}; + + // Self state + bool exit_locked{}; + s32 fatal_section_count{}; + bool operation_mode_changed_notification_enabled{true}; + bool performance_mode_changed_notification_enabled{true}; + FocusHandlingMode focus_handling_mode{}; + bool restart_message_enabled{}; + bool out_of_focus_suspension_enabled{true}; + Capture::AlbumImageOrientation album_image_orientation{}; + bool handles_request_to_display{}; + ScreenshotPermission screenshot_permission{}; + IdleTimeDetectionExtension idle_time_detection_extension{}; + bool auto_sleep_disabled{}; + u64 suspended_ticks{}; + bool album_image_taken_notification_enabled{}; + bool record_volume_muted{}; + + // Events + Event gpu_error_detected_event; + Event friend_invitation_storage_channel_event; + Event notification_storage_channel_event; + Event health_warning_disappeared_system_event; + Event acquired_sleep_lock_event; + Event pop_from_general_channel_event; + Event library_applet_launchable_event; + Event accumulated_suspended_tick_changed_event; + Event sleep_lock_event; + + // Frontend state + std::shared_ptr frontend{}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp new file mode 100644 index 000000000..9f7ccfbf2 --- /dev/null +++ b/src/core/hle/service/am/applet_manager.cpp @@ -0,0 +1,352 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "common/uuid.h" +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/am/applets/applet_controller.h" +#include "core/hle/service/am/applets/applet_mii_edit_types.h" +#include "core/hle/service/am/applets/applet_software_keyboard_types.h" +#include "hid_core/hid_types.h" + +namespace Service::AM { + +namespace { + +constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA; + +struct LaunchParameterAccountPreselectedUser { + u32 magic; + u32 is_account_selected; + Common::UUID current_user; + INSERT_PADDING_BYTES(0x70); +}; +static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); + +AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system, + std::shared_ptr& applet) { + applet->caller_applet_storage = std::make_shared(system); + return applet->caller_applet_storage->in_data; +} + +void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = 1, + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector argument_data(sizeof(arguments)); + std::vector settings_data{2}; + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + channel.PushData(std::make_shared(system, std::move(argument_data))); + channel.PushData(std::make_shared(system, std::move(settings_data))); +} + +void PushInShowController(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments common_args = { + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast(Applets::ControllerAppletVersion::Version8), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + Applets::ControllerSupportArgNew user_args = { + .header = {.player_count_min = 1, + .player_count_max = 4, + .enable_take_over_connection = true, + .enable_left_justify = false, + .enable_permit_joy_dual = true, + .enable_single_mode = false, + .enable_identification_color = false}, + .identification_colors = {}, + .enable_explain_text = false, + .explain_text = {}, + }; + + Applets::ControllerSupportArgPrivate private_args = { + .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), + .arg_size = sizeof(Applets::ControllerSupportArgNew), + .is_home_menu = true, + .flag_1 = true, + .mode = Applets::ControllerSupportMode::ShowControllerSupport, + .caller = Applets::ControllerSupportCaller:: + Application, // switchbrew: Always zero except with + // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, + // which sets this to the input param + .style_set = Core::HID::NpadStyleSet::None, + .joy_hold_type = 0, + }; + std::vector common_args_data(sizeof(common_args)); + std::vector private_args_data(sizeof(private_args)); + std::vector user_args_data(sizeof(user_args)); + + std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); + std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); + std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); + + channel.PushData(std::make_shared(system, std::move(common_args_data))); + channel.PushData(std::make_shared(system, std::move(private_args_data))); + channel.PushData(std::make_shared(system, std::move(user_args_data))); +} + +void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast(Applets::CabinetAppletVersion::Version1), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + const Applets::StartParamForAmiiboSettings amiibo_settings{ + .param_1 = 0, + .applet_mode = system.GetAppletManager().GetCabinetMode(), + .flags = Applets::CabinetFlags::None, + .amiibo_settings_1 = 0, + .device_handle = 0, + .tag_info{}, + .register_info{}, + .amiibo_settings_3{}, + }; + + std::vector argument_data(sizeof(arguments)); + std::vector settings_data(sizeof(amiibo_settings)); + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); + channel.PushData(std::make_shared(system, std::move(argument_data))); + channel.PushData(std::make_shared(system, std::move(settings_data))); +} + +void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { + struct MiiEditV3 { + Applets::MiiEditAppletInputCommon common; + Applets::MiiEditAppletInputV3 input; + }; + static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); + + MiiEditV3 mii_arguments{ + .common = + { + .version = Applets::MiiEditAppletVersion::Version3, + .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, + }, + .input{}, + }; + + std::vector argument_data(sizeof(mii_arguments)); + std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); + + channel.PushData(std::make_shared(system, std::move(argument_data))); +} + +void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast(Applets::SwkbdAppletVersion::Version524301), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector initial_string(0); + + const Applets::SwkbdConfigCommon swkbd_config{ + .type = Applets::SwkbdType::Qwerty, + .ok_text{}, + .left_optional_symbol_key{}, + .right_optional_symbol_key{}, + .use_prediction = false, + .key_disable_flags{}, + .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .header_text{}, + .sub_text{}, + .guide_text{}, + .max_text_length = 500, + .min_text_length = 0, + .password_mode = Applets::SwkbdPasswordMode::Disabled, + .text_draw_type = Applets::SwkbdTextDrawType::Box, + .enable_return_button = true, + .use_utf8 = false, + .use_blur_background = true, + .initial_string_offset{}, + .initial_string_length = static_cast(initial_string.size()), + .user_dictionary_offset{}, + .user_dictionary_entries{}, + .use_text_check = false, + }; + + Applets::SwkbdConfigNew swkbd_config_new{}; + + std::vector argument_data(sizeof(arguments)); + std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); + std::vector work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); + + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); + std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, + sizeof(Applets::SwkbdConfigNew)); + std::memcpy(work_buffer.data(), initial_string.data(), + swkbd_config.initial_string_length * sizeof(char16_t)); + + channel.PushData(std::make_shared(system, std::move(argument_data))); + channel.PushData(std::make_shared(system, std::move(swkbd_data))); + channel.PushData(std::make_shared(system, std::move(work_buffer))); +} + +} // namespace + +AppletManager::AppletManager(Core::System& system) : m_system(system) {} +AppletManager::~AppletManager() { + this->Reset(); +} + +void AppletManager::InsertApplet(std::shared_ptr applet) { + std::scoped_lock lk{m_lock}; + + m_applets.emplace(applet->aruid, std::move(applet)); +} + +void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { + std::shared_ptr applet; + { + std::scoped_lock lk{m_lock}; + + const auto it = m_applets.find(aruid); + if (it == m_applets.end()) { + return; + } + + applet = it->second; + m_applets.erase(it); + } + + // Terminate process. + applet->process->Terminate(); +} + +void AppletManager::CreateAndInsertByFrontendAppletParameters( + AppletResourceUserId aruid, const FrontendAppletParameters& params) { + // TODO: this should be run inside AM so that the events will have a parent process + // TODO: have am create the guest process + auto applet = std::make_shared(m_system, std::make_unique(m_system)); + + applet->aruid = aruid; + applet->program_id = params.program_id; + applet->applet_id = params.applet_id; + applet->type = params.applet_type; + applet->previous_program_index = params.previous_program_index; + + // Push UserChannel data from previous application + if (params.launch_type == LaunchType::ApplicationInitiated) { + applet->user_channel_launch_parameter.swap(m_system.GetUserChannel()); + } + + // TODO: Read whether we need a preselected user from NACP? + // TODO: This can be done quite easily from loader + { + LaunchParameterAccountPreselectedUser lp{}; + + lp.magic = LaunchParameterAccountPreselectedUserMagic; + lp.is_account_selected = 1; + + Account::ProfileManager profile_manager{}; + const auto uuid = profile_manager.GetUser(static_cast(Settings::values.current_user)); + ASSERT(uuid.has_value() && uuid->IsValid()); + lp.current_user = *uuid; + + std::vector buffer(sizeof(LaunchParameterAccountPreselectedUser)); + std::memcpy(buffer.data(), &lp, buffer.size()); + + applet->preselected_user_launch_parameter.push_back(std::move(buffer)); + } + + // Starting from frontend, some applets require input data. + switch (applet->applet_id) { + case AppletId::Cabinet: + PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::MiiEdit: + PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::PhotoViewer: + PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::SoftwareKeyboard: + PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::Controller: + PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + default: + break; + } + + // Applet was started by frontend, so it is foreground. + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->focus_state = FocusState::InFocus; + + this->InsertApplet(std::move(applet)); +} + +std::shared_ptr AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const { + std::scoped_lock lk{m_lock}; + + if (const auto it = m_applets.find(aruid); it != m_applets.end()) { + return it->second; + } + + return {}; +} + +void AppletManager::Reset() { + std::scoped_lock lk{m_lock}; + + m_applets.clear(); +} + +void AppletManager::RequestExit() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.RequestExit(); + } +} + +void AppletManager::RequestResume() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.RequestResume(); + } +} + +void AppletManager::OperationModeChanged() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.OperationModeChanged(); + } +} + +void AppletManager::FocusStateChanged() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.FocusStateChanged(); + } +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_manager.h b/src/core/hle/service/am/applet_manager.h new file mode 100644 index 000000000..4875de309 --- /dev/null +++ b/src/core/hle/service/am/applet_manager.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "core/hle/service/am/applet.h" + +namespace Core { +class System; +} + +namespace Service::AM { + +enum class LaunchType { + FrontendInitiated, + ApplicationInitiated, +}; + +struct FrontendAppletParameters { + ProgramId program_id{}; + AppletId applet_id{}; + AppletType applet_type{}; + LaunchType launch_type{}; + s32 program_index{}; + s32 previous_program_index{-1}; +}; + +class AppletManager { +public: + explicit AppletManager(Core::System& system); + ~AppletManager(); + + void InsertApplet(std::shared_ptr applet); + void TerminateAndRemoveApplet(AppletResourceUserId aruid); + + void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid, + const FrontendAppletParameters& params); + std::shared_ptr GetByAppletResourceUserId(AppletResourceUserId aruid) const; + + void Reset(); + + void RequestExit(); + void RequestResume(); + void OperationModeChanged(); + void FocusStateChanged(); + +private: + Core::System& m_system; + + mutable std::mutex m_lock{}; + std::map> m_applets{}; + + // AudioController state goes here +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp new file mode 100644 index 000000000..b9426f7b6 --- /dev/null +++ b/src/core/hle/service/am/hid_registration.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/am/hid_registration.h" +#include "core/hle/service/am/process.h" +#include "core/hle/service/hid/hid_server.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/resource_manager.h" + +namespace Service::AM { + +HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) { + m_hid_server = system.ServiceManager().GetService("hid"); + + if (m_process.IsInitialized()) { + m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(), + true); + } +} + +HidRegistration::~HidRegistration() { + if (m_process.IsInitialized()) { + m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId( + m_process.GetProcessId()); + } +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/hid_registration.h b/src/core/hle/service/am/hid_registration.h new file mode 100644 index 000000000..8a732349c --- /dev/null +++ b/src/core/hle/service/am/hid_registration.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +namespace Core { +class System; +} + +namespace Service::HID { +class IHidServer; +} + +namespace Service::AM { + +class Process; + +class HidRegistration { +public: + explicit HidRegistration(Core::System& system, Process& process); + ~HidRegistration(); + +private: + Process& m_process; + std::shared_ptr m_hid_server; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_storage.cpp b/src/core/hle/service/am/library_applet_storage.cpp new file mode 100644 index 000000000..46e6c0111 --- /dev/null +++ b/src/core/hle/service/am/library_applet_storage.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/memory.h" + +namespace Service::AM { + +namespace { + +Result ValidateOffset(s64 offset, size_t size, size_t data_size) { + R_UNLESS(offset >= 0, AM::ResultInvalidOffset); + + const size_t begin = offset; + const size_t end = begin + size; + + R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset); + R_SUCCEED(); +} + +class BufferLibraryAppletStorage final : public LibraryAppletStorage { +public: + explicit BufferLibraryAppletStorage(std::vector&& data) : m_data(std::move(data)) {} + ~BufferLibraryAppletStorage() = default; + + Result Read(s64 offset, void* buffer, size_t size) override { + R_TRY(ValidateOffset(offset, size, m_data.size())); + + std::memcpy(buffer, m_data.data() + offset, size); + + R_SUCCEED(); + } + + Result Write(s64 offset, const void* buffer, size_t size) override { + R_TRY(ValidateOffset(offset, size, m_data.size())); + + std::memcpy(m_data.data() + offset, buffer, size); + + R_SUCCEED(); + } + + s64 GetSize() override { + return m_data.size(); + } + + Kernel::KTransferMemory* GetHandle() override { + return nullptr; + } + +private: + std::vector m_data; +}; + +class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage { +public: + explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, bool is_writable, + s64 size) + : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) { + m_trmem->Open(); + } + + ~TransferMemoryLibraryAppletStorage() { + m_trmem->Close(); + m_trmem = nullptr; + } + + Result Read(s64 offset, void* buffer, size_t size) override { + R_TRY(ValidateOffset(offset, size, m_size)); + + m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); + + R_SUCCEED(); + } + + Result Write(s64 offset, const void* buffer, size_t size) override { + R_UNLESS(m_is_writable, ResultUnknown); + R_TRY(ValidateOffset(offset, size, m_size)); + + m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); + + R_SUCCEED(); + } + + s64 GetSize() override { + return m_size; + } + + Kernel::KTransferMemory* GetHandle() override { + return nullptr; + } + +protected: + Core::Memory::Memory& m_memory; + Kernel::KTransferMemory* m_trmem; + bool m_is_writable; + s64 m_size; +}; + +class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage { +public: + explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, s64 size) + : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {} + ~HandleLibraryAppletStorage() = default; + + Kernel::KTransferMemory* GetHandle() override { + return m_trmem; + } +}; + +} // namespace + +LibraryAppletStorage::~LibraryAppletStorage() = default; + +std::vector LibraryAppletStorage::GetData() { + std::vector data(this->GetSize()); + this->Read(0, data.data(), data.size()); + return data; +} + +std::shared_ptr CreateStorage(std::vector&& data) { + return std::make_shared(std::move(data)); +} + +std::shared_ptr CreateTransferMemoryStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + bool is_writable, s64 size) { + return std::make_shared(memory, trmem, is_writable, size); +} + +std::shared_ptr CreateHandleStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + s64 size) { + return std::make_shared(memory, trmem, size); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_storage.h b/src/core/hle/service/am/library_applet_storage.h new file mode 100644 index 000000000..7f53f3a9c --- /dev/null +++ b/src/core/hle/service/am/library_applet_storage.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core::Memory { +class Memory; +} + +namespace Kernel { +class KTransferMemory; +} + +namespace Service::AM { + +class LibraryAppletStorage { +public: + virtual ~LibraryAppletStorage(); + virtual Result Read(s64 offset, void* buffer, size_t size) = 0; + virtual Result Write(s64 offset, const void* buffer, size_t size) = 0; + virtual s64 GetSize() = 0; + virtual Kernel::KTransferMemory* GetHandle() = 0; + + std::vector GetData(); +}; + +std::shared_ptr CreateStorage(std::vector&& data); +std::shared_ptr CreateTransferMemoryStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + bool is_writable, s64 size); +std::shared_ptr CreateHandleStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, s64 size); + +} // namespace Service::AM diff --git a/src/core/hle/service/am/managed_layer_holder.cpp b/src/core/hle/service/am/managed_layer_holder.cpp new file mode 100644 index 000000000..61eb8641a --- /dev/null +++ b/src/core/hle/service/am/managed_layer_holder.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/managed_layer_holder.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" + +namespace Service::AM { + +ManagedLayerHolder::ManagedLayerHolder() = default; +ManagedLayerHolder::~ManagedLayerHolder() { + if (!m_nvnflinger) { + return; + } + + for (const auto& layer : m_managed_display_layers) { + m_nvnflinger->DestroyLayer(layer); + } + + for (const auto& layer : m_managed_display_recording_layers) { + m_nvnflinger->DestroyLayer(layer); + } + + m_nvnflinger = nullptr; +} + +void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) { + m_nvnflinger = nvnflinger; +} + +void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) { + // TODO(Subv): Find out how AM determines the display to use, for now just + // create the layer in the Default display. + const auto display_id = m_nvnflinger->OpenDisplay("Default"); + const auto layer_id = m_nvnflinger->CreateLayer(*display_id); + + m_managed_display_layers.emplace(*layer_id); + + *out_layer = *layer_id; +} + +void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer, + u64* out_recording_layer) { + // TODO(Subv): Find out how AM determines the display to use, for now just + // create the layer in the Default display. + // This calls nn::vi::CreateRecordingLayer() which creates another layer. + // Currently we do not support more than 1 layer per display, output 1 layer id for now. + // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse + // side effects. + // TODO: Support multiple layers + const auto display_id = m_nvnflinger->OpenDisplay("Default"); + const auto layer_id = m_nvnflinger->CreateLayer(*display_id); + + m_managed_display_layers.emplace(*layer_id); + + *out_layer = *layer_id; + *out_recording_layer = 0; +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/managed_layer_holder.h b/src/core/hle/service/am/managed_layer_holder.h new file mode 100644 index 000000000..f7fe03f24 --- /dev/null +++ b/src/core/hle/service/am/managed_layer_holder.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Service::Nvnflinger { +class Nvnflinger; +} + +namespace Service::AM { + +class ManagedLayerHolder { +public: + ManagedLayerHolder(); + ~ManagedLayerHolder(); + + void Initialize(Nvnflinger::Nvnflinger* nvnflinger); + void CreateManagedDisplayLayer(u64* out_layer); + void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer); + +private: + Nvnflinger::Nvnflinger* m_nvnflinger{}; + std::set m_managed_display_layers{}; + std::set m_managed_display_recording_layers{}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp new file mode 100644 index 000000000..16b685f86 --- /dev/null +++ b/src/core/hle/service/am/process.cpp @@ -0,0 +1,138 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" + +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/service/am/process.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" + +namespace Service::AM { + +Process::Process(Core::System& system) + : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(), + m_program_id(), m_process_started() {} + +Process::~Process() { + this->Finalize(); +} + +bool Process::Initialize(u64 program_id) { + // First, ensure we are not holding another process. + this->Finalize(); + + // Get the filesystem controller. + auto& fsc = m_system.GetFileSystemController(); + + // Attempt to load program NCA. + const FileSys::RegisteredCache* bis_system{}; + FileSys::VirtualFile nca{}; + + // Get the program NCA from built-in storage. + bis_system = fsc.GetSystemNANDContents(); + if (bis_system) { + nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program); + } + + // Ensure we retrieved a program NCA. + if (!nca) { + return false; + } + + // Get the appropriate loader to parse this NCA. + auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0); + + // Ensure we have a loader which can parse the NCA. + if (!app_loader) { + return false; + } + + // Create the process. + auto* const process = Kernel::KProcess::Create(m_system.Kernel()); + Kernel::KProcess::Register(m_system.Kernel(), process); + + // On exit, ensure we free the additional reference to the process. + SCOPE_EXIT({ process->Close(); }); + + // Insert process modules into memory. + const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); + + // Ensure loading was successful. + if (load_result != Loader::ResultStatus::Success) { + return false; + } + + // TODO: remove this, kernel already tracks this + m_system.Kernel().AppendNewProcess(process); + + // Note the load parameters from NPDM. + m_main_thread_priority = load_parameters->main_thread_priority; + m_main_thread_stack_size = load_parameters->main_thread_stack_size; + + // This process has not started yet. + m_process_started = false; + + // Take ownership of the process object. + m_process = process; + m_process->Open(); + + // We succeeded. + return true; +} + +void Process::Finalize() { + // Terminate, if we are currently holding a process. + this->Terminate(); + + // Close the process. + if (m_process) { + m_process->Close(); + + // TODO: remove this, kernel already tracks this + m_system.Kernel().RemoveProcess(m_process); + } + + // Clean up. + m_process = nullptr; + m_main_thread_priority = 0; + m_main_thread_stack_size = 0; + m_program_id = 0; + m_process_started = false; +} + +bool Process::Run() { + // If we already started the process, don't start again. + if (m_process_started) { + return false; + } + + // Start. + if (m_process) { + m_process->Run(m_main_thread_priority, m_main_thread_stack_size); + } + + // Mark as started. + m_process_started = true; + + // We succeeded. + return true; +} + +void Process::Terminate() { + if (m_process) { + m_process->Terminate(); + } +} + +u64 Process::GetProcessId() const { + if (m_process) { + return m_process->GetProcessId(); + } + + return 0; +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/process.h b/src/core/hle/service/am/process.h new file mode 100644 index 000000000..4b908ade4 --- /dev/null +++ b/src/core/hle/service/am/process.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Kernel { +class KProcess; +} + +namespace Core { +class System; +} + +namespace Service::AM { + +class Process { +public: + explicit Process(Core::System& system); + ~Process(); + + bool Initialize(u64 program_id); + void Finalize(); + + bool Run(); + void Terminate(); + + bool IsInitialized() const { + return m_process != nullptr; + } + u64 GetProcessId() const; + u64 GetProgramId() const { + return m_program_id; + } + Kernel::KProcess* GetProcess() const { + return m_process; + } + +private: + Core::System& m_system; + Kernel::KProcess* m_process{}; + s32 m_main_thread_priority{}; + u64 m_main_thread_stack_size{}; + u64 m_program_id{}; + bool m_process_started{}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp new file mode 100644 index 000000000..7211ef488 --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.cpp @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/system_buffer_manager.h" +#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" + +namespace Service::AM { + +SystemBufferManager::SystemBufferManager() = default; + +SystemBufferManager::~SystemBufferManager() { + if (!m_nvnflinger) { + return; + } + + // Clean up shared layers. + if (m_buffer_sharing_enabled) { + } +} + +bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, + AppletId applet_id) { + if (m_nvnflinger) { + return m_buffer_sharing_enabled; + } + + m_process = process; + m_nvnflinger = nvnflinger; + m_buffer_sharing_enabled = false; + m_system_shared_buffer_id = 0; + m_system_shared_layer_id = 0; + + if (applet_id <= AppletId::Application) { + return false; + } + + const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); + const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( + &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id); + + if (res.IsSuccess()) { + m_buffer_sharing_enabled = true; + } + + return m_buffer_sharing_enabled; +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h new file mode 100644 index 000000000..c60d73416 --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/common_funcs.h" +#include "common/common_types.h" + +#include "core/hle/service/am/am_types.h" + +namespace Kernel { +class KProcess; +} + +namespace Service::Nvnflinger { +class Nvnflinger; +} + +namespace Service::AM { + +class SystemBufferManager { +public: + SystemBufferManager(); + ~SystemBufferManager(); + + bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id); + + void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, + u64* out_system_shared_layer_id) { + *out_system_shared_buffer_id = m_system_shared_buffer_id; + *out_system_shared_layer_id = m_system_shared_layer_id; + } + +private: + Kernel::KProcess* m_process{}; + Nvnflinger::Nvnflinger* m_nvnflinger{}; + bool m_buffer_sharing_enabled{}; + u64 m_system_shared_buffer_id{}; + u64 m_system_shared_layer_id{}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/event.cpp b/src/core/hle/service/event.cpp new file mode 100644 index 000000000..375660d72 --- /dev/null +++ b/src/core/hle/service/event.cpp @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/event.h" +#include "core/hle/service/kernel_helpers.h" + +namespace Service { + +Event::Event(KernelHelpers::ServiceContext& ctx) { + m_event = ctx.CreateEvent("Event"); +} + +Event::~Event() { + m_event->GetReadableEvent().Close(); + m_event->Close(); +} + +void Event::Signal() { + m_event->Signal(); +} + +void Event::Clear() { + m_event->Clear(); +} + +Kernel::KReadableEvent* Event::GetHandle() { + return &m_event->GetReadableEvent(); +} + +} // namespace Service diff --git a/src/core/hle/service/event.h b/src/core/hle/service/event.h new file mode 100644 index 000000000..cdbc4635a --- /dev/null +++ b/src/core/hle/service/event.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Service { + +namespace KernelHelpers { +class ServiceContext; +} + +class Event { +public: + explicit Event(KernelHelpers::ServiceContext& ctx); + ~Event(); + + void Signal(); + void Clear(); + + Kernel::KReadableEvent* GetHandle(); + +private: + Kernel::KEvent* m_event; +}; + +} // namespace Service diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 86e272b41..e71652cdf 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -128,7 +128,7 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D // Ensure we maintain a clean state on failure. ON_RESULT_FAILURE { - ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); + R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)); }; // Assign the allocated memory to the handle. -- cgit v1.2.3 From dfb9fa0144ca79e596f6f2b1bc960b1a44745aa6 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 31 Dec 2023 09:40:32 -0500 Subject: am: re-namespace frontend applets to frontend directory --- .../app/src/main/jni/applets/software_keyboard.cpp | 12 +- .../app/src/main/jni/applets/software_keyboard.h | 4 +- src/android/app/src/main/jni/native.cpp | 12 +- src/core/CMakeLists.txt | 46 +- src/core/core.cpp | 24 +- src/core/core.h | 15 +- src/core/frontend/applets/general.cpp | 59 + src/core/frontend/applets/general.h | 63 + src/core/frontend/applets/general_frontend.cpp | 59 - src/core/frontend/applets/general_frontend.h | 63 - src/core/frontend/applets/profile_select.h | 8 +- src/core/frontend/applets/software_keyboard.cpp | 12 +- src/core/frontend/applets/software_keyboard.h | 22 +- src/core/frontend/applets/web_browser.cpp | 4 +- src/core/frontend/applets/web_browser.h | 4 +- src/core/hle/service/am/applet_manager.cpp | 54 +- src/core/hle/service/am/applets/applet_cabinet.cpp | 187 --- src/core/hle/service/am/applets/applet_cabinet.h | 114 -- .../hle/service/am/applets/applet_controller.cpp | 273 ----- .../hle/service/am/applets/applet_controller.h | 157 --- src/core/hle/service/am/applets/applet_error.cpp | 223 ---- src/core/hle/service/am/applets/applet_error.h | 53 - .../service/am/applets/applet_general_backend.cpp | 269 ----- .../service/am/applets/applet_general_backend.h | 92 -- .../hle/service/am/applets/applet_mii_edit.cpp | 181 --- src/core/hle/service/am/applets/applet_mii_edit.h | 52 - .../hle/service/am/applets/applet_mii_edit_types.h | 83 -- .../service/am/applets/applet_profile_select.cpp | 124 -- .../hle/service/am/applets/applet_profile_select.h | 143 --- .../am/applets/applet_software_keyboard.cpp | 1277 -------------------- .../service/am/applets/applet_software_keyboard.h | 187 --- .../am/applets/applet_software_keyboard_types.h | 354 ------ .../hle/service/am/applets/applet_web_browser.cpp | 508 -------- .../hle/service/am/applets/applet_web_browser.h | 87 -- .../service/am/applets/applet_web_browser_types.h | 177 --- src/core/hle/service/am/applets/applets.cpp | 340 ------ src/core/hle/service/am/applets/applets.h | 289 ----- .../hle/service/am/frontend/applet_cabinet.cpp | 187 +++ src/core/hle/service/am/frontend/applet_cabinet.h | 114 ++ .../hle/service/am/frontend/applet_controller.cpp | 273 +++++ .../hle/service/am/frontend/applet_controller.h | 157 +++ src/core/hle/service/am/frontend/applet_error.cpp | 223 ++++ src/core/hle/service/am/frontend/applet_error.h | 53 + .../hle/service/am/frontend/applet_general.cpp | 269 +++++ src/core/hle/service/am/frontend/applet_general.h | 92 ++ .../hle/service/am/frontend/applet_mii_edit.cpp | 181 +++ src/core/hle/service/am/frontend/applet_mii_edit.h | 52 + .../service/am/frontend/applet_mii_edit_types.h | 83 ++ .../service/am/frontend/applet_profile_select.cpp | 124 ++ .../service/am/frontend/applet_profile_select.h | 143 +++ .../am/frontend/applet_software_keyboard.cpp | 1277 ++++++++++++++++++++ .../service/am/frontend/applet_software_keyboard.h | 187 +++ .../am/frontend/applet_software_keyboard_types.h | 354 ++++++ .../hle/service/am/frontend/applet_web_browser.cpp | 508 ++++++++ .../hle/service/am/frontend/applet_web_browser.h | 87 ++ .../service/am/frontend/applet_web_browser_types.h | 177 +++ src/core/hle/service/am/frontend/applets.cpp | 341 ++++++ src/core/hle/service/am/frontend/applets.h | 206 ++++ .../hle/service/am/library_applet_accessor.cpp | 2 +- src/core/hle/service/am/library_applet_accessor.h | 6 +- src/core/hle/service/am/library_applet_creator.cpp | 10 +- .../service/am/library_applet_self_accessor.cpp | 116 +- .../hle/service/am/process_winding_controller.cpp | 10 +- src/core/hle/service/am/self_controller.cpp | 4 +- src/yuzu/applets/qt_profile_select.cpp | 4 +- src/yuzu/applets/qt_software_keyboard.cpp | 10 +- src/yuzu/applets/qt_software_keyboard.h | 17 +- src/yuzu/applets/qt_web_browser.cpp | 12 +- src/yuzu/applets/qt_web_browser.h | 10 +- src/yuzu/main.cpp | 66 +- src/yuzu/main.h | 15 +- 71 files changed, 5461 insertions(+), 5540 deletions(-) create mode 100644 src/core/frontend/applets/general.cpp create mode 100644 src/core/frontend/applets/general.h delete mode 100644 src/core/frontend/applets/general_frontend.cpp delete mode 100644 src/core/frontend/applets/general_frontend.h delete mode 100644 src/core/hle/service/am/applets/applet_cabinet.cpp delete mode 100644 src/core/hle/service/am/applets/applet_cabinet.h delete mode 100644 src/core/hle/service/am/applets/applet_controller.cpp delete mode 100644 src/core/hle/service/am/applets/applet_controller.h delete mode 100644 src/core/hle/service/am/applets/applet_error.cpp delete mode 100644 src/core/hle/service/am/applets/applet_error.h delete mode 100644 src/core/hle/service/am/applets/applet_general_backend.cpp delete mode 100644 src/core/hle/service/am/applets/applet_general_backend.h delete mode 100644 src/core/hle/service/am/applets/applet_mii_edit.cpp delete mode 100644 src/core/hle/service/am/applets/applet_mii_edit.h delete mode 100644 src/core/hle/service/am/applets/applet_mii_edit_types.h delete mode 100644 src/core/hle/service/am/applets/applet_profile_select.cpp delete mode 100644 src/core/hle/service/am/applets/applet_profile_select.h delete mode 100644 src/core/hle/service/am/applets/applet_software_keyboard.cpp delete mode 100644 src/core/hle/service/am/applets/applet_software_keyboard.h delete mode 100644 src/core/hle/service/am/applets/applet_software_keyboard_types.h delete mode 100644 src/core/hle/service/am/applets/applet_web_browser.cpp delete mode 100644 src/core/hle/service/am/applets/applet_web_browser.h delete mode 100644 src/core/hle/service/am/applets/applet_web_browser_types.h delete mode 100644 src/core/hle/service/am/applets/applets.cpp delete mode 100644 src/core/hle/service/am/applets/applets.h create mode 100644 src/core/hle/service/am/frontend/applet_cabinet.cpp create mode 100644 src/core/hle/service/am/frontend/applet_cabinet.h create mode 100644 src/core/hle/service/am/frontend/applet_controller.cpp create mode 100644 src/core/hle/service/am/frontend/applet_controller.h create mode 100644 src/core/hle/service/am/frontend/applet_error.cpp create mode 100644 src/core/hle/service/am/frontend/applet_error.h create mode 100644 src/core/hle/service/am/frontend/applet_general.cpp create mode 100644 src/core/hle/service/am/frontend/applet_general.h create mode 100644 src/core/hle/service/am/frontend/applet_mii_edit.cpp create mode 100644 src/core/hle/service/am/frontend/applet_mii_edit.h create mode 100644 src/core/hle/service/am/frontend/applet_mii_edit_types.h create mode 100644 src/core/hle/service/am/frontend/applet_profile_select.cpp create mode 100644 src/core/hle/service/am/frontend/applet_profile_select.h create mode 100644 src/core/hle/service/am/frontend/applet_software_keyboard.cpp create mode 100644 src/core/hle/service/am/frontend/applet_software_keyboard.h create mode 100644 src/core/hle/service/am/frontend/applet_software_keyboard_types.h create mode 100644 src/core/hle/service/am/frontend/applet_web_browser.cpp create mode 100644 src/core/hle/service/am/frontend/applet_web_browser.h create mode 100644 src/core/hle/service/am/frontend/applet_web_browser_types.h create mode 100644 src/core/hle/service/am/frontend/applets.cpp create mode 100644 src/core/hle/service/am/frontend/applets.h diff --git a/src/android/app/src/main/jni/applets/software_keyboard.cpp b/src/android/app/src/main/jni/applets/software_keyboard.cpp index 74e040478..9943483e8 100644 --- a/src/android/app/src/main/jni/applets/software_keyboard.cpp +++ b/src/android/app/src/main/jni/applets/software_keyboard.cpp @@ -82,7 +82,7 @@ AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobj const jstring string = reinterpret_cast(env->GetObjectField( object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;"))); return ResultData{GetJString(env, string), - static_cast(env->GetIntField( + static_cast(env->GetIntField( object, env->GetFieldID(s_keyboard_data_class, "result", "I")))}; } @@ -149,7 +149,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const { } void AndroidKeyboard::ShowTextCheckDialog( - Service::AM::Applets::SwkbdTextCheckResult text_check_result, + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const { LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog."); } @@ -204,7 +204,7 @@ void AndroidKeyboard::InlineTextChanged( "\ncursor_position={}", Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, text_parameters.input_text, text_parameters.cursor_position); } @@ -219,7 +219,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) { m_current_text += submitted_text; - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text, m_current_text.size()); } @@ -236,12 +236,12 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) { case KEYCODE_BACK: case KEYCODE_ENTER: m_is_inline_active = false; - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, m_current_text, static_cast(m_current_text.size())); break; case KEYCODE_DEL: m_current_text.pop_back(); - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text, m_current_text.size()); break; } diff --git a/src/android/app/src/main/jni/applets/software_keyboard.h b/src/android/app/src/main/jni/applets/software_keyboard.h index b2fb59b68..2affc01f6 100644 --- a/src/android/app/src/main/jni/applets/software_keyboard.h +++ b/src/android/app/src/main/jni/applets/software_keyboard.h @@ -24,7 +24,7 @@ public: void ShowNormalKeyboard() const override; - void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const override; void ShowInlineKeyboard( @@ -45,7 +45,7 @@ private: static ResultData CreateFromFrontend(jobject object); std::string text; - Service::AM::Applets::SwkbdResult result{}; + Service::AM::Frontend::SwkbdResult result{}; }; void SubmitNormalText(const ResultData& result) const; diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 64627db88..1da510b7a 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -42,14 +42,14 @@ #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" -#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/general.h" #include "core/frontend/applets/mii_edit.h" #include "core/frontend/applets/profile_select.h" #include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/web_browser.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "frontend_common/config.h" @@ -226,7 +226,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string m_system.ApplySettings(); Settings::LogSettings(); m_system.HIDCore().ReloadInputDevices(); - m_system.SetAppletFrontendSet({ + m_system.SetFrontendAppletSet({ nullptr, // Amiibo Settings nullptr, // Controller Selector nullptr, // Error Display @@ -809,13 +809,13 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz, jint jappletId) { - EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId( - static_cast(jappletId)); + EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCurrentAppletId( + static_cast(jappletId)); } void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz, jint jcabinetMode) { - EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode( + EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCabinetMode( static_cast(jcabinetMode)); } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 049946426..5fb0ad822 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -176,8 +176,8 @@ add_library(core STATIC frontend/applets/controller.h frontend/applets/error.cpp frontend/applets/error.h - frontend/applets/general_frontend.cpp - frontend/applets/general_frontend.h + frontend/applets/general.cpp + frontend/applets/general.h frontend/applets/mii_edit.cpp frontend/applets/mii_edit.h frontend/applets/profile_select.cpp @@ -390,6 +390,27 @@ add_library(core STATIC hle/service/acc/errors.h hle/service/acc/profile_manager.cpp hle/service/acc/profile_manager.h + hle/service/am/frontend/applet_cabinet.cpp + hle/service/am/frontend/applet_cabinet.h + hle/service/am/frontend/applet_controller.cpp + hle/service/am/frontend/applet_controller.h + hle/service/am/frontend/applet_error.cpp + hle/service/am/frontend/applet_error.h + hle/service/am/frontend/applet_general.cpp + hle/service/am/frontend/applet_general.h + hle/service/am/frontend/applet_mii_edit.cpp + hle/service/am/frontend/applet_mii_edit.h + hle/service/am/frontend/applet_mii_edit_types.h + hle/service/am/frontend/applet_profile_select.cpp + hle/service/am/frontend/applet_profile_select.h + hle/service/am/frontend/applet_software_keyboard.cpp + hle/service/am/frontend/applet_software_keyboard.h + hle/service/am/frontend/applet_software_keyboard_types.h + hle/service/am/frontend/applet_web_browser.cpp + hle/service/am/frontend/applet_web_browser.h + hle/service/am/frontend/applet_web_browser_types.h + hle/service/am/frontend/applets.cpp + hle/service/am/frontend/applets.h hle/service/am/am.cpp hle/service/am/am.h hle/service/am/am_results.h @@ -402,27 +423,6 @@ add_library(core STATIC hle/service/am/applet_manager.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h - hle/service/am/applets/applet_cabinet.cpp - hle/service/am/applets/applet_cabinet.h - hle/service/am/applets/applet_controller.cpp - hle/service/am/applets/applet_controller.h - hle/service/am/applets/applet_error.cpp - hle/service/am/applets/applet_error.h - hle/service/am/applets/applet_general_backend.cpp - hle/service/am/applets/applet_general_backend.h - hle/service/am/applets/applet_mii_edit.cpp - hle/service/am/applets/applet_mii_edit.h - hle/service/am/applets/applet_mii_edit_types.h - hle/service/am/applets/applet_profile_select.cpp - hle/service/am/applets/applet_profile_select.h - hle/service/am/applets/applet_software_keyboard.cpp - hle/service/am/applets/applet_software_keyboard.h - hle/service/am/applets/applet_software_keyboard_types.h - hle/service/am/applets/applet_web_browser.cpp - hle/service/am/applets/applet_web_browser.h - hle/service/am/applets/applet_web_browser_types.h - hle/service/am/applets/applets.cpp - hle/service/am/applets/applets.h hle/service/am/applet_common_functions.cpp hle/service/am/applet_common_functions.h hle/service/am/applet_message_queue.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 11bf8d2f6..2bf377b24 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -36,7 +36,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/service/acc/profile_manager.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/glue/glue_manager.h" @@ -135,8 +135,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) - : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, - cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {} + : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, + reporter{system}, frontend_applets{system}, profile_manager{} {} void Initialize(System& system) { device_memory = std::make_unique(); @@ -157,7 +157,7 @@ struct System::Impl { } // Create default implementations of applets if one is not provided. - applet_manager.SetDefaultAppletsIfMissing(); + frontend_applets.SetDefaultAppletsIfMissing(); is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); @@ -567,7 +567,7 @@ struct System::Impl { std::unique_ptr renderdoc_api; /// Frontend applets - Service::AM::Applets::AppletManager applet_manager; + Service::AM::Frontend::FrontendAppletHolder frontend_applets; /// APM (Performance) services Service::APM::Controller apm_controller{core_timing}; @@ -871,20 +871,20 @@ void System::RegisterCheatList(const std::vector& list, impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); } -void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) { - impl->applet_manager.SetAppletFrontendSet(std::move(set)); +void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) { + impl->frontend_applets.SetFrontendAppletSet(std::move(set)); } void System::SetDefaultAppletFrontendSet() { - impl->applet_manager.SetDefaultAppletFrontendSet(); + impl->frontend_applets.SetDefaultAppletFrontendSet(); } -Service::AM::Applets::AppletManager& System::GetAppletManager() { - return impl->applet_manager; +Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { + return impl->frontend_applets; } -const Service::AM::Applets::AppletManager& System::GetAppletManager() const { - return impl->applet_manager; +const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const { + return impl->frontend_applets; } void System::SetContentProvider(std::unique_ptr provider) { diff --git a/src/core/core.h b/src/core/core.h index d8862e9ce..800e69501 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -50,10 +50,10 @@ namespace Account { class ProfileManager; } // namespace Account -namespace AM::Applets { -struct AppletFrontendSet; -class AppletManager; -} // namespace AM::Applets +namespace AM::Frontend { +struct FrontendAppletSet; +class FrontendAppletHolder; +} // namespace AM::Frontend namespace APM { class Controller; @@ -344,11 +344,12 @@ public: const std::array& build_id, u64 main_region_begin, u64 main_region_size); - void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); + void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); void SetDefaultAppletFrontendSet(); - [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); - [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const; + [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); + [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() + const; void SetContentProvider(std::unique_ptr provider); diff --git a/src/core/frontend/applets/general.cpp b/src/core/frontend/applets/general.cpp new file mode 100644 index 000000000..4c299ee9c --- /dev/null +++ b/src/core/frontend/applets/general.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/frontend/applets/general.h" + +namespace Core::Frontend { + +ParentalControlsApplet::~ParentalControlsApplet() = default; + +DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default; + +void DefaultParentalControlsApplet::Close() const {} + +void DefaultParentalControlsApplet::VerifyPIN(std::function finished, + bool suspend_future_verification_temporarily) { + LOG_INFO(Service_AM, + "Application requested frontend to verify PIN (normal), " + "suspend_future_verification_temporarily={}, verifying as correct.", + suspend_future_verification_temporarily); + finished(true); +} + +void DefaultParentalControlsApplet::VerifyPINForSettings(std::function finished) { + LOG_INFO(Service_AM, + "Application requested frontend to verify PIN (settings), verifying as correct."); + finished(true); +} + +void DefaultParentalControlsApplet::RegisterPIN(std::function finished) { + LOG_INFO(Service_AM, "Application requested frontend to register new PIN"); + finished(); +} + +void DefaultParentalControlsApplet::ChangePIN(std::function finished) { + LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value"); + finished(); +} + +PhotoViewerApplet::~PhotoViewerApplet() = default; + +DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default; + +void DefaultPhotoViewerApplet::Close() const {} + +void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, + std::function finished) const { + LOG_INFO(Service_AM, + "Application requested frontend to display stored photos for title_id={:016X}", + title_id); + finished(); +} + +void DefaultPhotoViewerApplet::ShowAllPhotos(std::function finished) const { + LOG_INFO(Service_AM, "Application requested frontend to display all stored photos."); + finished(); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/general.h b/src/core/frontend/applets/general.h new file mode 100644 index 000000000..319838ac7 --- /dev/null +++ b/src/core/frontend/applets/general.h @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "common/common_types.h" + +#include "core/frontend/applets/applet.h" + +namespace Core::Frontend { + +class ParentalControlsApplet : public Applet { +public: + virtual ~ParentalControlsApplet(); + + // Prompts the user to enter a PIN and calls the callback with whether or not it matches the + // correct PIN. If the bool is passed, and the PIN was recently entered correctly, the frontend + // should not prompt and simply return true. + virtual void VerifyPIN(std::function finished, + bool suspend_future_verification_temporarily) = 0; + + // Prompts the user to enter a PIN and calls the callback for correctness. Frontends can + // optionally alert the user that this is to change parental controls settings. + virtual void VerifyPINForSettings(std::function finished) = 0; + + // Prompts the user to create a new PIN for pctl and stores it with the service. + virtual void RegisterPIN(std::function finished) = 0; + + // Prompts the user to verify the current PIN and then store a new one into pctl. + virtual void ChangePIN(std::function finished) = 0; +}; + +class DefaultParentalControlsApplet final : public ParentalControlsApplet { +public: + ~DefaultParentalControlsApplet() override; + + void Close() const override; + void VerifyPIN(std::function finished, + bool suspend_future_verification_temporarily) override; + void VerifyPINForSettings(std::function finished) override; + void RegisterPIN(std::function finished) override; + void ChangePIN(std::function finished) override; +}; + +class PhotoViewerApplet : public Applet { +public: + virtual ~PhotoViewerApplet(); + + virtual void ShowPhotosForApplication(u64 title_id, std::function finished) const = 0; + virtual void ShowAllPhotos(std::function finished) const = 0; +}; + +class DefaultPhotoViewerApplet final : public PhotoViewerApplet { +public: + ~DefaultPhotoViewerApplet() override; + + void Close() const override; + void ShowPhotosForApplication(u64 title_id, std::function finished) const override; + void ShowAllPhotos(std::function finished) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp deleted file mode 100644 index b4b213a31..000000000 --- a/src/core/frontend/applets/general_frontend.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/logging/log.h" -#include "core/frontend/applets/general_frontend.h" - -namespace Core::Frontend { - -ParentalControlsApplet::~ParentalControlsApplet() = default; - -DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default; - -void DefaultParentalControlsApplet::Close() const {} - -void DefaultParentalControlsApplet::VerifyPIN(std::function finished, - bool suspend_future_verification_temporarily) { - LOG_INFO(Service_AM, - "Application requested frontend to verify PIN (normal), " - "suspend_future_verification_temporarily={}, verifying as correct.", - suspend_future_verification_temporarily); - finished(true); -} - -void DefaultParentalControlsApplet::VerifyPINForSettings(std::function finished) { - LOG_INFO(Service_AM, - "Application requested frontend to verify PIN (settings), verifying as correct."); - finished(true); -} - -void DefaultParentalControlsApplet::RegisterPIN(std::function finished) { - LOG_INFO(Service_AM, "Application requested frontend to register new PIN"); - finished(); -} - -void DefaultParentalControlsApplet::ChangePIN(std::function finished) { - LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value"); - finished(); -} - -PhotoViewerApplet::~PhotoViewerApplet() = default; - -DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default; - -void DefaultPhotoViewerApplet::Close() const {} - -void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, - std::function finished) const { - LOG_INFO(Service_AM, - "Application requested frontend to display stored photos for title_id={:016X}", - title_id); - finished(); -} - -void DefaultPhotoViewerApplet::ShowAllPhotos(std::function finished) const { - LOG_INFO(Service_AM, "Application requested frontend to display all stored photos."); - finished(); -} - -} // namespace Core::Frontend diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h deleted file mode 100644 index 319838ac7..000000000 --- a/src/core/frontend/applets/general_frontend.h +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include "common/common_types.h" - -#include "core/frontend/applets/applet.h" - -namespace Core::Frontend { - -class ParentalControlsApplet : public Applet { -public: - virtual ~ParentalControlsApplet(); - - // Prompts the user to enter a PIN and calls the callback with whether or not it matches the - // correct PIN. If the bool is passed, and the PIN was recently entered correctly, the frontend - // should not prompt and simply return true. - virtual void VerifyPIN(std::function finished, - bool suspend_future_verification_temporarily) = 0; - - // Prompts the user to enter a PIN and calls the callback for correctness. Frontends can - // optionally alert the user that this is to change parental controls settings. - virtual void VerifyPINForSettings(std::function finished) = 0; - - // Prompts the user to create a new PIN for pctl and stores it with the service. - virtual void RegisterPIN(std::function finished) = 0; - - // Prompts the user to verify the current PIN and then store a new one into pctl. - virtual void ChangePIN(std::function finished) = 0; -}; - -class DefaultParentalControlsApplet final : public ParentalControlsApplet { -public: - ~DefaultParentalControlsApplet() override; - - void Close() const override; - void VerifyPIN(std::function finished, - bool suspend_future_verification_temporarily) override; - void VerifyPINForSettings(std::function finished) override; - void RegisterPIN(std::function finished) override; - void ChangePIN(std::function finished) override; -}; - -class PhotoViewerApplet : public Applet { -public: - virtual ~PhotoViewerApplet(); - - virtual void ShowPhotosForApplication(u64 title_id, std::function finished) const = 0; - virtual void ShowAllPhotos(std::function finished) const = 0; -}; - -class DefaultPhotoViewerApplet final : public PhotoViewerApplet { -public: - ~DefaultPhotoViewerApplet() override; - - void Close() const override; - void ShowPhotosForApplication(u64 title_id, std::function finished) const override; - void ShowAllPhotos(std::function finished) const override; -}; - -} // namespace Core::Frontend diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h index 92e2737ea..880b69ad6 100644 --- a/src/core/frontend/applets/profile_select.h +++ b/src/core/frontend/applets/profile_select.h @@ -8,15 +8,15 @@ #include "common/uuid.h" #include "core/frontend/applets/applet.h" -#include "core/hle/service/am/applets/applet_profile_select.h" +#include "core/hle/service/am/frontend/applet_profile_select.h" namespace Core::Frontend { struct ProfileSelectParameters { - Service::AM::Applets::UiMode mode; + Service::AM::Frontend::UiMode mode; std::array invalid_uid_list; - Service::AM::Applets::UiSettingsDisplayOptions display_options; - Service::AM::Applets::UserSelectionPurpose purpose; + Service::AM::Frontend::UiSettingsDisplayOptions display_options; + Service::AM::Frontend::UserSelectionPurpose purpose; }; class ProfileSelectApplet : public Applet { diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp index 7655d215b..d00da8ac9 100644 --- a/src/core/frontend/applets/software_keyboard.cpp +++ b/src/core/frontend/applets/software_keyboard.cpp @@ -69,7 +69,7 @@ void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const { } void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog( - Service::AM::Applets::SwkbdTextCheckResult text_check_result, + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const { LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog."); } @@ -118,7 +118,7 @@ void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_ "\ncursor_position={}", Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, text_parameters.input_text, text_parameters.cursor_position); } @@ -127,22 +127,22 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const { } void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const { - submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true); + submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true); } void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const { std::this_thread::sleep_for(std::chrono::milliseconds(500)); for (std::size_t index = 0; index < text.size(); ++index) { - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, std::u16string(text.data(), text.data() + index + 1), static_cast(index) + 1); std::this_thread::sleep_for(std::chrono::milliseconds(250)); } - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text), - static_cast(text.size())); + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, + std::u16string(text), static_cast(text.size())); } } // namespace Core::Frontend diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h index 8ed96da24..a32a98e4c 100644 --- a/src/core/frontend/applets/software_keyboard.h +++ b/src/core/frontend/applets/software_keyboard.h @@ -8,7 +8,7 @@ #include "common/common_types.h" #include "core/frontend/applets/applet.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" namespace Core::Frontend { @@ -23,10 +23,10 @@ struct KeyboardInitializeParameters { u32 max_text_length; u32 min_text_length; s32 initial_cursor_position; - Service::AM::Applets::SwkbdType type; - Service::AM::Applets::SwkbdPasswordMode password_mode; - Service::AM::Applets::SwkbdTextDrawType text_draw_type; - Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; + Service::AM::Frontend::SwkbdType type; + Service::AM::Frontend::SwkbdPasswordMode password_mode; + Service::AM::Frontend::SwkbdTextDrawType text_draw_type; + Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags; bool use_blur_background; bool enable_backspace_button; bool enable_return_button; @@ -40,8 +40,8 @@ struct InlineAppearParameters { f32 key_top_scale_y; f32 key_top_translate_x; f32 key_top_translate_y; - Service::AM::Applets::SwkbdType type; - Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; + Service::AM::Frontend::SwkbdType type; + Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags; bool key_top_as_floating; bool enable_backspace_button; bool enable_return_button; @@ -56,9 +56,9 @@ struct InlineTextParameters { class SoftwareKeyboardApplet : public Applet { public: using SubmitInlineCallback = - std::function; + std::function; using SubmitNormalCallback = - std::function; + std::function; virtual ~SoftwareKeyboardApplet(); @@ -69,7 +69,7 @@ public: virtual void ShowNormalKeyboard() const = 0; - virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const = 0; virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0; @@ -93,7 +93,7 @@ public: void ShowNormalKeyboard() const override; - void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const override; void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override; diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp index 6e703ef06..eca8d6d98 100644 --- a/src/core/frontend/applets/web_browser.cpp +++ b/src/core/frontend/applets/web_browser.cpp @@ -18,7 +18,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url, LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}", local_url); - callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); + callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/"); } void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url, @@ -26,7 +26,7 @@ void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_ur LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}", external_url); - callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); + callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/"); } } // namespace Core::Frontend diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h index 178bbdd3f..b70856a22 100644 --- a/src/core/frontend/applets/web_browser.h +++ b/src/core/frontend/applets/web_browser.h @@ -6,7 +6,7 @@ #include #include "core/frontend/applets/applet.h" -#include "core/hle/service/am/applets/applet_web_browser_types.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" namespace Core::Frontend { @@ -14,7 +14,7 @@ class WebBrowserApplet : public Applet { public: using ExtractROMFSCallback = std::function; using OpenWebPageCallback = - std::function; + std::function; virtual ~WebBrowserApplet(); diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index 9f7ccfbf2..4aac5dba7 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -7,10 +7,10 @@ #include "core/core_timing.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_manager.h" -#include "core/hle/service/am/applets/applet_cabinet.h" -#include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/am/applets/applet_mii_edit_types.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" #include "hid_core/hid_types.h" namespace Service::AM { @@ -54,13 +54,13 @@ void PushInShowController(Core::System& system, AppletStorageChannel& channel) { const CommonArguments common_args = { .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, - .library_version = static_cast(Applets::ControllerAppletVersion::Version8), + .library_version = static_cast(Frontend::ControllerAppletVersion::Version8), .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; - Applets::ControllerSupportArgNew user_args = { + Frontend::ControllerSupportArgNew user_args = { .header = {.player_count_min = 1, .player_count_max = 4, .enable_take_over_connection = true, @@ -73,13 +73,13 @@ void PushInShowController(Core::System& system, AppletStorageChannel& channel) { .explain_text = {}, }; - Applets::ControllerSupportArgPrivate private_args = { - .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), - .arg_size = sizeof(Applets::ControllerSupportArgNew), + Frontend::ControllerSupportArgPrivate private_args = { + .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate), + .arg_size = sizeof(Frontend::ControllerSupportArgNew), .is_home_menu = true, .flag_1 = true, - .mode = Applets::ControllerSupportMode::ShowControllerSupport, - .caller = Applets::ControllerSupportCaller:: + .mode = Frontend::ControllerSupportMode::ShowControllerSupport, + .caller = Frontend::ControllerSupportCaller:: Application, // switchbrew: Always zero except with // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, // which sets this to the input param @@ -103,16 +103,16 @@ void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, - .library_version = static_cast(Applets::CabinetAppletVersion::Version1), + .library_version = static_cast(Frontend::CabinetAppletVersion::Version1), .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; - const Applets::StartParamForAmiiboSettings amiibo_settings{ + const Frontend::StartParamForAmiiboSettings amiibo_settings{ .param_1 = 0, - .applet_mode = system.GetAppletManager().GetCabinetMode(), - .flags = Applets::CabinetFlags::None, + .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(), + .flags = Frontend::CabinetFlags::None, .amiibo_settings_1 = 0, .device_handle = 0, .tag_info{}, @@ -130,16 +130,16 @@ void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { struct MiiEditV3 { - Applets::MiiEditAppletInputCommon common; - Applets::MiiEditAppletInputV3 input; + Frontend::MiiEditAppletInputCommon common; + Frontend::MiiEditAppletInputV3 input; }; static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); MiiEditV3 mii_arguments{ .common = { - .version = Applets::MiiEditAppletVersion::Version3, - .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, + .version = Frontend::MiiEditAppletVersion::Version3, + .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit, }, .input{}, }; @@ -154,7 +154,7 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, - .library_version = static_cast(Applets::SwkbdAppletVersion::Version524301), + .library_version = static_cast(Frontend::SwkbdAppletVersion::Version524301), .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), @@ -162,21 +162,21 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan std::vector initial_string(0); - const Applets::SwkbdConfigCommon swkbd_config{ - .type = Applets::SwkbdType::Qwerty, + const Frontend::SwkbdConfigCommon swkbd_config{ + .type = Frontend::SwkbdType::Qwerty, .ok_text{}, .left_optional_symbol_key{}, .right_optional_symbol_key{}, .use_prediction = false, .key_disable_flags{}, - .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start, .header_text{}, .sub_text{}, .guide_text{}, .max_text_length = 500, .min_text_length = 0, - .password_mode = Applets::SwkbdPasswordMode::Disabled, - .text_draw_type = Applets::SwkbdTextDrawType::Box, + .password_mode = Frontend::SwkbdPasswordMode::Disabled, + .text_draw_type = Frontend::SwkbdTextDrawType::Box, .enable_return_button = true, .use_utf8 = false, .use_blur_background = true, @@ -187,7 +187,7 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan .use_text_check = false, }; - Applets::SwkbdConfigNew swkbd_config_new{}; + Frontend::SwkbdConfigNew swkbd_config_new{}; std::vector argument_data(sizeof(arguments)); std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); @@ -196,7 +196,7 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, - sizeof(Applets::SwkbdConfigNew)); + sizeof(Frontend::SwkbdConfigNew)); std::memcpy(work_buffer.data(), initial_string.data(), swkbd_config.initial_string_length * sizeof(char16_t)); diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp deleted file mode 100644 index 1b756fbd7..000000000 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/core.h" -#include "core/frontend/applets/cabinet.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_cabinet.h" -#include "core/hle/service/am/storage.h" -#include "core/hle/service/mii/mii_manager.h" -#include "core/hle/service/nfc/common/device.h" -#include "hid_core/hid_core.h" - -namespace Service::AM::Applets { - -Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::CabinetApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, - service_context{system_, "CabinetApplet"} { - - availability_change_event = - service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); -} - -Cabinet::~Cabinet() { - service_context.CloseEvent(availability_change_event); -}; - -void Cabinet::Initialize() { - Applet::Initialize(); - - LOG_INFO(Service_HID, "Initializing Cabinet Applet."); - - LOG_DEBUG(Service_HID, - "Initializing Applet with common_args: arg_version={}, lib_version={}, " - "play_startup_sound={}, size={}, system_tick={}, theme_color={}", - common_args.arguments_version, common_args.library_version, - common_args.play_startup_sound, common_args.size, common_args.system_tick, - common_args.theme_color); - - const auto storage = broker.PopNormalDataToApplet(); - ASSERT(storage != nullptr); - - const auto applet_input_data = storage->GetData(); - ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); - - std::memcpy(&applet_input_common, applet_input_data.data(), - sizeof(StartParamForAmiiboSettings)); -} - -bool Cabinet::TransactionComplete() const { - return is_complete; -} - -Result Cabinet::GetStatus() const { - return ResultSuccess; -} - -void Cabinet::ExecuteInteractive() { - ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); -} - -void Cabinet::Execute() { - if (is_complete) { - return; - } - - const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { - DisplayCompleted(apply_changes, amiibo_name); - }; - - // TODO: listen on all controllers - if (nfp_device == nullptr) { - nfp_device = std::make_shared( - system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); - nfp_device->Initialize(); - nfp_device->StartDetection(Service::NFC::NfcProtocol::All); - } - - const Core::Frontend::CabinetParameters parameters{ - .tag_info = applet_input_common.tag_info, - .register_info = applet_input_common.register_info, - .mode = applet_input_common.applet_mode, - }; - - switch (applet_input_common.applet_mode) { - case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: - case Service::NFP::CabinetMode::StartGameDataEraser: - case Service::NFP::CabinetMode::StartRestorer: - case Service::NFP::CabinetMode::StartFormatter: - frontend.ShowCabinetApplet(callback, parameters, nfp_device); - break; - default: - UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); - DisplayCompleted(false, {}); - break; - } -} - -void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { - Service::Mii::MiiManager manager; - ReturnValueForAmiiboSettings applet_output{}; - - if (!apply_changes) { - Cancel(); - } - - if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound && - nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) { - Cancel(); - } - - if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) { - nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All); - } - - switch (applet_input_common.applet_mode) { - case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { - Service::NFP::RegisterInfoPrivate register_info{}; - std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(), - std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1)); - register_info.mii_store_data.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); - register_info.mii_store_data.SetNickname({u'y', u'u', u'z', u'u'}); - nfp_device->SetRegisterInfoPrivate(register_info); - break; - } - case Service::NFP::CabinetMode::StartGameDataEraser: - nfp_device->DeleteApplicationArea(); - break; - case Service::NFP::CabinetMode::StartRestorer: - nfp_device->Restore(); - break; - case Service::NFP::CabinetMode::StartFormatter: - nfp_device->Format(); - break; - default: - UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); - break; - } - - applet_output.device_handle = applet_input_common.device_handle; - applet_output.result = CabinetResult::Cancel; - const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); - const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); - nfp_device->Finalize(); - - if (reg_result.IsSuccess()) { - applet_output.result |= CabinetResult::RegisterInfo; - } - - if (tag_result.IsSuccess()) { - applet_output.result |= CabinetResult::TagInfo; - } - - std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); - std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); - - is_complete = true; - - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); -} - -void Cabinet::Cancel() { - ReturnValueForAmiiboSettings applet_output{}; - applet_output.device_handle = applet_input_common.device_handle; - applet_output.result = CabinetResult::Cancel; - nfp_device->Finalize(); - - std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); - std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); - - is_complete = true; - - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); -} - -Result Cabinet::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h deleted file mode 100644 index f498796f7..000000000 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nfp/nfp_types.h" - -namespace Kernel { -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Core { -class System; -} // namespace Core - -namespace Service::NFC { -class NfcDevice; -} - -namespace Service::AM::Applets { - -enum class CabinetAppletVersion : u32 { - Version1 = 0x1, -}; - -enum class CabinetFlags : u8 { - None = 0, - DeviceHandle = 1 << 0, - TagInfo = 1 << 1, - RegisterInfo = 1 << 2, - All = DeviceHandle | TagInfo | RegisterInfo, -}; -DECLARE_ENUM_FLAG_OPERATORS(CabinetFlags) - -enum class CabinetResult : u8 { - Cancel = 0, - TagInfo = 1 << 1, - RegisterInfo = 1 << 2, - All = TagInfo | RegisterInfo, -}; -DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) - -// This is nn::nfp::AmiiboSettingsStartParam -struct AmiiboSettingsStartParam { - u64 device_handle; - std::array param_1; - u8 param_2; -}; -static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, - "AmiiboSettingsStartParam is an invalid size"); - -#pragma pack(push, 1) -// This is nn::nfp::StartParamForAmiiboSettings -struct StartParamForAmiiboSettings { - u8 param_1; - Service::NFP::CabinetMode applet_mode; - CabinetFlags flags; - u8 amiibo_settings_1; - u64 device_handle; - Service::NFP::TagInfo tag_info; - Service::NFP::RegisterInfo register_info; - std::array amiibo_settings_3; - INSERT_PADDING_BYTES(0x24); -}; -static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, - "StartParamForAmiiboSettings is an invalid size"); - -// This is nn::nfp::ReturnValueForAmiiboSettings -struct ReturnValueForAmiiboSettings { - CabinetResult result; - INSERT_PADDING_BYTES(0x3); - u64 device_handle; - Service::NFP::TagInfo tag_info; - Service::NFP::RegisterInfo register_info; - INSERT_PADDING_BYTES(0x24); -}; -static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, - "ReturnValueForAmiiboSettings is an invalid size"); -#pragma pack(pop) - -class Cabinet final : public Applet { -public: - explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::CabinetApplet& frontend_); - ~Cabinet() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); - void Cancel(); - Result RequestExit() override; - -private: - const Core::Frontend::CabinetApplet& frontend; - Core::System& system; - - bool is_complete{false}; - std::shared_ptr nfp_device; - Kernel::KEvent* availability_change_event; - KernelHelpers::ServiceContext service_context; - StartParamForAmiiboSettings applet_input_common{}; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp deleted file mode 100644 index bc8de6b60..000000000 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include - -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/frontend/applets/controller.h" -#include "core/hle/result.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/am/storage.h" -#include "hid_core/frontend/emulated_controller.h" -#include "hid_core/hid_core.h" -#include "hid_core/hid_types.h" -#include "hid_core/resources/npad/npad.h" - -namespace Service::AM::Applets { - -[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101}; -[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID, - 3102}; - -static Core::Frontend::ControllerParameters ConvertToFrontendParameters( - ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, - std::vector identification_colors, std::vector text) { - Core::HID::NpadStyleTag npad_style_set; - npad_style_set.raw = private_arg.style_set; - - return { - .min_players = std::max(s8{1}, header.player_count_min), - .max_players = header.player_count_max, - .keep_controllers_connected = header.enable_take_over_connection, - .enable_single_mode = header.enable_single_mode, - .enable_border_color = header.enable_identification_color, - .border_colors = std::move(identification_colors), - .enable_explain_text = enable_text, - .explain_text = std::move(text), - .allow_pro_controller = npad_style_set.fullkey == 1, - .allow_handheld = npad_style_set.handheld == 1, - .allow_dual_joycons = npad_style_set.joycon_dual == 1, - .allow_left_joycon = npad_style_set.joycon_left == 1, - .allow_right_joycon = npad_style_set.joycon_right == 1, - }; -} - -Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ControllerApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -Controller::~Controller() = default; - -void Controller::Initialize() { - Applet::Initialize(); - - LOG_INFO(Service_HID, "Initializing Controller Applet."); - - LOG_DEBUG(Service_HID, - "Initializing Applet with common_args: arg_version={}, lib_version={}, " - "play_startup_sound={}, size={}, system_tick={}, theme_color={}", - common_args.arguments_version, common_args.library_version, - common_args.play_startup_sound, common_args.size, common_args.system_tick, - common_args.theme_color); - - controller_applet_version = ControllerAppletVersion{common_args.library_version}; - - const auto private_arg_storage = broker.PopNormalDataToApplet(); - ASSERT(private_arg_storage != nullptr); - - const auto& private_arg = private_arg_storage->GetData(); - ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); - - std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size()); - ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), - "Unknown ControllerSupportArgPrivate revision={} with size={}", - controller_applet_version, controller_private_arg.arg_private_size); - - // Some games such as Cave Story+ set invalid values for the ControllerSupportMode. - // Defer to arg_size to set the ControllerSupportMode. - if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) { - switch (controller_private_arg.arg_size) { - case sizeof(ControllerSupportArgOld): - case sizeof(ControllerSupportArgNew): - controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; - break; - case sizeof(ControllerUpdateFirmwareArg): - controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate; - break; - case sizeof(ControllerKeyRemappingArg): - controller_private_arg.mode = - ControllerSupportMode::ShowControllerKeyRemappingForSystem; - break; - default: - UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}", - controller_private_arg.mode, controller_private_arg.arg_size); - controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; - break; - } - } - - // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller. - // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem. - if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) { - if (controller_private_arg.flag_1 && - (controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate || - controller_private_arg.mode == - ControllerSupportMode::ShowControllerKeyRemappingForSystem)) { - controller_private_arg.caller = ControllerSupportCaller::System; - } else { - controller_private_arg.caller = ControllerSupportCaller::Application; - } - } - - switch (controller_private_arg.mode) { - case ControllerSupportMode::ShowControllerSupport: - case ControllerSupportMode::ShowControllerStrapGuide: { - const auto user_arg_storage = broker.PopNormalDataToApplet(); - ASSERT(user_arg_storage != nullptr); - - const auto& user_arg = user_arg_storage->GetData(); - switch (controller_applet_version) { - case ControllerAppletVersion::Version3: - case ControllerAppletVersion::Version4: - case ControllerAppletVersion::Version5: - ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); - std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size()); - break; - case ControllerAppletVersion::Version7: - case ControllerAppletVersion::Version8: - ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); - std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size()); - break; - default: - UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", - controller_applet_version, controller_private_arg.arg_size); - ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); - std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); - break; - } - break; - } - case ControllerSupportMode::ShowControllerFirmwareUpdate: { - const auto update_arg_storage = broker.PopNormalDataToApplet(); - ASSERT(update_arg_storage != nullptr); - - const auto& update_arg = update_arg_storage->GetData(); - ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg)); - - std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size()); - break; - } - case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { - const auto remapping_arg_storage = broker.PopNormalDataToApplet(); - ASSERT(remapping_arg_storage != nullptr); - - const auto& remapping_arg = remapping_arg_storage->GetData(); - ASSERT(remapping_arg.size() == sizeof(ControllerKeyRemappingArg)); - - std::memcpy(&controller_key_remapping_arg, remapping_arg.data(), remapping_arg.size()); - break; - } - default: { - UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); - break; - } - } -} - -bool Controller::TransactionComplete() const { - return complete; -} - -Result Controller::GetStatus() const { - return status; -} - -void Controller::ExecuteInteractive() { - ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); -} - -void Controller::Execute() { - switch (controller_private_arg.mode) { - case ControllerSupportMode::ShowControllerSupport: { - const auto parameters = [this] { - switch (controller_applet_version) { - case ControllerAppletVersion::Version3: - case ControllerAppletVersion::Version4: - case ControllerAppletVersion::Version5: - return ConvertToFrontendParameters( - controller_private_arg, controller_user_arg_old.header, - controller_user_arg_old.enable_explain_text, - std::vector( - controller_user_arg_old.identification_colors.begin(), - controller_user_arg_old.identification_colors.end()), - std::vector(controller_user_arg_old.explain_text.begin(), - controller_user_arg_old.explain_text.end())); - case ControllerAppletVersion::Version7: - case ControllerAppletVersion::Version8: - default: - return ConvertToFrontendParameters( - controller_private_arg, controller_user_arg_new.header, - controller_user_arg_new.enable_explain_text, - std::vector( - controller_user_arg_new.identification_colors.begin(), - controller_user_arg_new.identification_colors.end()), - std::vector(controller_user_arg_new.explain_text.begin(), - controller_user_arg_new.explain_text.end())); - } - }(); - - is_single_mode = parameters.enable_single_mode; - - LOG_DEBUG(Service_HID, - "Controller Parameters: min_players={}, max_players={}, " - "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, " - "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, " - "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}", - parameters.min_players, parameters.max_players, - parameters.keep_controllers_connected, parameters.enable_single_mode, - parameters.enable_border_color, parameters.enable_explain_text, - parameters.allow_pro_controller, parameters.allow_handheld, - parameters.allow_dual_joycons, parameters.allow_left_joycon, - parameters.allow_right_joycon); - - frontend.ReconfigureControllers( - [this](bool is_success) { ConfigurationComplete(is_success); }, parameters); - break; - } - case ControllerSupportMode::ShowControllerStrapGuide: - case ControllerSupportMode::ShowControllerFirmwareUpdate: - case ControllerSupportMode::ShowControllerKeyRemappingForSystem: - UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", - controller_private_arg.mode); - ConfigurationComplete(true); - break; - default: { - ConfigurationComplete(true); - break; - } - } -} - -void Controller::ConfigurationComplete(bool is_success) { - ControllerSupportResultInfo result_info{}; - - // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. - // Otherwise, only count connected players from P1-P8. - result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount(); - - result_info.selected_id = static_cast(system.HIDCore().GetFirstNpadId()); - - result_info.result = - is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel; - - LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", - result_info.player_count, result_info.selected_id, result_info.result); - - complete = true; - out_data = std::vector(sizeof(ControllerSupportResultInfo)); - std::memcpy(out_data.data(), &result_info, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); -} - -Result Controller::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h deleted file mode 100644 index 9f839f3d7..000000000 --- a/src/core/hle/service/am/applets/applet_controller.h +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} - -namespace Core::HID { -enum class NpadStyleSet : u32; -} - -namespace Service::AM::Applets { - -using IdentificationColor = std::array; -using ExplainText = std::array; - -enum class ControllerAppletVersion : u32_le { - Version3 = 0x3, // 1.0.0 - 2.3.0 - Version4 = 0x4, // 3.0.0 - 5.1.0 - Version5 = 0x5, // 6.0.0 - 7.0.1 - Version7 = 0x7, // 8.0.0 - 10.2.0 - Version8 = 0x8, // 11.0.0+ -}; - -enum class ControllerSupportMode : u8 { - ShowControllerSupport, - ShowControllerStrapGuide, - ShowControllerFirmwareUpdate, - ShowControllerKeyRemappingForSystem, - - MaxControllerSupportMode, -}; - -enum class ControllerSupportCaller : u8 { - Application, - System, - - MaxControllerSupportCaller, -}; - -enum class ControllerSupportResult : u32 { - Success = 0, - Cancel = 2, -}; - -struct ControllerSupportArgPrivate { - u32 arg_private_size{}; - u32 arg_size{}; - bool is_home_menu{}; - bool flag_1{}; - ControllerSupportMode mode{}; - ControllerSupportCaller caller{}; - Core::HID::NpadStyleSet style_set{}; - u32 joy_hold_type{}; -}; -static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, - "ControllerSupportArgPrivate has incorrect size."); - -struct ControllerSupportArgHeader { - s8 player_count_min{}; - s8 player_count_max{}; - bool enable_take_over_connection{}; - bool enable_left_justify{}; - bool enable_permit_joy_dual{}; - bool enable_single_mode{}; - bool enable_identification_color{}; -}; -static_assert(sizeof(ControllerSupportArgHeader) == 0x7, - "ControllerSupportArgHeader has incorrect size."); - -// LibraryAppletVersion 0x3, 0x4, 0x5 -struct ControllerSupportArgOld { - ControllerSupportArgHeader header{}; - std::array identification_colors{}; - bool enable_explain_text{}; - std::array explain_text{}; -}; -static_assert(sizeof(ControllerSupportArgOld) == 0x21C, - "ControllerSupportArgOld has incorrect size."); - -// LibraryAppletVersion 0x7, 0x8 -struct ControllerSupportArgNew { - ControllerSupportArgHeader header{}; - std::array identification_colors{}; - bool enable_explain_text{}; - std::array explain_text{}; -}; -static_assert(sizeof(ControllerSupportArgNew) == 0x430, - "ControllerSupportArgNew has incorrect size."); - -struct ControllerUpdateFirmwareArg { - bool enable_force_update{}; - INSERT_PADDING_BYTES(3); -}; -static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4, - "ControllerUpdateFirmwareArg has incorrect size."); - -struct ControllerKeyRemappingArg { - u64 unknown{}; - u32 unknown_2{}; - INSERT_PADDING_WORDS(1); -}; -static_assert(sizeof(ControllerKeyRemappingArg) == 0x10, - "ControllerKeyRemappingArg has incorrect size."); - -struct ControllerSupportResultInfo { - s8 player_count{}; - INSERT_PADDING_BYTES(3); - u32 selected_id{}; - ControllerSupportResult result{}; -}; -static_assert(sizeof(ControllerSupportResultInfo) == 0xC, - "ControllerSupportResultInfo has incorrect size."); - -class Controller final : public Applet { -public: - explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ControllerApplet& frontend_); - ~Controller() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void ConfigurationComplete(bool is_success); - -private: - const Core::Frontend::ControllerApplet& frontend; - Core::System& system; - - ControllerAppletVersion controller_applet_version; - ControllerSupportArgPrivate controller_private_arg; - ControllerSupportArgOld controller_user_arg_old; - ControllerSupportArgNew controller_user_arg_new; - ControllerUpdateFirmwareArg controller_update_arg; - ControllerKeyRemappingArg controller_key_remapping_arg; - bool complete{false}; - Result status{ResultSuccess}; - bool is_single_mode{false}; - std::vector out_data; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp deleted file mode 100644 index 96126832c..000000000 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/frontend/applets/error.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_error.h" -#include "core/hle/service/am/storage.h" -#include "core/reporter.h" - -namespace Service::AM::Applets { - -struct ErrorCode { - u32 error_category{}; - u32 error_number{}; - - static constexpr ErrorCode FromU64(u64 error_code) { - return { - .error_category{static_cast(error_code >> 32)}, - .error_number{static_cast(error_code & 0xFFFFFFFF)}, - }; - } - - static constexpr ErrorCode FromResult(Result result) { - return { - .error_category{2000 + static_cast(result.GetModule())}, - .error_number{result.GetDescription()}, - }; - } - - constexpr Result ToResult() const { - return Result{static_cast(error_category - 2000), error_number}; - } -}; -static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size."); - -#pragma pack(push, 4) -struct ShowError { - u8 mode; - bool jump; - INSERT_PADDING_BYTES_NOINIT(4); - bool use_64bit_error_code; - INSERT_PADDING_BYTES_NOINIT(1); - u64 error_code_64; - u32 error_code_32; -}; -static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); -#pragma pack(pop) - -struct ShowErrorRecord { - u8 mode; - bool jump; - INSERT_PADDING_BYTES_NOINIT(6); - u64 error_code_64; - u64 posix_time; -}; -static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect size."); - -struct SystemErrorArg { - u8 mode; - bool jump; - INSERT_PADDING_BYTES_NOINIT(6); - u64 error_code_64; - std::array language_code; - std::array main_text; - std::array detail_text; -}; -static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect size."); - -struct ApplicationErrorArg { - u8 mode; - bool jump; - INSERT_PADDING_BYTES_NOINIT(6); - u32 error_code; - std::array language_code; - std::array main_text; - std::array detail_text; -}; -static_assert(sizeof(ApplicationErrorArg) == 0x1014, "ApplicationErrorArg has incorrect size."); - -union Error::ErrorArguments { - ShowError error; - ShowErrorRecord error_record; - SystemErrorArg system_error; - ApplicationErrorArg application_error; - std::array raw{}; -}; - -namespace { -template -void CopyArgumentData(const std::vector& data, T& variable) { - ASSERT(data.size() >= sizeof(T)); - std::memcpy(&variable, data.data(), sizeof(T)); -} - -Result Decode64BitError(u64 error) { - return ErrorCode::FromU64(error).ToResult(); -} - -} // Anonymous namespace - -Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ErrorApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -Error::~Error() = default; - -void Error::Initialize() { - Applet::Initialize(); - args = std::make_unique(); - complete = false; - - const auto storage = broker.PopNormalDataToApplet(); - ASSERT(storage != nullptr); - const auto data = storage->GetData(); - - ASSERT(!data.empty()); - std::memcpy(&mode, data.data(), sizeof(ErrorAppletMode)); - - switch (mode) { - case ErrorAppletMode::ShowError: - CopyArgumentData(data, args->error); - if (args->error.use_64bit_error_code) { - error_code = Decode64BitError(args->error.error_code_64); - } else { - error_code = Result(args->error.error_code_32); - } - break; - case ErrorAppletMode::ShowSystemError: - CopyArgumentData(data, args->system_error); - error_code = Result(Decode64BitError(args->system_error.error_code_64)); - break; - case ErrorAppletMode::ShowApplicationError: - CopyArgumentData(data, args->application_error); - error_code = Result(args->application_error.error_code); - break; - case ErrorAppletMode::ShowErrorPctl: - CopyArgumentData(data, args->error_record); - error_code = Decode64BitError(args->error_record.error_code_64); - break; - case ErrorAppletMode::ShowErrorRecord: - CopyArgumentData(data, args->error_record); - error_code = Decode64BitError(args->error_record.error_code_64); - break; - default: - UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); - break; - } -} - -bool Error::TransactionComplete() const { - return complete; -} - -Result Error::GetStatus() const { - return ResultSuccess; -} - -void Error::ExecuteInteractive() { - ASSERT_MSG(false, "Unexpected interactive applet data!"); -} - -void Error::Execute() { - if (complete) { - return; - } - - const auto callback = [this] { DisplayCompleted(); }; - const auto title_id = system.GetApplicationProcessProgramID(); - const auto& reporter{system.GetReporter()}; - - switch (mode) { - case ErrorAppletMode::ShowError: - reporter.SaveErrorReport(title_id, error_code); - frontend.ShowError(error_code, callback); - break; - case ErrorAppletMode::ShowSystemError: - case ErrorAppletMode::ShowApplicationError: { - const auto is_system = mode == ErrorAppletMode::ShowSystemError; - const auto& main_text = - is_system ? args->system_error.main_text : args->application_error.main_text; - const auto& detail_text = - is_system ? args->system_error.detail_text : args->application_error.detail_text; - - const auto main_text_string = - Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()); - const auto detail_text_string = - Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()); - - reporter.SaveErrorReport(title_id, error_code, main_text_string, detail_text_string); - frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback); - break; - } - case ErrorAppletMode::ShowErrorPctl: - case ErrorAppletMode::ShowErrorRecord: - reporter.SaveErrorReport(title_id, error_code, - fmt::format("{:016X}", args->error_record.posix_time)); - frontend.ShowErrorWithTimestamp( - error_code, std::chrono::seconds{args->error_record.posix_time}, callback); - break; - default: - UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); - DisplayCompleted(); - } -} - -void Error::DisplayCompleted() { - complete = true; - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector{})); - broker.SignalStateChanged(); -} - -Result Error::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_error.h b/src/core/hle/service/am/applets/applet_error.h deleted file mode 100644 index d822a32bb..000000000 --- a/src/core/hle/service/am/applets/applet_error.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} - -namespace Service::AM::Applets { - -enum class ErrorAppletMode : u8 { - ShowError = 0, - ShowSystemError = 1, - ShowApplicationError = 2, - ShowEula = 3, - ShowErrorPctl = 4, - ShowErrorRecord = 5, - ShowUpdateEula = 8, -}; - -class Error final : public Applet { -public: - explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ErrorApplet& frontend_); - ~Error() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void DisplayCompleted(); - -private: - union ErrorArguments; - - const Core::Frontend::ErrorApplet& frontend; - Result error_code = ResultSuccess; - ErrorAppletMode mode = ErrorAppletMode::ShowError; - std::unique_ptr args; - - bool complete = false; - Core::System& system; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp deleted file mode 100644 index c010c78e2..000000000 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "common/hex_util.h" -#include "common/logging/log.h" -#include "core/core.h" -#include "core/frontend/applets/general_frontend.h" -#include "core/hle/result.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_general_backend.h" -#include "core/hle/service/am/storage.h" -#include "core/reporter.h" - -namespace Service::AM::Applets { - -constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; - -static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { - std::shared_ptr storage = broker.PopNormalDataToApplet(); - for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { - const auto data = storage->GetData(); - LOG_INFO(Service_AM, - "called (STUBBED), during {} received normal data with size={:08X}, data={}", - prefix, data.size(), Common::HexToString(data)); - } - - storage = broker.PopInteractiveDataToApplet(); - for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) { - const auto data = storage->GetData(); - LOG_INFO(Service_AM, - "called (STUBBED), during {} received interactive data with size={:08X}, data={}", - prefix, data.size(), Common::HexToString(data)); - } -} - -Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, - Core::Frontend::ParentalControlsApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -Auth::~Auth() = default; - -void Auth::Initialize() { - Applet::Initialize(); - complete = false; - - const auto storage = broker.PopNormalDataToApplet(); - ASSERT(storage != nullptr); - const auto data = storage->GetData(); - ASSERT(data.size() >= 0xC); - - struct Arg { - INSERT_PADDING_BYTES(4); - AuthAppletType type; - u8 arg0; - u8 arg1; - u8 arg2; - INSERT_PADDING_BYTES(1); - }; - static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size."); - - Arg arg{}; - std::memcpy(&arg, data.data(), sizeof(Arg)); - - type = arg.type; - arg0 = arg.arg0; - arg1 = arg.arg1; - arg2 = arg.arg2; -} - -bool Auth::TransactionComplete() const { - return complete; -} - -Result Auth::GetStatus() const { - return successful ? ResultSuccess : ERROR_INVALID_PIN; -} - -void Auth::ExecuteInteractive() { - ASSERT_MSG(false, "Unexpected interactive applet data."); -} - -void Auth::Execute() { - if (complete) { - return; - } - - const auto unimplemented_log = [this] { - UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " - "arg1={:02X}, arg2={:02X}", - type, arg0, arg1, arg2); - }; - - switch (type) { - case AuthAppletType::ShowParentalAuthentication: { - const auto callback = [this](bool is_successful) { AuthFinished(is_successful); }; - - if (arg0 == 1 && arg1 == 0 && arg2 == 1) { - // ShowAuthenticatorForConfiguration - frontend.VerifyPINForSettings(callback); - } else if (arg1 == 0 && arg2 == 0) { - // ShowParentalAuthentication(bool) - frontend.VerifyPIN(callback, static_cast(arg0)); - } else { - unimplemented_log(); - } - break; - } - case AuthAppletType::RegisterParentalPasscode: { - const auto callback = [this] { AuthFinished(true); }; - - if (arg0 == 0 && arg1 == 0 && arg2 == 0) { - // RegisterParentalPasscode - frontend.RegisterPIN(callback); - } else { - unimplemented_log(); - } - break; - } - case AuthAppletType::ChangeParentalPasscode: { - const auto callback = [this] { AuthFinished(true); }; - - if (arg0 == 0 && arg1 == 0 && arg2 == 0) { - // ChangeParentalPasscode - frontend.ChangePIN(callback); - } else { - unimplemented_log(); - } - break; - } - default: - unimplemented_log(); - break; - } -} - -void Auth::AuthFinished(bool is_successful) { - successful = is_successful; - - struct Return { - Result result_code; - }; - static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size."); - - Return return_{GetStatus()}; - - std::vector out(sizeof(Return)); - std::memcpy(out.data(), &return_, sizeof(Return)); - - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out))); - broker.SignalStateChanged(); -} - -Result Auth::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::PhotoViewerApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -PhotoViewer::~PhotoViewer() = default; - -void PhotoViewer::Initialize() { - Applet::Initialize(); - complete = false; - - const auto storage = broker.PopNormalDataToApplet(); - ASSERT(storage != nullptr); - const auto data = storage->GetData(); - ASSERT(!data.empty()); - mode = static_cast(data[0]); -} - -bool PhotoViewer::TransactionComplete() const { - return complete; -} - -Result PhotoViewer::GetStatus() const { - return ResultSuccess; -} - -void PhotoViewer::ExecuteInteractive() { - ASSERT_MSG(false, "Unexpected interactive applet data."); -} - -void PhotoViewer::Execute() { - if (complete) - return; - - const auto callback = [this] { ViewFinished(); }; - switch (mode) { - case PhotoViewerAppletMode::CurrentApp: - frontend.ShowPhotosForApplication(system.GetApplicationProcessProgramID(), callback); - break; - case PhotoViewerAppletMode::AllApps: - frontend.ShowAllPhotos(callback); - break; - default: - UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); - break; - } -} - -void PhotoViewer::ViewFinished() { - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector{})); - broker.SignalStateChanged(); -} - -Result PhotoViewer::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) - : Applet{system_, applet_mode_}, id{id_}, system{system_} {} - -StubApplet::~StubApplet() = default; - -void StubApplet::Initialize() { - LOG_WARNING(Service_AM, "called (STUBBED)"); - Applet::Initialize(); - - const auto data = broker.PeekDataToAppletForDebug(); - system.GetReporter().SaveUnimplementedAppletReport( - static_cast(id), static_cast(common_args.arguments_version), - common_args.library_version, static_cast(common_args.theme_color), - common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive); - - LogCurrentStorage(broker, "Initialize"); -} - -bool StubApplet::TransactionComplete() const { - LOG_WARNING(Service_AM, "called (STUBBED)"); - return true; -} - -Result StubApplet::GetStatus() const { - LOG_WARNING(Service_AM, "called (STUBBED)"); - return ResultSuccess; -} - -void StubApplet::ExecuteInteractive() { - LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "ExecuteInteractive"); - - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared(system, std::vector(0x1000))); - broker.SignalStateChanged(); -} - -void StubApplet::Execute() { - LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "Execute"); - - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared(system, std::vector(0x1000))); - broker.SignalStateChanged(); -} - -Result StubApplet::RequestExit() { - // Nothing to do. - R_SUCCEED(); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_general_backend.h b/src/core/hle/service/am/applets/applet_general_backend.h deleted file mode 100644 index 34ecaebb9..000000000 --- a/src/core/hle/service/am/applets/applet_general_backend.h +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} - -namespace Service::AM::Applets { - -enum class AuthAppletType : u32 { - ShowParentalAuthentication, - RegisterParentalPasscode, - ChangeParentalPasscode, -}; - -class Auth final : public Applet { -public: - explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, - Core::Frontend::ParentalControlsApplet& frontend_); - ~Auth() override; - - void Initialize() override; - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void AuthFinished(bool is_successful = true); - -private: - Core::Frontend::ParentalControlsApplet& frontend; - Core::System& system; - bool complete = false; - bool successful = false; - - AuthAppletType type = AuthAppletType::ShowParentalAuthentication; - u8 arg0 = 0; - u8 arg1 = 0; - u8 arg2 = 0; -}; - -enum class PhotoViewerAppletMode : u8 { - CurrentApp = 0, - AllApps = 1, -}; - -class PhotoViewer final : public Applet { -public: - explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::PhotoViewerApplet& frontend_); - ~PhotoViewer() override; - - void Initialize() override; - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void ViewFinished(); - -private: - const Core::Frontend::PhotoViewerApplet& frontend; - bool complete = false; - PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; - Core::System& system; -}; - -class StubApplet final : public Applet { -public: - explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); - ~StubApplet() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - -private: - AppletId id; - Core::System& system; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp deleted file mode 100644 index 1576b45c4..000000000 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/core.h" -#include "core/frontend/applets/mii_edit.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_mii_edit.h" -#include "core/hle/service/am/storage.h" -#include "core/hle/service/mii/mii.h" -#include "core/hle/service/mii/mii_manager.h" -#include "core/hle/service/sm/sm.h" - -namespace Service::AM::Applets { - -MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::MiiEditApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -MiiEdit::~MiiEdit() = default; - -void MiiEdit::Initialize() { - // Note: MiiEdit is not initialized with common arguments. - // Instead, it is initialized by an AppletInput storage with size 0x100 bytes. - // Do NOT call Applet::Initialize() here. - - const auto storage = broker.PopNormalDataToApplet(); - ASSERT(storage != nullptr); - - const auto applet_input_data = storage->GetData(); - ASSERT(applet_input_data.size() >= sizeof(MiiEditAppletInputCommon)); - - std::memcpy(&applet_input_common, applet_input_data.data(), sizeof(MiiEditAppletInputCommon)); - - LOG_INFO(Service_AM, - "Initializing MiiEdit Applet with MiiEditAppletVersion={} and MiiEditAppletMode={}", - applet_input_common.version, applet_input_common.applet_mode); - - switch (applet_input_common.version) { - case MiiEditAppletVersion::Version3: - ASSERT(applet_input_data.size() == - sizeof(MiiEditAppletInputCommon) + sizeof(MiiEditAppletInputV3)); - std::memcpy(&applet_input_v3, applet_input_data.data() + sizeof(MiiEditAppletInputCommon), - sizeof(MiiEditAppletInputV3)); - break; - case MiiEditAppletVersion::Version4: - ASSERT(applet_input_data.size() == - sizeof(MiiEditAppletInputCommon) + sizeof(MiiEditAppletInputV4)); - std::memcpy(&applet_input_v4, applet_input_data.data() + sizeof(MiiEditAppletInputCommon), - sizeof(MiiEditAppletInputV4)); - break; - default: - UNIMPLEMENTED_MSG("Unknown MiiEditAppletVersion={} with size={}", - applet_input_common.version, applet_input_data.size()); - ASSERT(applet_input_data.size() >= - sizeof(MiiEditAppletInputCommon) + sizeof(MiiEditAppletInputV4)); - std::memcpy(&applet_input_v4, applet_input_data.data() + sizeof(MiiEditAppletInputCommon), - sizeof(MiiEditAppletInputV4)); - break; - } - - manager = system.ServiceManager().GetService("mii:e")->GetMiiManager(); - if (manager == nullptr) { - manager = std::make_shared(); - } - manager->Initialize(metadata); -} - -bool MiiEdit::TransactionComplete() const { - return is_complete; -} - -Result MiiEdit::GetStatus() const { - return ResultSuccess; -} - -void MiiEdit::ExecuteInteractive() { - ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); -} - -void MiiEdit::Execute() { - if (is_complete) { - return; - } - - // This is a default stub for each of the MiiEdit applet modes. - switch (applet_input_common.applet_mode) { - case MiiEditAppletMode::ShowMiiEdit: - case MiiEditAppletMode::AppendMiiImage: - case MiiEditAppletMode::UpdateMiiImage: - MiiEditOutput(MiiEditResult::Success, 0); - break; - case MiiEditAppletMode::AppendMii: { - Mii::StoreData store_data{}; - store_data.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); - store_data.SetNickname({u'y', u'u', u'z', u'u'}); - store_data.SetChecksum(); - const auto result = manager->AddOrReplace(metadata, store_data); - - if (result.IsError()) { - MiiEditOutput(MiiEditResult::Cancel, 0); - break; - } - - s32 index = manager->FindIndex(store_data.GetCreateId(), false); - - if (index == -1) { - MiiEditOutput(MiiEditResult::Cancel, 0); - break; - } - - MiiEditOutput(MiiEditResult::Success, index); - break; - } - case MiiEditAppletMode::CreateMii: { - Mii::CharInfo char_info{}; - manager->BuildRandom(char_info, Mii::Age::All, Mii::Gender::All, Mii::Race::All); - - const MiiEditCharInfo edit_char_info{ - .mii_info{char_info}, - }; - - MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info); - break; - } - case MiiEditAppletMode::EditMii: { - const MiiEditCharInfo edit_char_info{ - .mii_info{applet_input_v4.char_info.mii_info}, - }; - - MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info); - break; - } - default: - UNIMPLEMENTED_MSG("Unknown MiiEditAppletMode={}", applet_input_common.applet_mode); - - MiiEditOutput(MiiEditResult::Success, 0); - break; - } -} - -void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) { - const MiiEditAppletOutput applet_output{ - .result{result}, - .index{index}, - }; - - LOG_INFO(Input, "called, result={}, index={}", result, index); - - std::vector out_data(sizeof(MiiEditAppletOutput)); - std::memcpy(out_data.data(), &applet_output, sizeof(MiiEditAppletOutput)); - - is_complete = true; - - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); -} - -void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, - const MiiEditCharInfo& char_info) { - const MiiEditAppletOutputForCharInfoEditing applet_output{ - .result{result}, - .char_info{char_info}, - }; - - std::vector out_data(sizeof(MiiEditAppletOutputForCharInfoEditing)); - std::memcpy(out_data.data(), &applet_output, sizeof(MiiEditAppletOutputForCharInfoEditing)); - - is_complete = true; - - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); -} - -Result MiiEdit::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/applets/applet_mii_edit.h deleted file mode 100644 index 7ff34af49..000000000 --- a/src/core/hle/service/am/applets/applet_mii_edit.h +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applet_mii_edit_types.h" -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} // namespace Core - -namespace Service::Mii { -struct DatabaseSessionMetadata; -class MiiManager; -} // namespace Service::Mii - -namespace Service::AM::Applets { - -class MiiEdit final : public Applet { -public: - explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::MiiEditApplet& frontend_); - ~MiiEdit() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void MiiEditOutput(MiiEditResult result, s32 index); - - void MiiEditOutputForCharInfoEditing(MiiEditResult result, const MiiEditCharInfo& char_info); - -private: - const Core::Frontend::MiiEditApplet& frontend; - Core::System& system; - - MiiEditAppletInputCommon applet_input_common{}; - MiiEditAppletInputV3 applet_input_v3{}; - MiiEditAppletInputV4 applet_input_v4{}; - - bool is_complete{false}; - std::shared_ptr manager = nullptr; - Mii::DatabaseSessionMetadata metadata{}; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_mii_edit_types.h b/src/core/hle/service/am/applets/applet_mii_edit_types.h deleted file mode 100644 index f3d764073..000000000 --- a/src/core/hle/service/am/applets/applet_mii_edit_types.h +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/uuid.h" -#include "core/hle/service/mii/types/char_info.h" - -namespace Service::AM::Applets { - -enum class MiiEditAppletVersion : s32 { - Version3 = 0x3, // 1.0.0 - 10.1.1 - Version4 = 0x4, // 10.2.0+ -}; - -// This is nn::mii::AppletMode -enum class MiiEditAppletMode : u32 { - ShowMiiEdit = 0, - AppendMii = 1, - AppendMiiImage = 2, - UpdateMiiImage = 3, - CreateMii = 4, - EditMii = 5, -}; - -enum class MiiEditResult : u32 { - Success, - Cancel, -}; - -struct MiiEditCharInfo { - Service::Mii::CharInfo mii_info{}; -}; -static_assert(sizeof(MiiEditCharInfo) == 0x58, "MiiEditCharInfo has incorrect size."); - -struct MiiEditAppletInputCommon { - MiiEditAppletVersion version{}; - MiiEditAppletMode applet_mode{}; -}; -static_assert(sizeof(MiiEditAppletInputCommon) == 0x8, - "MiiEditAppletInputCommon has incorrect size."); - -struct MiiEditAppletInputV3 { - u32 special_mii_key_code{}; - std::array valid_uuids{}; - Common::UUID used_uuid{}; - INSERT_PADDING_BYTES(0x64); -}; -static_assert(sizeof(MiiEditAppletInputV3) == 0x100 - sizeof(MiiEditAppletInputCommon), - "MiiEditAppletInputV3 has incorrect size."); - -struct MiiEditAppletInputV4 { - u32 special_mii_key_code{}; - MiiEditCharInfo char_info{}; - INSERT_PADDING_BYTES(0x28); - Common::UUID used_uuid{}; - INSERT_PADDING_BYTES(0x64); -}; -static_assert(sizeof(MiiEditAppletInputV4) == 0x100 - sizeof(MiiEditAppletInputCommon), - "MiiEditAppletInputV4 has incorrect size."); - -// This is nn::mii::AppletOutput -struct MiiEditAppletOutput { - MiiEditResult result{}; - s32 index{}; - INSERT_PADDING_BYTES(0x18); -}; -static_assert(sizeof(MiiEditAppletOutput) == 0x20, "MiiEditAppletOutput has incorrect size."); - -// This is nn::mii::AppletOutputForCharInfoEditing -struct MiiEditAppletOutputForCharInfoEditing { - MiiEditResult result{}; - MiiEditCharInfo char_info{}; - INSERT_PADDING_BYTES(0x24); -}; -static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80, - "MiiEditAppletOutputForCharInfoEditing has incorrect size."); - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp deleted file mode 100644 index f32db6842..000000000 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -#include "common/assert.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/frontend/applets/profile_select.h" -#include "core/hle/service/acc/errors.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_profile_select.h" -#include "core/hle/service/am/storage.h" - -namespace Service::AM::Applets { - -ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ProfileSelectApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -ProfileSelect::~ProfileSelect() = default; - -void ProfileSelect::Initialize() { - complete = false; - status = ResultSuccess; - final_data.clear(); - - Applet::Initialize(); - profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; - - const auto user_config_storage = broker.PopNormalDataToApplet(); - ASSERT(user_config_storage != nullptr); - const auto& user_config = user_config_storage->GetData(); - - LOG_INFO(Service_AM, "Initializing Profile Select Applet with version={}", - profile_select_version); - - switch (profile_select_version) { - case ProfileSelectAppletVersion::Version1: - ASSERT(user_config.size() == sizeof(UiSettingsV1)); - std::memcpy(&config_old, user_config.data(), sizeof(UiSettingsV1)); - break; - case ProfileSelectAppletVersion::Version2: - case ProfileSelectAppletVersion::Version3: - ASSERT(user_config.size() == sizeof(UiSettings)); - std::memcpy(&config, user_config.data(), sizeof(UiSettings)); - break; - default: - UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); - break; - } -} - -bool ProfileSelect::TransactionComplete() const { - return complete; -} - -Result ProfileSelect::GetStatus() const { - return status; -} - -void ProfileSelect::ExecuteInteractive() { - ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); -} - -void ProfileSelect::Execute() { - if (complete) { - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(final_data))); - return; - } - - Core::Frontend::ProfileSelectParameters parameters{}; - - switch (profile_select_version) { - case ProfileSelectAppletVersion::Version1: - parameters = { - .mode = config_old.mode, - .invalid_uid_list = config_old.invalid_uid_list, - .display_options = config_old.display_options, - .purpose = UserSelectionPurpose::General, - }; - break; - case ProfileSelectAppletVersion::Version2: - case ProfileSelectAppletVersion::Version3: - parameters = { - .mode = config.mode, - .invalid_uid_list = config.invalid_uid_list, - .display_options = config.display_options, - .purpose = config.purpose, - }; - break; - default: - UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); - break; - } - - frontend.SelectProfile([this](std::optional uuid) { SelectionComplete(uuid); }, - parameters); -} - -void ProfileSelect::SelectionComplete(std::optional uuid) { - UiReturnArg output{}; - - if (uuid.has_value() && uuid->IsValid()) { - output.result = 0; - output.uuid_selected = *uuid; - } else { - status = Account::ResultCancelledByUser; - output.result = Account::ResultCancelledByUser.raw; - output.uuid_selected = Common::InvalidUUID; - } - - final_data = std::vector(sizeof(UiReturnArg)); - std::memcpy(final_data.data(), &output, final_data.size()); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(final_data))); - broker.SignalStateChanged(); -} - -Result ProfileSelect::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h deleted file mode 100644 index 673eed516..000000000 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/common_funcs.h" -#include "common/uuid.h" -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} - -namespace Service::AM::Applets { - -enum class ProfileSelectAppletVersion : u32 { - Version1 = 0x1, // 1.0.0+ - Version2 = 0x10000, // 2.0.0+ - Version3 = 0x20000, // 6.0.0+ -}; - -// This is nn::account::UiMode -enum class UiMode { - UserSelector, - UserCreator, - EnsureNetworkServiceAccountAvailable, - UserIconEditor, - UserNicknameEditor, - UserCreatorForStarter, - NintendoAccountAuthorizationRequestContext, - IntroduceExternalNetworkServiceAccount, - IntroduceExternalNetworkServiceAccountForRegistration, - NintendoAccountNnidLinker, - LicenseRequirementsForNetworkService, - LicenseRequirementsForNetworkServiceWithUserContextImpl, - UserCreatorForImmediateNaLoginTest, - UserQualificationPromoter, -}; - -// This is nn::account::UserSelectionPurpose -enum class UserSelectionPurpose { - General, - GameCardRegistration, - EShopLaunch, - EShopItemShow, - PicturePost, - NintendoAccountLinkage, - SettingsUpdate, - SaveDataDeletion, - UserMigration, - SaveDataTransfer, -}; - -// This is nn::account::NintendoAccountStartupDialogType -enum class NintendoAccountStartupDialogType { - LoginAndCreate, - Login, - Create, -}; - -// This is nn::account::UserSelectionSettingsForSystemService -struct UserSelectionSettingsForSystemService { - UserSelectionPurpose purpose; - bool enable_user_creation; - INSERT_PADDING_BYTES(0x3); -}; -static_assert(sizeof(UserSelectionSettingsForSystemService) == 0x8, - "UserSelectionSettingsForSystemService has incorrect size."); - -struct UiSettingsDisplayOptions { - bool is_network_service_account_required; - bool is_skip_enabled; - bool is_system_or_launcher; - bool is_registration_permitted; - bool show_skip_button; - bool additional_select; - bool show_user_selector; - bool is_unqualified_user_selectable; -}; -static_assert(sizeof(UiSettingsDisplayOptions) == 0x8, - "UiSettingsDisplayOptions has incorrect size."); - -struct UiSettingsV1 { - UiMode mode; - INSERT_PADDING_BYTES(0x4); - std::array invalid_uid_list; - u64 application_id; - UiSettingsDisplayOptions display_options; -}; -static_assert(sizeof(UiSettingsV1) == 0x98, "UiSettings has incorrect size."); - -// This is nn::account::UiSettings -struct UiSettings { - UiMode mode; - INSERT_PADDING_BYTES(0x4); - std::array invalid_uid_list; - u64 application_id; - UiSettingsDisplayOptions display_options; - UserSelectionPurpose purpose; - INSERT_PADDING_BYTES(0x4); -}; -static_assert(sizeof(UiSettings) == 0xA0, "UiSettings has incorrect size."); - -// This is nn::account::UiReturnArg -struct UiReturnArg { - u64 result; - Common::UUID uuid_selected; -}; -static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); - -class ProfileSelect final : public Applet { -public: - explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ProfileSelectApplet& frontend_); - ~ProfileSelect() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void SelectionComplete(std::optional uuid); - -private: - const Core::Frontend::ProfileSelectApplet& frontend; - - UiSettings config; - UiSettingsV1 config_old; - ProfileSelectAppletVersion profile_select_version; - - bool complete = false; - Result status = ResultSuccess; - std::vector final_data; - Core::System& system; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp deleted file mode 100644 index a6a07cef3..000000000 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ /dev/null @@ -1,1277 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/string_util.h" -#include "core/core.h" -#include "core/frontend/applets/software_keyboard.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_software_keyboard.h" -#include "core/hle/service/am/storage.h" - -namespace Service::AM::Applets { - -namespace { - -// The maximum number of UTF-16 characters that can be input into the swkbd text field. -constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500; - -constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType); -constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4; -constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC; - -constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) { - switch (text_check_result) { - case SwkbdTextCheckResult::Success: - return "Success"; - case SwkbdTextCheckResult::Failure: - return "Failure"; - case SwkbdTextCheckResult::Confirm: - return "Confirm"; - case SwkbdTextCheckResult::Silent: - return "Silent"; - default: - UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result); - return "Unknown"; - } -} - -void SetReplyBase(std::vector& reply, SwkbdState state, SwkbdReplyType reply_type) { - std::memcpy(reply.data(), &state, sizeof(SwkbdState)); - std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType)); -} - -} // Anonymous namespace - -SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, - Core::Frontend::SoftwareKeyboardApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} - -SoftwareKeyboard::~SoftwareKeyboard() = default; - -void SoftwareKeyboard::Initialize() { - Applet::Initialize(); - - LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", - applet_mode); - - LOG_DEBUG(Service_AM, - "Initializing Applet with common_args: arg_version={}, lib_version={}, " - "play_startup_sound={}, size={}, system_tick={}, theme_color={}", - common_args.arguments_version, common_args.library_version, - common_args.play_startup_sound, common_args.size, common_args.system_tick, - common_args.theme_color); - - swkbd_applet_version = SwkbdAppletVersion{common_args.library_version}; - - switch (applet_mode) { - case LibraryAppletMode::AllForeground: - InitializeForeground(); - break; - case LibraryAppletMode::Background: - case LibraryAppletMode::BackgroundIndirectDisplay: - InitializeBackground(applet_mode); - break; - default: - ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode); - break; - } -} - -bool SoftwareKeyboard::TransactionComplete() const { - return complete; -} - -Result SoftwareKeyboard::GetStatus() const { - return status; -} - -void SoftwareKeyboard::ExecuteInteractive() { - if (complete) { - return; - } - - if (is_background) { - ProcessInlineKeyboardRequest(); - } else { - ProcessTextCheck(); - } -} - -void SoftwareKeyboard::Execute() { - if (complete) { - return; - } - - if (is_background) { - return; - } - - ShowNormalKeyboard(); -} - -void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text, - bool confirmed) { - if (complete) { - return; - } - - if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) { - if (confirmed) { - SubmitNormalOutputAndExit(result, submitted_text); - } else { - SubmitForTextCheck(submitted_text); - } - } else { - SubmitNormalOutputAndExit(result, submitted_text); - } -} - -void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text, - s32 cursor_position) { - if (complete) { - return; - } - - current_text = std::move(submitted_text); - current_cursor_position = cursor_position; - - if (inline_use_utf8) { - switch (reply_type) { - case SwkbdReplyType::ChangedString: - reply_type = SwkbdReplyType::ChangedStringUtf8; - break; - case SwkbdReplyType::MovedCursor: - reply_type = SwkbdReplyType::MovedCursorUtf8; - break; - case SwkbdReplyType::DecidedEnter: - reply_type = SwkbdReplyType::DecidedEnterUtf8; - break; - default: - break; - } - } - - if (use_changed_string_v2) { - switch (reply_type) { - case SwkbdReplyType::ChangedString: - reply_type = SwkbdReplyType::ChangedStringV2; - break; - case SwkbdReplyType::ChangedStringUtf8: - reply_type = SwkbdReplyType::ChangedStringUtf8V2; - break; - default: - break; - } - } - - if (use_moved_cursor_v2) { - switch (reply_type) { - case SwkbdReplyType::MovedCursor: - reply_type = SwkbdReplyType::MovedCursorV2; - break; - case SwkbdReplyType::MovedCursorUtf8: - reply_type = SwkbdReplyType::MovedCursorUtf8V2; - break; - default: - break; - } - } - - SendReply(reply_type); -} - -void SoftwareKeyboard::InitializeForeground() { - LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet."); - - is_background = false; - - const auto swkbd_config_storage = broker.PopNormalDataToApplet(); - ASSERT(swkbd_config_storage != nullptr); - - const auto& swkbd_config_data = swkbd_config_storage->GetData(); - ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon)); - - std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon)); - - switch (swkbd_applet_version) { - case SwkbdAppletVersion::Version5: - case SwkbdAppletVersion::Version65542: - ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld)); - std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), - sizeof(SwkbdConfigOld)); - break; - case SwkbdAppletVersion::Version196615: - case SwkbdAppletVersion::Version262152: - case SwkbdAppletVersion::Version327689: - ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2)); - std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), - sizeof(SwkbdConfigOld2)); - break; - case SwkbdAppletVersion::Version393227: - case SwkbdAppletVersion::Version524301: - ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew)); - std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), - sizeof(SwkbdConfigNew)); - break; - default: - UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version, - swkbd_config_data.size()); - ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew)); - std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), - sizeof(SwkbdConfigNew)); - break; - } - - const auto work_buffer_storage = broker.PopNormalDataToApplet(); - ASSERT(work_buffer_storage != nullptr); - - if (swkbd_config_common.initial_string_length == 0) { - InitializeFrontendNormalKeyboard(); - return; - } - - const auto& work_buffer = work_buffer_storage->GetData(); - - std::vector initial_string(swkbd_config_common.initial_string_length); - - std::memcpy(initial_string.data(), - work_buffer.data() + swkbd_config_common.initial_string_offset, - swkbd_config_common.initial_string_length * sizeof(char16_t)); - - initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(), - initial_string.size()); - - LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text)); - - InitializeFrontendNormalKeyboard(); -} - -void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) { - LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet."); - - is_background = true; - - const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); - ASSERT(swkbd_inline_initialize_arg_storage != nullptr); - - const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); - ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg)); - - std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(), - swkbd_inline_initialize_arg.size()); - - if (swkbd_initialize_arg.library_applet_mode_flag) { - ASSERT(library_applet_mode == LibraryAppletMode::Background); - } else { - ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay); - } -} - -void SoftwareKeyboard::ProcessTextCheck() { - const auto text_check_storage = broker.PopInteractiveDataToApplet(); - ASSERT(text_check_storage != nullptr); - - const auto& text_check_data = text_check_storage->GetData(); - ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck)); - - SwkbdTextCheck swkbd_text_check; - - std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck)); - - std::u16string text_check_message = [this, &swkbd_text_check]() -> std::u16string { - if (swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure || - swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm) { - return swkbd_config_common.use_utf8 - ? Common::UTF8ToUTF16(Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast( - swkbd_text_check.text_check_message.data()), - swkbd_text_check.text_check_message.size() * sizeof(char16_t))) - : Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_text_check.text_check_message.data(), - swkbd_text_check.text_check_message.size()); - } else { - return u""; - } - }(); - - LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}", - GetTextCheckResultName(swkbd_text_check.text_check_result), - Common::UTF16ToUTF8(text_check_message)); - - switch (swkbd_text_check.text_check_result) { - case SwkbdTextCheckResult::Success: - SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text); - break; - case SwkbdTextCheckResult::Failure: - ShowTextCheckDialog(SwkbdTextCheckResult::Failure, std::move(text_check_message)); - break; - case SwkbdTextCheckResult::Confirm: - ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, std::move(text_check_message)); - break; - case SwkbdTextCheckResult::Silent: - default: - break; - } -} - -void SoftwareKeyboard::ProcessInlineKeyboardRequest() { - const auto request_data_storage = broker.PopInteractiveDataToApplet(); - ASSERT(request_data_storage != nullptr); - - const auto& request_data = request_data_storage->GetData(); - ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand)); - - SwkbdRequestCommand request_command; - - std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand)); - - switch (request_command) { - case SwkbdRequestCommand::Finalize: - RequestFinalize(request_data); - break; - case SwkbdRequestCommand::SetUserWordInfo: - RequestSetUserWordInfo(request_data); - break; - case SwkbdRequestCommand::SetCustomizeDic: - RequestSetCustomizeDic(request_data); - break; - case SwkbdRequestCommand::Calc: - RequestCalc(request_data); - break; - case SwkbdRequestCommand::SetCustomizedDictionaries: - RequestSetCustomizedDictionaries(request_data); - break; - case SwkbdRequestCommand::UnsetCustomizedDictionaries: - RequestUnsetCustomizedDictionaries(request_data); - break; - case SwkbdRequestCommand::SetChangedStringV2Flag: - RequestSetChangedStringV2Flag(request_data); - break; - case SwkbdRequestCommand::SetMovedCursorV2Flag: - RequestSetMovedCursorV2Flag(request_data); - break; - default: - UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command); - break; - } -} - -void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, - std::u16string submitted_text) { - std::vector out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE); - - if (swkbd_config_common.use_utf8) { - std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text); - - LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result, - utf8_submitted_text); - - std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); - std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(), - utf8_submitted_text.size()); - } else { - LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result, - Common::UTF16ToUTF8(submitted_text)); - - std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); - std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(), - submitted_text.size() * sizeof(char16_t)); - } - - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - - ExitKeyboard(); -} - -void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { - current_text = std::move(submitted_text); - - std::vector out_data(sizeof(u64) + STRING_BUFFER_SIZE); - - if (swkbd_config_common.use_utf8) { - std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text); - // Include the null terminator in the buffer size. - const u64 buffer_size = utf8_submitted_text.size() + 1; - - LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size, - utf8_submitted_text); - - std::memcpy(out_data.data(), &buffer_size, sizeof(u64)); - std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(), - utf8_submitted_text.size()); - } else { - // Include the null terminator in the buffer size. - const u64 buffer_size = (current_text.size() + 1) * sizeof(char16_t); - - LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size, - Common::UTF16ToUTF8(current_text)); - - std::memcpy(out_data.data(), &buffer_size, sizeof(u64)); - std::memcpy(out_data.data() + sizeof(u64), current_text.data(), - current_text.size() * sizeof(char16_t)); - } - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(out_data))); -} - -void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { - switch (reply_type) { - case SwkbdReplyType::FinishedInitialize: - ReplyFinishedInitialize(); - break; - case SwkbdReplyType::Default: - ReplyDefault(); - break; - case SwkbdReplyType::ChangedString: - ReplyChangedString(); - break; - case SwkbdReplyType::MovedCursor: - ReplyMovedCursor(); - break; - case SwkbdReplyType::MovedTab: - ReplyMovedTab(); - break; - case SwkbdReplyType::DecidedEnter: - ReplyDecidedEnter(); - break; - case SwkbdReplyType::DecidedCancel: - ReplyDecidedCancel(); - break; - case SwkbdReplyType::ChangedStringUtf8: - ReplyChangedStringUtf8(); - break; - case SwkbdReplyType::MovedCursorUtf8: - ReplyMovedCursorUtf8(); - break; - case SwkbdReplyType::DecidedEnterUtf8: - ReplyDecidedEnterUtf8(); - break; - case SwkbdReplyType::UnsetCustomizeDic: - ReplyUnsetCustomizeDic(); - break; - case SwkbdReplyType::ReleasedUserWordInfo: - ReplyReleasedUserWordInfo(); - break; - case SwkbdReplyType::UnsetCustomizedDictionaries: - ReplyUnsetCustomizedDictionaries(); - break; - case SwkbdReplyType::ChangedStringV2: - ReplyChangedStringV2(); - break; - case SwkbdReplyType::MovedCursorV2: - ReplyMovedCursorV2(); - break; - case SwkbdReplyType::ChangedStringUtf8V2: - ReplyChangedStringUtf8V2(); - break; - case SwkbdReplyType::MovedCursorUtf8V2: - ReplyMovedCursorUtf8V2(); - break; - default: - UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type); - ReplyDefault(); - break; - } -} - -void SoftwareKeyboard::ChangeState(SwkbdState state) { - swkbd_state = state; - - ReplyDefault(); -} - -void SoftwareKeyboard::InitializeFrontendNormalKeyboard() { - std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size()); - - std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size()); - - std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size()); - - std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size()); - - const u32 max_text_length = - swkbd_config_common.max_text_length > 0 && - swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH - ? swkbd_config_common.max_text_length - : DEFAULT_MAX_TEXT_LENGTH; - - const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length - ? swkbd_config_common.min_text_length - : 0; - - const s32 initial_cursor_position = [this] { - switch (swkbd_config_common.initial_cursor_position) { - case SwkbdInitialCursorPosition::Start: - default: - return 0; - case SwkbdInitialCursorPosition::End: - return static_cast(initial_text.size()); - } - }(); - - const auto text_draw_type = [this, max_text_length] { - switch (swkbd_config_common.text_draw_type) { - case SwkbdTextDrawType::Line: - default: - return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; - case SwkbdTextDrawType::Box: - case SwkbdTextDrawType::DownloadCode: - return swkbd_config_common.text_draw_type; - } - }(); - - const auto enable_return_button = - text_draw_type == SwkbdTextDrawType::Box ? swkbd_config_common.enable_return_button : false; - - const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227 - ? swkbd_config_new.disable_cancel_button - : false; - - Core::Frontend::KeyboardInitializeParameters initialize_parameters{ - .ok_text{std::move(ok_text)}, - .header_text{std::move(header_text)}, - .sub_text{std::move(sub_text)}, - .guide_text{std::move(guide_text)}, - .initial_text{initial_text}, - .left_optional_symbol_key{swkbd_config_common.left_optional_symbol_key}, - .right_optional_symbol_key{swkbd_config_common.right_optional_symbol_key}, - .max_text_length{max_text_length}, - .min_text_length{min_text_length}, - .initial_cursor_position{initial_cursor_position}, - .type{swkbd_config_common.type}, - .password_mode{swkbd_config_common.password_mode}, - .text_draw_type{text_draw_type}, - .key_disable_flags{swkbd_config_common.key_disable_flags}, - .use_blur_background{swkbd_config_common.use_blur_background}, - .enable_backspace_button{true}, - .enable_return_button{enable_return_button}, - .disable_cancel_button{disable_cancel_button}, - }; - - frontend.InitializeKeyboard( - false, std::move(initialize_parameters), - [this](SwkbdResult result, std::u16string submitted_text, bool confirmed) { - SubmitTextNormal(result, submitted_text, confirmed); - }, - {}); -} - -void SoftwareKeyboard::InitializeFrontendInlineKeyboard( - Core::Frontend::KeyboardInitializeParameters initialize_parameters) { - frontend.InitializeKeyboard( - true, std::move(initialize_parameters), {}, - [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) { - SubmitTextInline(reply_type, submitted_text, cursor_position); - }); -} - -void SoftwareKeyboard::InitializeFrontendInlineKeyboardOld() { - const auto& appear_arg = swkbd_calc_arg_old.appear_arg; - - std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - appear_arg.ok_text.data(), appear_arg.ok_text.size()); - - const u32 max_text_length = - appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH - ? appear_arg.max_text_length - : DEFAULT_MAX_TEXT_LENGTH; - - const u32 min_text_length = - appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; - - const s32 initial_cursor_position = current_cursor_position > 0 ? current_cursor_position : 0; - - const auto text_draw_type = - max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; - - Core::Frontend::KeyboardInitializeParameters initialize_parameters{ - .ok_text{std::move(ok_text)}, - .header_text{}, - .sub_text{}, - .guide_text{}, - .initial_text{current_text}, - .left_optional_symbol_key{appear_arg.left_optional_symbol_key}, - .right_optional_symbol_key{appear_arg.right_optional_symbol_key}, - .max_text_length{max_text_length}, - .min_text_length{min_text_length}, - .initial_cursor_position{initial_cursor_position}, - .type{appear_arg.type}, - .password_mode{SwkbdPasswordMode::Disabled}, - .text_draw_type{text_draw_type}, - .key_disable_flags{appear_arg.key_disable_flags}, - .use_blur_background{false}, - .enable_backspace_button{swkbd_calc_arg_old.enable_backspace_button}, - .enable_return_button{appear_arg.enable_return_button}, - .disable_cancel_button{appear_arg.disable_cancel_button}, - }; - - InitializeFrontendInlineKeyboard(std::move(initialize_parameters)); -} - -void SoftwareKeyboard::InitializeFrontendInlineKeyboardNew() { - const auto& appear_arg = swkbd_calc_arg_new.appear_arg; - - std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - appear_arg.ok_text.data(), appear_arg.ok_text.size()); - - const u32 max_text_length = - appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH - ? appear_arg.max_text_length - : DEFAULT_MAX_TEXT_LENGTH; - - const u32 min_text_length = - appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; - - const s32 initial_cursor_position = current_cursor_position > 0 ? current_cursor_position : 0; - - const auto text_draw_type = - max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; - - Core::Frontend::KeyboardInitializeParameters initialize_parameters{ - .ok_text{std::move(ok_text)}, - .header_text{}, - .sub_text{}, - .guide_text{}, - .initial_text{current_text}, - .left_optional_symbol_key{appear_arg.left_optional_symbol_key}, - .right_optional_symbol_key{appear_arg.right_optional_symbol_key}, - .max_text_length{max_text_length}, - .min_text_length{min_text_length}, - .initial_cursor_position{initial_cursor_position}, - .type{appear_arg.type}, - .password_mode{SwkbdPasswordMode::Disabled}, - .text_draw_type{text_draw_type}, - .key_disable_flags{appear_arg.key_disable_flags}, - .use_blur_background{false}, - .enable_backspace_button{swkbd_calc_arg_new.enable_backspace_button}, - .enable_return_button{appear_arg.enable_return_button}, - .disable_cancel_button{appear_arg.disable_cancel_button}, - }; - - InitializeFrontendInlineKeyboard(std::move(initialize_parameters)); -} - -void SoftwareKeyboard::ShowNormalKeyboard() { - frontend.ShowNormalKeyboard(); -} - -void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result, - std::u16string text_check_message) { - frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message)); -} - -void SoftwareKeyboard::ShowInlineKeyboard( - Core::Frontend::InlineAppearParameters appear_parameters) { - frontend.ShowInlineKeyboard(std::move(appear_parameters)); - - ChangeState(SwkbdState::InitializedIsShown); -} - -void SoftwareKeyboard::ShowInlineKeyboardOld() { - if (swkbd_state != SwkbdState::InitializedIsHidden) { - return; - } - - ChangeState(SwkbdState::InitializedIsAppearing); - - const auto& appear_arg = swkbd_calc_arg_old.appear_arg; - - const u32 max_text_length = - appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH - ? appear_arg.max_text_length - : DEFAULT_MAX_TEXT_LENGTH; - - const u32 min_text_length = - appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; - - Core::Frontend::InlineAppearParameters appear_parameters{ - .max_text_length{max_text_length}, - .min_text_length{min_text_length}, - .key_top_scale_x{swkbd_calc_arg_old.key_top_scale_x}, - .key_top_scale_y{swkbd_calc_arg_old.key_top_scale_y}, - .key_top_translate_x{swkbd_calc_arg_old.key_top_translate_x}, - .key_top_translate_y{swkbd_calc_arg_old.key_top_translate_y}, - .type{appear_arg.type}, - .key_disable_flags{appear_arg.key_disable_flags}, - .key_top_as_floating{swkbd_calc_arg_old.key_top_as_floating}, - .enable_backspace_button{swkbd_calc_arg_old.enable_backspace_button}, - .enable_return_button{appear_arg.enable_return_button}, - .disable_cancel_button{appear_arg.disable_cancel_button}, - }; - - ShowInlineKeyboard(std::move(appear_parameters)); -} - -void SoftwareKeyboard::ShowInlineKeyboardNew() { - if (swkbd_state != SwkbdState::InitializedIsHidden) { - return; - } - - ChangeState(SwkbdState::InitializedIsAppearing); - - const auto& appear_arg = swkbd_calc_arg_new.appear_arg; - - const u32 max_text_length = - appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH - ? appear_arg.max_text_length - : DEFAULT_MAX_TEXT_LENGTH; - - const u32 min_text_length = - appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; - - Core::Frontend::InlineAppearParameters appear_parameters{ - .max_text_length{max_text_length}, - .min_text_length{min_text_length}, - .key_top_scale_x{swkbd_calc_arg_new.key_top_scale_x}, - .key_top_scale_y{swkbd_calc_arg_new.key_top_scale_y}, - .key_top_translate_x{swkbd_calc_arg_new.key_top_translate_x}, - .key_top_translate_y{swkbd_calc_arg_new.key_top_translate_y}, - .type{appear_arg.type}, - .key_disable_flags{appear_arg.key_disable_flags}, - .key_top_as_floating{swkbd_calc_arg_new.key_top_as_floating}, - .enable_backspace_button{swkbd_calc_arg_new.enable_backspace_button}, - .enable_return_button{appear_arg.enable_return_button}, - .disable_cancel_button{appear_arg.disable_cancel_button}, - }; - - ShowInlineKeyboard(std::move(appear_parameters)); -} - -void SoftwareKeyboard::HideInlineKeyboard() { - if (swkbd_state != SwkbdState::InitializedIsShown) { - return; - } - - ChangeState(SwkbdState::InitializedIsDisappearing); - - frontend.HideInlineKeyboard(); - - ChangeState(SwkbdState::InitializedIsHidden); -} - -void SoftwareKeyboard::InlineTextChanged() { - Core::Frontend::InlineTextParameters text_parameters{ - .input_text{current_text}, - .cursor_position{current_cursor_position}, - }; - - frontend.InlineTextChanged(std::move(text_parameters)); -} - -void SoftwareKeyboard::ExitKeyboard() { - complete = true; - status = ResultSuccess; - - frontend.ExitKeyboard(); - - broker.SignalStateChanged(); -} - -Result SoftwareKeyboard::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -// Inline Software Keyboard Requests - -void SoftwareKeyboard::RequestFinalize(const std::vector& request_data) { - LOG_DEBUG(Service_AM, "Processing Request: Finalize"); - - ChangeState(SwkbdState::NotInitialized); - - ExitKeyboard(); -} - -void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector& request_data) { - LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented."); - - ReplyReleasedUserWordInfo(); -} - -void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector& request_data) { - LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented."); -} - -void SoftwareKeyboard::RequestCalc(const std::vector& request_data) { - LOG_DEBUG(Service_AM, "Processing Request: Calc"); - - ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon)); - - std::memcpy(&swkbd_calc_arg_common, request_data.data() + sizeof(SwkbdRequestCommand), - sizeof(SwkbdCalcArgCommon)); - - switch (swkbd_calc_arg_common.calc_arg_size) { - case sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgOld): - ASSERT(request_data.size() == - sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgOld)); - std::memcpy(&swkbd_calc_arg_old, - request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon), - sizeof(SwkbdCalcArgOld)); - RequestCalcOld(); - break; - case sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew): - ASSERT(request_data.size() == - sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew)); - std::memcpy(&swkbd_calc_arg_new, - request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon), - sizeof(SwkbdCalcArgNew)); - RequestCalcNew(); - break; - default: - UNIMPLEMENTED_MSG("Unknown SwkbdCalcArg size={}", swkbd_calc_arg_common.calc_arg_size); - ASSERT(request_data.size() >= - sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew)); - std::memcpy(&swkbd_calc_arg_new, - request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon), - sizeof(SwkbdCalcArgNew)); - RequestCalcNew(); - break; - } -} - -void SoftwareKeyboard::RequestCalcOld() { - if (swkbd_calc_arg_common.flags.set_input_text) { - current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_calc_arg_old.input_text.data(), swkbd_calc_arg_old.input_text.size()); - } - - if (swkbd_calc_arg_common.flags.set_cursor_position) { - current_cursor_position = swkbd_calc_arg_old.cursor_position; - } - - if (swkbd_calc_arg_common.flags.set_utf8_mode) { - inline_use_utf8 = swkbd_calc_arg_old.utf8_mode; - } - - if (swkbd_state <= SwkbdState::InitializedIsHidden && - swkbd_calc_arg_common.flags.unset_customize_dic) { - ReplyUnsetCustomizeDic(); - } - - if (swkbd_state <= SwkbdState::InitializedIsHidden && - swkbd_calc_arg_common.flags.unset_user_word_info) { - ReplyReleasedUserWordInfo(); - } - - if (swkbd_state == SwkbdState::NotInitialized && - swkbd_calc_arg_common.flags.set_initialize_arg) { - InitializeFrontendInlineKeyboardOld(); - - ChangeState(SwkbdState::InitializedIsHidden); - - ReplyFinishedInitialize(); - } - - if (!swkbd_calc_arg_common.flags.set_initialize_arg && - (swkbd_calc_arg_common.flags.set_input_text || - swkbd_calc_arg_common.flags.set_cursor_position)) { - InlineTextChanged(); - } - - if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg_common.flags.appear) { - ShowInlineKeyboardOld(); - return; - } - - if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg_common.flags.disappear) { - HideInlineKeyboard(); - return; - } -} - -void SoftwareKeyboard::RequestCalcNew() { - if (swkbd_calc_arg_common.flags.set_input_text) { - current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( - swkbd_calc_arg_new.input_text.data(), swkbd_calc_arg_new.input_text.size()); - } - - if (swkbd_calc_arg_common.flags.set_cursor_position) { - current_cursor_position = swkbd_calc_arg_new.cursor_position; - } - - if (swkbd_calc_arg_common.flags.set_utf8_mode) { - inline_use_utf8 = swkbd_calc_arg_new.utf8_mode; - } - - if (swkbd_state <= SwkbdState::InitializedIsHidden && - swkbd_calc_arg_common.flags.unset_customize_dic) { - ReplyUnsetCustomizeDic(); - } - - if (swkbd_state <= SwkbdState::InitializedIsHidden && - swkbd_calc_arg_common.flags.unset_user_word_info) { - ReplyReleasedUserWordInfo(); - } - - if (swkbd_state == SwkbdState::NotInitialized && - swkbd_calc_arg_common.flags.set_initialize_arg) { - InitializeFrontendInlineKeyboardNew(); - - ChangeState(SwkbdState::InitializedIsHidden); - - ReplyFinishedInitialize(); - } - - if (!swkbd_calc_arg_common.flags.set_initialize_arg && - (swkbd_calc_arg_common.flags.set_input_text || - swkbd_calc_arg_common.flags.set_cursor_position)) { - InlineTextChanged(); - } - - if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg_common.flags.appear) { - ShowInlineKeyboardNew(); - return; - } - - if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg_common.flags.disappear) { - HideInlineKeyboard(); - return; - } -} - -void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector& request_data) { - LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented."); -} - -void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector& request_data) { - LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries"); - - ReplyUnsetCustomizedDictionaries(); -} - -void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector& request_data) { - LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag"); - - ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1); - - std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1); -} - -void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector& request_data) { - LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag"); - - ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1); - - std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1); -} - -// Inline Software Keyboard Replies - -void SoftwareKeyboard::ReplyFinishedInitialize() { - LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize"); - - std::vector reply(REPLY_BASE_SIZE + 1); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyDefault() { - LOG_DEBUG(Service_AM, "Sending Reply: Default"); - - std::vector reply(REPLY_BASE_SIZE); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyChangedString() { - LOG_DEBUG(Service_AM, "Sending Reply: ChangedString"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString); - - const SwkbdChangedStringArg changed_string_arg{ - .text_length{static_cast(current_text.size())}, - .dictionary_start_cursor_position{-1}, - .dictionary_end_cursor_position{-1}, - .cursor_position{current_cursor_position}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), - current_text.size() * sizeof(char16_t)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, - sizeof(SwkbdChangedStringArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyMovedCursor() { - LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor); - - const SwkbdMovedCursorArg moved_cursor_arg{ - .text_length{static_cast(current_text.size())}, - .cursor_position{current_cursor_position}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), - current_text.size() * sizeof(char16_t)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, - sizeof(SwkbdMovedCursorArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyMovedTab() { - LOG_DEBUG(Service_AM, "Sending Reply: MovedTab"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab); - - const SwkbdMovedTabArg moved_tab_arg{ - .text_length{static_cast(current_text.size())}, - .cursor_position{current_cursor_position}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), - current_text.size() * sizeof(char16_t)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, - sizeof(SwkbdMovedTabArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyDecidedEnter() { - LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter); - - const SwkbdDecidedEnterArg decided_enter_arg{ - .text_length{static_cast(current_text.size())}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), - current_text.size() * sizeof(char16_t)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, - sizeof(SwkbdDecidedEnterArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); - - HideInlineKeyboard(); -} - -void SoftwareKeyboard::ReplyDecidedCancel() { - LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel"); - - std::vector reply(REPLY_BASE_SIZE); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); - - HideInlineKeyboard(); -} - -void SoftwareKeyboard::ReplyChangedStringUtf8() { - LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8); - - std::string utf8_current_text = Common::UTF16ToUTF8(current_text); - - const SwkbdChangedStringArg changed_string_arg{ - .text_length{static_cast(current_text.size())}, - .dictionary_start_cursor_position{-1}, - .dictionary_end_cursor_position{-1}, - .cursor_position{current_cursor_position}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, - sizeof(SwkbdChangedStringArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyMovedCursorUtf8() { - LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8); - - std::string utf8_current_text = Common::UTF16ToUTF8(current_text); - - const SwkbdMovedCursorArg moved_cursor_arg{ - .text_length{static_cast(current_text.size())}, - .cursor_position{current_cursor_position}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, - sizeof(SwkbdMovedCursorArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyDecidedEnterUtf8() { - LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg)); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8); - - std::string utf8_current_text = Common::UTF16ToUTF8(current_text); - - const SwkbdDecidedEnterArg decided_enter_arg{ - .text_length{static_cast(current_text.size())}, - }; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, - sizeof(SwkbdDecidedEnterArg)); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); - - HideInlineKeyboard(); -} - -void SoftwareKeyboard::ReplyUnsetCustomizeDic() { - LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic"); - - std::vector reply(REPLY_BASE_SIZE); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyReleasedUserWordInfo() { - LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo"); - - std::vector reply(REPLY_BASE_SIZE); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { - LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries"); - - std::vector reply(REPLY_BASE_SIZE); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyChangedStringV2() { - LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2); - - const SwkbdChangedStringArg changed_string_arg{ - .text_length{static_cast(current_text.size())}, - .dictionary_start_cursor_position{-1}, - .dictionary_end_cursor_position{-1}, - .cursor_position{current_cursor_position}, - }; - - constexpr u8 flag = 0; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), - current_text.size() * sizeof(char16_t)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, - sizeof(SwkbdChangedStringArg)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), - &flag, 1); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyMovedCursorV2() { - LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2); - - const SwkbdMovedCursorArg moved_cursor_arg{ - .text_length{static_cast(current_text.size())}, - .cursor_position{current_cursor_position}, - }; - - constexpr u8 flag = 0; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), - current_text.size() * sizeof(char16_t)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, - sizeof(SwkbdMovedCursorArg)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), - &flag, 1); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyChangedStringUtf8V2() { - LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2); - - std::string utf8_current_text = Common::UTF16ToUTF8(current_text); - - const SwkbdChangedStringArg changed_string_arg{ - .text_length{static_cast(current_text.size())}, - .dictionary_start_cursor_position{-1}, - .dictionary_end_cursor_position{-1}, - .cursor_position{current_cursor_position}, - }; - - constexpr u8 flag = 0; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, - sizeof(SwkbdChangedStringArg)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), - &flag, 1); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { - LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2"); - - std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1); - - SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2); - - std::string utf8_current_text = Common::UTF16ToUTF8(current_text); - - const SwkbdMovedCursorArg moved_cursor_arg{ - .text_length{static_cast(current_text.size())}, - .cursor_position{current_cursor_position}, - }; - - constexpr u8 flag = 0; - - std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, - sizeof(SwkbdMovedCursorArg)); - std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), - &flag, 1); - - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/applets/applet_software_keyboard.h deleted file mode 100644 index 2e919811b..000000000 --- a/src/core/hle/service/am/applets/applet_software_keyboard.h +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} - -namespace Core::Frontend { -struct KeyboardInitializeParameters; -struct InlineAppearParameters; -} // namespace Core::Frontend - -namespace Service::AM::Applets { - -class SoftwareKeyboard final : public Applet { -public: - explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, - Core::Frontend::SoftwareKeyboardApplet& frontend_); - ~SoftwareKeyboard() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - /** - * Submits the input text to the application. - * If text checking is enabled, the application will verify the input text. - * If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted. - * This should only be used by the normal software keyboard. - * - * @param result SwkbdResult enum - * @param submitted_text UTF-16 encoded string - * @param confirmed Whether the text has been confirmed after TextCheckResult::Confirm - */ - void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text, bool confirmed); - - /** - * Submits the input text to the application. - * If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted. - * This should only be used by the inline software keyboard. - * - * @param reply_type SwkbdReplyType enum - * @param submitted_text UTF-16 encoded string - * @param cursor_position The current position of the text cursor - */ - void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text, - s32 cursor_position); - -private: - /// Initializes the normal software keyboard. - void InitializeForeground(); - - /// Initializes the inline software keyboard. - void InitializeBackground(LibraryAppletMode library_applet_mode); - - /// Processes the text check sent by the application. - void ProcessTextCheck(); - - /// Processes the inline software keyboard request command sent by the application. - void ProcessInlineKeyboardRequest(); - - /// Submits the input text and exits the applet. - void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text); - - /// Submits the input text for text checking. - void SubmitForTextCheck(std::u16string submitted_text); - - /// Sends a reply to the application after processing a request command. - void SendReply(SwkbdReplyType reply_type); - - /// Changes the inline keyboard state. - void ChangeState(SwkbdState state); - - /** - * Signals the frontend to initialize the normal software keyboard with common parameters. - * Note that this does not cause the keyboard to appear. - * Use the ShowNormalKeyboard() functions to cause the keyboard to appear. - */ - void InitializeFrontendNormalKeyboard(); - - /** - * Signals the frontend to initialize the inline software keyboard with common parameters. - * Note that this does not cause the keyboard to appear. - * Use the ShowInlineKeyboard() to cause the keyboard to appear. - */ - void InitializeFrontendInlineKeyboard( - Core::Frontend::KeyboardInitializeParameters initialize_parameters); - - void InitializeFrontendInlineKeyboardOld(); - void InitializeFrontendInlineKeyboardNew(); - - /// Signals the frontend to show the normal software keyboard. - void ShowNormalKeyboard(); - - /// Signals the frontend to show the text check dialog. - void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result, - std::u16string text_check_message); - - /// Signals the frontend to show the inline software keyboard. - void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters); - - void ShowInlineKeyboardOld(); - void ShowInlineKeyboardNew(); - - /// Signals the frontend to hide the inline software keyboard. - void HideInlineKeyboard(); - - /// Signals the frontend that the current inline keyboard text has changed. - void InlineTextChanged(); - - /// Signals both the frontend and application that the software keyboard is exiting. - void ExitKeyboard(); - - // Inline Software Keyboard Requests - - void RequestFinalize(const std::vector& request_data); - void RequestSetUserWordInfo(const std::vector& request_data); - void RequestSetCustomizeDic(const std::vector& request_data); - void RequestCalc(const std::vector& request_data); - void RequestCalcOld(); - void RequestCalcNew(); - void RequestSetCustomizedDictionaries(const std::vector& request_data); - void RequestUnsetCustomizedDictionaries(const std::vector& request_data); - void RequestSetChangedStringV2Flag(const std::vector& request_data); - void RequestSetMovedCursorV2Flag(const std::vector& request_data); - - // Inline Software Keyboard Replies - - void ReplyFinishedInitialize(); - void ReplyDefault(); - void ReplyChangedString(); - void ReplyMovedCursor(); - void ReplyMovedTab(); - void ReplyDecidedEnter(); - void ReplyDecidedCancel(); - void ReplyChangedStringUtf8(); - void ReplyMovedCursorUtf8(); - void ReplyDecidedEnterUtf8(); - void ReplyUnsetCustomizeDic(); - void ReplyReleasedUserWordInfo(); - void ReplyUnsetCustomizedDictionaries(); - void ReplyChangedStringV2(); - void ReplyMovedCursorV2(); - void ReplyChangedStringUtf8V2(); - void ReplyMovedCursorUtf8V2(); - - Core::Frontend::SoftwareKeyboardApplet& frontend; - Core::System& system; - - SwkbdAppletVersion swkbd_applet_version; - - SwkbdConfigCommon swkbd_config_common; - SwkbdConfigOld swkbd_config_old; - SwkbdConfigOld2 swkbd_config_old2; - SwkbdConfigNew swkbd_config_new; - std::u16string initial_text; - - SwkbdState swkbd_state{SwkbdState::NotInitialized}; - SwkbdInitializeArg swkbd_initialize_arg; - SwkbdCalcArgCommon swkbd_calc_arg_common; - SwkbdCalcArgOld swkbd_calc_arg_old; - SwkbdCalcArgNew swkbd_calc_arg_new; - bool use_changed_string_v2{false}; - bool use_moved_cursor_v2{false}; - bool inline_use_utf8{false}; - s32 current_cursor_position{}; - - std::u16string current_text; - - bool is_background{false}; - - bool complete{false}; - Result status{ResultSuccess}; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_software_keyboard_types.h b/src/core/hle/service/am/applets/applet_software_keyboard_types.h deleted file mode 100644 index 1f696900e..000000000 --- a/src/core/hle/service/am/applets/applet_software_keyboard_types.h +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/swap.h" -#include "common/uuid.h" - -namespace Service::AM::Applets { - -constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; -constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; -constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128; -constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256; -constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4; - -enum class SwkbdAppletVersion : u32_le { - Version5 = 0x5, // 1.0.0 - Version65542 = 0x10006, // 2.0.0 - 2.3.0 - Version196615 = 0x30007, // 3.0.0 - 3.0.2 - Version262152 = 0x40008, // 4.0.0 - 4.1.0 - Version327689 = 0x50009, // 5.0.0 - 5.1.0 - Version393227 = 0x6000B, // 6.0.0 - 7.0.1 - Version524301 = 0x8000D, // 8.0.0+ -}; - -enum class SwkbdType : u32 { - Normal, - NumberPad, - Qwerty, - Unknown3, - Latin, - SimplifiedChinese, - TraditionalChinese, - Korean, -}; - -enum class SwkbdInitialCursorPosition : u32 { - Start, - End, -}; - -enum class SwkbdPasswordMode : u32 { - Disabled, - Enabled, -}; - -enum class SwkbdTextDrawType : u32 { - Line, - Box, - DownloadCode, -}; - -enum class SwkbdResult : u32 { - Ok, - Cancel, -}; - -enum class SwkbdTextCheckResult : u32 { - Success, - Failure, - Confirm, - Silent, -}; - -enum class SwkbdState : u32 { - NotInitialized = 0x0, - InitializedIsHidden = 0x1, - InitializedIsAppearing = 0x2, - InitializedIsShown = 0x3, - InitializedIsDisappearing = 0x4, -}; - -enum class SwkbdRequestCommand : u32 { - Finalize = 0x4, - SetUserWordInfo = 0x6, - SetCustomizeDic = 0x7, - Calc = 0xA, - SetCustomizedDictionaries = 0xB, - UnsetCustomizedDictionaries = 0xC, - SetChangedStringV2Flag = 0xD, - SetMovedCursorV2Flag = 0xE, -}; - -enum class SwkbdReplyType : u32 { - FinishedInitialize = 0x0, - Default = 0x1, - ChangedString = 0x2, - MovedCursor = 0x3, - MovedTab = 0x4, - DecidedEnter = 0x5, - DecidedCancel = 0x6, - ChangedStringUtf8 = 0x7, - MovedCursorUtf8 = 0x8, - DecidedEnterUtf8 = 0x9, - UnsetCustomizeDic = 0xA, - ReleasedUserWordInfo = 0xB, - UnsetCustomizedDictionaries = 0xC, - ChangedStringV2 = 0xD, - MovedCursorV2 = 0xE, - ChangedStringUtf8V2 = 0xF, - MovedCursorUtf8V2 = 0x10, -}; - -struct SwkbdKeyDisableFlags { - union { - u32 raw{}; - - BitField<1, 1, u32> space; - BitField<2, 1, u32> at; - BitField<3, 1, u32> percent; - BitField<4, 1, u32> slash; - BitField<5, 1, u32> backslash; - BitField<6, 1, u32> numbers; - BitField<7, 1, u32> download_code; - BitField<8, 1, u32> username; - }; -}; -static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size."); - -struct SwkbdConfigCommon { - SwkbdType type{}; - std::array ok_text{}; - char16_t left_optional_symbol_key{}; - char16_t right_optional_symbol_key{}; - bool use_prediction{}; - INSERT_PADDING_BYTES(1); - SwkbdKeyDisableFlags key_disable_flags{}; - SwkbdInitialCursorPosition initial_cursor_position{}; - std::array header_text{}; - std::array sub_text{}; - std::array guide_text{}; - u32 max_text_length{}; - u32 min_text_length{}; - SwkbdPasswordMode password_mode{}; - SwkbdTextDrawType text_draw_type{}; - bool enable_return_button{}; - bool use_utf8{}; - bool use_blur_background{}; - INSERT_PADDING_BYTES(1); - u32 initial_string_offset{}; - u32 initial_string_length{}; - u32 user_dictionary_offset{}; - u32 user_dictionary_entries{}; - bool use_text_check{}; - INSERT_PADDING_BYTES(3); -}; -static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size."); - -#pragma pack(push, 4) -// SwkbdAppletVersion 0x5, 0x10006 -struct SwkbdConfigOld { - INSERT_PADDING_WORDS(1); - VAddr text_check_callback{}; -}; -static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon), - "SwkbdConfigOld has incorrect size."); - -// SwkbdAppletVersion 0x30007, 0x40008, 0x50009 -struct SwkbdConfigOld2 { - INSERT_PADDING_WORDS(1); - VAddr text_check_callback{}; - std::array text_grouping{}; -}; -static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon), - "SwkbdConfigOld2 has incorrect size."); - -// SwkbdAppletVersion 0x6000B, 0x8000D -struct SwkbdConfigNew { - std::array text_grouping{}; - std::array customized_dictionary_set_entries{}; - u8 total_customized_dictionary_set_entries{}; - bool disable_cancel_button{}; - INSERT_PADDING_BYTES(18); -}; -static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon), - "SwkbdConfigNew has incorrect size."); -#pragma pack(pop) - -struct SwkbdTextCheck { - SwkbdTextCheckResult text_check_result{}; - std::array text_check_message{}; -}; -static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size."); - -struct SwkbdCalcArgFlags { - union { - u64 raw{}; - - BitField<0, 1, u64> set_initialize_arg; - BitField<1, 1, u64> set_volume; - BitField<2, 1, u64> appear; - BitField<3, 1, u64> set_input_text; - BitField<4, 1, u64> set_cursor_position; - BitField<5, 1, u64> set_utf8_mode; - BitField<6, 1, u64> unset_customize_dic; - BitField<7, 1, u64> disappear; - BitField<8, 1, u64> unknown; - BitField<9, 1, u64> set_key_top_translate_scale; - BitField<10, 1, u64> unset_user_word_info; - BitField<11, 1, u64> set_disable_hardware_keyboard; - }; -}; -static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size."); - -struct SwkbdInitializeArg { - u32 unknown{}; - bool library_applet_mode_flag{}; - bool is_above_hos_500{}; - INSERT_PADDING_BYTES(2); -}; -static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size."); - -struct SwkbdAppearArgOld { - SwkbdType type{}; - std::array ok_text{}; - char16_t left_optional_symbol_key{}; - char16_t right_optional_symbol_key{}; - bool use_prediction{}; - bool disable_cancel_button{}; - SwkbdKeyDisableFlags key_disable_flags{}; - u32 max_text_length{}; - u32 min_text_length{}; - bool enable_return_button{}; - INSERT_PADDING_BYTES(3); - u32 flags{}; - bool is_use_save_data{}; - INSERT_PADDING_BYTES(7); - Common::UUID user_id{}; -}; -static_assert(sizeof(SwkbdAppearArgOld) == 0x48, "SwkbdAppearArg has incorrect size."); - -struct SwkbdAppearArgNew { - SwkbdType type{}; - std::array ok_text{}; - char16_t left_optional_symbol_key{}; - char16_t right_optional_symbol_key{}; - bool use_prediction{}; - bool disable_cancel_button{}; - SwkbdKeyDisableFlags key_disable_flags{}; - u32 max_text_length{}; - u32 min_text_length{}; - bool enable_return_button{}; - INSERT_PADDING_BYTES(3); - u32 flags{}; - bool is_use_save_data{}; - INSERT_PADDING_BYTES(7); - Common::UUID user_id{}; - u64 start_sampling_number{}; - INSERT_PADDING_WORDS(8); -}; -static_assert(sizeof(SwkbdAppearArgNew) == 0x70, "SwkbdAppearArg has incorrect size."); - -struct SwkbdCalcArgCommon { - u32 unknown{}; - u16 calc_arg_size{}; - INSERT_PADDING_BYTES(2); - SwkbdCalcArgFlags flags{}; - SwkbdInitializeArg initialize_arg{}; -}; -static_assert(sizeof(SwkbdCalcArgCommon) == 0x18, "SwkbdCalcArgCommon has incorrect size."); - -struct SwkbdCalcArgOld { - f32 volume{}; - s32 cursor_position{}; - SwkbdAppearArgOld appear_arg{}; - std::array input_text{}; - bool utf8_mode{}; - INSERT_PADDING_BYTES(1); - bool enable_backspace_button{}; - INSERT_PADDING_BYTES(3); - bool key_top_as_floating{}; - bool footer_scalable{}; - bool alpha_enabled_in_input_mode{}; - u8 input_mode_fade_type{}; - bool disable_touch{}; - bool disable_hardware_keyboard{}; - INSERT_PADDING_BYTES(8); - f32 key_top_scale_x{}; - f32 key_top_scale_y{}; - f32 key_top_translate_x{}; - f32 key_top_translate_y{}; - f32 key_top_bg_alpha{}; - f32 footer_bg_alpha{}; - f32 balloon_scale{}; - INSERT_PADDING_WORDS(4); - u8 se_group{}; - INSERT_PADDING_BYTES(3); -}; -static_assert(sizeof(SwkbdCalcArgOld) == 0x4A0 - sizeof(SwkbdCalcArgCommon), - "SwkbdCalcArgOld has incorrect size."); - -struct SwkbdCalcArgNew { - SwkbdAppearArgNew appear_arg{}; - f32 volume{}; - s32 cursor_position{}; - std::array input_text{}; - bool utf8_mode{}; - INSERT_PADDING_BYTES(1); - bool enable_backspace_button{}; - INSERT_PADDING_BYTES(3); - bool key_top_as_floating{}; - bool footer_scalable{}; - bool alpha_enabled_in_input_mode{}; - u8 input_mode_fade_type{}; - bool disable_touch{}; - bool disable_hardware_keyboard{}; - INSERT_PADDING_BYTES(8); - f32 key_top_scale_x{}; - f32 key_top_scale_y{}; - f32 key_top_translate_x{}; - f32 key_top_translate_y{}; - f32 key_top_bg_alpha{}; - f32 footer_bg_alpha{}; - f32 balloon_scale{}; - INSERT_PADDING_WORDS(4); - u8 se_group{}; - INSERT_PADDING_BYTES(3); - INSERT_PADDING_WORDS(8); -}; -static_assert(sizeof(SwkbdCalcArgNew) == 0x4E8 - sizeof(SwkbdCalcArgCommon), - "SwkbdCalcArgNew has incorrect size."); - -struct SwkbdChangedStringArg { - u32 text_length{}; - s32 dictionary_start_cursor_position{}; - s32 dictionary_end_cursor_position{}; - s32 cursor_position{}; -}; -static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size."); - -struct SwkbdMovedCursorArg { - u32 text_length{}; - s32 cursor_position{}; -}; -static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size."); - -struct SwkbdMovedTabArg { - u32 text_length{}; - s32 cursor_position{}; -}; -static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size."); - -struct SwkbdDecidedEnterArg { - u32 text_length{}; -}; -static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp deleted file mode 100644 index 871737b3e..000000000 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ /dev/null @@ -1,508 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "common/fs/file.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "common/logging/log.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/fs_filesystem.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/patch_manager.h" -#include "core/file_sys/registered_cache.h" -#include "core/file_sys/romfs.h" -#include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs/vfs_vector.h" -#include "core/frontend/applets/web_browser.h" -#include "core/hle/result.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/applet_web_browser.h" -#include "core/hle/service/am/storage.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/ns/iplatform_service_manager.h" -#include "core/loader/loader.h" - -namespace Service::AM::Applets { - -namespace { - -template -void ParseRawValue(T& value, const std::vector& data) { - static_assert(std::is_trivially_copyable_v, - "It's undefined behavior to use memcpy with non-trivially copyable objects"); - std::memcpy(&value, data.data(), data.size()); -} - -template -T ParseRawValue(const std::vector& data) { - T value; - ParseRawValue(value, data); - return value; -} - -std::string ParseStringValue(const std::vector& data) { - return Common::StringFromFixedZeroTerminatedBuffer(reinterpret_cast(data.data()), - data.size()); -} - -std::string GetMainURL(const std::string& url) { - const auto index = url.find('?'); - - if (index == std::string::npos) { - return url; - } - - return url.substr(0, index); -} - -std::string ResolveURL(const std::string& url) { - const auto index = url.find_first_of('%'); - - if (index == std::string::npos) { - return url; - } - - return url.substr(0, index) + "lp1" + url.substr(index + 1); -} - -WebArgInputTLVMap ReadWebArgs(const std::vector& web_arg, WebArgHeader& web_arg_header) { - std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader)); - - if (web_arg.size() == sizeof(WebArgHeader)) { - return {}; - } - - WebArgInputTLVMap input_tlv_map; - - u64 current_offset = sizeof(WebArgHeader); - - for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) { - if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) { - return input_tlv_map; - } - - WebArgInputTLV input_tlv; - std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV)); - - current_offset += sizeof(WebArgInputTLV); - - if (web_arg.size() < current_offset + input_tlv.arg_data_size) { - return input_tlv_map; - } - - std::vector data(input_tlv.arg_data_size); - std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size); - - current_offset += input_tlv.arg_data_size; - - input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data)); - } - - return input_tlv_map; -} - -FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id, - FileSys::ContentRecordType nca_type) { - if (nca_type == FileSys::ContentRecordType::Data) { - const auto nca = - system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type); - - if (nca == nullptr) { - LOG_ERROR(Service_AM, - "NCA of type={} with title_id={:016X} is not found in the System NAND!", - nca_type, title_id); - return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); - } - - return nca->GetRomFS(); - } else { - const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type); - - if (nca == nullptr) { - if (nca_type == FileSys::ContentRecordType::HtmlDocument) { - LOG_WARNING(Service_AM, "Falling back to AppLoader to get the RomFS."); - FileSys::VirtualFile romfs; - system.GetAppLoader().ReadManualRomFS(romfs); - if (romfs != nullptr) { - return romfs; - } - } - - LOG_ERROR(Service_AM, - "NCA of type={} with title_id={:016X} is not found in the ContentProvider!", - nca_type, title_id); - return nullptr; - } - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; - - return pm.PatchRomFS(nca.get(), nca->GetRomFS(), nca_type); - } -} - -void ExtractSharedFonts(Core::System& system) { - static constexpr std::array DECRYPTED_SHARED_FONTS{ - "FontStandard.ttf", - "FontChineseSimplified.ttf", - "FontExtendedChineseSimplified.ttf", - "FontChineseTraditional.ttf", - "FontKorean.ttf", - "FontNintendoExtended.ttf", - "FontNintendoExtended2.ttf", - }; - - const auto fonts_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts"; - - for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { - const auto font_file_path = fonts_dir / DECRYPTED_SHARED_FONTS[i]; - - if (Common::FS::Exists(font_file_path)) { - continue; - } - - const auto font = NS::SHARED_FONTS[i]; - const auto font_title_id = static_cast(font.first); - - const auto nca = system.GetFileSystemController().GetSystemNANDContents()->GetEntry( - font_title_id, FileSys::ContentRecordType::Data); - - FileSys::VirtualFile romfs; - - if (!nca) { - romfs = FileSys::SystemArchive::SynthesizeSystemArchive(font_title_id); - } else { - romfs = nca->GetRomFS(); - } - - if (!romfs) { - LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} cannot be extracted!", - font_title_id); - continue; - } - - const auto extracted_romfs = FileSys::ExtractRomFS(romfs); - - if (!extracted_romfs) { - LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} failed to extract!", - font_title_id); - continue; - } - - const auto font_file = extracted_romfs->GetFile(font.second); - - if (!font_file) { - LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} has no font file \"{}\"!", - font_title_id, font.second); - continue; - } - - std::vector font_data_u32(font_file->GetSize() / sizeof(u32)); - font_file->ReadBytes(font_data_u32.data(), font_file->GetSize()); - - std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), - Common::swap32); - - std::vector decrypted_data(font_file->GetSize() - 8); - - NS::DecryptSharedFontToTTF(font_data_u32, decrypted_data); - - FileSys::VirtualFile decrypted_font = std::make_shared( - std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); - - const auto temp_dir = system.GetFilesystem()->CreateDirectory( - Common::FS::PathToUTF8String(fonts_dir), FileSys::OpenMode::ReadWrite); - - const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); - - FileSys::VfsRawCopy(decrypted_font, out_file); - } -} - -} // namespace - -WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::WebBrowserApplet& frontend_) - : Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {} - -WebBrowser::~WebBrowser() = default; - -void WebBrowser::Initialize() { - Applet::Initialize(); - - LOG_INFO(Service_AM, "Initializing Web Browser Applet."); - - LOG_DEBUG(Service_AM, - "Initializing Applet with common_args: arg_version={}, lib_version={}, " - "play_startup_sound={}, size={}, system_tick={}, theme_color={}", - common_args.arguments_version, common_args.library_version, - common_args.play_startup_sound, common_args.size, common_args.system_tick, - common_args.theme_color); - - web_applet_version = WebAppletVersion{common_args.library_version}; - - const auto web_arg_storage = broker.PopNormalDataToApplet(); - ASSERT(web_arg_storage != nullptr); - - const auto& web_arg = web_arg_storage->GetData(); - ASSERT_OR_EXECUTE(web_arg.size() >= sizeof(WebArgHeader), { return; }); - - web_arg_input_tlv_map = ReadWebArgs(web_arg, web_arg_header); - - LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}", - web_arg_header.total_tlv_entries, web_arg_header.shim_kind); - - ExtractSharedFonts(system); - - switch (web_arg_header.shim_kind) { - case ShimKind::Shop: - InitializeShop(); - break; - case ShimKind::Login: - InitializeLogin(); - break; - case ShimKind::Offline: - InitializeOffline(); - break; - case ShimKind::Share: - InitializeShare(); - break; - case ShimKind::Web: - InitializeWeb(); - break; - case ShimKind::Wifi: - InitializeWifi(); - break; - case ShimKind::Lobby: - InitializeLobby(); - break; - default: - ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); - break; - } -} - -bool WebBrowser::TransactionComplete() const { - return complete; -} - -Result WebBrowser::GetStatus() const { - return status; -} - -void WebBrowser::ExecuteInteractive() { - UNIMPLEMENTED_MSG("WebSession is not implemented"); -} - -void WebBrowser::Execute() { - switch (web_arg_header.shim_kind) { - case ShimKind::Shop: - ExecuteShop(); - break; - case ShimKind::Login: - ExecuteLogin(); - break; - case ShimKind::Offline: - ExecuteOffline(); - break; - case ShimKind::Share: - ExecuteShare(); - break; - case ShimKind::Web: - ExecuteWeb(); - break; - case ShimKind::Wifi: - ExecuteWifi(); - break; - case ShimKind::Lobby: - ExecuteLobby(); - break; - default: - ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); - WebBrowserExit(WebExitReason::EndButtonPressed); - break; - } -} - -void WebBrowser::ExtractOfflineRomFS() { - LOG_DEBUG(Service_AM, "Extracting RomFS to {}", - Common::FS::PathToUTF8String(offline_cache_dir)); - - const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); - - const auto temp_dir = system.GetFilesystem()->CreateDirectory( - Common::FS::PathToUTF8String(offline_cache_dir), FileSys::OpenMode::ReadWrite); - - FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); -} - -void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) { - if ((web_arg_header.shim_kind == ShimKind::Share && - web_applet_version >= WebAppletVersion::Version196608) || - (web_arg_header.shim_kind == ShimKind::Web && - web_applet_version >= WebAppletVersion::Version524288)) { - // TODO: Push Output TLVs instead of a WebCommonReturnValue - } - - WebCommonReturnValue web_common_return_value; - - web_common_return_value.exit_reason = exit_reason; - std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size()); - web_common_return_value.last_url_size = last_url.size(); - - LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}", - exit_reason, last_url, last_url.size()); - - complete = true; - std::vector out_data(sizeof(WebCommonReturnValue)); - std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); -} - -Result WebBrowser::RequestExit() { - frontend.Close(); - R_SUCCEED(); -} - -bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const { - return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end(); -} - -std::optional> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) { - const auto map_it = web_arg_input_tlv_map.find(input_tlv_type); - - if (map_it == web_arg_input_tlv_map.end()) { - return std::nullopt; - } - - return map_it->second; -} - -void WebBrowser::InitializeShop() {} - -void WebBrowser::InitializeLogin() {} - -void WebBrowser::InitializeOffline() { - const auto document_path = - ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value()); - - const auto document_kind = - ParseRawValue(GetInputTLVData(WebArgInputTLVType::DocumentKind).value()); - - std::string additional_paths; - - switch (document_kind) { - case DocumentKind::OfflineHtmlPage: - default: - title_id = system.GetApplicationProcessProgramID(); - nca_type = FileSys::ContentRecordType::HtmlDocument; - additional_paths = "html-document"; - break; - case DocumentKind::ApplicationLegalInformation: - title_id = ParseRawValue(GetInputTLVData(WebArgInputTLVType::ApplicationID).value()); - nca_type = FileSys::ContentRecordType::LegalInformation; - break; - case DocumentKind::SystemDataPage: - title_id = ParseRawValue(GetInputTLVData(WebArgInputTLVType::SystemDataID).value()); - nca_type = FileSys::ContentRecordType::Data; - break; - } - - static constexpr std::array RESOURCE_TYPES{ - "manual", - "legal_information", - "system_data", - }; - - offline_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / - fmt::format("offline_web_applet_{}/{:016X}", - RESOURCE_TYPES[static_cast(document_kind) - 1], title_id); - - offline_document = Common::FS::ConcatPathSafe( - offline_cache_dir, fmt::format("{}/{}", additional_paths, document_path)); -} - -void WebBrowser::InitializeShare() {} - -void WebBrowser::InitializeWeb() { - external_url = ParseStringValue(GetInputTLVData(WebArgInputTLVType::InitialURL).value()); - - // Resolve Nintendo CDN URLs. - external_url = ResolveURL(external_url); -} - -void WebBrowser::InitializeWifi() {} - -void WebBrowser::InitializeLobby() {} - -void WebBrowser::ExecuteShop() { - LOG_WARNING(Service_AM, "(STUBBED) called, Shop Applet is not implemented"); - WebBrowserExit(WebExitReason::EndButtonPressed); -} - -void WebBrowser::ExecuteLogin() { - LOG_WARNING(Service_AM, "(STUBBED) called, Login Applet is not implemented"); - WebBrowserExit(WebExitReason::EndButtonPressed); -} - -void WebBrowser::ExecuteOffline() { - // TODO (Morph): This is a hack for WebSession foreground web applets such as those used by - // Super Mario 3D All-Stars. - // TODO (Morph): Implement WebSession. - if (applet_mode == LibraryAppletMode::AllForegroundInitiallyHidden) { - LOG_WARNING(Service_AM, "WebSession is not implemented"); - return; - } - - const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document)); - - if (!Common::FS::Exists(main_url)) { - offline_romfs = GetOfflineRomFS(system, title_id, nca_type); - - if (offline_romfs == nullptr) { - LOG_ERROR(Service_AM, - "RomFS with title_id={:016X} and nca_type={} cannot be extracted!", title_id, - nca_type); - WebBrowserExit(WebExitReason::WindowClosed); - return; - } - } - - LOG_INFO(Service_AM, "Opening offline document at {}", - Common::FS::PathToUTF8String(offline_document)); - - frontend.OpenLocalWebPage( - Common::FS::PathToUTF8String(offline_document), [this] { ExtractOfflineRomFS(); }, - [this](WebExitReason exit_reason, std::string last_url) { - WebBrowserExit(exit_reason, last_url); - }); -} - -void WebBrowser::ExecuteShare() { - LOG_WARNING(Service_AM, "(STUBBED) called, Share Applet is not implemented"); - WebBrowserExit(WebExitReason::EndButtonPressed); -} - -void WebBrowser::ExecuteWeb() { - LOG_INFO(Service_AM, "Opening external URL at {}", external_url); - - frontend.OpenExternalWebPage(external_url, - [this](WebExitReason exit_reason, std::string last_url) { - WebBrowserExit(exit_reason, last_url); - }); -} - -void WebBrowser::ExecuteWifi() { - LOG_WARNING(Service_AM, "(STUBBED) called, Wifi Applet is not implemented"); - WebBrowserExit(WebExitReason::EndButtonPressed); -} - -void WebBrowser::ExecuteLobby() { - LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); - WebBrowserExit(WebExitReason::EndButtonPressed); -} -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/applets/applet_web_browser.h deleted file mode 100644 index 36adb2510..000000000 --- a/src/core/hle/service/am/applets/applet_web_browser.h +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "common/common_types.h" -#include "core/file_sys/vfs/vfs_types.h" -#include "core/hle/result.h" -#include "core/hle/service/am/applets/applet_web_browser_types.h" -#include "core/hle/service/am/applets/applets.h" - -namespace Core { -class System; -} - -namespace FileSys { -enum class ContentRecordType : u8; -} - -namespace Service::AM::Applets { - -class WebBrowser final : public Applet { -public: - WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::WebBrowserApplet& frontend_); - - ~WebBrowser() override; - - void Initialize() override; - - bool TransactionComplete() const override; - Result GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; - Result RequestExit() override; - - void ExtractOfflineRomFS(); - - void WebBrowserExit(WebExitReason exit_reason, std::string last_url = ""); - -private: - bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const; - - std::optional> GetInputTLVData(WebArgInputTLVType input_tlv_type); - - // Initializers for the various types of browser applets - void InitializeShop(); - void InitializeLogin(); - void InitializeOffline(); - void InitializeShare(); - void InitializeWeb(); - void InitializeWifi(); - void InitializeLobby(); - - // Executors for the various types of browser applets - void ExecuteShop(); - void ExecuteLogin(); - void ExecuteOffline(); - void ExecuteShare(); - void ExecuteWeb(); - void ExecuteWifi(); - void ExecuteLobby(); - - const Core::Frontend::WebBrowserApplet& frontend; - - bool complete{false}; - Result status{ResultSuccess}; - - WebAppletVersion web_applet_version{}; - WebArgHeader web_arg_header{}; - WebArgInputTLVMap web_arg_input_tlv_map; - - u64 title_id{}; - FileSys::ContentRecordType nca_type{}; - std::filesystem::path offline_cache_dir; - std::filesystem::path offline_document; - FileSys::VirtualFile offline_romfs; - - std::string external_url; - - Core::System& system; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_web_browser_types.h b/src/core/hle/service/am/applets/applet_web_browser_types.h deleted file mode 100644 index c522c5c1a..000000000 --- a/src/core/hle/service/am/applets/applet_web_browser_types.h +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/swap.h" - -namespace Service::AM::Applets { - -enum class WebAppletVersion : u32_le { - Version0 = 0x0, // Only used by WifiWebAuthApplet - Version131072 = 0x20000, // 1.0.0 - 2.3.0 - Version196608 = 0x30000, // 3.0.0 - 4.1.0 - Version327680 = 0x50000, // 5.0.0 - 5.1.0 - Version393216 = 0x60000, // 6.0.0 - 7.0.1 - Version524288 = 0x80000, // 8.0.0+ -}; - -enum class ShimKind : u32 { - Shop = 1, - Login = 2, - Offline = 3, - Share = 4, - Web = 5, - Wifi = 6, - Lobby = 7, -}; - -enum class WebExitReason : u32 { - EndButtonPressed = 0, - BackButtonPressed = 1, - ExitRequested = 2, - CallbackURL = 3, - WindowClosed = 4, - ErrorDialog = 7, -}; - -enum class WebArgInputTLVType : u16 { - InitialURL = 0x1, - CallbackURL = 0x3, - CallbackableURL = 0x4, - ApplicationID = 0x5, - DocumentPath = 0x6, - DocumentKind = 0x7, - SystemDataID = 0x8, - ShareStartPage = 0x9, - Whitelist = 0xA, - News = 0xB, - UserID = 0xE, - AlbumEntry0 = 0xF, - ScreenShotEnabled = 0x10, - EcClientCertEnabled = 0x11, - PlayReportEnabled = 0x13, - BootDisplayKind = 0x17, - BackgroundKind = 0x18, - FooterEnabled = 0x19, - PointerEnabled = 0x1A, - LeftStickMode = 0x1B, - KeyRepeatFrame1 = 0x1C, - KeyRepeatFrame2 = 0x1D, - BootAsMediaPlayerInverted = 0x1E, - DisplayURLKind = 0x1F, - BootAsMediaPlayer = 0x21, - ShopJumpEnabled = 0x22, - MediaAutoPlayEnabled = 0x23, - LobbyParameter = 0x24, - ApplicationAlbumEntry = 0x26, - JsExtensionEnabled = 0x27, - AdditionalCommentText = 0x28, - TouchEnabledOnContents = 0x29, - UserAgentAdditionalString = 0x2A, - AdditionalMediaData0 = 0x2B, - MediaPlayerAutoCloseEnabled = 0x2C, - PageCacheEnabled = 0x2D, - WebAudioEnabled = 0x2E, - YouTubeVideoWhitelist = 0x31, - FooterFixedKind = 0x32, - PageFadeEnabled = 0x33, - MediaCreatorApplicationRatingAge = 0x34, - BootLoadingIconEnabled = 0x35, - PageScrollIndicatorEnabled = 0x36, - MediaPlayerSpeedControlEnabled = 0x37, - AlbumEntry1 = 0x38, - AlbumEntry2 = 0x39, - AlbumEntry3 = 0x3A, - AdditionalMediaData1 = 0x3B, - AdditionalMediaData2 = 0x3C, - AdditionalMediaData3 = 0x3D, - BootFooterButton = 0x3E, - OverrideWebAudioVolume = 0x3F, - OverrideMediaAudioVolume = 0x40, - BootMode = 0x41, - WebSessionEnabled = 0x42, - MediaPlayerOfflineEnabled = 0x43, -}; - -enum class WebArgOutputTLVType : u16 { - ShareExitReason = 0x1, - LastURL = 0x2, - LastURLSize = 0x3, - SharePostResult = 0x4, - PostServiceName = 0x5, - PostServiceNameSize = 0x6, - PostID = 0x7, - PostIDSize = 0x8, - MediaPlayerAutoClosedByCompletion = 0x9, -}; - -enum class DocumentKind : u32 { - OfflineHtmlPage = 1, - ApplicationLegalInformation = 2, - SystemDataPage = 3, -}; - -enum class ShareStartPage : u32 { - Default, - Settings, -}; - -enum class BootDisplayKind : u32 { - Default, - White, - Black, -}; - -enum class BackgroundKind : u32 { - Default, -}; - -enum class LeftStickMode : u32 { - Pointer, - Cursor, -}; - -enum class WebSessionBootMode : u32 { - AllForeground, - AllForegroundInitiallyHidden, -}; - -struct WebArgHeader { - u16 total_tlv_entries{}; - INSERT_PADDING_BYTES(2); - ShimKind shim_kind{}; -}; -static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); - -struct WebArgInputTLV { - WebArgInputTLVType input_tlv_type{}; - u16 arg_data_size{}; - INSERT_PADDING_WORDS(1); -}; -static_assert(sizeof(WebArgInputTLV) == 0x8, "WebArgInputTLV has incorrect size."); - -struct WebArgOutputTLV { - WebArgOutputTLVType output_tlv_type{}; - u16 arg_data_size{}; - INSERT_PADDING_WORDS(1); -}; -static_assert(sizeof(WebArgOutputTLV) == 0x8, "WebArgOutputTLV has incorrect size."); - -struct WebCommonReturnValue { - WebExitReason exit_reason{}; - INSERT_PADDING_WORDS(1); - std::array last_url{}; - u64 last_url_size{}; -}; -static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); - -using WebArgInputTLVMap = std::unordered_map>; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp deleted file mode 100644 index 6a47f4b7a..000000000 --- a/src/core/hle/service/am/applets/applets.cpp +++ /dev/null @@ -1,340 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -#include "common/assert.h" -#include "core/core.h" -#include "core/frontend/applets/cabinet.h" -#include "core/frontend/applets/controller.h" -#include "core/frontend/applets/error.h" -#include "core/frontend/applets/general_frontend.h" -#include "core/frontend/applets/mii_edit.h" -#include "core/frontend/applets/profile_select.h" -#include "core/frontend/applets/software_keyboard.h" -#include "core/frontend/applets/web_browser.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/am/applet_ae.h" -#include "core/hle/service/am/applet_message_queue.h" -#include "core/hle/service/am/applet_oe.h" -#include "core/hle/service/am/applets/applet_cabinet.h" -#include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/am/applets/applet_error.h" -#include "core/hle/service/am/applets/applet_general_backend.h" -#include "core/hle/service/am/applets/applet_mii_edit.h" -#include "core/hle/service/am/applets/applet_profile_select.h" -#include "core/hle/service/am/applets/applet_software_keyboard.h" -#include "core/hle/service/am/applets/applet_web_browser.h" -#include "core/hle/service/am/applets/applets.h" -#include "core/hle/service/am/storage.h" -#include "core/hle/service/sm/sm.h" - -namespace Service::AM::Applets { - -AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) - : system{system_}, applet_mode{applet_mode_}, - service_context{system, "ILibraryAppletAccessor"} { - state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent"); - pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent"); - pop_interactive_out_data_event = - service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent"); -} - -AppletDataBroker::~AppletDataBroker() { - service_context.CloseEvent(state_changed_event); - service_context.CloseEvent(pop_out_data_event); - service_context.CloseEvent(pop_interactive_out_data_event); -} - -AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const { - std::vector> out_normal; - - for (const auto& storage : in_channel) { - out_normal.push_back(storage->GetData()); - } - - std::vector> out_interactive; - - for (const auto& storage : in_interactive_channel) { - out_interactive.push_back(storage->GetData()); - } - - return {std::move(out_normal), std::move(out_interactive)}; -} - -std::shared_ptr AppletDataBroker::PopNormalDataToGame() { - if (out_channel.empty()) - return nullptr; - - auto out = std::move(out_channel.front()); - out_channel.pop_front(); - pop_out_data_event->Clear(); - return out; -} - -std::shared_ptr AppletDataBroker::PopNormalDataToApplet() { - if (in_channel.empty()) - return nullptr; - - auto out = std::move(in_channel.front()); - in_channel.pop_front(); - return out; -} - -std::shared_ptr AppletDataBroker::PopInteractiveDataToGame() { - if (out_interactive_channel.empty()) - return nullptr; - - auto out = std::move(out_interactive_channel.front()); - out_interactive_channel.pop_front(); - pop_interactive_out_data_event->Clear(); - return out; -} - -std::shared_ptr AppletDataBroker::PopInteractiveDataToApplet() { - if (in_interactive_channel.empty()) - return nullptr; - - auto out = std::move(in_interactive_channel.front()); - in_interactive_channel.pop_front(); - return out; -} - -void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr&& storage) { - in_channel.emplace_back(std::move(storage)); -} - -void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr&& storage) { - out_channel.emplace_back(std::move(storage)); - pop_out_data_event->Signal(); -} - -void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr&& storage) { - in_interactive_channel.emplace_back(std::move(storage)); -} - -void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr&& storage) { - out_interactive_channel.emplace_back(std::move(storage)); - pop_interactive_out_data_event->Signal(); -} - -void AppletDataBroker::SignalStateChanged() { - state_changed_event->Signal(); - - switch (applet_mode) { - case LibraryAppletMode::AllForeground: - case LibraryAppletMode::AllForegroundInitiallyHidden: { - auto applet_oe = system.ServiceManager().GetService("appletOE"); - auto applet_ae = system.ServiceManager().GetService("appletAE"); - - if (applet_oe) { - applet_oe->GetMessageQueue()->FocusStateChanged(); - break; - } - - if (applet_ae) { - applet_ae->GetMessageQueue()->FocusStateChanged(); - break; - } - break; - } - default: - break; - } -} - -Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() { - return pop_out_data_event->GetReadableEvent(); -} - -Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() { - return pop_interactive_out_data_event->GetReadableEvent(); -} - -Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() { - return state_changed_event->GetReadableEvent(); -} - -Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_) - : broker{system_, applet_mode_}, applet_mode{applet_mode_} {} - -Applet::~Applet() = default; - -void Applet::Initialize() { - const auto common = broker.PopNormalDataToApplet(); - ASSERT(common != nullptr); - - const auto common_data = common->GetData(); - - ASSERT(common_data.size() >= sizeof(CommonArguments)); - std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); - - initialized = true; -} - -AppletFrontendSet::AppletFrontendSet() = default; - -AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, - ControllerApplet controller_applet, ErrorApplet error_applet, - MiiEdit mii_edit_, - ParentalControlsApplet parental_controls_applet, - PhotoViewer photo_viewer_, ProfileSelect profile_select_, - SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) - : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, - error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, - parental_controls{std::move(parental_controls_applet)}, - photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, - software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} - -AppletFrontendSet::~AppletFrontendSet() = default; - -AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default; - -AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default; - -AppletManager::AppletManager(Core::System& system_) : system{system_} {} - -AppletManager::~AppletManager() = default; - -const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { - return frontend; -} - -NFP::CabinetMode AppletManager::GetCabinetMode() const { - return cabinet_mode; -} - -AppletId AppletManager::GetCurrentAppletId() const { - return current_applet_id; -} - -void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { - if (set.cabinet != nullptr) { - frontend.cabinet = std::move(set.cabinet); - } - - if (set.controller != nullptr) { - frontend.controller = std::move(set.controller); - } - - if (set.error != nullptr) { - frontend.error = std::move(set.error); - } - - if (set.mii_edit != nullptr) { - frontend.mii_edit = std::move(set.mii_edit); - } - - if (set.parental_controls != nullptr) { - frontend.parental_controls = std::move(set.parental_controls); - } - - if (set.photo_viewer != nullptr) { - frontend.photo_viewer = std::move(set.photo_viewer); - } - - if (set.profile_select != nullptr) { - frontend.profile_select = std::move(set.profile_select); - } - - if (set.software_keyboard != nullptr) { - frontend.software_keyboard = std::move(set.software_keyboard); - } - - if (set.web_browser != nullptr) { - frontend.web_browser = std::move(set.web_browser); - } -} - -void AppletManager::SetCabinetMode(NFP::CabinetMode mode) { - cabinet_mode = mode; -} - -void AppletManager::SetCurrentAppletId(AppletId applet_id) { - current_applet_id = applet_id; -} - -void AppletManager::SetDefaultAppletFrontendSet() { - ClearAll(); - SetDefaultAppletsIfMissing(); -} - -void AppletManager::SetDefaultAppletsIfMissing() { - if (frontend.cabinet == nullptr) { - frontend.cabinet = std::make_unique(); - } - - if (frontend.controller == nullptr) { - frontend.controller = - std::make_unique(system.HIDCore()); - } - - if (frontend.error == nullptr) { - frontend.error = std::make_unique(); - } - - if (frontend.mii_edit == nullptr) { - frontend.mii_edit = std::make_unique(); - } - - if (frontend.parental_controls == nullptr) { - frontend.parental_controls = - std::make_unique(); - } - - if (frontend.photo_viewer == nullptr) { - frontend.photo_viewer = std::make_unique(); - } - - if (frontend.profile_select == nullptr) { - frontend.profile_select = std::make_unique(); - } - - if (frontend.software_keyboard == nullptr) { - frontend.software_keyboard = - std::make_unique(); - } - - if (frontend.web_browser == nullptr) { - frontend.web_browser = std::make_unique(); - } -} - -void AppletManager::ClearAll() { - frontend = {}; -} - -std::shared_ptr AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const { - switch (id) { - case AppletId::Auth: - return std::make_shared(system, mode, *frontend.parental_controls); - case AppletId::Cabinet: - return std::make_shared(system, mode, *frontend.cabinet); - case AppletId::Controller: - return std::make_shared(system, mode, *frontend.controller); - case AppletId::Error: - return std::make_shared(system, mode, *frontend.error); - case AppletId::ProfileSelect: - return std::make_shared(system, mode, *frontend.profile_select); - case AppletId::SoftwareKeyboard: - return std::make_shared(system, mode, *frontend.software_keyboard); - case AppletId::MiiEdit: - return std::make_shared(system, mode, *frontend.mii_edit); - case AppletId::Web: - case AppletId::Shop: - case AppletId::OfflineWeb: - case AppletId::LoginShare: - case AppletId::WebAuth: - return std::make_shared(system, mode, *frontend.web_browser); - case AppletId::PhotoViewer: - return std::make_shared(system, mode, *frontend.photo_viewer); - default: - UNIMPLEMENTED_MSG( - "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", - static_cast(id)); - return std::make_shared(system, id, mode); - } -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h deleted file mode 100644 index 0bf2598b7..000000000 --- a/src/core/hle/service/am/applets/applets.h +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "common/swap.h" -#include "core/hle/service/kernel_helpers.h" - -union Result; - -namespace Core { -class System; -} - -namespace Core::Frontend { -class CabinetApplet; -class ControllerApplet; -class ECommerceApplet; -class ErrorApplet; -class MiiEditApplet; -class ParentalControlsApplet; -class PhotoViewerApplet; -class ProfileSelectApplet; -class SoftwareKeyboardApplet; -class WebBrowserApplet; -} // namespace Core::Frontend - -namespace Kernel { -class KernelCore; -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::NFP { -enum class CabinetMode : u8; -} // namespace Service::NFP - -namespace Service::AM { - -class IStorage; - -namespace Applets { - -enum class AppletId : u32 { - None = 0x00, - Application = 0x01, - OverlayDisplay = 0x02, - QLaunch = 0x03, - Starter = 0x04, - Auth = 0x0A, - Cabinet = 0x0B, - Controller = 0x0C, - DataErase = 0x0D, - Error = 0x0E, - NetConnect = 0x0F, - ProfileSelect = 0x10, - SoftwareKeyboard = 0x11, - MiiEdit = 0x12, - Web = 0x13, - Shop = 0x14, - PhotoViewer = 0x15, - Settings = 0x16, - OfflineWeb = 0x17, - LoginShare = 0x18, - WebAuth = 0x19, - MyPage = 0x1A, -}; - -enum class AppletProgramId : u64 { - QLaunch = 0x0100000000001000ull, - Auth = 0x0100000000001001ull, - Cabinet = 0x0100000000001002ull, - Controller = 0x0100000000001003ull, - DataErase = 0x0100000000001004ull, - Error = 0x0100000000001005ull, - NetConnect = 0x0100000000001006ull, - ProfileSelect = 0x0100000000001007ull, - SoftwareKeyboard = 0x0100000000001008ull, - MiiEdit = 0x0100000000001009ull, - Web = 0x010000000000100Aull, - Shop = 0x010000000000100Bull, - OverlayDisplay = 0x010000000000100Cull, - PhotoViewer = 0x010000000000100Dull, - Settings = 0x010000000000100Eull, - OfflineWeb = 0x010000000000100Full, - LoginShare = 0x0100000000001010ull, - WebAuth = 0x0100000000001011ull, - Starter = 0x0100000000001012ull, - MyPage = 0x0100000000001013ull, - MaxProgramId = 0x0100000000001FFFull, -}; - -enum class LibraryAppletMode : u32 { - AllForeground = 0, - Background = 1, - NoUI = 2, - BackgroundIndirectDisplay = 3, - AllForegroundInitiallyHidden = 4, -}; - -enum class CommonArgumentVersion : u32 { - Version0, - Version1, - Version2, - Version3, -}; - -enum class CommonArgumentSize : u32 { - Version3 = 0x20, -}; - -enum class ThemeColor : u32 { - BasicWhite = 0, - BasicBlack = 3, -}; - -struct CommonArguments { - CommonArgumentVersion arguments_version; - CommonArgumentSize size; - u32 library_version; - ThemeColor theme_color; - bool play_startup_sound; - u64_le system_tick; -}; -static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); - -class AppletDataBroker final { -public: - explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_); - ~AppletDataBroker(); - - struct RawChannelData { - std::vector> normal; - std::vector> interactive; - }; - - // Retrieves but does not pop the data sent to applet. - RawChannelData PeekDataToAppletForDebug() const; - - std::shared_ptr PopNormalDataToGame(); - std::shared_ptr PopNormalDataToApplet(); - - std::shared_ptr PopInteractiveDataToGame(); - std::shared_ptr PopInteractiveDataToApplet(); - - void PushNormalDataFromGame(std::shared_ptr&& storage); - void PushNormalDataFromApplet(std::shared_ptr&& storage); - - void PushInteractiveDataFromGame(std::shared_ptr&& storage); - void PushInteractiveDataFromApplet(std::shared_ptr&& storage); - - void SignalStateChanged(); - - Kernel::KReadableEvent& GetNormalDataEvent(); - Kernel::KReadableEvent& GetInteractiveDataEvent(); - Kernel::KReadableEvent& GetStateChangedEvent(); - -private: - Core::System& system; - LibraryAppletMode applet_mode; - - KernelHelpers::ServiceContext service_context; - - // Queues are named from applet's perspective - - // PopNormalDataToApplet and PushNormalDataFromGame - std::deque> in_channel; - - // PopNormalDataToGame and PushNormalDataFromApplet - std::deque> out_channel; - - // PopInteractiveDataToApplet and PushInteractiveDataFromGame - std::deque> in_interactive_channel; - - // PopInteractiveDataToGame and PushInteractiveDataFromApplet - std::deque> out_interactive_channel; - - Kernel::KEvent* state_changed_event; - - // Signaled on PushNormalDataFromApplet - Kernel::KEvent* pop_out_data_event; - - // Signaled on PushInteractiveDataFromApplet - Kernel::KEvent* pop_interactive_out_data_event; -}; - -class Applet { -public: - explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_); - virtual ~Applet(); - - virtual void Initialize(); - - virtual bool TransactionComplete() const = 0; - virtual Result GetStatus() const = 0; - virtual void ExecuteInteractive() = 0; - virtual void Execute() = 0; - virtual Result RequestExit() = 0; - - AppletDataBroker& GetBroker() { - return broker; - } - - const AppletDataBroker& GetBroker() const { - return broker; - } - - LibraryAppletMode GetLibraryAppletMode() const { - return applet_mode; - } - - bool IsInitialized() const { - return initialized; - } - -protected: - CommonArguments common_args{}; - AppletDataBroker broker; - LibraryAppletMode applet_mode; - bool initialized = false; -}; - -struct AppletFrontendSet { - using CabinetApplet = std::unique_ptr; - using ControllerApplet = std::unique_ptr; - using ErrorApplet = std::unique_ptr; - using MiiEdit = std::unique_ptr; - using ParentalControlsApplet = std::unique_ptr; - using PhotoViewer = std::unique_ptr; - using ProfileSelect = std::unique_ptr; - using SoftwareKeyboard = std::unique_ptr; - using WebBrowser = std::unique_ptr; - - AppletFrontendSet(); - AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, - ErrorApplet error_applet, MiiEdit mii_edit_, - ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, - ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, - WebBrowser web_browser_); - ~AppletFrontendSet(); - - AppletFrontendSet(const AppletFrontendSet&) = delete; - AppletFrontendSet& operator=(const AppletFrontendSet&) = delete; - - AppletFrontendSet(AppletFrontendSet&&) noexcept; - AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; - - CabinetApplet cabinet; - ControllerApplet controller; - ErrorApplet error; - MiiEdit mii_edit; - ParentalControlsApplet parental_controls; - PhotoViewer photo_viewer; - ProfileSelect profile_select; - SoftwareKeyboard software_keyboard; - WebBrowser web_browser; -}; - -class AppletManager { -public: - explicit AppletManager(Core::System& system_); - ~AppletManager(); - - const AppletFrontendSet& GetAppletFrontendSet() const; - NFP::CabinetMode GetCabinetMode() const; - AppletId GetCurrentAppletId() const; - - void SetAppletFrontendSet(AppletFrontendSet set); - void SetCabinetMode(NFP::CabinetMode mode); - void SetCurrentAppletId(AppletId applet_id); - void SetDefaultAppletFrontendSet(); - void SetDefaultAppletsIfMissing(); - void ClearAll(); - - std::shared_ptr GetApplet(AppletId id, LibraryAppletMode mode) const; - -private: - AppletId current_applet_id{}; - NFP::CabinetMode cabinet_mode{}; - - AppletFrontendSet frontend; - Core::System& system; -}; - -} // namespace Applets -} // namespace Service::AM diff --git a/src/core/hle/service/am/frontend/applet_cabinet.cpp b/src/core/hle/service/am/frontend/applet_cabinet.cpp new file mode 100644 index 000000000..f1f49e83b --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_cabinet.cpp @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/nfc/common/device.h" +#include "hid_core/hid_core.h" + +namespace Service::AM::Frontend { + +Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, + system{system_}, service_context{system_, "CabinetApplet"} { + + availability_change_event = + service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); +} + +Cabinet::~Cabinet() { + service_context.CloseEvent(availability_change_event); +}; + +void Cabinet::Initialize() { + FrontendApplet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Cabinet Applet."); + + LOG_DEBUG(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + + const auto applet_input_data = storage->GetData(); + ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); + + std::memcpy(&applet_input_common, applet_input_data.data(), + sizeof(StartParamForAmiiboSettings)); +} + +bool Cabinet::TransactionComplete() const { + return is_complete; +} + +Result Cabinet::GetStatus() const { + return ResultSuccess; +} + +void Cabinet::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void Cabinet::Execute() { + if (is_complete) { + return; + } + + const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { + DisplayCompleted(apply_changes, amiibo_name); + }; + + // TODO: listen on all controllers + if (nfp_device == nullptr) { + nfp_device = std::make_shared( + system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); + nfp_device->Initialize(); + nfp_device->StartDetection(Service::NFC::NfcProtocol::All); + } + + const Core::Frontend::CabinetParameters parameters{ + .tag_info = applet_input_common.tag_info, + .register_info = applet_input_common.register_info, + .mode = applet_input_common.applet_mode, + }; + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: + case Service::NFP::CabinetMode::StartGameDataEraser: + case Service::NFP::CabinetMode::StartRestorer: + case Service::NFP::CabinetMode::StartFormatter: + frontend.ShowCabinetApplet(callback, parameters, nfp_device); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + DisplayCompleted(false, {}); + break; + } +} + +void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { + Service::Mii::MiiManager manager; + ReturnValueForAmiiboSettings applet_output{}; + + if (!apply_changes) { + Cancel(); + } + + if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound && + nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) { + Cancel(); + } + + if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) { + nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All); + } + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { + Service::NFP::RegisterInfoPrivate register_info{}; + std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(), + std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1)); + register_info.mii_store_data.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); + register_info.mii_store_data.SetNickname({u'y', u'u', u'z', u'u'}); + nfp_device->SetRegisterInfoPrivate(register_info); + break; + } + case Service::NFP::CabinetMode::StartGameDataEraser: + nfp_device->DeleteApplicationArea(); + break; + case Service::NFP::CabinetMode::StartRestorer: + nfp_device->Restore(); + break; + case Service::NFP::CabinetMode::StartFormatter: + nfp_device->Format(); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + break; + } + + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Cancel; + const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); + const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); + nfp_device->Finalize(); + + if (reg_result.IsSuccess()) { + applet_output.result |= CabinetResult::RegisterInfo; + } + + if (tag_result.IsSuccess()) { + applet_output.result |= CabinetResult::TagInfo; + } + + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +void Cabinet::Cancel() { + ReturnValueForAmiiboSettings applet_output{}; + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Cancel; + nfp_device->Finalize(); + + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +Result Cabinet::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_cabinet.h b/src/core/hle/service/am/frontend/applet_cabinet.h new file mode 100644 index 000000000..85d25bcb3 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_cabinet.h @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nfp/nfp_types.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} // namespace Core + +namespace Service::NFC { +class NfcDevice; +} + +namespace Service::AM::Frontend { + +enum class CabinetAppletVersion : u32 { + Version1 = 0x1, +}; + +enum class CabinetFlags : u8 { + None = 0, + DeviceHandle = 1 << 0, + TagInfo = 1 << 1, + RegisterInfo = 1 << 2, + All = DeviceHandle | TagInfo | RegisterInfo, +}; +DECLARE_ENUM_FLAG_OPERATORS(CabinetFlags) + +enum class CabinetResult : u8 { + Cancel = 0, + TagInfo = 1 << 1, + RegisterInfo = 1 << 2, + All = TagInfo | RegisterInfo, +}; +DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) + +// This is nn::nfp::AmiiboSettingsStartParam +struct AmiiboSettingsStartParam { + u64 device_handle; + std::array param_1; + u8 param_2; +}; +static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, + "AmiiboSettingsStartParam is an invalid size"); + +#pragma pack(push, 1) +// This is nn::nfp::StartParamForAmiiboSettings +struct StartParamForAmiiboSettings { + u8 param_1; + Service::NFP::CabinetMode applet_mode; + CabinetFlags flags; + u8 amiibo_settings_1; + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + std::array amiibo_settings_3; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, + "StartParamForAmiiboSettings is an invalid size"); + +// This is nn::nfp::ReturnValueForAmiiboSettings +struct ReturnValueForAmiiboSettings { + CabinetResult result; + INSERT_PADDING_BYTES(0x3); + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, + "ReturnValueForAmiiboSettings is an invalid size"); +#pragma pack(pop) + +class Cabinet final : public FrontendApplet { +public: + explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_); + ~Cabinet() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); + void Cancel(); + Result RequestExit() override; + +private: + const Core::Frontend::CabinetApplet& frontend; + Core::System& system; + + bool is_complete{false}; + std::shared_ptr nfp_device; + Kernel::KEvent* availability_change_event; + KernelHelpers::ServiceContext service_context; + StartParamForAmiiboSettings applet_input_common{}; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_controller.cpp b/src/core/hle/service/am/frontend/applet_controller.cpp new file mode 100644 index 000000000..b4114f6a3 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_controller.cpp @@ -0,0 +1,273 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/controller.h" +#include "core/hle/result.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/storage.h" +#include "hid_core/frontend/emulated_controller.h" +#include "hid_core/hid_core.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad.h" + +namespace Service::AM::Frontend { + +[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101}; +[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID, + 3102}; + +static Core::Frontend::ControllerParameters ConvertToFrontendParameters( + ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, + std::vector identification_colors, std::vector text) { + Core::HID::NpadStyleTag npad_style_set; + npad_style_set.raw = private_arg.style_set; + + return { + .min_players = std::max(s8{1}, header.player_count_min), + .max_players = header.player_count_max, + .keep_controllers_connected = header.enable_take_over_connection, + .enable_single_mode = header.enable_single_mode, + .enable_border_color = header.enable_identification_color, + .border_colors = std::move(identification_colors), + .enable_explain_text = enable_text, + .explain_text = std::move(text), + .allow_pro_controller = npad_style_set.fullkey == 1, + .allow_handheld = npad_style_set.handheld == 1, + .allow_dual_joycons = npad_style_set.joycon_dual == 1, + .allow_left_joycon = npad_style_set.joycon_left == 1, + .allow_right_joycon = npad_style_set.joycon_right == 1, + }; +} + +Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::ControllerApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +Controller::~Controller() = default; + +void Controller::Initialize() { + FrontendApplet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Controller Applet."); + + LOG_DEBUG(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + controller_applet_version = ControllerAppletVersion{common_args.library_version}; + + const auto private_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(private_arg_storage != nullptr); + + const auto& private_arg = private_arg_storage->GetData(); + ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); + + std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size()); + ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), + "Unknown ControllerSupportArgPrivate revision={} with size={}", + controller_applet_version, controller_private_arg.arg_private_size); + + // Some games such as Cave Story+ set invalid values for the ControllerSupportMode. + // Defer to arg_size to set the ControllerSupportMode. + if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) { + switch (controller_private_arg.arg_size) { + case sizeof(ControllerSupportArgOld): + case sizeof(ControllerSupportArgNew): + controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; + break; + case sizeof(ControllerUpdateFirmwareArg): + controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate; + break; + case sizeof(ControllerKeyRemappingArg): + controller_private_arg.mode = + ControllerSupportMode::ShowControllerKeyRemappingForSystem; + break; + default: + UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}", + controller_private_arg.mode, controller_private_arg.arg_size); + controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; + break; + } + } + + // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller. + // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem. + if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) { + if (controller_private_arg.flag_1 && + (controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate || + controller_private_arg.mode == + ControllerSupportMode::ShowControllerKeyRemappingForSystem)) { + controller_private_arg.caller = ControllerSupportCaller::System; + } else { + controller_private_arg.caller = ControllerSupportCaller::Application; + } + } + + switch (controller_private_arg.mode) { + case ControllerSupportMode::ShowControllerSupport: + case ControllerSupportMode::ShowControllerStrapGuide: { + const auto user_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(user_arg_storage != nullptr); + + const auto& user_arg = user_arg_storage->GetData(); + switch (controller_applet_version) { + case ControllerAppletVersion::Version3: + case ControllerAppletVersion::Version4: + case ControllerAppletVersion::Version5: + ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); + std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size()); + break; + case ControllerAppletVersion::Version7: + case ControllerAppletVersion::Version8: + ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); + std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size()); + break; + default: + UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", + controller_applet_version, controller_private_arg.arg_size); + ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); + std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); + break; + } + break; + } + case ControllerSupportMode::ShowControllerFirmwareUpdate: { + const auto update_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(update_arg_storage != nullptr); + + const auto& update_arg = update_arg_storage->GetData(); + ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg)); + + std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size()); + break; + } + case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { + const auto remapping_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(remapping_arg_storage != nullptr); + + const auto& remapping_arg = remapping_arg_storage->GetData(); + ASSERT(remapping_arg.size() == sizeof(ControllerKeyRemappingArg)); + + std::memcpy(&controller_key_remapping_arg, remapping_arg.data(), remapping_arg.size()); + break; + } + default: { + UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); + break; + } + } +} + +bool Controller::TransactionComplete() const { + return complete; +} + +Result Controller::GetStatus() const { + return status; +} + +void Controller::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void Controller::Execute() { + switch (controller_private_arg.mode) { + case ControllerSupportMode::ShowControllerSupport: { + const auto parameters = [this] { + switch (controller_applet_version) { + case ControllerAppletVersion::Version3: + case ControllerAppletVersion::Version4: + case ControllerAppletVersion::Version5: + return ConvertToFrontendParameters( + controller_private_arg, controller_user_arg_old.header, + controller_user_arg_old.enable_explain_text, + std::vector( + controller_user_arg_old.identification_colors.begin(), + controller_user_arg_old.identification_colors.end()), + std::vector(controller_user_arg_old.explain_text.begin(), + controller_user_arg_old.explain_text.end())); + case ControllerAppletVersion::Version7: + case ControllerAppletVersion::Version8: + default: + return ConvertToFrontendParameters( + controller_private_arg, controller_user_arg_new.header, + controller_user_arg_new.enable_explain_text, + std::vector( + controller_user_arg_new.identification_colors.begin(), + controller_user_arg_new.identification_colors.end()), + std::vector(controller_user_arg_new.explain_text.begin(), + controller_user_arg_new.explain_text.end())); + } + }(); + + is_single_mode = parameters.enable_single_mode; + + LOG_DEBUG(Service_HID, + "Controller Parameters: min_players={}, max_players={}, " + "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, " + "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, " + "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}", + parameters.min_players, parameters.max_players, + parameters.keep_controllers_connected, parameters.enable_single_mode, + parameters.enable_border_color, parameters.enable_explain_text, + parameters.allow_pro_controller, parameters.allow_handheld, + parameters.allow_dual_joycons, parameters.allow_left_joycon, + parameters.allow_right_joycon); + + frontend.ReconfigureControllers( + [this](bool is_success) { ConfigurationComplete(is_success); }, parameters); + break; + } + case ControllerSupportMode::ShowControllerStrapGuide: + case ControllerSupportMode::ShowControllerFirmwareUpdate: + case ControllerSupportMode::ShowControllerKeyRemappingForSystem: + UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", + controller_private_arg.mode); + ConfigurationComplete(true); + break; + default: { + ConfigurationComplete(true); + break; + } + } +} + +void Controller::ConfigurationComplete(bool is_success) { + ControllerSupportResultInfo result_info{}; + + // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. + // Otherwise, only count connected players from P1-P8. + result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount(); + + result_info.selected_id = static_cast(system.HIDCore().GetFirstNpadId()); + + result_info.result = + is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel; + + LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", + result_info.player_count, result_info.selected_id, result_info.result); + + complete = true; + out_data = std::vector(sizeof(ControllerSupportResultInfo)); + std::memcpy(out_data.data(), &result_info, out_data.size()); + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +Result Controller::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_controller.h b/src/core/hle/service/am/frontend/applet_controller.h new file mode 100644 index 000000000..bf2bed332 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_controller.h @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} + +namespace Core::HID { +enum class NpadStyleSet : u32; +} + +namespace Service::AM::Frontend { + +using IdentificationColor = std::array; +using ExplainText = std::array; + +enum class ControllerAppletVersion : u32_le { + Version3 = 0x3, // 1.0.0 - 2.3.0 + Version4 = 0x4, // 3.0.0 - 5.1.0 + Version5 = 0x5, // 6.0.0 - 7.0.1 + Version7 = 0x7, // 8.0.0 - 10.2.0 + Version8 = 0x8, // 11.0.0+ +}; + +enum class ControllerSupportMode : u8 { + ShowControllerSupport, + ShowControllerStrapGuide, + ShowControllerFirmwareUpdate, + ShowControllerKeyRemappingForSystem, + + MaxControllerSupportMode, +}; + +enum class ControllerSupportCaller : u8 { + Application, + System, + + MaxControllerSupportCaller, +}; + +enum class ControllerSupportResult : u32 { + Success = 0, + Cancel = 2, +}; + +struct ControllerSupportArgPrivate { + u32 arg_private_size{}; + u32 arg_size{}; + bool is_home_menu{}; + bool flag_1{}; + ControllerSupportMode mode{}; + ControllerSupportCaller caller{}; + Core::HID::NpadStyleSet style_set{}; + u32 joy_hold_type{}; +}; +static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, + "ControllerSupportArgPrivate has incorrect size."); + +struct ControllerSupportArgHeader { + s8 player_count_min{}; + s8 player_count_max{}; + bool enable_take_over_connection{}; + bool enable_left_justify{}; + bool enable_permit_joy_dual{}; + bool enable_single_mode{}; + bool enable_identification_color{}; +}; +static_assert(sizeof(ControllerSupportArgHeader) == 0x7, + "ControllerSupportArgHeader has incorrect size."); + +// LibraryAppletVersion 0x3, 0x4, 0x5 +struct ControllerSupportArgOld { + ControllerSupportArgHeader header{}; + std::array identification_colors{}; + bool enable_explain_text{}; + std::array explain_text{}; +}; +static_assert(sizeof(ControllerSupportArgOld) == 0x21C, + "ControllerSupportArgOld has incorrect size."); + +// LibraryAppletVersion 0x7, 0x8 +struct ControllerSupportArgNew { + ControllerSupportArgHeader header{}; + std::array identification_colors{}; + bool enable_explain_text{}; + std::array explain_text{}; +}; +static_assert(sizeof(ControllerSupportArgNew) == 0x430, + "ControllerSupportArgNew has incorrect size."); + +struct ControllerUpdateFirmwareArg { + bool enable_force_update{}; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4, + "ControllerUpdateFirmwareArg has incorrect size."); + +struct ControllerKeyRemappingArg { + u64 unknown{}; + u32 unknown_2{}; + INSERT_PADDING_WORDS(1); +}; +static_assert(sizeof(ControllerKeyRemappingArg) == 0x10, + "ControllerKeyRemappingArg has incorrect size."); + +struct ControllerSupportResultInfo { + s8 player_count{}; + INSERT_PADDING_BYTES(3); + u32 selected_id{}; + ControllerSupportResult result{}; +}; +static_assert(sizeof(ControllerSupportResultInfo) == 0xC, + "ControllerSupportResultInfo has incorrect size."); + +class Controller final : public FrontendApplet { +public: + explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::ControllerApplet& frontend_); + ~Controller() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void ConfigurationComplete(bool is_success); + +private: + const Core::Frontend::ControllerApplet& frontend; + Core::System& system; + + ControllerAppletVersion controller_applet_version; + ControllerSupportArgPrivate controller_private_arg; + ControllerSupportArgOld controller_user_arg_old; + ControllerSupportArgNew controller_user_arg_new; + ControllerUpdateFirmwareArg controller_update_arg; + ControllerKeyRemappingArg controller_key_remapping_arg; + bool complete{false}; + Result status{ResultSuccess}; + bool is_single_mode{false}; + std::vector out_data; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_error.cpp b/src/core/hle/service/am/frontend/applet_error.cpp new file mode 100644 index 000000000..48be77da2 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_error.cpp @@ -0,0 +1,223 @@ +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/error.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_error.h" +#include "core/hle/service/am/storage.h" +#include "core/reporter.h" + +namespace Service::AM::Frontend { + +struct ErrorCode { + u32 error_category{}; + u32 error_number{}; + + static constexpr ErrorCode FromU64(u64 error_code) { + return { + .error_category{static_cast(error_code >> 32)}, + .error_number{static_cast(error_code & 0xFFFFFFFF)}, + }; + } + + static constexpr ErrorCode FromResult(Result result) { + return { + .error_category{2000 + static_cast(result.GetModule())}, + .error_number{result.GetDescription()}, + }; + } + + constexpr Result ToResult() const { + return Result{static_cast(error_category - 2000), error_number}; + } +}; +static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size."); + +#pragma pack(push, 4) +struct ShowError { + u8 mode; + bool jump; + INSERT_PADDING_BYTES_NOINIT(4); + bool use_64bit_error_code; + INSERT_PADDING_BYTES_NOINIT(1); + u64 error_code_64; + u32 error_code_32; +}; +static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); +#pragma pack(pop) + +struct ShowErrorRecord { + u8 mode; + bool jump; + INSERT_PADDING_BYTES_NOINIT(6); + u64 error_code_64; + u64 posix_time; +}; +static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect size."); + +struct SystemErrorArg { + u8 mode; + bool jump; + INSERT_PADDING_BYTES_NOINIT(6); + u64 error_code_64; + std::array language_code; + std::array main_text; + std::array detail_text; +}; +static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect size."); + +struct ApplicationErrorArg { + u8 mode; + bool jump; + INSERT_PADDING_BYTES_NOINIT(6); + u32 error_code; + std::array language_code; + std::array main_text; + std::array detail_text; +}; +static_assert(sizeof(ApplicationErrorArg) == 0x1014, "ApplicationErrorArg has incorrect size."); + +union Error::ErrorArguments { + ShowError error; + ShowErrorRecord error_record; + SystemErrorArg system_error; + ApplicationErrorArg application_error; + std::array raw{}; +}; + +namespace { +template +void CopyArgumentData(const std::vector& data, T& variable) { + ASSERT(data.size() >= sizeof(T)); + std::memcpy(&variable, data.data(), sizeof(T)); +} + +Result Decode64BitError(u64 error) { + return ErrorCode::FromU64(error).ToResult(); +} + +} // Anonymous namespace + +Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::ErrorApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +Error::~Error() = default; + +void Error::Initialize() { + FrontendApplet::Initialize(); + args = std::make_unique(); + complete = false; + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + const auto data = storage->GetData(); + + ASSERT(!data.empty()); + std::memcpy(&mode, data.data(), sizeof(ErrorAppletMode)); + + switch (mode) { + case ErrorAppletMode::ShowError: + CopyArgumentData(data, args->error); + if (args->error.use_64bit_error_code) { + error_code = Decode64BitError(args->error.error_code_64); + } else { + error_code = Result(args->error.error_code_32); + } + break; + case ErrorAppletMode::ShowSystemError: + CopyArgumentData(data, args->system_error); + error_code = Result(Decode64BitError(args->system_error.error_code_64)); + break; + case ErrorAppletMode::ShowApplicationError: + CopyArgumentData(data, args->application_error); + error_code = Result(args->application_error.error_code); + break; + case ErrorAppletMode::ShowErrorPctl: + CopyArgumentData(data, args->error_record); + error_code = Decode64BitError(args->error_record.error_code_64); + break; + case ErrorAppletMode::ShowErrorRecord: + CopyArgumentData(data, args->error_record); + error_code = Decode64BitError(args->error_record.error_code_64); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); + break; + } +} + +bool Error::TransactionComplete() const { + return complete; +} + +Result Error::GetStatus() const { + return ResultSuccess; +} + +void Error::ExecuteInteractive() { + ASSERT_MSG(false, "Unexpected interactive applet data!"); +} + +void Error::Execute() { + if (complete) { + return; + } + + const auto callback = [this] { DisplayCompleted(); }; + const auto title_id = system.GetApplicationProcessProgramID(); + const auto& reporter{system.GetReporter()}; + + switch (mode) { + case ErrorAppletMode::ShowError: + reporter.SaveErrorReport(title_id, error_code); + frontend.ShowError(error_code, callback); + break; + case ErrorAppletMode::ShowSystemError: + case ErrorAppletMode::ShowApplicationError: { + const auto is_system = mode == ErrorAppletMode::ShowSystemError; + const auto& main_text = + is_system ? args->system_error.main_text : args->application_error.main_text; + const auto& detail_text = + is_system ? args->system_error.detail_text : args->application_error.detail_text; + + const auto main_text_string = + Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()); + const auto detail_text_string = + Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()); + + reporter.SaveErrorReport(title_id, error_code, main_text_string, detail_text_string); + frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback); + break; + } + case ErrorAppletMode::ShowErrorPctl: + case ErrorAppletMode::ShowErrorRecord: + reporter.SaveErrorReport(title_id, error_code, + fmt::format("{:016X}", args->error_record.posix_time)); + frontend.ShowErrorWithTimestamp( + error_code, std::chrono::seconds{args->error_record.posix_time}, callback); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); + DisplayCompleted(); + } +} + +void Error::DisplayCompleted() { + complete = true; + broker.PushNormalDataFromApplet(std::make_shared(system, std::vector{})); + broker.SignalStateChanged(); +} + +Result Error::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_error.h b/src/core/hle/service/am/frontend/applet_error.h new file mode 100644 index 000000000..639e3c224 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_error.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} + +namespace Service::AM::Frontend { + +enum class ErrorAppletMode : u8 { + ShowError = 0, + ShowSystemError = 1, + ShowApplicationError = 2, + ShowEula = 3, + ShowErrorPctl = 4, + ShowErrorRecord = 5, + ShowUpdateEula = 8, +}; + +class Error final : public FrontendApplet { +public: + explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::ErrorApplet& frontend_); + ~Error() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void DisplayCompleted(); + +private: + union ErrorArguments; + + const Core::Frontend::ErrorApplet& frontend; + Result error_code = ResultSuccess; + ErrorAppletMode mode = ErrorAppletMode::ShowError; + std::unique_ptr args; + + bool complete = false; + Core::System& system; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_general.cpp b/src/core/hle/service/am/frontend/applet_general.cpp new file mode 100644 index 000000000..e51171525 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_general.cpp @@ -0,0 +1,269 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/general.h" +#include "core/hle/result.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_general.h" +#include "core/hle/service/am/storage.h" +#include "core/reporter.h" + +namespace Service::AM::Frontend { + +constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; + +static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { + std::shared_ptr storage = broker.PopNormalDataToApplet(); + for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { + const auto data = storage->GetData(); + LOG_INFO(Service_AM, + "called (STUBBED), during {} received normal data with size={:08X}, data={}", + prefix, data.size(), Common::HexToString(data)); + } + + storage = broker.PopInteractiveDataToApplet(); + for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) { + const auto data = storage->GetData(); + LOG_INFO(Service_AM, + "called (STUBBED), during {} received interactive data with size={:08X}, data={}", + prefix, data.size(), Common::HexToString(data)); + } +} + +Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, + Core::Frontend::ParentalControlsApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +Auth::~Auth() = default; + +void Auth::Initialize() { + FrontendApplet::Initialize(); + complete = false; + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + const auto data = storage->GetData(); + ASSERT(data.size() >= 0xC); + + struct Arg { + INSERT_PADDING_BYTES(4); + AuthAppletType type; + u8 arg0; + u8 arg1; + u8 arg2; + INSERT_PADDING_BYTES(1); + }; + static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size."); + + Arg arg{}; + std::memcpy(&arg, data.data(), sizeof(Arg)); + + type = arg.type; + arg0 = arg.arg0; + arg1 = arg.arg1; + arg2 = arg.arg2; +} + +bool Auth::TransactionComplete() const { + return complete; +} + +Result Auth::GetStatus() const { + return successful ? ResultSuccess : ERROR_INVALID_PIN; +} + +void Auth::ExecuteInteractive() { + ASSERT_MSG(false, "Unexpected interactive applet data."); +} + +void Auth::Execute() { + if (complete) { + return; + } + + const auto unimplemented_log = [this] { + UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " + "arg1={:02X}, arg2={:02X}", + type, arg0, arg1, arg2); + }; + + switch (type) { + case AuthAppletType::ShowParentalAuthentication: { + const auto callback = [this](bool is_successful) { AuthFinished(is_successful); }; + + if (arg0 == 1 && arg1 == 0 && arg2 == 1) { + // ShowAuthenticatorForConfiguration + frontend.VerifyPINForSettings(callback); + } else if (arg1 == 0 && arg2 == 0) { + // ShowParentalAuthentication(bool) + frontend.VerifyPIN(callback, static_cast(arg0)); + } else { + unimplemented_log(); + } + break; + } + case AuthAppletType::RegisterParentalPasscode: { + const auto callback = [this] { AuthFinished(true); }; + + if (arg0 == 0 && arg1 == 0 && arg2 == 0) { + // RegisterParentalPasscode + frontend.RegisterPIN(callback); + } else { + unimplemented_log(); + } + break; + } + case AuthAppletType::ChangeParentalPasscode: { + const auto callback = [this] { AuthFinished(true); }; + + if (arg0 == 0 && arg1 == 0 && arg2 == 0) { + // ChangeParentalPasscode + frontend.ChangePIN(callback); + } else { + unimplemented_log(); + } + break; + } + default: + unimplemented_log(); + break; + } +} + +void Auth::AuthFinished(bool is_successful) { + successful = is_successful; + + struct Return { + Result result_code; + }; + static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size."); + + Return return_{GetStatus()}; + + std::vector out(sizeof(Return)); + std::memcpy(out.data(), &return_, sizeof(Return)); + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out))); + broker.SignalStateChanged(); +} + +Result Auth::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::PhotoViewerApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +PhotoViewer::~PhotoViewer() = default; + +void PhotoViewer::Initialize() { + FrontendApplet::Initialize(); + complete = false; + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + const auto data = storage->GetData(); + ASSERT(!data.empty()); + mode = static_cast(data[0]); +} + +bool PhotoViewer::TransactionComplete() const { + return complete; +} + +Result PhotoViewer::GetStatus() const { + return ResultSuccess; +} + +void PhotoViewer::ExecuteInteractive() { + ASSERT_MSG(false, "Unexpected interactive applet data."); +} + +void PhotoViewer::Execute() { + if (complete) + return; + + const auto callback = [this] { ViewFinished(); }; + switch (mode) { + case PhotoViewerAppletMode::CurrentApp: + frontend.ShowPhotosForApplication(system.GetApplicationProcessProgramID(), callback); + break; + case PhotoViewerAppletMode::AllApps: + frontend.ShowAllPhotos(callback); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); + break; + } +} + +void PhotoViewer::ViewFinished() { + broker.PushNormalDataFromApplet(std::make_shared(system, std::vector{})); + broker.SignalStateChanged(); +} + +Result PhotoViewer::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) + : FrontendApplet{system_, applet_mode_}, id{id_}, system{system_} {} + +StubApplet::~StubApplet() = default; + +void StubApplet::Initialize() { + LOG_WARNING(Service_AM, "called (STUBBED)"); + FrontendApplet::Initialize(); + + const auto data = broker.PeekDataToAppletForDebug(); + system.GetReporter().SaveUnimplementedAppletReport( + static_cast(id), static_cast(common_args.arguments_version), + common_args.library_version, static_cast(common_args.theme_color), + common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive); + + LogCurrentStorage(broker, "Initialize"); +} + +bool StubApplet::TransactionComplete() const { + LOG_WARNING(Service_AM, "called (STUBBED)"); + return true; +} + +Result StubApplet::GetStatus() const { + LOG_WARNING(Service_AM, "called (STUBBED)"); + return ResultSuccess; +} + +void StubApplet::ExecuteInteractive() { + LOG_WARNING(Service_AM, "called (STUBBED)"); + LogCurrentStorage(broker, "ExecuteInteractive"); + + broker.PushNormalDataFromApplet(std::make_shared(system, std::vector(0x1000))); + broker.PushInteractiveDataFromApplet( + std::make_shared(system, std::vector(0x1000))); + broker.SignalStateChanged(); +} + +void StubApplet::Execute() { + LOG_WARNING(Service_AM, "called (STUBBED)"); + LogCurrentStorage(broker, "Execute"); + + broker.PushNormalDataFromApplet(std::make_shared(system, std::vector(0x1000))); + broker.PushInteractiveDataFromApplet( + std::make_shared(system, std::vector(0x1000))); + broker.SignalStateChanged(); +} + +Result StubApplet::RequestExit() { + // Nothing to do. + R_SUCCEED(); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_general.h b/src/core/hle/service/am/frontend/applet_general.h new file mode 100644 index 000000000..b39a9a3f1 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_general.h @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} + +namespace Service::AM::Frontend { + +enum class AuthAppletType : u32 { + ShowParentalAuthentication, + RegisterParentalPasscode, + ChangeParentalPasscode, +}; + +class Auth final : public FrontendApplet { +public: + explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, + Core::Frontend::ParentalControlsApplet& frontend_); + ~Auth() override; + + void Initialize() override; + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void AuthFinished(bool is_successful = true); + +private: + Core::Frontend::ParentalControlsApplet& frontend; + Core::System& system; + bool complete = false; + bool successful = false; + + AuthAppletType type = AuthAppletType::ShowParentalAuthentication; + u8 arg0 = 0; + u8 arg1 = 0; + u8 arg2 = 0; +}; + +enum class PhotoViewerAppletMode : u8 { + CurrentApp = 0, + AllApps = 1, +}; + +class PhotoViewer final : public FrontendApplet { +public: + explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::PhotoViewerApplet& frontend_); + ~PhotoViewer() override; + + void Initialize() override; + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void ViewFinished(); + +private: + const Core::Frontend::PhotoViewerApplet& frontend; + bool complete = false; + PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; + Core::System& system; +}; + +class StubApplet final : public FrontendApplet { +public: + explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); + ~StubApplet() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + +private: + AppletId id; + Core::System& system; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_mii_edit.cpp b/src/core/hle/service/am/frontend/applet_mii_edit.cpp new file mode 100644 index 000000000..6203ebd2e --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_mii_edit.cpp @@ -0,0 +1,181 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/mii_edit.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_mii_edit.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/mii/mii.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM::Frontend { + +MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::MiiEditApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +MiiEdit::~MiiEdit() = default; + +void MiiEdit::Initialize() { + // Note: MiiEdit is not initialized with common arguments. + // Instead, it is initialized by an AppletInput storage with size 0x100 bytes. + // Do NOT call Applet::Initialize() here. + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + + const auto applet_input_data = storage->GetData(); + ASSERT(applet_input_data.size() >= sizeof(MiiEditAppletInputCommon)); + + std::memcpy(&applet_input_common, applet_input_data.data(), sizeof(MiiEditAppletInputCommon)); + + LOG_INFO(Service_AM, + "Initializing MiiEdit Applet with MiiEditAppletVersion={} and MiiEditAppletMode={}", + applet_input_common.version, applet_input_common.applet_mode); + + switch (applet_input_common.version) { + case MiiEditAppletVersion::Version3: + ASSERT(applet_input_data.size() == + sizeof(MiiEditAppletInputCommon) + sizeof(MiiEditAppletInputV3)); + std::memcpy(&applet_input_v3, applet_input_data.data() + sizeof(MiiEditAppletInputCommon), + sizeof(MiiEditAppletInputV3)); + break; + case MiiEditAppletVersion::Version4: + ASSERT(applet_input_data.size() == + sizeof(MiiEditAppletInputCommon) + sizeof(MiiEditAppletInputV4)); + std::memcpy(&applet_input_v4, applet_input_data.data() + sizeof(MiiEditAppletInputCommon), + sizeof(MiiEditAppletInputV4)); + break; + default: + UNIMPLEMENTED_MSG("Unknown MiiEditAppletVersion={} with size={}", + applet_input_common.version, applet_input_data.size()); + ASSERT(applet_input_data.size() >= + sizeof(MiiEditAppletInputCommon) + sizeof(MiiEditAppletInputV4)); + std::memcpy(&applet_input_v4, applet_input_data.data() + sizeof(MiiEditAppletInputCommon), + sizeof(MiiEditAppletInputV4)); + break; + } + + manager = system.ServiceManager().GetService("mii:e")->GetMiiManager(); + if (manager == nullptr) { + manager = std::make_shared(); + } + manager->Initialize(metadata); +} + +bool MiiEdit::TransactionComplete() const { + return is_complete; +} + +Result MiiEdit::GetStatus() const { + return ResultSuccess; +} + +void MiiEdit::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void MiiEdit::Execute() { + if (is_complete) { + return; + } + + // This is a default stub for each of the MiiEdit applet modes. + switch (applet_input_common.applet_mode) { + case MiiEditAppletMode::ShowMiiEdit: + case MiiEditAppletMode::AppendMiiImage: + case MiiEditAppletMode::UpdateMiiImage: + MiiEditOutput(MiiEditResult::Success, 0); + break; + case MiiEditAppletMode::AppendMii: { + Mii::StoreData store_data{}; + store_data.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); + store_data.SetNickname({u'y', u'u', u'z', u'u'}); + store_data.SetChecksum(); + const auto result = manager->AddOrReplace(metadata, store_data); + + if (result.IsError()) { + MiiEditOutput(MiiEditResult::Cancel, 0); + break; + } + + s32 index = manager->FindIndex(store_data.GetCreateId(), false); + + if (index == -1) { + MiiEditOutput(MiiEditResult::Cancel, 0); + break; + } + + MiiEditOutput(MiiEditResult::Success, index); + break; + } + case MiiEditAppletMode::CreateMii: { + Mii::CharInfo char_info{}; + manager->BuildRandom(char_info, Mii::Age::All, Mii::Gender::All, Mii::Race::All); + + const MiiEditCharInfo edit_char_info{ + .mii_info{char_info}, + }; + + MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info); + break; + } + case MiiEditAppletMode::EditMii: { + const MiiEditCharInfo edit_char_info{ + .mii_info{applet_input_v4.char_info.mii_info}, + }; + + MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info); + break; + } + default: + UNIMPLEMENTED_MSG("Unknown MiiEditAppletMode={}", applet_input_common.applet_mode); + + MiiEditOutput(MiiEditResult::Success, 0); + break; + } +} + +void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) { + const MiiEditAppletOutput applet_output{ + .result{result}, + .index{index}, + }; + + LOG_INFO(Input, "called, result={}, index={}", result, index); + + std::vector out_data(sizeof(MiiEditAppletOutput)); + std::memcpy(out_data.data(), &applet_output, sizeof(MiiEditAppletOutput)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, + const MiiEditCharInfo& char_info) { + const MiiEditAppletOutputForCharInfoEditing applet_output{ + .result{result}, + .char_info{char_info}, + }; + + std::vector out_data(sizeof(MiiEditAppletOutputForCharInfoEditing)); + std::memcpy(out_data.data(), &applet_output, sizeof(MiiEditAppletOutputForCharInfoEditing)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +Result MiiEdit::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_mii_edit.h b/src/core/hle/service/am/frontend/applet_mii_edit.h new file mode 100644 index 000000000..ebde37028 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_mii_edit.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} // namespace Core + +namespace Service::Mii { +struct DatabaseSessionMetadata; +class MiiManager; +} // namespace Service::Mii + +namespace Service::AM::Frontend { + +class MiiEdit final : public FrontendApplet { +public: + explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::MiiEditApplet& frontend_); + ~MiiEdit() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void MiiEditOutput(MiiEditResult result, s32 index); + + void MiiEditOutputForCharInfoEditing(MiiEditResult result, const MiiEditCharInfo& char_info); + +private: + const Core::Frontend::MiiEditApplet& frontend; + Core::System& system; + + MiiEditAppletInputCommon applet_input_common{}; + MiiEditAppletInputV3 applet_input_v3{}; + MiiEditAppletInputV4 applet_input_v4{}; + + bool is_complete{false}; + std::shared_ptr manager = nullptr; + Mii::DatabaseSessionMetadata metadata{}; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_mii_edit_types.h b/src/core/hle/service/am/frontend/applet_mii_edit_types.h new file mode 100644 index 000000000..23d9d7a69 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_mii_edit_types.h @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/uuid.h" +#include "core/hle/service/mii/types/char_info.h" + +namespace Service::AM::Frontend { + +enum class MiiEditAppletVersion : s32 { + Version3 = 0x3, // 1.0.0 - 10.1.1 + Version4 = 0x4, // 10.2.0+ +}; + +// This is nn::mii::AppletMode +enum class MiiEditAppletMode : u32 { + ShowMiiEdit = 0, + AppendMii = 1, + AppendMiiImage = 2, + UpdateMiiImage = 3, + CreateMii = 4, + EditMii = 5, +}; + +enum class MiiEditResult : u32 { + Success, + Cancel, +}; + +struct MiiEditCharInfo { + Service::Mii::CharInfo mii_info{}; +}; +static_assert(sizeof(MiiEditCharInfo) == 0x58, "MiiEditCharInfo has incorrect size."); + +struct MiiEditAppletInputCommon { + MiiEditAppletVersion version{}; + MiiEditAppletMode applet_mode{}; +}; +static_assert(sizeof(MiiEditAppletInputCommon) == 0x8, + "MiiEditAppletInputCommon has incorrect size."); + +struct MiiEditAppletInputV3 { + u32 special_mii_key_code{}; + std::array valid_uuids{}; + Common::UUID used_uuid{}; + INSERT_PADDING_BYTES(0x64); +}; +static_assert(sizeof(MiiEditAppletInputV3) == 0x100 - sizeof(MiiEditAppletInputCommon), + "MiiEditAppletInputV3 has incorrect size."); + +struct MiiEditAppletInputV4 { + u32 special_mii_key_code{}; + MiiEditCharInfo char_info{}; + INSERT_PADDING_BYTES(0x28); + Common::UUID used_uuid{}; + INSERT_PADDING_BYTES(0x64); +}; +static_assert(sizeof(MiiEditAppletInputV4) == 0x100 - sizeof(MiiEditAppletInputCommon), + "MiiEditAppletInputV4 has incorrect size."); + +// This is nn::mii::AppletOutput +struct MiiEditAppletOutput { + MiiEditResult result{}; + s32 index{}; + INSERT_PADDING_BYTES(0x18); +}; +static_assert(sizeof(MiiEditAppletOutput) == 0x20, "MiiEditAppletOutput has incorrect size."); + +// This is nn::mii::AppletOutputForCharInfoEditing +struct MiiEditAppletOutputForCharInfoEditing { + MiiEditResult result{}; + MiiEditCharInfo char_info{}; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80, + "MiiEditAppletOutputForCharInfoEditing has incorrect size."); + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_profile_select.cpp b/src/core/hle/service/am/frontend/applet_profile_select.cpp new file mode 100644 index 000000000..5d71f985e --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_profile_select.cpp @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/assert.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/profile_select.h" +#include "core/hle/service/acc/errors.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_profile_select.h" +#include "core/hle/service/am/storage.h" + +namespace Service::AM::Frontend { + +ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::ProfileSelectApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +ProfileSelect::~ProfileSelect() = default; + +void ProfileSelect::Initialize() { + complete = false; + status = ResultSuccess; + final_data.clear(); + + FrontendApplet::Initialize(); + profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; + + const auto user_config_storage = broker.PopNormalDataToApplet(); + ASSERT(user_config_storage != nullptr); + const auto& user_config = user_config_storage->GetData(); + + LOG_INFO(Service_AM, "Initializing Profile Select Applet with version={}", + profile_select_version); + + switch (profile_select_version) { + case ProfileSelectAppletVersion::Version1: + ASSERT(user_config.size() == sizeof(UiSettingsV1)); + std::memcpy(&config_old, user_config.data(), sizeof(UiSettingsV1)); + break; + case ProfileSelectAppletVersion::Version2: + case ProfileSelectAppletVersion::Version3: + ASSERT(user_config.size() == sizeof(UiSettings)); + std::memcpy(&config, user_config.data(), sizeof(UiSettings)); + break; + default: + UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); + break; + } +} + +bool ProfileSelect::TransactionComplete() const { + return complete; +} + +Result ProfileSelect::GetStatus() const { + return status; +} + +void ProfileSelect::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void ProfileSelect::Execute() { + if (complete) { + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(final_data))); + return; + } + + Core::Frontend::ProfileSelectParameters parameters{}; + + switch (profile_select_version) { + case ProfileSelectAppletVersion::Version1: + parameters = { + .mode = config_old.mode, + .invalid_uid_list = config_old.invalid_uid_list, + .display_options = config_old.display_options, + .purpose = UserSelectionPurpose::General, + }; + break; + case ProfileSelectAppletVersion::Version2: + case ProfileSelectAppletVersion::Version3: + parameters = { + .mode = config.mode, + .invalid_uid_list = config.invalid_uid_list, + .display_options = config.display_options, + .purpose = config.purpose, + }; + break; + default: + UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); + break; + } + + frontend.SelectProfile([this](std::optional uuid) { SelectionComplete(uuid); }, + parameters); +} + +void ProfileSelect::SelectionComplete(std::optional uuid) { + UiReturnArg output{}; + + if (uuid.has_value() && uuid->IsValid()) { + output.result = 0; + output.uuid_selected = *uuid; + } else { + status = Account::ResultCancelledByUser; + output.result = Account::ResultCancelledByUser.raw; + output.uuid_selected = Common::InvalidUUID; + } + + final_data = std::vector(sizeof(UiReturnArg)); + std::memcpy(final_data.data(), &output, final_data.size()); + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(final_data))); + broker.SignalStateChanged(); +} + +Result ProfileSelect::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_profile_select.h b/src/core/hle/service/am/frontend/applet_profile_select.h new file mode 100644 index 000000000..43ec67c8e --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_profile_select.h @@ -0,0 +1,143 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/common_funcs.h" +#include "common/uuid.h" +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} + +namespace Service::AM::Frontend { + +enum class ProfileSelectAppletVersion : u32 { + Version1 = 0x1, // 1.0.0+ + Version2 = 0x10000, // 2.0.0+ + Version3 = 0x20000, // 6.0.0+ +}; + +// This is nn::account::UiMode +enum class UiMode { + UserSelector, + UserCreator, + EnsureNetworkServiceAccountAvailable, + UserIconEditor, + UserNicknameEditor, + UserCreatorForStarter, + NintendoAccountAuthorizationRequestContext, + IntroduceExternalNetworkServiceAccount, + IntroduceExternalNetworkServiceAccountForRegistration, + NintendoAccountNnidLinker, + LicenseRequirementsForNetworkService, + LicenseRequirementsForNetworkServiceWithUserContextImpl, + UserCreatorForImmediateNaLoginTest, + UserQualificationPromoter, +}; + +// This is nn::account::UserSelectionPurpose +enum class UserSelectionPurpose { + General, + GameCardRegistration, + EShopLaunch, + EShopItemShow, + PicturePost, + NintendoAccountLinkage, + SettingsUpdate, + SaveDataDeletion, + UserMigration, + SaveDataTransfer, +}; + +// This is nn::account::NintendoAccountStartupDialogType +enum class NintendoAccountStartupDialogType { + LoginAndCreate, + Login, + Create, +}; + +// This is nn::account::UserSelectionSettingsForSystemService +struct UserSelectionSettingsForSystemService { + UserSelectionPurpose purpose; + bool enable_user_creation; + INSERT_PADDING_BYTES(0x3); +}; +static_assert(sizeof(UserSelectionSettingsForSystemService) == 0x8, + "UserSelectionSettingsForSystemService has incorrect size."); + +struct UiSettingsDisplayOptions { + bool is_network_service_account_required; + bool is_skip_enabled; + bool is_system_or_launcher; + bool is_registration_permitted; + bool show_skip_button; + bool additional_select; + bool show_user_selector; + bool is_unqualified_user_selectable; +}; +static_assert(sizeof(UiSettingsDisplayOptions) == 0x8, + "UiSettingsDisplayOptions has incorrect size."); + +struct UiSettingsV1 { + UiMode mode; + INSERT_PADDING_BYTES(0x4); + std::array invalid_uid_list; + u64 application_id; + UiSettingsDisplayOptions display_options; +}; +static_assert(sizeof(UiSettingsV1) == 0x98, "UiSettings has incorrect size."); + +// This is nn::account::UiSettings +struct UiSettings { + UiMode mode; + INSERT_PADDING_BYTES(0x4); + std::array invalid_uid_list; + u64 application_id; + UiSettingsDisplayOptions display_options; + UserSelectionPurpose purpose; + INSERT_PADDING_BYTES(0x4); +}; +static_assert(sizeof(UiSettings) == 0xA0, "UiSettings has incorrect size."); + +// This is nn::account::UiReturnArg +struct UiReturnArg { + u64 result; + Common::UUID uuid_selected; +}; +static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); + +class ProfileSelect final : public FrontendApplet { +public: + explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::ProfileSelectApplet& frontend_); + ~ProfileSelect() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void SelectionComplete(std::optional uuid); + +private: + const Core::Frontend::ProfileSelectApplet& frontend; + + UiSettings config; + UiSettingsV1 config_old; + ProfileSelectAppletVersion profile_select_version; + + bool complete = false; + Result status = ResultSuccess; + std::vector final_data; + Core::System& system; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard.cpp b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp new file mode 100644 index 000000000..7974995cc --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp @@ -0,0 +1,1277 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_software_keyboard.h" +#include "core/hle/service/am/storage.h" + +namespace Service::AM::Frontend { + +namespace { + +// The maximum number of UTF-16 characters that can be input into the swkbd text field. +constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500; + +constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType); +constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4; +constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC; + +constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) { + switch (text_check_result) { + case SwkbdTextCheckResult::Success: + return "Success"; + case SwkbdTextCheckResult::Failure: + return "Failure"; + case SwkbdTextCheckResult::Confirm: + return "Confirm"; + case SwkbdTextCheckResult::Silent: + return "Silent"; + default: + UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result); + return "Unknown"; + } +} + +void SetReplyBase(std::vector& reply, SwkbdState state, SwkbdReplyType reply_type) { + std::memcpy(reply.data(), &state, sizeof(SwkbdState)); + std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType)); +} + +} // Anonymous namespace + +SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, + Core::Frontend::SoftwareKeyboardApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + +SoftwareKeyboard::~SoftwareKeyboard() = default; + +void SoftwareKeyboard::Initialize() { + FrontendApplet::Initialize(); + + LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", + applet_mode); + + LOG_DEBUG(Service_AM, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + swkbd_applet_version = SwkbdAppletVersion{common_args.library_version}; + + switch (applet_mode) { + case LibraryAppletMode::AllForeground: + InitializeForeground(); + break; + case LibraryAppletMode::Background: + case LibraryAppletMode::BackgroundIndirectDisplay: + InitializeBackground(applet_mode); + break; + default: + ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode); + break; + } +} + +bool SoftwareKeyboard::TransactionComplete() const { + return complete; +} + +Result SoftwareKeyboard::GetStatus() const { + return status; +} + +void SoftwareKeyboard::ExecuteInteractive() { + if (complete) { + return; + } + + if (is_background) { + ProcessInlineKeyboardRequest(); + } else { + ProcessTextCheck(); + } +} + +void SoftwareKeyboard::Execute() { + if (complete) { + return; + } + + if (is_background) { + return; + } + + ShowNormalKeyboard(); +} + +void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text, + bool confirmed) { + if (complete) { + return; + } + + if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) { + if (confirmed) { + SubmitNormalOutputAndExit(result, submitted_text); + } else { + SubmitForTextCheck(submitted_text); + } + } else { + SubmitNormalOutputAndExit(result, submitted_text); + } +} + +void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text, + s32 cursor_position) { + if (complete) { + return; + } + + current_text = std::move(submitted_text); + current_cursor_position = cursor_position; + + if (inline_use_utf8) { + switch (reply_type) { + case SwkbdReplyType::ChangedString: + reply_type = SwkbdReplyType::ChangedStringUtf8; + break; + case SwkbdReplyType::MovedCursor: + reply_type = SwkbdReplyType::MovedCursorUtf8; + break; + case SwkbdReplyType::DecidedEnter: + reply_type = SwkbdReplyType::DecidedEnterUtf8; + break; + default: + break; + } + } + + if (use_changed_string_v2) { + switch (reply_type) { + case SwkbdReplyType::ChangedString: + reply_type = SwkbdReplyType::ChangedStringV2; + break; + case SwkbdReplyType::ChangedStringUtf8: + reply_type = SwkbdReplyType::ChangedStringUtf8V2; + break; + default: + break; + } + } + + if (use_moved_cursor_v2) { + switch (reply_type) { + case SwkbdReplyType::MovedCursor: + reply_type = SwkbdReplyType::MovedCursorV2; + break; + case SwkbdReplyType::MovedCursorUtf8: + reply_type = SwkbdReplyType::MovedCursorUtf8V2; + break; + default: + break; + } + } + + SendReply(reply_type); +} + +void SoftwareKeyboard::InitializeForeground() { + LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet."); + + is_background = false; + + const auto swkbd_config_storage = broker.PopNormalDataToApplet(); + ASSERT(swkbd_config_storage != nullptr); + + const auto& swkbd_config_data = swkbd_config_storage->GetData(); + ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon)); + + std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon)); + + switch (swkbd_applet_version) { + case SwkbdAppletVersion::Version5: + case SwkbdAppletVersion::Version65542: + ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld)); + std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), + sizeof(SwkbdConfigOld)); + break; + case SwkbdAppletVersion::Version196615: + case SwkbdAppletVersion::Version262152: + case SwkbdAppletVersion::Version327689: + ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2)); + std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), + sizeof(SwkbdConfigOld2)); + break; + case SwkbdAppletVersion::Version393227: + case SwkbdAppletVersion::Version524301: + ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew)); + std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), + sizeof(SwkbdConfigNew)); + break; + default: + UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version, + swkbd_config_data.size()); + ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew)); + std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), + sizeof(SwkbdConfigNew)); + break; + } + + const auto work_buffer_storage = broker.PopNormalDataToApplet(); + ASSERT(work_buffer_storage != nullptr); + + if (swkbd_config_common.initial_string_length == 0) { + InitializeFrontendNormalKeyboard(); + return; + } + + const auto& work_buffer = work_buffer_storage->GetData(); + + std::vector initial_string(swkbd_config_common.initial_string_length); + + std::memcpy(initial_string.data(), + work_buffer.data() + swkbd_config_common.initial_string_offset, + swkbd_config_common.initial_string_length * sizeof(char16_t)); + + initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(), + initial_string.size()); + + LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text)); + + InitializeFrontendNormalKeyboard(); +} + +void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) { + LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet."); + + is_background = true; + + const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(swkbd_inline_initialize_arg_storage != nullptr); + + const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); + ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg)); + + std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(), + swkbd_inline_initialize_arg.size()); + + if (swkbd_initialize_arg.library_applet_mode_flag) { + ASSERT(library_applet_mode == LibraryAppletMode::Background); + } else { + ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay); + } +} + +void SoftwareKeyboard::ProcessTextCheck() { + const auto text_check_storage = broker.PopInteractiveDataToApplet(); + ASSERT(text_check_storage != nullptr); + + const auto& text_check_data = text_check_storage->GetData(); + ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck)); + + SwkbdTextCheck swkbd_text_check; + + std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck)); + + std::u16string text_check_message = [this, &swkbd_text_check]() -> std::u16string { + if (swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure || + swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm) { + return swkbd_config_common.use_utf8 + ? Common::UTF8ToUTF16(Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast( + swkbd_text_check.text_check_message.data()), + swkbd_text_check.text_check_message.size() * sizeof(char16_t))) + : Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_text_check.text_check_message.data(), + swkbd_text_check.text_check_message.size()); + } else { + return u""; + } + }(); + + LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}", + GetTextCheckResultName(swkbd_text_check.text_check_result), + Common::UTF16ToUTF8(text_check_message)); + + switch (swkbd_text_check.text_check_result) { + case SwkbdTextCheckResult::Success: + SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text); + break; + case SwkbdTextCheckResult::Failure: + ShowTextCheckDialog(SwkbdTextCheckResult::Failure, std::move(text_check_message)); + break; + case SwkbdTextCheckResult::Confirm: + ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, std::move(text_check_message)); + break; + case SwkbdTextCheckResult::Silent: + default: + break; + } +} + +void SoftwareKeyboard::ProcessInlineKeyboardRequest() { + const auto request_data_storage = broker.PopInteractiveDataToApplet(); + ASSERT(request_data_storage != nullptr); + + const auto& request_data = request_data_storage->GetData(); + ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand)); + + SwkbdRequestCommand request_command; + + std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand)); + + switch (request_command) { + case SwkbdRequestCommand::Finalize: + RequestFinalize(request_data); + break; + case SwkbdRequestCommand::SetUserWordInfo: + RequestSetUserWordInfo(request_data); + break; + case SwkbdRequestCommand::SetCustomizeDic: + RequestSetCustomizeDic(request_data); + break; + case SwkbdRequestCommand::Calc: + RequestCalc(request_data); + break; + case SwkbdRequestCommand::SetCustomizedDictionaries: + RequestSetCustomizedDictionaries(request_data); + break; + case SwkbdRequestCommand::UnsetCustomizedDictionaries: + RequestUnsetCustomizedDictionaries(request_data); + break; + case SwkbdRequestCommand::SetChangedStringV2Flag: + RequestSetChangedStringV2Flag(request_data); + break; + case SwkbdRequestCommand::SetMovedCursorV2Flag: + RequestSetMovedCursorV2Flag(request_data); + break; + default: + UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command); + break; + } +} + +void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, + std::u16string submitted_text) { + std::vector out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE); + + if (swkbd_config_common.use_utf8) { + std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text); + + LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result, + utf8_submitted_text); + + std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); + std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(), + utf8_submitted_text.size()); + } else { + LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result, + Common::UTF16ToUTF8(submitted_text)); + + std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); + std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(), + submitted_text.size() * sizeof(char16_t)); + } + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + + ExitKeyboard(); +} + +void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { + current_text = std::move(submitted_text); + + std::vector out_data(sizeof(u64) + STRING_BUFFER_SIZE); + + if (swkbd_config_common.use_utf8) { + std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text); + // Include the null terminator in the buffer size. + const u64 buffer_size = utf8_submitted_text.size() + 1; + + LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size, + utf8_submitted_text); + + std::memcpy(out_data.data(), &buffer_size, sizeof(u64)); + std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(), + utf8_submitted_text.size()); + } else { + // Include the null terminator in the buffer size. + const u64 buffer_size = (current_text.size() + 1) * sizeof(char16_t); + + LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size, + Common::UTF16ToUTF8(current_text)); + + std::memcpy(out_data.data(), &buffer_size, sizeof(u64)); + std::memcpy(out_data.data() + sizeof(u64), current_text.data(), + current_text.size() * sizeof(char16_t)); + } + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(out_data))); +} + +void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { + switch (reply_type) { + case SwkbdReplyType::FinishedInitialize: + ReplyFinishedInitialize(); + break; + case SwkbdReplyType::Default: + ReplyDefault(); + break; + case SwkbdReplyType::ChangedString: + ReplyChangedString(); + break; + case SwkbdReplyType::MovedCursor: + ReplyMovedCursor(); + break; + case SwkbdReplyType::MovedTab: + ReplyMovedTab(); + break; + case SwkbdReplyType::DecidedEnter: + ReplyDecidedEnter(); + break; + case SwkbdReplyType::DecidedCancel: + ReplyDecidedCancel(); + break; + case SwkbdReplyType::ChangedStringUtf8: + ReplyChangedStringUtf8(); + break; + case SwkbdReplyType::MovedCursorUtf8: + ReplyMovedCursorUtf8(); + break; + case SwkbdReplyType::DecidedEnterUtf8: + ReplyDecidedEnterUtf8(); + break; + case SwkbdReplyType::UnsetCustomizeDic: + ReplyUnsetCustomizeDic(); + break; + case SwkbdReplyType::ReleasedUserWordInfo: + ReplyReleasedUserWordInfo(); + break; + case SwkbdReplyType::UnsetCustomizedDictionaries: + ReplyUnsetCustomizedDictionaries(); + break; + case SwkbdReplyType::ChangedStringV2: + ReplyChangedStringV2(); + break; + case SwkbdReplyType::MovedCursorV2: + ReplyMovedCursorV2(); + break; + case SwkbdReplyType::ChangedStringUtf8V2: + ReplyChangedStringUtf8V2(); + break; + case SwkbdReplyType::MovedCursorUtf8V2: + ReplyMovedCursorUtf8V2(); + break; + default: + UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type); + ReplyDefault(); + break; + } +} + +void SoftwareKeyboard::ChangeState(SwkbdState state) { + swkbd_state = state; + + ReplyDefault(); +} + +void SoftwareKeyboard::InitializeFrontendNormalKeyboard() { + std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size()); + + std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size()); + + std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size()); + + std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size()); + + const u32 max_text_length = + swkbd_config_common.max_text_length > 0 && + swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH + ? swkbd_config_common.max_text_length + : DEFAULT_MAX_TEXT_LENGTH; + + const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length + ? swkbd_config_common.min_text_length + : 0; + + const s32 initial_cursor_position = [this] { + switch (swkbd_config_common.initial_cursor_position) { + case SwkbdInitialCursorPosition::Start: + default: + return 0; + case SwkbdInitialCursorPosition::End: + return static_cast(initial_text.size()); + } + }(); + + const auto text_draw_type = [this, max_text_length] { + switch (swkbd_config_common.text_draw_type) { + case SwkbdTextDrawType::Line: + default: + return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; + case SwkbdTextDrawType::Box: + case SwkbdTextDrawType::DownloadCode: + return swkbd_config_common.text_draw_type; + } + }(); + + const auto enable_return_button = + text_draw_type == SwkbdTextDrawType::Box ? swkbd_config_common.enable_return_button : false; + + const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227 + ? swkbd_config_new.disable_cancel_button + : false; + + Core::Frontend::KeyboardInitializeParameters initialize_parameters{ + .ok_text{std::move(ok_text)}, + .header_text{std::move(header_text)}, + .sub_text{std::move(sub_text)}, + .guide_text{std::move(guide_text)}, + .initial_text{initial_text}, + .left_optional_symbol_key{swkbd_config_common.left_optional_symbol_key}, + .right_optional_symbol_key{swkbd_config_common.right_optional_symbol_key}, + .max_text_length{max_text_length}, + .min_text_length{min_text_length}, + .initial_cursor_position{initial_cursor_position}, + .type{swkbd_config_common.type}, + .password_mode{swkbd_config_common.password_mode}, + .text_draw_type{text_draw_type}, + .key_disable_flags{swkbd_config_common.key_disable_flags}, + .use_blur_background{swkbd_config_common.use_blur_background}, + .enable_backspace_button{true}, + .enable_return_button{enable_return_button}, + .disable_cancel_button{disable_cancel_button}, + }; + + frontend.InitializeKeyboard( + false, std::move(initialize_parameters), + [this](SwkbdResult result, std::u16string submitted_text, bool confirmed) { + SubmitTextNormal(result, submitted_text, confirmed); + }, + {}); +} + +void SoftwareKeyboard::InitializeFrontendInlineKeyboard( + Core::Frontend::KeyboardInitializeParameters initialize_parameters) { + frontend.InitializeKeyboard( + true, std::move(initialize_parameters), {}, + [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) { + SubmitTextInline(reply_type, submitted_text, cursor_position); + }); +} + +void SoftwareKeyboard::InitializeFrontendInlineKeyboardOld() { + const auto& appear_arg = swkbd_calc_arg_old.appear_arg; + + std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + appear_arg.ok_text.data(), appear_arg.ok_text.size()); + + const u32 max_text_length = + appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH + ? appear_arg.max_text_length + : DEFAULT_MAX_TEXT_LENGTH; + + const u32 min_text_length = + appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; + + const s32 initial_cursor_position = current_cursor_position > 0 ? current_cursor_position : 0; + + const auto text_draw_type = + max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; + + Core::Frontend::KeyboardInitializeParameters initialize_parameters{ + .ok_text{std::move(ok_text)}, + .header_text{}, + .sub_text{}, + .guide_text{}, + .initial_text{current_text}, + .left_optional_symbol_key{appear_arg.left_optional_symbol_key}, + .right_optional_symbol_key{appear_arg.right_optional_symbol_key}, + .max_text_length{max_text_length}, + .min_text_length{min_text_length}, + .initial_cursor_position{initial_cursor_position}, + .type{appear_arg.type}, + .password_mode{SwkbdPasswordMode::Disabled}, + .text_draw_type{text_draw_type}, + .key_disable_flags{appear_arg.key_disable_flags}, + .use_blur_background{false}, + .enable_backspace_button{swkbd_calc_arg_old.enable_backspace_button}, + .enable_return_button{appear_arg.enable_return_button}, + .disable_cancel_button{appear_arg.disable_cancel_button}, + }; + + InitializeFrontendInlineKeyboard(std::move(initialize_parameters)); +} + +void SoftwareKeyboard::InitializeFrontendInlineKeyboardNew() { + const auto& appear_arg = swkbd_calc_arg_new.appear_arg; + + std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + appear_arg.ok_text.data(), appear_arg.ok_text.size()); + + const u32 max_text_length = + appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH + ? appear_arg.max_text_length + : DEFAULT_MAX_TEXT_LENGTH; + + const u32 min_text_length = + appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; + + const s32 initial_cursor_position = current_cursor_position > 0 ? current_cursor_position : 0; + + const auto text_draw_type = + max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; + + Core::Frontend::KeyboardInitializeParameters initialize_parameters{ + .ok_text{std::move(ok_text)}, + .header_text{}, + .sub_text{}, + .guide_text{}, + .initial_text{current_text}, + .left_optional_symbol_key{appear_arg.left_optional_symbol_key}, + .right_optional_symbol_key{appear_arg.right_optional_symbol_key}, + .max_text_length{max_text_length}, + .min_text_length{min_text_length}, + .initial_cursor_position{initial_cursor_position}, + .type{appear_arg.type}, + .password_mode{SwkbdPasswordMode::Disabled}, + .text_draw_type{text_draw_type}, + .key_disable_flags{appear_arg.key_disable_flags}, + .use_blur_background{false}, + .enable_backspace_button{swkbd_calc_arg_new.enable_backspace_button}, + .enable_return_button{appear_arg.enable_return_button}, + .disable_cancel_button{appear_arg.disable_cancel_button}, + }; + + InitializeFrontendInlineKeyboard(std::move(initialize_parameters)); +} + +void SoftwareKeyboard::ShowNormalKeyboard() { + frontend.ShowNormalKeyboard(); +} + +void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result, + std::u16string text_check_message) { + frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message)); +} + +void SoftwareKeyboard::ShowInlineKeyboard( + Core::Frontend::InlineAppearParameters appear_parameters) { + frontend.ShowInlineKeyboard(std::move(appear_parameters)); + + ChangeState(SwkbdState::InitializedIsShown); +} + +void SoftwareKeyboard::ShowInlineKeyboardOld() { + if (swkbd_state != SwkbdState::InitializedIsHidden) { + return; + } + + ChangeState(SwkbdState::InitializedIsAppearing); + + const auto& appear_arg = swkbd_calc_arg_old.appear_arg; + + const u32 max_text_length = + appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH + ? appear_arg.max_text_length + : DEFAULT_MAX_TEXT_LENGTH; + + const u32 min_text_length = + appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; + + Core::Frontend::InlineAppearParameters appear_parameters{ + .max_text_length{max_text_length}, + .min_text_length{min_text_length}, + .key_top_scale_x{swkbd_calc_arg_old.key_top_scale_x}, + .key_top_scale_y{swkbd_calc_arg_old.key_top_scale_y}, + .key_top_translate_x{swkbd_calc_arg_old.key_top_translate_x}, + .key_top_translate_y{swkbd_calc_arg_old.key_top_translate_y}, + .type{appear_arg.type}, + .key_disable_flags{appear_arg.key_disable_flags}, + .key_top_as_floating{swkbd_calc_arg_old.key_top_as_floating}, + .enable_backspace_button{swkbd_calc_arg_old.enable_backspace_button}, + .enable_return_button{appear_arg.enable_return_button}, + .disable_cancel_button{appear_arg.disable_cancel_button}, + }; + + ShowInlineKeyboard(std::move(appear_parameters)); +} + +void SoftwareKeyboard::ShowInlineKeyboardNew() { + if (swkbd_state != SwkbdState::InitializedIsHidden) { + return; + } + + ChangeState(SwkbdState::InitializedIsAppearing); + + const auto& appear_arg = swkbd_calc_arg_new.appear_arg; + + const u32 max_text_length = + appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH + ? appear_arg.max_text_length + : DEFAULT_MAX_TEXT_LENGTH; + + const u32 min_text_length = + appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; + + Core::Frontend::InlineAppearParameters appear_parameters{ + .max_text_length{max_text_length}, + .min_text_length{min_text_length}, + .key_top_scale_x{swkbd_calc_arg_new.key_top_scale_x}, + .key_top_scale_y{swkbd_calc_arg_new.key_top_scale_y}, + .key_top_translate_x{swkbd_calc_arg_new.key_top_translate_x}, + .key_top_translate_y{swkbd_calc_arg_new.key_top_translate_y}, + .type{appear_arg.type}, + .key_disable_flags{appear_arg.key_disable_flags}, + .key_top_as_floating{swkbd_calc_arg_new.key_top_as_floating}, + .enable_backspace_button{swkbd_calc_arg_new.enable_backspace_button}, + .enable_return_button{appear_arg.enable_return_button}, + .disable_cancel_button{appear_arg.disable_cancel_button}, + }; + + ShowInlineKeyboard(std::move(appear_parameters)); +} + +void SoftwareKeyboard::HideInlineKeyboard() { + if (swkbd_state != SwkbdState::InitializedIsShown) { + return; + } + + ChangeState(SwkbdState::InitializedIsDisappearing); + + frontend.HideInlineKeyboard(); + + ChangeState(SwkbdState::InitializedIsHidden); +} + +void SoftwareKeyboard::InlineTextChanged() { + Core::Frontend::InlineTextParameters text_parameters{ + .input_text{current_text}, + .cursor_position{current_cursor_position}, + }; + + frontend.InlineTextChanged(std::move(text_parameters)); +} + +void SoftwareKeyboard::ExitKeyboard() { + complete = true; + status = ResultSuccess; + + frontend.ExitKeyboard(); + + broker.SignalStateChanged(); +} + +Result SoftwareKeyboard::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +// Inline Software Keyboard Requests + +void SoftwareKeyboard::RequestFinalize(const std::vector& request_data) { + LOG_DEBUG(Service_AM, "Processing Request: Finalize"); + + ChangeState(SwkbdState::NotInitialized); + + ExitKeyboard(); +} + +void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector& request_data) { + LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented."); + + ReplyReleasedUserWordInfo(); +} + +void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector& request_data) { + LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented."); +} + +void SoftwareKeyboard::RequestCalc(const std::vector& request_data) { + LOG_DEBUG(Service_AM, "Processing Request: Calc"); + + ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon)); + + std::memcpy(&swkbd_calc_arg_common, request_data.data() + sizeof(SwkbdRequestCommand), + sizeof(SwkbdCalcArgCommon)); + + switch (swkbd_calc_arg_common.calc_arg_size) { + case sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgOld): + ASSERT(request_data.size() == + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgOld)); + std::memcpy(&swkbd_calc_arg_old, + request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon), + sizeof(SwkbdCalcArgOld)); + RequestCalcOld(); + break; + case sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew): + ASSERT(request_data.size() == + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew)); + std::memcpy(&swkbd_calc_arg_new, + request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon), + sizeof(SwkbdCalcArgNew)); + RequestCalcNew(); + break; + default: + UNIMPLEMENTED_MSG("Unknown SwkbdCalcArg size={}", swkbd_calc_arg_common.calc_arg_size); + ASSERT(request_data.size() >= + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon) + sizeof(SwkbdCalcArgNew)); + std::memcpy(&swkbd_calc_arg_new, + request_data.data() + sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArgCommon), + sizeof(SwkbdCalcArgNew)); + RequestCalcNew(); + break; + } +} + +void SoftwareKeyboard::RequestCalcOld() { + if (swkbd_calc_arg_common.flags.set_input_text) { + current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_calc_arg_old.input_text.data(), swkbd_calc_arg_old.input_text.size()); + } + + if (swkbd_calc_arg_common.flags.set_cursor_position) { + current_cursor_position = swkbd_calc_arg_old.cursor_position; + } + + if (swkbd_calc_arg_common.flags.set_utf8_mode) { + inline_use_utf8 = swkbd_calc_arg_old.utf8_mode; + } + + if (swkbd_state <= SwkbdState::InitializedIsHidden && + swkbd_calc_arg_common.flags.unset_customize_dic) { + ReplyUnsetCustomizeDic(); + } + + if (swkbd_state <= SwkbdState::InitializedIsHidden && + swkbd_calc_arg_common.flags.unset_user_word_info) { + ReplyReleasedUserWordInfo(); + } + + if (swkbd_state == SwkbdState::NotInitialized && + swkbd_calc_arg_common.flags.set_initialize_arg) { + InitializeFrontendInlineKeyboardOld(); + + ChangeState(SwkbdState::InitializedIsHidden); + + ReplyFinishedInitialize(); + } + + if (!swkbd_calc_arg_common.flags.set_initialize_arg && + (swkbd_calc_arg_common.flags.set_input_text || + swkbd_calc_arg_common.flags.set_cursor_position)) { + InlineTextChanged(); + } + + if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg_common.flags.appear) { + ShowInlineKeyboardOld(); + return; + } + + if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg_common.flags.disappear) { + HideInlineKeyboard(); + return; + } +} + +void SoftwareKeyboard::RequestCalcNew() { + if (swkbd_calc_arg_common.flags.set_input_text) { + current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + swkbd_calc_arg_new.input_text.data(), swkbd_calc_arg_new.input_text.size()); + } + + if (swkbd_calc_arg_common.flags.set_cursor_position) { + current_cursor_position = swkbd_calc_arg_new.cursor_position; + } + + if (swkbd_calc_arg_common.flags.set_utf8_mode) { + inline_use_utf8 = swkbd_calc_arg_new.utf8_mode; + } + + if (swkbd_state <= SwkbdState::InitializedIsHidden && + swkbd_calc_arg_common.flags.unset_customize_dic) { + ReplyUnsetCustomizeDic(); + } + + if (swkbd_state <= SwkbdState::InitializedIsHidden && + swkbd_calc_arg_common.flags.unset_user_word_info) { + ReplyReleasedUserWordInfo(); + } + + if (swkbd_state == SwkbdState::NotInitialized && + swkbd_calc_arg_common.flags.set_initialize_arg) { + InitializeFrontendInlineKeyboardNew(); + + ChangeState(SwkbdState::InitializedIsHidden); + + ReplyFinishedInitialize(); + } + + if (!swkbd_calc_arg_common.flags.set_initialize_arg && + (swkbd_calc_arg_common.flags.set_input_text || + swkbd_calc_arg_common.flags.set_cursor_position)) { + InlineTextChanged(); + } + + if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg_common.flags.appear) { + ShowInlineKeyboardNew(); + return; + } + + if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg_common.flags.disappear) { + HideInlineKeyboard(); + return; + } +} + +void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector& request_data) { + LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented."); +} + +void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector& request_data) { + LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries"); + + ReplyUnsetCustomizedDictionaries(); +} + +void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector& request_data) { + LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag"); + + ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1); + + std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1); +} + +void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector& request_data) { + LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag"); + + ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1); + + std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1); +} + +// Inline Software Keyboard Replies + +void SoftwareKeyboard::ReplyFinishedInitialize() { + LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize"); + + std::vector reply(REPLY_BASE_SIZE + 1); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyDefault() { + LOG_DEBUG(Service_AM, "Sending Reply: Default"); + + std::vector reply(REPLY_BASE_SIZE); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyChangedString() { + LOG_DEBUG(Service_AM, "Sending Reply: ChangedString"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString); + + const SwkbdChangedStringArg changed_string_arg{ + .text_length{static_cast(current_text.size())}, + .dictionary_start_cursor_position{-1}, + .dictionary_end_cursor_position{-1}, + .cursor_position{current_cursor_position}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), + current_text.size() * sizeof(char16_t)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, + sizeof(SwkbdChangedStringArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyMovedCursor() { + LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor); + + const SwkbdMovedCursorArg moved_cursor_arg{ + .text_length{static_cast(current_text.size())}, + .cursor_position{current_cursor_position}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), + current_text.size() * sizeof(char16_t)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, + sizeof(SwkbdMovedCursorArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyMovedTab() { + LOG_DEBUG(Service_AM, "Sending Reply: MovedTab"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab); + + const SwkbdMovedTabArg moved_tab_arg{ + .text_length{static_cast(current_text.size())}, + .cursor_position{current_cursor_position}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), + current_text.size() * sizeof(char16_t)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, + sizeof(SwkbdMovedTabArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyDecidedEnter() { + LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter); + + const SwkbdDecidedEnterArg decided_enter_arg{ + .text_length{static_cast(current_text.size())}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), + current_text.size() * sizeof(char16_t)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, + sizeof(SwkbdDecidedEnterArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + + HideInlineKeyboard(); +} + +void SoftwareKeyboard::ReplyDecidedCancel() { + LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel"); + + std::vector reply(REPLY_BASE_SIZE); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + + HideInlineKeyboard(); +} + +void SoftwareKeyboard::ReplyChangedStringUtf8() { + LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8); + + std::string utf8_current_text = Common::UTF16ToUTF8(current_text); + + const SwkbdChangedStringArg changed_string_arg{ + .text_length{static_cast(current_text.size())}, + .dictionary_start_cursor_position{-1}, + .dictionary_end_cursor_position{-1}, + .cursor_position{current_cursor_position}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, + sizeof(SwkbdChangedStringArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyMovedCursorUtf8() { + LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8); + + std::string utf8_current_text = Common::UTF16ToUTF8(current_text); + + const SwkbdMovedCursorArg moved_cursor_arg{ + .text_length{static_cast(current_text.size())}, + .cursor_position{current_cursor_position}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, + sizeof(SwkbdMovedCursorArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyDecidedEnterUtf8() { + LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg)); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8); + + std::string utf8_current_text = Common::UTF16ToUTF8(current_text); + + const SwkbdDecidedEnterArg decided_enter_arg{ + .text_length{static_cast(current_text.size())}, + }; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, + sizeof(SwkbdDecidedEnterArg)); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + + HideInlineKeyboard(); +} + +void SoftwareKeyboard::ReplyUnsetCustomizeDic() { + LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic"); + + std::vector reply(REPLY_BASE_SIZE); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyReleasedUserWordInfo() { + LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo"); + + std::vector reply(REPLY_BASE_SIZE); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { + LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries"); + + std::vector reply(REPLY_BASE_SIZE); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyChangedStringV2() { + LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2); + + const SwkbdChangedStringArg changed_string_arg{ + .text_length{static_cast(current_text.size())}, + .dictionary_start_cursor_position{-1}, + .dictionary_end_cursor_position{-1}, + .cursor_position{current_cursor_position}, + }; + + constexpr u8 flag = 0; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), + current_text.size() * sizeof(char16_t)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, + sizeof(SwkbdChangedStringArg)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), + &flag, 1); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyMovedCursorV2() { + LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2); + + const SwkbdMovedCursorArg moved_cursor_arg{ + .text_length{static_cast(current_text.size())}, + .cursor_position{current_cursor_position}, + }; + + constexpr u8 flag = 0; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), + current_text.size() * sizeof(char16_t)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, + sizeof(SwkbdMovedCursorArg)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), + &flag, 1); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyChangedStringUtf8V2() { + LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2); + + std::string utf8_current_text = Common::UTF16ToUTF8(current_text); + + const SwkbdChangedStringArg changed_string_arg{ + .text_length{static_cast(current_text.size())}, + .dictionary_start_cursor_position{-1}, + .dictionary_end_cursor_position{-1}, + .cursor_position{current_cursor_position}, + }; + + constexpr u8 flag = 0; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, + sizeof(SwkbdChangedStringArg)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), + &flag, 1); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { + LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2"); + + std::vector reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1); + + SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2); + + std::string utf8_current_text = Common::UTF16ToUTF8(current_text); + + const SwkbdMovedCursorArg moved_cursor_arg{ + .text_length{static_cast(current_text.size())}, + .cursor_position{current_cursor_position}, + }; + + constexpr u8 flag = 0; + + std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, + sizeof(SwkbdMovedCursorArg)); + std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), + &flag, 1); + + broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard.h b/src/core/hle/service/am/frontend/applet_software_keyboard.h new file mode 100644 index 000000000..00ad0add3 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.h @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} + +namespace Core::Frontend { +struct KeyboardInitializeParameters; +struct InlineAppearParameters; +} // namespace Core::Frontend + +namespace Service::AM::Frontend { + +class SoftwareKeyboard final : public FrontendApplet { +public: + explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, + Core::Frontend::SoftwareKeyboardApplet& frontend_); + ~SoftwareKeyboard() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + /** + * Submits the input text to the application. + * If text checking is enabled, the application will verify the input text. + * If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted. + * This should only be used by the normal software keyboard. + * + * @param result SwkbdResult enum + * @param submitted_text UTF-16 encoded string + * @param confirmed Whether the text has been confirmed after TextCheckResult::Confirm + */ + void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text, bool confirmed); + + /** + * Submits the input text to the application. + * If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted. + * This should only be used by the inline software keyboard. + * + * @param reply_type SwkbdReplyType enum + * @param submitted_text UTF-16 encoded string + * @param cursor_position The current position of the text cursor + */ + void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text, + s32 cursor_position); + +private: + /// Initializes the normal software keyboard. + void InitializeForeground(); + + /// Initializes the inline software keyboard. + void InitializeBackground(LibraryAppletMode library_applet_mode); + + /// Processes the text check sent by the application. + void ProcessTextCheck(); + + /// Processes the inline software keyboard request command sent by the application. + void ProcessInlineKeyboardRequest(); + + /// Submits the input text and exits the applet. + void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text); + + /// Submits the input text for text checking. + void SubmitForTextCheck(std::u16string submitted_text); + + /// Sends a reply to the application after processing a request command. + void SendReply(SwkbdReplyType reply_type); + + /// Changes the inline keyboard state. + void ChangeState(SwkbdState state); + + /** + * Signals the frontend to initialize the normal software keyboard with common parameters. + * Note that this does not cause the keyboard to appear. + * Use the ShowNormalKeyboard() functions to cause the keyboard to appear. + */ + void InitializeFrontendNormalKeyboard(); + + /** + * Signals the frontend to initialize the inline software keyboard with common parameters. + * Note that this does not cause the keyboard to appear. + * Use the ShowInlineKeyboard() to cause the keyboard to appear. + */ + void InitializeFrontendInlineKeyboard( + Core::Frontend::KeyboardInitializeParameters initialize_parameters); + + void InitializeFrontendInlineKeyboardOld(); + void InitializeFrontendInlineKeyboardNew(); + + /// Signals the frontend to show the normal software keyboard. + void ShowNormalKeyboard(); + + /// Signals the frontend to show the text check dialog. + void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result, + std::u16string text_check_message); + + /// Signals the frontend to show the inline software keyboard. + void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters); + + void ShowInlineKeyboardOld(); + void ShowInlineKeyboardNew(); + + /// Signals the frontend to hide the inline software keyboard. + void HideInlineKeyboard(); + + /// Signals the frontend that the current inline keyboard text has changed. + void InlineTextChanged(); + + /// Signals both the frontend and application that the software keyboard is exiting. + void ExitKeyboard(); + + // Inline Software Keyboard Requests + + void RequestFinalize(const std::vector& request_data); + void RequestSetUserWordInfo(const std::vector& request_data); + void RequestSetCustomizeDic(const std::vector& request_data); + void RequestCalc(const std::vector& request_data); + void RequestCalcOld(); + void RequestCalcNew(); + void RequestSetCustomizedDictionaries(const std::vector& request_data); + void RequestUnsetCustomizedDictionaries(const std::vector& request_data); + void RequestSetChangedStringV2Flag(const std::vector& request_data); + void RequestSetMovedCursorV2Flag(const std::vector& request_data); + + // Inline Software Keyboard Replies + + void ReplyFinishedInitialize(); + void ReplyDefault(); + void ReplyChangedString(); + void ReplyMovedCursor(); + void ReplyMovedTab(); + void ReplyDecidedEnter(); + void ReplyDecidedCancel(); + void ReplyChangedStringUtf8(); + void ReplyMovedCursorUtf8(); + void ReplyDecidedEnterUtf8(); + void ReplyUnsetCustomizeDic(); + void ReplyReleasedUserWordInfo(); + void ReplyUnsetCustomizedDictionaries(); + void ReplyChangedStringV2(); + void ReplyMovedCursorV2(); + void ReplyChangedStringUtf8V2(); + void ReplyMovedCursorUtf8V2(); + + Core::Frontend::SoftwareKeyboardApplet& frontend; + Core::System& system; + + SwkbdAppletVersion swkbd_applet_version; + + SwkbdConfigCommon swkbd_config_common; + SwkbdConfigOld swkbd_config_old; + SwkbdConfigOld2 swkbd_config_old2; + SwkbdConfigNew swkbd_config_new; + std::u16string initial_text; + + SwkbdState swkbd_state{SwkbdState::NotInitialized}; + SwkbdInitializeArg swkbd_initialize_arg; + SwkbdCalcArgCommon swkbd_calc_arg_common; + SwkbdCalcArgOld swkbd_calc_arg_old; + SwkbdCalcArgNew swkbd_calc_arg_new; + bool use_changed_string_v2{false}; + bool use_moved_cursor_v2{false}; + bool inline_use_utf8{false}; + s32 current_cursor_position{}; + + std::u16string current_text; + + bool is_background{false}; + + bool complete{false}; + Result status{ResultSuccess}; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard_types.h b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h new file mode 100644 index 000000000..a25ff2a6d --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h @@ -0,0 +1,354 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "common/uuid.h" + +namespace Service::AM::Frontend { + +constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; +constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; +constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128; +constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256; +constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4; + +enum class SwkbdAppletVersion : u32_le { + Version5 = 0x5, // 1.0.0 + Version65542 = 0x10006, // 2.0.0 - 2.3.0 + Version196615 = 0x30007, // 3.0.0 - 3.0.2 + Version262152 = 0x40008, // 4.0.0 - 4.1.0 + Version327689 = 0x50009, // 5.0.0 - 5.1.0 + Version393227 = 0x6000B, // 6.0.0 - 7.0.1 + Version524301 = 0x8000D, // 8.0.0+ +}; + +enum class SwkbdType : u32 { + Normal, + NumberPad, + Qwerty, + Unknown3, + Latin, + SimplifiedChinese, + TraditionalChinese, + Korean, +}; + +enum class SwkbdInitialCursorPosition : u32 { + Start, + End, +}; + +enum class SwkbdPasswordMode : u32 { + Disabled, + Enabled, +}; + +enum class SwkbdTextDrawType : u32 { + Line, + Box, + DownloadCode, +}; + +enum class SwkbdResult : u32 { + Ok, + Cancel, +}; + +enum class SwkbdTextCheckResult : u32 { + Success, + Failure, + Confirm, + Silent, +}; + +enum class SwkbdState : u32 { + NotInitialized = 0x0, + InitializedIsHidden = 0x1, + InitializedIsAppearing = 0x2, + InitializedIsShown = 0x3, + InitializedIsDisappearing = 0x4, +}; + +enum class SwkbdRequestCommand : u32 { + Finalize = 0x4, + SetUserWordInfo = 0x6, + SetCustomizeDic = 0x7, + Calc = 0xA, + SetCustomizedDictionaries = 0xB, + UnsetCustomizedDictionaries = 0xC, + SetChangedStringV2Flag = 0xD, + SetMovedCursorV2Flag = 0xE, +}; + +enum class SwkbdReplyType : u32 { + FinishedInitialize = 0x0, + Default = 0x1, + ChangedString = 0x2, + MovedCursor = 0x3, + MovedTab = 0x4, + DecidedEnter = 0x5, + DecidedCancel = 0x6, + ChangedStringUtf8 = 0x7, + MovedCursorUtf8 = 0x8, + DecidedEnterUtf8 = 0x9, + UnsetCustomizeDic = 0xA, + ReleasedUserWordInfo = 0xB, + UnsetCustomizedDictionaries = 0xC, + ChangedStringV2 = 0xD, + MovedCursorV2 = 0xE, + ChangedStringUtf8V2 = 0xF, + MovedCursorUtf8V2 = 0x10, +}; + +struct SwkbdKeyDisableFlags { + union { + u32 raw{}; + + BitField<1, 1, u32> space; + BitField<2, 1, u32> at; + BitField<3, 1, u32> percent; + BitField<4, 1, u32> slash; + BitField<5, 1, u32> backslash; + BitField<6, 1, u32> numbers; + BitField<7, 1, u32> download_code; + BitField<8, 1, u32> username; + }; +}; +static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size."); + +struct SwkbdConfigCommon { + SwkbdType type{}; + std::array ok_text{}; + char16_t left_optional_symbol_key{}; + char16_t right_optional_symbol_key{}; + bool use_prediction{}; + INSERT_PADDING_BYTES(1); + SwkbdKeyDisableFlags key_disable_flags{}; + SwkbdInitialCursorPosition initial_cursor_position{}; + std::array header_text{}; + std::array sub_text{}; + std::array guide_text{}; + u32 max_text_length{}; + u32 min_text_length{}; + SwkbdPasswordMode password_mode{}; + SwkbdTextDrawType text_draw_type{}; + bool enable_return_button{}; + bool use_utf8{}; + bool use_blur_background{}; + INSERT_PADDING_BYTES(1); + u32 initial_string_offset{}; + u32 initial_string_length{}; + u32 user_dictionary_offset{}; + u32 user_dictionary_entries{}; + bool use_text_check{}; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size."); + +#pragma pack(push, 4) +// SwkbdAppletVersion 0x5, 0x10006 +struct SwkbdConfigOld { + INSERT_PADDING_WORDS(1); + VAddr text_check_callback{}; +}; +static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon), + "SwkbdConfigOld has incorrect size."); + +// SwkbdAppletVersion 0x30007, 0x40008, 0x50009 +struct SwkbdConfigOld2 { + INSERT_PADDING_WORDS(1); + VAddr text_check_callback{}; + std::array text_grouping{}; +}; +static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon), + "SwkbdConfigOld2 has incorrect size."); + +// SwkbdAppletVersion 0x6000B, 0x8000D +struct SwkbdConfigNew { + std::array text_grouping{}; + std::array customized_dictionary_set_entries{}; + u8 total_customized_dictionary_set_entries{}; + bool disable_cancel_button{}; + INSERT_PADDING_BYTES(18); +}; +static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon), + "SwkbdConfigNew has incorrect size."); +#pragma pack(pop) + +struct SwkbdTextCheck { + SwkbdTextCheckResult text_check_result{}; + std::array text_check_message{}; +}; +static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size."); + +struct SwkbdCalcArgFlags { + union { + u64 raw{}; + + BitField<0, 1, u64> set_initialize_arg; + BitField<1, 1, u64> set_volume; + BitField<2, 1, u64> appear; + BitField<3, 1, u64> set_input_text; + BitField<4, 1, u64> set_cursor_position; + BitField<5, 1, u64> set_utf8_mode; + BitField<6, 1, u64> unset_customize_dic; + BitField<7, 1, u64> disappear; + BitField<8, 1, u64> unknown; + BitField<9, 1, u64> set_key_top_translate_scale; + BitField<10, 1, u64> unset_user_word_info; + BitField<11, 1, u64> set_disable_hardware_keyboard; + }; +}; +static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size."); + +struct SwkbdInitializeArg { + u32 unknown{}; + bool library_applet_mode_flag{}; + bool is_above_hos_500{}; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size."); + +struct SwkbdAppearArgOld { + SwkbdType type{}; + std::array ok_text{}; + char16_t left_optional_symbol_key{}; + char16_t right_optional_symbol_key{}; + bool use_prediction{}; + bool disable_cancel_button{}; + SwkbdKeyDisableFlags key_disable_flags{}; + u32 max_text_length{}; + u32 min_text_length{}; + bool enable_return_button{}; + INSERT_PADDING_BYTES(3); + u32 flags{}; + bool is_use_save_data{}; + INSERT_PADDING_BYTES(7); + Common::UUID user_id{}; +}; +static_assert(sizeof(SwkbdAppearArgOld) == 0x48, "SwkbdAppearArg has incorrect size."); + +struct SwkbdAppearArgNew { + SwkbdType type{}; + std::array ok_text{}; + char16_t left_optional_symbol_key{}; + char16_t right_optional_symbol_key{}; + bool use_prediction{}; + bool disable_cancel_button{}; + SwkbdKeyDisableFlags key_disable_flags{}; + u32 max_text_length{}; + u32 min_text_length{}; + bool enable_return_button{}; + INSERT_PADDING_BYTES(3); + u32 flags{}; + bool is_use_save_data{}; + INSERT_PADDING_BYTES(7); + Common::UUID user_id{}; + u64 start_sampling_number{}; + INSERT_PADDING_WORDS(8); +}; +static_assert(sizeof(SwkbdAppearArgNew) == 0x70, "SwkbdAppearArg has incorrect size."); + +struct SwkbdCalcArgCommon { + u32 unknown{}; + u16 calc_arg_size{}; + INSERT_PADDING_BYTES(2); + SwkbdCalcArgFlags flags{}; + SwkbdInitializeArg initialize_arg{}; +}; +static_assert(sizeof(SwkbdCalcArgCommon) == 0x18, "SwkbdCalcArgCommon has incorrect size."); + +struct SwkbdCalcArgOld { + f32 volume{}; + s32 cursor_position{}; + SwkbdAppearArgOld appear_arg{}; + std::array input_text{}; + bool utf8_mode{}; + INSERT_PADDING_BYTES(1); + bool enable_backspace_button{}; + INSERT_PADDING_BYTES(3); + bool key_top_as_floating{}; + bool footer_scalable{}; + bool alpha_enabled_in_input_mode{}; + u8 input_mode_fade_type{}; + bool disable_touch{}; + bool disable_hardware_keyboard{}; + INSERT_PADDING_BYTES(8); + f32 key_top_scale_x{}; + f32 key_top_scale_y{}; + f32 key_top_translate_x{}; + f32 key_top_translate_y{}; + f32 key_top_bg_alpha{}; + f32 footer_bg_alpha{}; + f32 balloon_scale{}; + INSERT_PADDING_WORDS(4); + u8 se_group{}; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(SwkbdCalcArgOld) == 0x4A0 - sizeof(SwkbdCalcArgCommon), + "SwkbdCalcArgOld has incorrect size."); + +struct SwkbdCalcArgNew { + SwkbdAppearArgNew appear_arg{}; + f32 volume{}; + s32 cursor_position{}; + std::array input_text{}; + bool utf8_mode{}; + INSERT_PADDING_BYTES(1); + bool enable_backspace_button{}; + INSERT_PADDING_BYTES(3); + bool key_top_as_floating{}; + bool footer_scalable{}; + bool alpha_enabled_in_input_mode{}; + u8 input_mode_fade_type{}; + bool disable_touch{}; + bool disable_hardware_keyboard{}; + INSERT_PADDING_BYTES(8); + f32 key_top_scale_x{}; + f32 key_top_scale_y{}; + f32 key_top_translate_x{}; + f32 key_top_translate_y{}; + f32 key_top_bg_alpha{}; + f32 footer_bg_alpha{}; + f32 balloon_scale{}; + INSERT_PADDING_WORDS(4); + u8 se_group{}; + INSERT_PADDING_BYTES(3); + INSERT_PADDING_WORDS(8); +}; +static_assert(sizeof(SwkbdCalcArgNew) == 0x4E8 - sizeof(SwkbdCalcArgCommon), + "SwkbdCalcArgNew has incorrect size."); + +struct SwkbdChangedStringArg { + u32 text_length{}; + s32 dictionary_start_cursor_position{}; + s32 dictionary_end_cursor_position{}; + s32 cursor_position{}; +}; +static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size."); + +struct SwkbdMovedCursorArg { + u32 text_length{}; + s32 cursor_position{}; +}; +static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size."); + +struct SwkbdMovedTabArg { + u32 text_length{}; + s32 cursor_position{}; +}; +static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size."); + +struct SwkbdDecidedEnterArg { + u32 text_length{}; +}; +static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp new file mode 100644 index 000000000..28a20c72b --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp @@ -0,0 +1,508 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/system_archive.h" +#include "core/file_sys/vfs/vfs_vector.h" +#include "core/frontend/applets/web_browser.h" +#include "core/hle/result.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/frontend/applet_web_browser.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/ns/iplatform_service_manager.h" +#include "core/loader/loader.h" + +namespace Service::AM::Frontend { + +namespace { + +template +void ParseRawValue(T& value, const std::vector& data) { + static_assert(std::is_trivially_copyable_v, + "It's undefined behavior to use memcpy with non-trivially copyable objects"); + std::memcpy(&value, data.data(), data.size()); +} + +template +T ParseRawValue(const std::vector& data) { + T value; + ParseRawValue(value, data); + return value; +} + +std::string ParseStringValue(const std::vector& data) { + return Common::StringFromFixedZeroTerminatedBuffer(reinterpret_cast(data.data()), + data.size()); +} + +std::string GetMainURL(const std::string& url) { + const auto index = url.find('?'); + + if (index == std::string::npos) { + return url; + } + + return url.substr(0, index); +} + +std::string ResolveURL(const std::string& url) { + const auto index = url.find_first_of('%'); + + if (index == std::string::npos) { + return url; + } + + return url.substr(0, index) + "lp1" + url.substr(index + 1); +} + +WebArgInputTLVMap ReadWebArgs(const std::vector& web_arg, WebArgHeader& web_arg_header) { + std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader)); + + if (web_arg.size() == sizeof(WebArgHeader)) { + return {}; + } + + WebArgInputTLVMap input_tlv_map; + + u64 current_offset = sizeof(WebArgHeader); + + for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) { + if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) { + return input_tlv_map; + } + + WebArgInputTLV input_tlv; + std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV)); + + current_offset += sizeof(WebArgInputTLV); + + if (web_arg.size() < current_offset + input_tlv.arg_data_size) { + return input_tlv_map; + } + + std::vector data(input_tlv.arg_data_size); + std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size); + + current_offset += input_tlv.arg_data_size; + + input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data)); + } + + return input_tlv_map; +} + +FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id, + FileSys::ContentRecordType nca_type) { + if (nca_type == FileSys::ContentRecordType::Data) { + const auto nca = + system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type); + + if (nca == nullptr) { + LOG_ERROR(Service_AM, + "NCA of type={} with title_id={:016X} is not found in the System NAND!", + nca_type, title_id); + return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); + } + + return nca->GetRomFS(); + } else { + const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type); + + if (nca == nullptr) { + if (nca_type == FileSys::ContentRecordType::HtmlDocument) { + LOG_WARNING(Service_AM, "Falling back to AppLoader to get the RomFS."); + FileSys::VirtualFile romfs; + system.GetAppLoader().ReadManualRomFS(romfs); + if (romfs != nullptr) { + return romfs; + } + } + + LOG_ERROR(Service_AM, + "NCA of type={} with title_id={:016X} is not found in the ContentProvider!", + nca_type, title_id); + return nullptr; + } + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + + return pm.PatchRomFS(nca.get(), nca->GetRomFS(), nca_type); + } +} + +void ExtractSharedFonts(Core::System& system) { + static constexpr std::array DECRYPTED_SHARED_FONTS{ + "FontStandard.ttf", + "FontChineseSimplified.ttf", + "FontExtendedChineseSimplified.ttf", + "FontChineseTraditional.ttf", + "FontKorean.ttf", + "FontNintendoExtended.ttf", + "FontNintendoExtended2.ttf", + }; + + const auto fonts_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts"; + + for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { + const auto font_file_path = fonts_dir / DECRYPTED_SHARED_FONTS[i]; + + if (Common::FS::Exists(font_file_path)) { + continue; + } + + const auto font = NS::SHARED_FONTS[i]; + const auto font_title_id = static_cast(font.first); + + const auto nca = system.GetFileSystemController().GetSystemNANDContents()->GetEntry( + font_title_id, FileSys::ContentRecordType::Data); + + FileSys::VirtualFile romfs; + + if (!nca) { + romfs = FileSys::SystemArchive::SynthesizeSystemArchive(font_title_id); + } else { + romfs = nca->GetRomFS(); + } + + if (!romfs) { + LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} cannot be extracted!", + font_title_id); + continue; + } + + const auto extracted_romfs = FileSys::ExtractRomFS(romfs); + + if (!extracted_romfs) { + LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} failed to extract!", + font_title_id); + continue; + } + + const auto font_file = extracted_romfs->GetFile(font.second); + + if (!font_file) { + LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} has no font file \"{}\"!", + font_title_id, font.second); + continue; + } + + std::vector font_data_u32(font_file->GetSize() / sizeof(u32)); + font_file->ReadBytes(font_data_u32.data(), font_file->GetSize()); + + std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), + Common::swap32); + + std::vector decrypted_data(font_file->GetSize() - 8); + + NS::DecryptSharedFontToTTF(font_data_u32, decrypted_data); + + FileSys::VirtualFile decrypted_font = std::make_shared( + std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); + + const auto temp_dir = system.GetFilesystem()->CreateDirectory( + Common::FS::PathToUTF8String(fonts_dir), FileSys::OpenMode::ReadWrite); + + const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); + + FileSys::VfsRawCopy(decrypted_font, out_file); + } +} + +} // namespace + +WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::WebBrowserApplet& frontend_) + : FrontendApplet{system_, applet_mode_}, frontend(frontend_), system{system_} {} + +WebBrowser::~WebBrowser() = default; + +void WebBrowser::Initialize() { + FrontendApplet::Initialize(); + + LOG_INFO(Service_AM, "Initializing Web Browser Applet."); + + LOG_DEBUG(Service_AM, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + web_applet_version = WebAppletVersion{common_args.library_version}; + + const auto web_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(web_arg_storage != nullptr); + + const auto& web_arg = web_arg_storage->GetData(); + ASSERT_OR_EXECUTE(web_arg.size() >= sizeof(WebArgHeader), { return; }); + + web_arg_input_tlv_map = ReadWebArgs(web_arg, web_arg_header); + + LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}", + web_arg_header.total_tlv_entries, web_arg_header.shim_kind); + + ExtractSharedFonts(system); + + switch (web_arg_header.shim_kind) { + case ShimKind::Shop: + InitializeShop(); + break; + case ShimKind::Login: + InitializeLogin(); + break; + case ShimKind::Offline: + InitializeOffline(); + break; + case ShimKind::Share: + InitializeShare(); + break; + case ShimKind::Web: + InitializeWeb(); + break; + case ShimKind::Wifi: + InitializeWifi(); + break; + case ShimKind::Lobby: + InitializeLobby(); + break; + default: + ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); + break; + } +} + +bool WebBrowser::TransactionComplete() const { + return complete; +} + +Result WebBrowser::GetStatus() const { + return status; +} + +void WebBrowser::ExecuteInteractive() { + UNIMPLEMENTED_MSG("WebSession is not implemented"); +} + +void WebBrowser::Execute() { + switch (web_arg_header.shim_kind) { + case ShimKind::Shop: + ExecuteShop(); + break; + case ShimKind::Login: + ExecuteLogin(); + break; + case ShimKind::Offline: + ExecuteOffline(); + break; + case ShimKind::Share: + ExecuteShare(); + break; + case ShimKind::Web: + ExecuteWeb(); + break; + case ShimKind::Wifi: + ExecuteWifi(); + break; + case ShimKind::Lobby: + ExecuteLobby(); + break; + default: + ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind); + WebBrowserExit(WebExitReason::EndButtonPressed); + break; + } +} + +void WebBrowser::ExtractOfflineRomFS() { + LOG_DEBUG(Service_AM, "Extracting RomFS to {}", + Common::FS::PathToUTF8String(offline_cache_dir)); + + const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); + + const auto temp_dir = system.GetFilesystem()->CreateDirectory( + Common::FS::PathToUTF8String(offline_cache_dir), FileSys::OpenMode::ReadWrite); + + FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); +} + +void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) { + if ((web_arg_header.shim_kind == ShimKind::Share && + web_applet_version >= WebAppletVersion::Version196608) || + (web_arg_header.shim_kind == ShimKind::Web && + web_applet_version >= WebAppletVersion::Version524288)) { + // TODO: Push Output TLVs instead of a WebCommonReturnValue + } + + WebCommonReturnValue web_common_return_value; + + web_common_return_value.exit_reason = exit_reason; + std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size()); + web_common_return_value.last_url_size = last_url.size(); + + LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}", + exit_reason, last_url, last_url.size()); + + complete = true; + std::vector out_data(sizeof(WebCommonReturnValue)); + std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +Result WebBrowser::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + +bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const { + return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end(); +} + +std::optional> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) { + const auto map_it = web_arg_input_tlv_map.find(input_tlv_type); + + if (map_it == web_arg_input_tlv_map.end()) { + return std::nullopt; + } + + return map_it->second; +} + +void WebBrowser::InitializeShop() {} + +void WebBrowser::InitializeLogin() {} + +void WebBrowser::InitializeOffline() { + const auto document_path = + ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value()); + + const auto document_kind = + ParseRawValue(GetInputTLVData(WebArgInputTLVType::DocumentKind).value()); + + std::string additional_paths; + + switch (document_kind) { + case DocumentKind::OfflineHtmlPage: + default: + title_id = system.GetApplicationProcessProgramID(); + nca_type = FileSys::ContentRecordType::HtmlDocument; + additional_paths = "html-document"; + break; + case DocumentKind::ApplicationLegalInformation: + title_id = ParseRawValue(GetInputTLVData(WebArgInputTLVType::ApplicationID).value()); + nca_type = FileSys::ContentRecordType::LegalInformation; + break; + case DocumentKind::SystemDataPage: + title_id = ParseRawValue(GetInputTLVData(WebArgInputTLVType::SystemDataID).value()); + nca_type = FileSys::ContentRecordType::Data; + break; + } + + static constexpr std::array RESOURCE_TYPES{ + "manual", + "legal_information", + "system_data", + }; + + offline_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / + fmt::format("offline_web_applet_{}/{:016X}", + RESOURCE_TYPES[static_cast(document_kind) - 1], title_id); + + offline_document = Common::FS::ConcatPathSafe( + offline_cache_dir, fmt::format("{}/{}", additional_paths, document_path)); +} + +void WebBrowser::InitializeShare() {} + +void WebBrowser::InitializeWeb() { + external_url = ParseStringValue(GetInputTLVData(WebArgInputTLVType::InitialURL).value()); + + // Resolve Nintendo CDN URLs. + external_url = ResolveURL(external_url); +} + +void WebBrowser::InitializeWifi() {} + +void WebBrowser::InitializeLobby() {} + +void WebBrowser::ExecuteShop() { + LOG_WARNING(Service_AM, "(STUBBED) called, Shop Applet is not implemented"); + WebBrowserExit(WebExitReason::EndButtonPressed); +} + +void WebBrowser::ExecuteLogin() { + LOG_WARNING(Service_AM, "(STUBBED) called, Login Applet is not implemented"); + WebBrowserExit(WebExitReason::EndButtonPressed); +} + +void WebBrowser::ExecuteOffline() { + // TODO (Morph): This is a hack for WebSession foreground web applets such as those used by + // Super Mario 3D All-Stars. + // TODO (Morph): Implement WebSession. + if (applet_mode == LibraryAppletMode::AllForegroundInitiallyHidden) { + LOG_WARNING(Service_AM, "WebSession is not implemented"); + return; + } + + const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document)); + + if (!Common::FS::Exists(main_url)) { + offline_romfs = GetOfflineRomFS(system, title_id, nca_type); + + if (offline_romfs == nullptr) { + LOG_ERROR(Service_AM, + "RomFS with title_id={:016X} and nca_type={} cannot be extracted!", title_id, + nca_type); + WebBrowserExit(WebExitReason::WindowClosed); + return; + } + } + + LOG_INFO(Service_AM, "Opening offline document at {}", + Common::FS::PathToUTF8String(offline_document)); + + frontend.OpenLocalWebPage( + Common::FS::PathToUTF8String(offline_document), [this] { ExtractOfflineRomFS(); }, + [this](WebExitReason exit_reason, std::string last_url) { + WebBrowserExit(exit_reason, last_url); + }); +} + +void WebBrowser::ExecuteShare() { + LOG_WARNING(Service_AM, "(STUBBED) called, Share Applet is not implemented"); + WebBrowserExit(WebExitReason::EndButtonPressed); +} + +void WebBrowser::ExecuteWeb() { + LOG_INFO(Service_AM, "Opening external URL at {}", external_url); + + frontend.OpenExternalWebPage(external_url, + [this](WebExitReason exit_reason, std::string last_url) { + WebBrowserExit(exit_reason, last_url); + }); +} + +void WebBrowser::ExecuteWifi() { + LOG_WARNING(Service_AM, "(STUBBED) called, Wifi Applet is not implemented"); + WebBrowserExit(WebExitReason::EndButtonPressed); +} + +void WebBrowser::ExecuteLobby() { + LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); + WebBrowserExit(WebExitReason::EndButtonPressed); +} +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_web_browser.h b/src/core/hle/service/am/frontend/applet_web_browser.h new file mode 100644 index 000000000..613d8e9ea --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_web_browser.h @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "core/file_sys/vfs/vfs_types.h" +#include "core/hle/result.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" +#include "core/hle/service/am/frontend/applets.h" + +namespace Core { +class System; +} + +namespace FileSys { +enum class ContentRecordType : u8; +} + +namespace Service::AM::Frontend { + +class WebBrowser final : public FrontendApplet { +public: + WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::WebBrowserApplet& frontend_); + + ~WebBrowser() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + Result RequestExit() override; + + void ExtractOfflineRomFS(); + + void WebBrowserExit(WebExitReason exit_reason, std::string last_url = ""); + +private: + bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const; + + std::optional> GetInputTLVData(WebArgInputTLVType input_tlv_type); + + // Initializers for the various types of browser applets + void InitializeShop(); + void InitializeLogin(); + void InitializeOffline(); + void InitializeShare(); + void InitializeWeb(); + void InitializeWifi(); + void InitializeLobby(); + + // Executors for the various types of browser applets + void ExecuteShop(); + void ExecuteLogin(); + void ExecuteOffline(); + void ExecuteShare(); + void ExecuteWeb(); + void ExecuteWifi(); + void ExecuteLobby(); + + const Core::Frontend::WebBrowserApplet& frontend; + + bool complete{false}; + Result status{ResultSuccess}; + + WebAppletVersion web_applet_version{}; + WebArgHeader web_arg_header{}; + WebArgInputTLVMap web_arg_input_tlv_map; + + u64 title_id{}; + FileSys::ContentRecordType nca_type{}; + std::filesystem::path offline_cache_dir; + std::filesystem::path offline_document; + FileSys::VirtualFile offline_romfs; + + std::string external_url; + + Core::System& system; +}; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_web_browser_types.h b/src/core/hle/service/am/frontend/applet_web_browser_types.h new file mode 100644 index 000000000..2f7c05c24 --- /dev/null +++ b/src/core/hle/service/am/frontend/applet_web_browser_types.h @@ -0,0 +1,177 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" + +namespace Service::AM::Frontend { + +enum class WebAppletVersion : u32_le { + Version0 = 0x0, // Only used by WifiWebAuthApplet + Version131072 = 0x20000, // 1.0.0 - 2.3.0 + Version196608 = 0x30000, // 3.0.0 - 4.1.0 + Version327680 = 0x50000, // 5.0.0 - 5.1.0 + Version393216 = 0x60000, // 6.0.0 - 7.0.1 + Version524288 = 0x80000, // 8.0.0+ +}; + +enum class ShimKind : u32 { + Shop = 1, + Login = 2, + Offline = 3, + Share = 4, + Web = 5, + Wifi = 6, + Lobby = 7, +}; + +enum class WebExitReason : u32 { + EndButtonPressed = 0, + BackButtonPressed = 1, + ExitRequested = 2, + CallbackURL = 3, + WindowClosed = 4, + ErrorDialog = 7, +}; + +enum class WebArgInputTLVType : u16 { + InitialURL = 0x1, + CallbackURL = 0x3, + CallbackableURL = 0x4, + ApplicationID = 0x5, + DocumentPath = 0x6, + DocumentKind = 0x7, + SystemDataID = 0x8, + ShareStartPage = 0x9, + Whitelist = 0xA, + News = 0xB, + UserID = 0xE, + AlbumEntry0 = 0xF, + ScreenShotEnabled = 0x10, + EcClientCertEnabled = 0x11, + PlayReportEnabled = 0x13, + BootDisplayKind = 0x17, + BackgroundKind = 0x18, + FooterEnabled = 0x19, + PointerEnabled = 0x1A, + LeftStickMode = 0x1B, + KeyRepeatFrame1 = 0x1C, + KeyRepeatFrame2 = 0x1D, + BootAsMediaPlayerInverted = 0x1E, + DisplayURLKind = 0x1F, + BootAsMediaPlayer = 0x21, + ShopJumpEnabled = 0x22, + MediaAutoPlayEnabled = 0x23, + LobbyParameter = 0x24, + ApplicationAlbumEntry = 0x26, + JsExtensionEnabled = 0x27, + AdditionalCommentText = 0x28, + TouchEnabledOnContents = 0x29, + UserAgentAdditionalString = 0x2A, + AdditionalMediaData0 = 0x2B, + MediaPlayerAutoCloseEnabled = 0x2C, + PageCacheEnabled = 0x2D, + WebAudioEnabled = 0x2E, + YouTubeVideoWhitelist = 0x31, + FooterFixedKind = 0x32, + PageFadeEnabled = 0x33, + MediaCreatorApplicationRatingAge = 0x34, + BootLoadingIconEnabled = 0x35, + PageScrollIndicatorEnabled = 0x36, + MediaPlayerSpeedControlEnabled = 0x37, + AlbumEntry1 = 0x38, + AlbumEntry2 = 0x39, + AlbumEntry3 = 0x3A, + AdditionalMediaData1 = 0x3B, + AdditionalMediaData2 = 0x3C, + AdditionalMediaData3 = 0x3D, + BootFooterButton = 0x3E, + OverrideWebAudioVolume = 0x3F, + OverrideMediaAudioVolume = 0x40, + BootMode = 0x41, + WebSessionEnabled = 0x42, + MediaPlayerOfflineEnabled = 0x43, +}; + +enum class WebArgOutputTLVType : u16 { + ShareExitReason = 0x1, + LastURL = 0x2, + LastURLSize = 0x3, + SharePostResult = 0x4, + PostServiceName = 0x5, + PostServiceNameSize = 0x6, + PostID = 0x7, + PostIDSize = 0x8, + MediaPlayerAutoClosedByCompletion = 0x9, +}; + +enum class DocumentKind : u32 { + OfflineHtmlPage = 1, + ApplicationLegalInformation = 2, + SystemDataPage = 3, +}; + +enum class ShareStartPage : u32 { + Default, + Settings, +}; + +enum class BootDisplayKind : u32 { + Default, + White, + Black, +}; + +enum class BackgroundKind : u32 { + Default, +}; + +enum class LeftStickMode : u32 { + Pointer, + Cursor, +}; + +enum class WebSessionBootMode : u32 { + AllForeground, + AllForegroundInitiallyHidden, +}; + +struct WebArgHeader { + u16 total_tlv_entries{}; + INSERT_PADDING_BYTES(2); + ShimKind shim_kind{}; +}; +static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); + +struct WebArgInputTLV { + WebArgInputTLVType input_tlv_type{}; + u16 arg_data_size{}; + INSERT_PADDING_WORDS(1); +}; +static_assert(sizeof(WebArgInputTLV) == 0x8, "WebArgInputTLV has incorrect size."); + +struct WebArgOutputTLV { + WebArgOutputTLVType output_tlv_type{}; + u16 arg_data_size{}; + INSERT_PADDING_WORDS(1); +}; +static_assert(sizeof(WebArgOutputTLV) == 0x8, "WebArgOutputTLV has incorrect size."); + +struct WebCommonReturnValue { + WebExitReason exit_reason{}; + INSERT_PADDING_WORDS(1); + std::array last_url{}; + u64 last_url_size{}; +}; +static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); + +using WebArgInputTLVMap = std::unordered_map>; + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp new file mode 100644 index 000000000..4e8f806d7 --- /dev/null +++ b/src/core/hle/service/am/frontend/applets.cpp @@ -0,0 +1,341 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/assert.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/error.h" +#include "core/frontend/applets/general.h" +#include "core/frontend/applets/mii_edit.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/web_browser.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/frontend/applet_error.h" +#include "core/hle/service/am/frontend/applet_general.h" +#include "core/hle/service/am/frontend/applet_mii_edit.h" +#include "core/hle/service/am/frontend/applet_profile_select.h" +#include "core/hle/service/am/frontend/applet_software_keyboard.h" +#include "core/hle/service/am/frontend/applet_web_browser.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM::Frontend { + +AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) + : system{system_}, applet_mode{applet_mode_}, + service_context{system, "ILibraryAppletAccessor"} { + state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent"); + pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent"); + pop_interactive_out_data_event = + service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent"); +} + +AppletDataBroker::~AppletDataBroker() { + service_context.CloseEvent(state_changed_event); + service_context.CloseEvent(pop_out_data_event); + service_context.CloseEvent(pop_interactive_out_data_event); +} + +AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const { + std::vector> out_normal; + + for (const auto& storage : in_channel) { + out_normal.push_back(storage->GetData()); + } + + std::vector> out_interactive; + + for (const auto& storage : in_interactive_channel) { + out_interactive.push_back(storage->GetData()); + } + + return {std::move(out_normal), std::move(out_interactive)}; +} + +std::shared_ptr AppletDataBroker::PopNormalDataToGame() { + if (out_channel.empty()) + return nullptr; + + auto out = std::move(out_channel.front()); + out_channel.pop_front(); + pop_out_data_event->Clear(); + return out; +} + +std::shared_ptr AppletDataBroker::PopNormalDataToApplet() { + if (in_channel.empty()) + return nullptr; + + auto out = std::move(in_channel.front()); + in_channel.pop_front(); + return out; +} + +std::shared_ptr AppletDataBroker::PopInteractiveDataToGame() { + if (out_interactive_channel.empty()) + return nullptr; + + auto out = std::move(out_interactive_channel.front()); + out_interactive_channel.pop_front(); + pop_interactive_out_data_event->Clear(); + return out; +} + +std::shared_ptr AppletDataBroker::PopInteractiveDataToApplet() { + if (in_interactive_channel.empty()) + return nullptr; + + auto out = std::move(in_interactive_channel.front()); + in_interactive_channel.pop_front(); + return out; +} + +void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr&& storage) { + in_channel.emplace_back(std::move(storage)); +} + +void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr&& storage) { + out_channel.emplace_back(std::move(storage)); + pop_out_data_event->Signal(); +} + +void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr&& storage) { + in_interactive_channel.emplace_back(std::move(storage)); +} + +void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr&& storage) { + out_interactive_channel.emplace_back(std::move(storage)); + pop_interactive_out_data_event->Signal(); +} + +void AppletDataBroker::SignalStateChanged() { + state_changed_event->Signal(); + + switch (applet_mode) { + case LibraryAppletMode::AllForeground: + case LibraryAppletMode::AllForegroundInitiallyHidden: { + auto applet_oe = system.ServiceManager().GetService("appletOE"); + auto applet_ae = system.ServiceManager().GetService("appletAE"); + + if (applet_oe) { + applet_oe->GetMessageQueue()->FocusStateChanged(); + break; + } + + if (applet_ae) { + applet_ae->GetMessageQueue()->FocusStateChanged(); + break; + } + break; + } + default: + break; + } +} + +Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() { + return pop_out_data_event->GetReadableEvent(); +} + +Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() { + return pop_interactive_out_data_event->GetReadableEvent(); +} + +Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() { + return state_changed_event->GetReadableEvent(); +} + +FrontendApplet::FrontendApplet(Core::System& system_, LibraryAppletMode applet_mode_) + : broker{system_, applet_mode_}, applet_mode{applet_mode_} {} + +FrontendApplet::~FrontendApplet() = default; + +void FrontendApplet::Initialize() { + const auto common = broker.PopNormalDataToApplet(); + ASSERT(common != nullptr); + + const auto common_data = common->GetData(); + + ASSERT(common_data.size() >= sizeof(CommonArguments)); + std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); + + initialized = true; +} + +FrontendAppletSet::FrontendAppletSet() = default; + +FrontendAppletSet::FrontendAppletSet(CabinetApplet cabinet_applet, + ControllerApplet controller_applet, ErrorApplet error_applet, + MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, + PhotoViewer photo_viewer_, ProfileSelect profile_select_, + SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) + : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, + error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, + parental_controls{std::move(parental_controls_applet)}, + photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, + software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} + +FrontendAppletSet::~FrontendAppletSet() = default; + +FrontendAppletSet::FrontendAppletSet(FrontendAppletSet&&) noexcept = default; + +FrontendAppletSet& FrontendAppletSet::operator=(FrontendAppletSet&&) noexcept = default; + +FrontendAppletHolder::FrontendAppletHolder(Core::System& system_) : system{system_} {} + +FrontendAppletHolder::~FrontendAppletHolder() = default; + +const FrontendAppletSet& FrontendAppletHolder::GetFrontendAppletSet() const { + return frontend; +} + +NFP::CabinetMode FrontendAppletHolder::GetCabinetMode() const { + return cabinet_mode; +} + +AppletId FrontendAppletHolder::GetCurrentAppletId() const { + return current_applet_id; +} + +void FrontendAppletHolder::SetFrontendAppletSet(FrontendAppletSet set) { + if (set.cabinet != nullptr) { + frontend.cabinet = std::move(set.cabinet); + } + + if (set.controller != nullptr) { + frontend.controller = std::move(set.controller); + } + + if (set.error != nullptr) { + frontend.error = std::move(set.error); + } + + if (set.mii_edit != nullptr) { + frontend.mii_edit = std::move(set.mii_edit); + } + + if (set.parental_controls != nullptr) { + frontend.parental_controls = std::move(set.parental_controls); + } + + if (set.photo_viewer != nullptr) { + frontend.photo_viewer = std::move(set.photo_viewer); + } + + if (set.profile_select != nullptr) { + frontend.profile_select = std::move(set.profile_select); + } + + if (set.software_keyboard != nullptr) { + frontend.software_keyboard = std::move(set.software_keyboard); + } + + if (set.web_browser != nullptr) { + frontend.web_browser = std::move(set.web_browser); + } +} + +void FrontendAppletHolder::SetCabinetMode(NFP::CabinetMode mode) { + cabinet_mode = mode; +} + +void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) { + current_applet_id = applet_id; +} + +void FrontendAppletHolder::SetDefaultAppletFrontendSet() { + ClearAll(); + SetDefaultAppletsIfMissing(); +} + +void FrontendAppletHolder::SetDefaultAppletsIfMissing() { + if (frontend.cabinet == nullptr) { + frontend.cabinet = std::make_unique(); + } + + if (frontend.controller == nullptr) { + frontend.controller = + std::make_unique(system.HIDCore()); + } + + if (frontend.error == nullptr) { + frontend.error = std::make_unique(); + } + + if (frontend.mii_edit == nullptr) { + frontend.mii_edit = std::make_unique(); + } + + if (frontend.parental_controls == nullptr) { + frontend.parental_controls = + std::make_unique(); + } + + if (frontend.photo_viewer == nullptr) { + frontend.photo_viewer = std::make_unique(); + } + + if (frontend.profile_select == nullptr) { + frontend.profile_select = std::make_unique(); + } + + if (frontend.software_keyboard == nullptr) { + frontend.software_keyboard = + std::make_unique(); + } + + if (frontend.web_browser == nullptr) { + frontend.web_browser = std::make_unique(); + } +} + +void FrontendAppletHolder::ClearAll() { + frontend = {}; +} + +std::shared_ptr FrontendAppletHolder::GetApplet(AppletId id, + LibraryAppletMode mode) const { + switch (id) { + case AppletId::Auth: + return std::make_shared(system, mode, *frontend.parental_controls); + case AppletId::Cabinet: + return std::make_shared(system, mode, *frontend.cabinet); + case AppletId::Controller: + return std::make_shared(system, mode, *frontend.controller); + case AppletId::Error: + return std::make_shared(system, mode, *frontend.error); + case AppletId::ProfileSelect: + return std::make_shared(system, mode, *frontend.profile_select); + case AppletId::SoftwareKeyboard: + return std::make_shared(system, mode, *frontend.software_keyboard); + case AppletId::MiiEdit: + return std::make_shared(system, mode, *frontend.mii_edit); + case AppletId::Web: + case AppletId::Shop: + case AppletId::OfflineWeb: + case AppletId::LoginShare: + case AppletId::WebAuth: + return std::make_shared(system, mode, *frontend.web_browser); + case AppletId::PhotoViewer: + return std::make_shared(system, mode, *frontend.photo_viewer); + default: + UNIMPLEMENTED_MSG( + "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", + static_cast(id)); + return std::make_shared(system, id, mode); + } +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applets.h b/src/core/hle/service/am/frontend/applets.h new file mode 100644 index 000000000..f58147955 --- /dev/null +++ b/src/core/hle/service/am/frontend/applets.h @@ -0,0 +1,206 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/swap.h" +#include "core/hle/service/am/applet.h" + +union Result; + +namespace Core { +class System; +} + +namespace Core::Frontend { +class CabinetApplet; +class ControllerApplet; +class ECommerceApplet; +class ErrorApplet; +class MiiEditApplet; +class ParentalControlsApplet; +class PhotoViewerApplet; +class ProfileSelectApplet; +class SoftwareKeyboardApplet; +class WebBrowserApplet; +} // namespace Core::Frontend + +namespace Kernel { +class KernelCore; +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Service::NFP { +enum class CabinetMode : u8; +} // namespace Service::NFP + +namespace Service::AM { + +class IStorage; + +namespace Frontend { + +class AppletDataBroker final { +public: + explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_); + ~AppletDataBroker(); + + struct RawChannelData { + std::vector> normal; + std::vector> interactive; + }; + + // Retrieves but does not pop the data sent to applet. + RawChannelData PeekDataToAppletForDebug() const; + + std::shared_ptr PopNormalDataToGame(); + std::shared_ptr PopNormalDataToApplet(); + + std::shared_ptr PopInteractiveDataToGame(); + std::shared_ptr PopInteractiveDataToApplet(); + + void PushNormalDataFromGame(std::shared_ptr&& storage); + void PushNormalDataFromApplet(std::shared_ptr&& storage); + + void PushInteractiveDataFromGame(std::shared_ptr&& storage); + void PushInteractiveDataFromApplet(std::shared_ptr&& storage); + + void SignalStateChanged(); + + Kernel::KReadableEvent& GetNormalDataEvent(); + Kernel::KReadableEvent& GetInteractiveDataEvent(); + Kernel::KReadableEvent& GetStateChangedEvent(); + +private: + Core::System& system; + LibraryAppletMode applet_mode; + + KernelHelpers::ServiceContext service_context; + + // Queues are named from applet's perspective + + // PopNormalDataToApplet and PushNormalDataFromGame + std::deque> in_channel; + + // PopNormalDataToGame and PushNormalDataFromApplet + std::deque> out_channel; + + // PopInteractiveDataToApplet and PushInteractiveDataFromGame + std::deque> in_interactive_channel; + + // PopInteractiveDataToGame and PushInteractiveDataFromApplet + std::deque> out_interactive_channel; + + Kernel::KEvent* state_changed_event; + + // Signaled on PushNormalDataFromApplet + Kernel::KEvent* pop_out_data_event; + + // Signaled on PushInteractiveDataFromApplet + Kernel::KEvent* pop_interactive_out_data_event; +}; + +class FrontendApplet { +public: + explicit FrontendApplet(Core::System& system_, LibraryAppletMode applet_mode_); + virtual ~FrontendApplet(); + + virtual void Initialize(); + + virtual bool TransactionComplete() const = 0; + virtual Result GetStatus() const = 0; + virtual void ExecuteInteractive() = 0; + virtual void Execute() = 0; + virtual Result RequestExit() = 0; + + AppletDataBroker& GetBroker() { + return broker; + } + + const AppletDataBroker& GetBroker() const { + return broker; + } + + LibraryAppletMode GetLibraryAppletMode() const { + return applet_mode; + } + + bool IsInitialized() const { + return initialized; + } + +protected: + CommonArguments common_args{}; + AppletDataBroker broker; + LibraryAppletMode applet_mode; + bool initialized = false; +}; + +struct FrontendAppletSet { + using CabinetApplet = std::unique_ptr; + using ControllerApplet = std::unique_ptr; + using ErrorApplet = std::unique_ptr; + using MiiEdit = std::unique_ptr; + using ParentalControlsApplet = std::unique_ptr; + using PhotoViewer = std::unique_ptr; + using ProfileSelect = std::unique_ptr; + using SoftwareKeyboard = std::unique_ptr; + using WebBrowser = std::unique_ptr; + + FrontendAppletSet(); + FrontendAppletSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, + ErrorApplet error_applet, MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, + ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, + WebBrowser web_browser_); + ~FrontendAppletSet(); + + FrontendAppletSet(const FrontendAppletSet&) = delete; + FrontendAppletSet& operator=(const FrontendAppletSet&) = delete; + + FrontendAppletSet(FrontendAppletSet&&) noexcept; + FrontendAppletSet& operator=(FrontendAppletSet&&) noexcept; + + CabinetApplet cabinet; + ControllerApplet controller; + ErrorApplet error; + MiiEdit mii_edit; + ParentalControlsApplet parental_controls; + PhotoViewer photo_viewer; + ProfileSelect profile_select; + SoftwareKeyboard software_keyboard; + WebBrowser web_browser; +}; + +class FrontendAppletHolder { +public: + explicit FrontendAppletHolder(Core::System& system_); + ~FrontendAppletHolder(); + + const FrontendAppletSet& GetFrontendAppletSet() const; + NFP::CabinetMode GetCabinetMode() const; + AppletId GetCurrentAppletId() const; + + void SetFrontendAppletSet(FrontendAppletSet set); + void SetCabinetMode(NFP::CabinetMode mode); + void SetCurrentAppletId(AppletId applet_id); + void SetDefaultAppletFrontendSet(); + void SetDefaultAppletsIfMissing(); + void ClearAll(); + + std::shared_ptr GetApplet(AppletId id, LibraryAppletMode mode) const; + +private: + AppletId current_applet_id{}; + NFP::CabinetMode cabinet_mode{}; + + FrontendAppletSet frontend; + Core::System& system; +}; + +} // namespace Frontend +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_accessor.cpp b/src/core/hle/service/am/library_applet_accessor.cpp index 1cccdfcf2..dabbd6dbe 100644 --- a/src/core/hle/service/am/library_applet_accessor.cpp +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -9,7 +9,7 @@ namespace Service::AM { ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, - std::shared_ptr applet_) + std::shared_ptr applet_) : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { diff --git a/src/core/hle/service/am/library_applet_accessor.h b/src/core/hle/service/am/library_applet_accessor.h index 698467233..77f62906c 100644 --- a/src/core/hle/service/am/library_applet_accessor.h +++ b/src/core/hle/service/am/library_applet_accessor.h @@ -3,7 +3,7 @@ #pragma once -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/service.h" namespace Service::AM { @@ -11,7 +11,7 @@ namespace Service::AM { class ILibraryAppletAccessor final : public ServiceFramework { public: explicit ILibraryAppletAccessor(Core::System& system_, - std::shared_ptr applet_); + std::shared_ptr applet_); private: void GetAppletStateChangedEvent(HLERequestContext& ctx); @@ -28,7 +28,7 @@ private: void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); - std::shared_ptr applet; + std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp index c33f50a40..f80887517 100644 --- a/src/core/hle/service/am/library_applet_creator.cpp +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/kernel/k_transfer_memory.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" #include "core/hle/service/am/library_applet_creator.h" #include "core/hle/service/am/storage.h" @@ -28,14 +28,14 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default; void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto applet_id = rp.PopRaw(); - const auto applet_mode = rp.PopRaw(); + const auto applet_id = rp.PopRaw(); + const auto applet_mode = rp.PopRaw(); LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, applet_mode); - const auto& applet_manager{system.GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, applet_mode); + const auto& holder{system.GetFrontendAppletHolder()}; + const auto applet = holder.GetApplet(applet_id, applet_mode); if (applet == nullptr) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp index 0a12afbbd..c36f141f4 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -4,11 +4,11 @@ #include "core/core_timing.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am_results.h" -#include "core/hle/service/am/applets/applet_cabinet.h" -#include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/am/applets/applet_mii_edit_types.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_self_accessor.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/ipc_helpers.h" @@ -59,20 +59,20 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) // clang-format on RegisterHandlers(functions); - switch (system.GetAppletManager().GetCurrentAppletId()) { - case Applets::AppletId::Cabinet: + switch (system.GetFrontendAppletHolder().GetCurrentAppletId()) { + case AppletId::Cabinet: PushInShowCabinetData(); break; - case Applets::AppletId::MiiEdit: + case AppletId::MiiEdit: PushInShowMiiEditData(); break; - case Applets::AppletId::PhotoViewer: + case AppletId::PhotoViewer: PushInShowAlbum(); break; - case Applets::AppletId::SoftwareKeyboard: + case AppletId::SoftwareKeyboard: PushInShowSoftwareKeyboard(); break; - case Applets::AppletId::Controller: + case AppletId::Controller: PushInShowController(); break; default: @@ -117,15 +117,15 @@ void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { struct LibraryAppletInfo { - Applets::AppletId applet_id; - Applets::LibraryAppletMode library_applet_mode; + AppletId applet_id; + LibraryAppletMode library_applet_mode; }; LOG_WARNING(Service_AM, "(STUBBED) called"); const LibraryAppletInfo applet_info{ - .applet_id = system.GetAppletManager().GetCurrentAppletId(), - .library_applet_mode = Applets::LibraryAppletMode::AllForeground, + .applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(), + .library_applet_mode = LibraryAppletMode::AllForeground, }; IPC::ResponseBuilder rb{ctx, 4}; @@ -135,7 +135,7 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { struct AppletIdentityInfo { - Applets::AppletId applet_id; + AppletId applet_id; INSERT_PADDING_BYTES(0x4); u64 application_id; }; @@ -144,7 +144,7 @@ void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ct LOG_WARNING(Service_AM, "(STUBBED) called"); const AppletIdentityInfo applet_info{ - .applet_id = Applets::AppletId::QLaunch, + .applet_id = AppletId::QLaunch, .application_id = 0x0100000000001000ull, }; @@ -155,7 +155,7 @@ void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ct void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { struct AppletIdentityInfo { - Applets::AppletId applet_id; + AppletId applet_id; INSERT_PADDING_BYTES(0x4); u64 application_id; }; @@ -163,7 +163,7 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& LOG_WARNING(Service_AM, "(STUBBED) called"); const AppletIdentityInfo applet_info{ - .applet_id = Applets::AppletId::QLaunch, + .applet_id = AppletId::QLaunch, .application_id = 0x0100000000001000ull, }; @@ -208,11 +208,11 @@ void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext } void ILibraryAppletSelfAccessor::PushInShowAlbum() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, .library_version = 1, - .theme_color = Applets::ThemeColor::BasicBlack, + .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; @@ -225,16 +225,16 @@ void ILibraryAppletSelfAccessor::PushInShowAlbum() { } void ILibraryAppletSelfAccessor::PushInShowController() { - const Applets::CommonArguments common_args = { - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast(Applets::ControllerAppletVersion::Version8), - .theme_color = Applets::ThemeColor::BasicBlack, + const CommonArguments common_args = { + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast(Frontend::ControllerAppletVersion::Version8), + .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; - Applets::ControllerSupportArgNew user_args = { + Frontend::ControllerSupportArgNew user_args = { .header = {.player_count_min = 1, .player_count_max = 4, .enable_take_over_connection = true, @@ -247,13 +247,13 @@ void ILibraryAppletSelfAccessor::PushInShowController() { .explain_text = {}, }; - Applets::ControllerSupportArgPrivate private_args = { - .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), - .arg_size = sizeof(Applets::ControllerSupportArgNew), + Frontend::ControllerSupportArgPrivate private_args = { + .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate), + .arg_size = sizeof(Frontend::ControllerSupportArgNew), .is_home_menu = true, .flag_1 = true, - .mode = Applets::ControllerSupportMode::ShowControllerSupport, - .caller = Applets::ControllerSupportCaller:: + .mode = Frontend::ControllerSupportMode::ShowControllerSupport, + .caller = Frontend::ControllerSupportCaller:: Application, // switchbrew: Always zero except with // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, // which sets this to the input param @@ -274,19 +274,19 @@ void ILibraryAppletSelfAccessor::PushInShowController() { } void ILibraryAppletSelfAccessor::PushInShowCabinetData() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast(Applets::CabinetAppletVersion::Version1), - .theme_color = Applets::ThemeColor::BasicBlack, + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast(Frontend::CabinetAppletVersion::Version1), + .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; - const Applets::StartParamForAmiiboSettings amiibo_settings{ + const Frontend::StartParamForAmiiboSettings amiibo_settings{ .param_1 = 0, - .applet_mode = system.GetAppletManager().GetCabinetMode(), - .flags = Applets::CabinetFlags::None, + .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(), + .flags = Frontend::CabinetFlags::None, .amiibo_settings_1 = 0, .device_handle = 0, .tag_info{}, @@ -304,16 +304,16 @@ void ILibraryAppletSelfAccessor::PushInShowCabinetData() { void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { struct MiiEditV3 { - Applets::MiiEditAppletInputCommon common; - Applets::MiiEditAppletInputV3 input; + Frontend::MiiEditAppletInputCommon common; + Frontend::MiiEditAppletInputV3 input; }; static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); MiiEditV3 mii_arguments{ .common = { - .version = Applets::MiiEditAppletVersion::Version3, - .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, + .version = Frontend::MiiEditAppletVersion::Version3, + .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit, }, .input{}, }; @@ -325,32 +325,32 @@ void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { } void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast(Applets::SwkbdAppletVersion::Version524301), - .theme_color = Applets::ThemeColor::BasicBlack, + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast(Frontend::SwkbdAppletVersion::Version524301), + .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; std::vector initial_string(0); - const Applets::SwkbdConfigCommon swkbd_config{ - .type = Applets::SwkbdType::Qwerty, + const Frontend::SwkbdConfigCommon swkbd_config{ + .type = Frontend::SwkbdType::Qwerty, .ok_text{}, .left_optional_symbol_key{}, .right_optional_symbol_key{}, .use_prediction = false, .key_disable_flags{}, - .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start, .header_text{}, .sub_text{}, .guide_text{}, .max_text_length = 500, .min_text_length = 0, - .password_mode = Applets::SwkbdPasswordMode::Disabled, - .text_draw_type = Applets::SwkbdTextDrawType::Box, + .password_mode = Frontend::SwkbdPasswordMode::Disabled, + .text_draw_type = Frontend::SwkbdTextDrawType::Box, .enable_return_button = true, .use_utf8 = false, .use_blur_background = true, @@ -361,7 +361,7 @@ void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { .use_text_check = false, }; - Applets::SwkbdConfigNew swkbd_config_new{}; + Frontend::SwkbdConfigNew swkbd_config_new{}; std::vector argument_data(sizeof(arguments)); std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); @@ -370,7 +370,7 @@ void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, - sizeof(Applets::SwkbdConfigNew)); + sizeof(Frontend::SwkbdConfigNew)); std::memcpy(work_buffer.data(), initial_string.data(), swkbd_config.initial_string_length * sizeof(char16_t)); diff --git a/src/core/hle/service/am/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp index 7b3ab157f..7954abd7a 100644 --- a/src/core/hle/service/am/process_winding_controller.cpp +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" #include "core/hle/service/am/process_winding_controller.h" #include "core/hle/service/ipc_helpers.h" @@ -48,14 +48,14 @@ void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { } void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { - const auto applet_id = system.GetAppletManager().GetCurrentAppletId(); - const auto applet_mode = Applets::LibraryAppletMode::AllForeground; + const auto applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(); + const auto applet_mode = LibraryAppletMode::AllForeground; LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, applet_mode); - const auto& applet_manager{system.GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, applet_mode); + const auto& holder{system.GetFrontendAppletHolder()}; + const auto applet = holder.GetApplet(applet_id, applet_mode); if (applet == nullptr) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp index 0f495c871..d5de1bb2f 100644 --- a/src/core/hle/service/am/self_controller.cpp +++ b/src/core/hle/service/am/self_controller.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/self_controller.h" #include "core/hle/service/caps/caps_su.h" #include "core/hle/service/ipc_helpers.h" @@ -271,7 +271,7 @@ Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { return ResultSuccess; } - if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) { + if (system.GetFrontendAppletHolder().GetCurrentAppletId() <= AppletId::Application) { return VI::ResultOperationFailed; } diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index 79162a491..66edd6acd 100644 --- a/src/yuzu/applets/qt_profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp @@ -162,7 +162,7 @@ void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) { void QtProfileSelectionDialog::SetWindowTitle( const Core::Frontend::ProfileSelectParameters& parameters) { - using Service::AM::Applets::UiMode; + using Service::AM::Frontend::UiMode; switch (parameters.mode) { case UiMode::UserCreator: case UiMode::UserCreatorForStarter: @@ -193,7 +193,7 @@ void QtProfileSelectionDialog::SetWindowTitle( void QtProfileSelectionDialog::SetDialogPurpose( const Core::Frontend::ProfileSelectParameters& parameters) { - using Service::AM::Applets::UserSelectionPurpose; + using Service::AM::Frontend::UserSelectionPurpose; switch (parameters.purpose) { case UserSelectionPurpose::GameCardRegistration: diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index ac81ace9e..2749e6ed3 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -20,7 +20,7 @@ namespace { -using namespace Service::AM::Applets; +using namespace Service::AM::Frontend; constexpr float BASE_HEADER_FONT_SIZE = 23.0f; constexpr float BASE_SUB_FONT_SIZE = 17.0f; @@ -389,7 +389,7 @@ void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) { } void QtSoftwareKeyboardDialog::ShowTextCheckDialog( - Service::AM::Applets::SwkbdTextCheckResult text_check_result, + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) { switch (text_check_result) { case SwkbdTextCheckResult::Success: @@ -1612,7 +1612,7 @@ void QtSoftwareKeyboard::ShowNormalKeyboard() const { } void QtSoftwareKeyboard::ShowTextCheckDialog( - Service::AM::Applets::SwkbdTextCheckResult text_check_result, + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const { emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message)); } @@ -1662,12 +1662,12 @@ void QtSoftwareKeyboard::ExitKeyboard() const { emit MainWindowExitKeyboard(); } -void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result, +void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, bool confirmed) const { submit_normal_callback(result, submitted_text, confirmed); } -void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, +void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) const { submit_inline_callback(reply_type, submitted_text, cursor_position); diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h index ac23ce047..7e2fdf09e 100644 --- a/src/yuzu/applets/qt_software_keyboard.h +++ b/src/yuzu/applets/qt_software_keyboard.h @@ -39,7 +39,7 @@ public: void ShowNormalKeyboard(QPoint pos, QSize size); - void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message); void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, @@ -52,10 +52,10 @@ public: void ExitKeyboard(); signals: - void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, + void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, bool confirmed = false) const; - void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, + void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) const; public slots: @@ -244,7 +244,7 @@ public: void ShowNormalKeyboard() const override; - void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const override; void ShowInlineKeyboard( @@ -262,8 +262,9 @@ signals: void MainWindowShowNormalKeyboard() const; - void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message) const; + void MainWindowShowTextCheckDialog( + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, + std::u16string text_check_message) const; void MainWindowShowInlineKeyboard( Core::Frontend::InlineAppearParameters appear_parameters) const; @@ -275,10 +276,10 @@ signals: void MainWindowExitKeyboard() const; private: - void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, + void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, bool confirmed) const; - void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, + void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) const; mutable SubmitNormalCallback submit_normal_callback; diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 34c5fd3be..cce9b2efb 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -96,7 +96,7 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system, [this] { if (page()->url() == url_interceptor->GetRequestedURL()) { SetFinished(true); - SetExitReason(Service::AM::Applets::WebExitReason::WindowClosed); + SetExitReason(Service::AM::Frontend::WebExitReason::WindowClosed); } }, Qt::QueuedConnection); @@ -115,7 +115,7 @@ void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url, FocusFirstLinkElement(); SetUserAgent(UserAgent::WebApplet); SetFinished(false); - SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); + SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed); SetLastURL("http://localhost/"); StartInputThread(); @@ -130,7 +130,7 @@ void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url, FocusFirstLinkElement(); SetUserAgent(UserAgent::WebApplet); SetFinished(false); - SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); + SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed); SetLastURL("http://localhost/"); StartInputThread(); @@ -170,11 +170,11 @@ void QtNXWebEngineView::SetFinished(bool finished_) { finished = finished_; } -Service::AM::Applets::WebExitReason QtNXWebEngineView::GetExitReason() const { +Service::AM::Frontend::WebExitReason QtNXWebEngineView::GetExitReason() const { return exit_reason; } -void QtNXWebEngineView::SetExitReason(Service::AM::Applets::WebExitReason exit_reason_) { +void QtNXWebEngineView::SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_) { exit_reason = exit_reason_; } @@ -441,7 +441,7 @@ void QtWebBrowser::MainWindowExtractOfflineRomFS() { extract_romfs_callback(); } -void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, +void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url) { if (callback) { callback(exit_reason, last_url); diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index 1234108ae..e8a0b6931 100644 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h @@ -85,8 +85,8 @@ public: [[nodiscard]] bool IsFinished() const; void SetFinished(bool finished_); - [[nodiscard]] Service::AM::Applets::WebExitReason GetExitReason() const; - void SetExitReason(Service::AM::Applets::WebExitReason exit_reason_); + [[nodiscard]] Service::AM::Frontend::WebExitReason GetExitReason() const; + void SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_); [[nodiscard]] const std::string& GetLastURL() const; void SetLastURL(std::string last_url_); @@ -176,8 +176,8 @@ private: std::atomic finished{}; - Service::AM::Applets::WebExitReason exit_reason{ - Service::AM::Applets::WebExitReason::EndButtonPressed}; + Service::AM::Frontend::WebExitReason exit_reason{ + Service::AM::Frontend::WebExitReason::EndButtonPressed}; std::string last_url{"http://localhost/"}; @@ -212,7 +212,7 @@ signals: private: void MainWindowExtractOfflineRomFS(); - void MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, + void MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url); mutable ExtractROMFSCallback extract_romfs_callback; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f51fd3fa3..90ddecbfc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -39,14 +39,14 @@ #include "core/file_sys/vfs/vfs_real.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" -#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/general.h" #include "core/frontend/applets/mii_edit.h" #include "core/frontend/applets/software_keyboard.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/set/system_settings_server.h" #include "frontend_common/content_manager.h" #include "hid_core/frontend/emulated_controller.h" @@ -631,13 +631,14 @@ void GMainWindow::RegisterMetaTypes() { qRegisterMetaType( "Core::Frontend::InlineAppearParameters"); qRegisterMetaType("Core::Frontend::InlineTextParameters"); - qRegisterMetaType("Service::AM::Applets::SwkbdResult"); - qRegisterMetaType( - "Service::AM::Applets::SwkbdTextCheckResult"); - qRegisterMetaType("Service::AM::Applets::SwkbdReplyType"); + qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdTextCheckResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdReplyType"); // Web Browser Applet - qRegisterMetaType("Service::AM::Applets::WebExitReason"); + qRegisterMetaType("Service::AM::Frontend::WebExitReason"); // Register loader types qRegisterMetaType("Core::SystemResultStatus"); @@ -747,7 +748,7 @@ void GMainWindow::SoftwareKeyboardInitialize( if (is_inline) { connect( software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this, - [this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text, + [this](Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) { emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position); }, @@ -755,7 +756,7 @@ void GMainWindow::SoftwareKeyboardInitialize( } else { connect( software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this, - [this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, + [this](Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, bool confirmed) { emit SoftwareKeyboardSubmitNormalText(result, submitted_text, confirmed); }, @@ -782,7 +783,7 @@ void GMainWindow::SoftwareKeyboardShowNormal() { } void GMainWindow::SoftwareKeyboardShowTextCheck( - Service::AM::Applets::SwkbdTextCheckResult text_check_result, + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) { if (!software_keyboard) { LOG_ERROR(Frontend, "The software keyboard is not initialized!"); @@ -853,7 +854,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, // Raw input breaks with the web applet, Disable web applets if enabled if (UISettings::values.disable_web_applet || Settings::values.enable_raw_input) { - emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, + emit WebBrowserClosed(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/"); return; } @@ -941,7 +942,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, if (variant.toBool()) { web_applet->SetFinished(true); web_applet->SetExitReason( - Service::AM::Applets::WebExitReason::EndButtonPressed); + Service::AM::Frontend::WebExitReason::EndButtonPressed); } }); @@ -951,7 +952,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) { if (!web_applet->IsFinished()) { web_applet->SetFinished(true); - web_applet->SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); + web_applet->SetExitReason(Service::AM::Frontend::WebExitReason::CallbackURL); } web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString()); @@ -984,7 +985,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, #else // Utilize the same fallback as the default web browser applet. - emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); + emit WebBrowserClosed(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/"); #endif } @@ -992,7 +993,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, void GMainWindow::WebBrowserRequestExit() { #ifdef YUZU_USE_QT_WEB_ENGINE if (web_applet) { - web_applet->SetExitReason(Service::AM::Applets::WebExitReason::ExitRequested); + web_applet->SetExitReason(Service::AM::Frontend::WebExitReason::ExitRequested); web_applet->SetFinished(true); } #endif @@ -1778,7 +1779,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->GetUserChannel().clear(); } - system->SetAppletFrontendSet({ + system->SetFrontendAppletSet({ std::make_unique(*this), // Amiibo Settings (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr @@ -1921,7 +1922,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t LOG_INFO(Frontend, "yuzu starting..."); if (program_id == 0 || - program_id > static_cast(Service::AM::Applets::AppletProgramId::MaxProgramId)) { + program_id > static_cast(Service::AM::AppletProgramId::MaxProgramId)) { StoreRecentFile(filename); // Put the filename on top of the list } @@ -1955,10 +1956,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) { const Core::Frontend::ProfileSelectParameters parameters{ - .mode = Service::AM::Applets::UiMode::UserSelector, + .mode = Service::AM::Frontend::UiMode::UserSelector, .invalid_uid_list = {}, .display_options = {}, - .purpose = Service::AM::Applets::UserSelectionPurpose::General, + .purpose = Service::AM::Frontend::UserSelectionPurpose::General, }; if (SelectAndSetCurrentUser(parameters) == false) { return; @@ -2161,7 +2162,7 @@ void GMainWindow::OnEmulationStopped() { OnTasStateChanged(); render_window->FinalizeCamera(); - system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::None); + system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); // Enable all controllers system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); @@ -2281,10 +2282,10 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target // User save data const auto select_profile = [this] { const Core::Frontend::ProfileSelectParameters parameters{ - .mode = Service::AM::Applets::UiMode::UserSelector, + .mode = Service::AM::Frontend::UiMode::UserSelector, .invalid_uid_list = {}, .display_options = {}, - .purpose = Service::AM::Applets::UserSelectionPurpose::General, + .purpose = Service::AM::Frontend::UserSelectionPurpose::General, }; QtProfileSelectionDialog dialog(*system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | @@ -4154,7 +4155,7 @@ void GMainWindow::OnToggleStatusBar() { } void GMainWindow::OnAlbum() { - constexpr u64 AlbumId = static_cast(Service::AM::Applets::AppletProgramId::PhotoViewer); + constexpr u64 AlbumId = static_cast(Service::AM::AppletProgramId::PhotoViewer); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4169,7 +4170,7 @@ void GMainWindow::OnAlbum() { return; } - system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); + system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); const auto filename = QString::fromStdString(album_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4177,7 +4178,7 @@ void GMainWindow::OnAlbum() { } void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { - constexpr u64 CabinetId = static_cast(Service::AM::Applets::AppletProgramId::Cabinet); + constexpr u64 CabinetId = static_cast(Service::AM::AppletProgramId::Cabinet); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4192,8 +4193,8 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { return; } - system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Cabinet); - system->GetAppletManager().SetCabinetMode(mode); + system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); + system->GetFrontendAppletHolder().SetCabinetMode(mode); const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4201,7 +4202,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { } void GMainWindow::OnMiiEdit() { - constexpr u64 MiiEditId = static_cast(Service::AM::Applets::AppletProgramId::MiiEdit); + constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4216,7 +4217,7 @@ void GMainWindow::OnMiiEdit() { return; } - system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); + system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4224,8 +4225,7 @@ void GMainWindow::OnMiiEdit() { } void GMainWindow::OnOpenControllerMenu() { - constexpr u64 ControllerAppletId = - static_cast(Service::AM::Applets::AppletProgramId::Controller); + constexpr u64 ControllerAppletId = static_cast(Service::AM::AppletProgramId::Controller); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4241,7 +4241,7 @@ void GMainWindow::OnOpenControllerMenu() { return; } - system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); + system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4565,7 +4565,7 @@ void GMainWindow::OnCheckFirmwareDecryption() { } bool GMainWindow::CheckFirmwarePresence() { - constexpr u64 MiiEditId = static_cast(Service::AM::Applets::AppletProgramId::MiiEdit); + constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6b72094ff..c079baffa 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -101,12 +101,12 @@ namespace InputCommon { class InputSubsystem; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class SwkbdResult : u32; enum class SwkbdTextCheckResult : u32; enum class SwkbdReplyType : u32; enum class WebExitReason : u32; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend namespace Service::NFC { class NfcDevice; @@ -204,13 +204,13 @@ signals: void ProfileSelectorFinishedSelection(std::optional uuid); - void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result, + void SoftwareKeyboardSubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, bool confirmed); - void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, + void SoftwareKeyboardSubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position); void WebBrowserExtractOfflineRomFS(); - void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); + void WebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url); void SigInterrupt(); @@ -228,8 +228,9 @@ public slots: void SoftwareKeyboardInitialize( bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); void SoftwareKeyboardShowNormal(); - void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message); + void SoftwareKeyboardShowTextCheck( + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, + std::u16string text_check_message); void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters); void SoftwareKeyboardHideInline(); void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); -- cgit v1.2.3 From 3155f4e96d10904f4a207e465f20fb4b25043f5c Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Jan 2024 18:26:53 -0500 Subject: am: retrieve main applet creation info from frontend --- .../main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | 2 +- .../yuzu/yuzu_emu/fragments/EmulationFragment.kt | 4 +- src/android/app/src/main/jni/native.cpp | 37 ++++++++--- src/android/app/src/main/jni/native.h | 5 +- src/core/core.cpp | 49 +++++++++------ src/core/core.h | 9 ++- src/yuzu/game_list.cpp | 12 ++-- src/yuzu/game_list.h | 3 +- src/yuzu/main.cpp | 72 ++++++++++++++-------- src/yuzu/main.h | 23 ++++--- src/yuzu_cmd/yuzu.cpp | 6 +- 11 files changed, 143 insertions(+), 79 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 53137b2e2..6ebb46af7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -261,7 +261,7 @@ object NativeLibrary { /** * Begins emulation. */ - external fun run(path: String?, programIndex: Int = 0) + external fun run(path: String?, programIndex: Int, frontendInitiated: Boolean) // Surface Handling external fun surfaceChanged(surf: Surface?) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 1f591ced1..937b8faf1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -927,7 +927,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { emulationThread.join() emulationThread = Thread({ Log.debug("[EmulationFragment] Starting emulation thread.") - NativeLibrary.run(gamePath, programIndex) + NativeLibrary.run(gamePath, programIndex, false) }, "NativeEmulation") emulationThread.start() } @@ -981,7 +981,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { State.STOPPED -> { emulationThread = Thread({ Log.debug("[EmulationFragment] Starting emulation thread.") - NativeLibrary.run(gamePath, programIndex) + NativeLibrary.run(gamePath, programIndex, true) }, "NativeEmulation") emulationThread.start() } diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 1da510b7a..654510129 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -48,6 +48,7 @@ #include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/web_browser.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/filesystem/filesystem.h" @@ -211,8 +212,15 @@ void EmulationSession::InitializeSystem(bool reload) { m_system.GetFileSystemController().CreateFactories(*m_vfs); } +void EmulationSession::SetAppletId(int applet_id) { + m_applet_id = applet_id; + m_system.GetFrontendAppletHolder().SetCurrentAppletId( + static_cast(m_applet_id)); +} + Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath, - const std::size_t program_index) { + const std::size_t program_index, + const bool frontend_initiated) { std::scoped_lock lock(m_mutex); // Create the render window. @@ -242,8 +250,13 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string ConfigureFilesystemProvider(filepath); // Load the ROM. - m_load_result = - m_system.Load(EmulationSession::GetInstance().Window(), filepath, 0, program_index); + Service::AM::FrontendAppletParameters params{ + .applet_id = static_cast(m_applet_id), + .launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated + : Service::AM::LaunchType::ApplicationInitiated, + .program_index = static_cast(program_index), + }; + m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params); if (m_load_result != Core::SystemResultStatus::Success) { return m_load_result; } @@ -339,6 +352,9 @@ void EmulationSession::RunEmulation() { } } } + + // Reset current applet ID. + m_applet_id = static_cast(Service::AM::AppletId::Application); } bool EmulationSession::IsHandheldOnly() { @@ -434,7 +450,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) { } static Core::SystemResultStatus RunEmulation(const std::string& filepath, - const size_t program_index = 0) { + const size_t program_index, + const bool frontend_initiated) { MicroProfileOnThreadCreate("EmuThread"); SCOPE_EXIT({ MicroProfileShutdown(); }); @@ -447,7 +464,8 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath, SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); - jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index); + jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, + frontend_initiated); if (result != Core::SystemResultStatus::Success) { return result; } @@ -744,10 +762,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj } void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path, - jint j_program_index) { + jint j_program_index, + jboolean j_frontend_initiated) { const std::string path = GetJString(env, j_path); - const Core::SystemResultStatus result{RunEmulation(path, j_program_index)}; + const Core::SystemResultStatus result{ + RunEmulation(path, j_program_index, j_frontend_initiated)}; if (result != Core::SystemResultStatus::Success) { env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetExitEmulationActivity(), static_cast(result)); @@ -809,8 +829,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz, jint jappletId) { - EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCurrentAppletId( - static_cast(jappletId)); + EmulationSession::GetInstance().SetAppletId(jappletId); } void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz, diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index bfe3fccca..e49d4e015 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h @@ -45,8 +45,10 @@ public: const Core::PerfStatsResults& PerfStats(); void ConfigureFilesystemProvider(const std::string& filepath); void InitializeSystem(bool reload); + void SetAppletId(int applet_id); Core::SystemResultStatus InitializeEmulation(const std::string& filepath, - const std::size_t program_index = 0); + const std::size_t program_index, + const bool frontend_initiated); bool IsHandheldOnly(); void SetDeviceType([[maybe_unused]] int index, int type); @@ -79,6 +81,7 @@ private: std::atomic m_is_paused = false; SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; std::unique_ptr m_manual_provider; + int m_applet_id{1}; // GPU driver parameters std::shared_ptr m_vulkan_library; diff --git a/src/core/core.cpp b/src/core/core.cpp index 2bf377b24..8c04685a5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -36,6 +36,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/filesystem/filesystem.h" @@ -136,7 +137,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, - reporter{system}, frontend_applets{system}, profile_manager{} {} + reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {} void Initialize(System& system) { device_memory = std::make_unique(); @@ -330,16 +331,27 @@ struct System::Impl { } SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, - const std::string& filepath, u64 program_id, - std::size_t program_index) { + const std::string& filepath, + Service::AM::FrontendAppletParameters& params) { app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), - program_id, program_index); + params.program_id, params.program_index); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); return SystemResultStatus::ErrorGetLoader; } + if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) { + LOG_ERROR(Core, "Failed to find title id for ROM!"); + } + + std::string name = "Unknown program"; + if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { + LOG_ERROR(Core, "Failed to read title for ROM!"); + } + + LOG_INFO(Core, "Loading {} ({})", name, params.program_id); + InitializeKernel(system); // Create the application process. @@ -373,6 +385,10 @@ struct System::Impl { cheat_engine->Initialize(); } + // Register with applet manager. + applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(), + params); + // All threads are started, begin main process execution, now that we're in the clear. main_process->Run(load_parameters->main_thread_priority, load_parameters->main_thread_stack_size); @@ -386,21 +402,13 @@ struct System::Impl { } } - if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { - LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result); - } - perf_stats = std::make_unique(program_id); + perf_stats = std::make_unique(params.program_id); // Reset counters and set time origin to current frame GetAndResetPerfStats(); perf_stats->BeginSystemFrame(); - std::string name = "Unknown Game"; - if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { - LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result); - } - std::string title_version; - const FileSys::PatchManager pm(program_id, system.GetFileSystemController(), + const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(), system.GetContentProvider()); const auto metadata = pm.GetControlMetadata(); if (metadata.first != nullptr) { @@ -409,14 +417,15 @@ struct System::Impl { if (auto room_member = room_network.GetRoomMember().lock()) { Network::GameInfo game_info; game_info.name = name; - game_info.id = program_id; + game_info.id = params.program_id; game_info.version = title_version; room_member->SendGameInfo(game_info); } // Workarounds: // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK - Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL; + Settings::values.renderer_amdvlk_depth_bias_workaround = + params.program_id == 0x1006A800016E000ULL; status = SystemResultStatus::Success; return status; @@ -455,6 +464,7 @@ struct System::Impl { } kernel.CloseServices(); kernel.ShutdownCores(); + applet_manager.Reset(); services.reset(); service_manager.reset(); fs_controller.Reset(); @@ -566,7 +576,8 @@ struct System::Impl { std::unique_ptr renderdoc_api; - /// Frontend applets + /// Applets + Service::AM::AppletManager applet_manager; Service::AM::Frontend::FrontendAppletHolder frontend_applets; /// APM (Performance) services @@ -680,8 +691,8 @@ void System::InitializeDebugger() { } SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, - u64 program_id, std::size_t program_index) { - return impl->Load(*this, emu_window, filepath, program_id, program_index); + Service::AM::FrontendAppletParameters& params) { + return impl->Load(*this, emu_window, filepath, params); } bool System::IsPoweredOn() const { diff --git a/src/core/core.h b/src/core/core.h index 800e69501..97e2d4b50 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -50,6 +50,11 @@ namespace Account { class ProfileManager; } // namespace Account +namespace AM { +struct FrontendAppletParameters; +class AppletManager; +} // namespace AM + namespace AM::Frontend { struct FrontendAppletSet; class FrontendAppletHolder; @@ -203,8 +208,8 @@ public: * @returns SystemResultStatus code, indicating if the operation succeeded. */ [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window, - const std::string& filepath, u64 program_id = 0, - std::size_t program_index = 0); + const std::string& filepath, + Service::AM::FrontendAppletParameters& params); /** * Indicates if the emulated system is powered on (all subsystems initialized and able to run an diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 59b317135..b40af957c 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -596,14 +596,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(open_save_location, &QAction::triggered, [this, program_id, path]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); }); - connect(start_game, &QAction::triggered, [this, path]() { - emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal, - AmLaunchType::UserInitiated); - }); - connect(start_game_global, &QAction::triggered, [this, path]() { - emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global, - AmLaunchType::UserInitiated); - }); + connect(start_game, &QAction::triggered, + [this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Normal); }); + connect(start_game_global, &QAction::triggered, + [this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Global); }); connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); }); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 563a3a35b..79f9c7ec0 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -106,8 +106,7 @@ public: static const QStringList supported_file_extensions; signals: - void BootGame(const QString& game_path, u64 program_id, std::size_t program_index, - StartGameType type, AmLaunchType launch_type); + void BootGame(const QString& game_path, StartGameType type); void GameChosen(const QString& game_path, const u64 title_id = 0); void OpenFolderRequested(u64 program_id, GameListOpenTarget target, const std::string& game_path); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 90ddecbfc..02508b20d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "core/hle/service/am/applet_manager.h" #include "core/loader/nca.h" #include "core/tools/renderdoc.h" @@ -569,7 +570,7 @@ GMainWindow::GMainWindow(std::unique_ptr config_, bool has_broken_vulk } if (!game_path.isEmpty()) { - BootGame(game_path); + BootGame(game_path, ApplicationAppletParameters()); } } @@ -1474,7 +1475,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) { } void GMainWindow::ConnectWidgetEvents() { - connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame); + connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGameFromList); connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); @@ -1762,8 +1763,7 @@ void GMainWindow::AllowOSSleep() { #endif } -bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index, - AmLaunchType launch_type) { +bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params) { // Shutdown previous session if the emu thread is still active... if (emu_thread != nullptr) { ShutdownGame(); @@ -1775,7 +1775,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->SetFilesystem(vfs); - if (launch_type == AmLaunchType::UserInitiated) { + if (params.launch_type == Service::AM::LaunchType::FrontendInitiated) { system->GetUserChannel().clear(); } @@ -1794,7 +1794,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p }); const Core::SystemResultStatus result{ - system->Load(*render_window, filename.toStdString(), program_id, program_index)}; + system->Load(*render_window, filename.toStdString(), params)}; const auto drd_callout = (UISettings::values.callout_flags.GetValue() & static_cast(CalloutFlag::DRDDeprecation)) == 0; @@ -1917,12 +1917,12 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { } } -void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, - StartGameType type, AmLaunchType launch_type) { +void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletParameters params, + StartGameType type) { LOG_INFO(Frontend, "yuzu starting..."); - if (program_id == 0 || - program_id > static_cast(Service::AM::AppletProgramId::MaxProgramId)) { + if (params.program_id == 0 || + params.program_id > static_cast(Service::AM::AppletProgramId::MaxProgramId)) { StoreRecentFile(filename); // Put the filename on top of the list } @@ -1937,7 +1937,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t ConfigureFilesystemProvider(filename.toStdString()); const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); - const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index); + const auto loader = Loader::GetLoader(*system, v_file, params.program_id, params.program_index); if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && type == StartGameType::Normal) { @@ -1971,7 +1971,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t // behavior of asking. user_flag_cmd_line = false; - if (!LoadROM(filename, program_id, program_index, launch_type)) { + if (!LoadROM(filename, params)) { return; } @@ -2061,6 +2061,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t OnStartGame(); } +void GMainWindow::BootGameFromList(const QString& filename, StartGameType with_config) { + BootGame(filename, ApplicationAppletParameters(), with_config); +} + bool GMainWindow::OnShutdownBegin() { if (!emulation_running) { return false; @@ -2241,7 +2245,10 @@ void GMainWindow::UpdateRecentFiles() { } void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { - BootGame(game_path, program_id); + auto params = ApplicationAppletParameters(); + params.program_id = program_id; + + BootGame(game_path, params); } void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, @@ -3173,7 +3180,7 @@ void GMainWindow::OnMenuLoadFile() { } UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); - BootGame(filename); + BootGame(filename, ApplicationAppletParameters()); } void GMainWindow::OnMenuLoadFolder() { @@ -3187,7 +3194,7 @@ void GMainWindow::OnMenuLoadFolder() { const QDir dir{dir_path}; const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files); if (matching_main.size() == 1) { - BootGame(dir.path() + QDir::separator() + matching_main[0]); + BootGame(dir.path() + QDir::separator() + matching_main[0], ApplicationAppletParameters()); } else { QMessageBox::warning(this, tr("Invalid Directory Selected"), tr("The directory you have selected does not contain a 'main' file.")); @@ -3381,7 +3388,7 @@ void GMainWindow::OnMenuRecentFile() { const QString filename = action->data().toString(); if (QFileInfo::exists(filename)) { - BootGame(filename); + BootGame(filename, ApplicationAppletParameters()); } else { // Display an error message and remove the file from the list. QMessageBox::information(this, tr("File not found"), @@ -3419,7 +3426,7 @@ void GMainWindow::OnRestartGame() { // Make a copy since ShutdownGame edits game_path const auto current_game = QString(current_game_path); ShutdownGame(); - BootGame(current_game); + BootGame(current_game, ApplicationAppletParameters()); } } @@ -3487,8 +3494,11 @@ void GMainWindow::OnLoadComplete() { void GMainWindow::OnExecuteProgram(std::size_t program_index) { ShutdownGame(); - BootGame(last_filename_booted, 0, program_index, StartGameType::Normal, - AmLaunchType::ApplicationInitiated); + + auto params = ApplicationAppletParameters(); + params.program_index = static_cast(program_index); + params.launch_type = Service::AM::LaunchType::ApplicationInitiated; + BootGame(last_filename_booted, params); } void GMainWindow::OnExit() { @@ -4174,7 +4184,7 @@ void GMainWindow::OnAlbum() { const auto filename = QString::fromStdString(album_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); - BootGame(filename, AlbumId); + BootGame(filename, LibraryAppletParameters(AlbumId, Service::AM::AppletId::PhotoViewer)); } void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { @@ -4198,7 +4208,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); - BootGame(filename, CabinetId); + BootGame(filename, LibraryAppletParameters(CabinetId, Service::AM::AppletId::Cabinet)); } void GMainWindow::OnMiiEdit() { @@ -4221,7 +4231,7 @@ void GMainWindow::OnMiiEdit() { const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); - BootGame(filename, MiiEditId); + BootGame(filename, LibraryAppletParameters(MiiEditId, Service::AM::AppletId::MiiEdit)); } void GMainWindow::OnOpenControllerMenu() { @@ -4245,7 +4255,8 @@ void GMainWindow::OnOpenControllerMenu() { const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); - BootGame(filename, ControllerAppletId); + BootGame(filename, + LibraryAppletParameters(ControllerAppletId, Service::AM::AppletId::Controller)); } void GMainWindow::OnCaptureScreenshot() { @@ -4728,7 +4739,7 @@ bool GMainWindow::DropAction(QDropEvent* event) { } else { // Game if (ConfirmChangeGame()) { - BootGame(filename); + BootGame(filename, ApplicationAppletParameters()); } } return true; @@ -4943,6 +4954,19 @@ void GMainWindow::changeEvent(QEvent* event) { QWidget::changeEvent(event); } +Service::AM::FrontendAppletParameters GMainWindow::ApplicationAppletParameters() { + return Service::AM::FrontendAppletParameters{}; +} + +Service::AM::FrontendAppletParameters GMainWindow::LibraryAppletParameters( + u64 program_id, Service::AM::AppletId applet_id) { + return Service::AM::FrontendAppletParameters{ + .program_id = program_id, + .applet_id = applet_id, + .applet_type = Service::AM::AppletType::LibraryApplet, + }; +} + void VolumeButton::wheelEvent(QWheelEvent* event) { int num_degrees = event->angleDelta().y() / 8; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index c079baffa..aba61e388 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -64,11 +64,6 @@ enum class StartGameType { Global, // Only uses global configuration }; -enum class AmLaunchType { - UserInitiated, - ApplicationInitiated, -}; - namespace Core { enum class SystemResultStatus : u32; class System; @@ -101,6 +96,11 @@ namespace InputCommon { class InputSubsystem; } +namespace Service::AM { +struct FrontendAppletParameters; +enum class AppletId : u32; +} // namespace Service::AM + namespace Service::AM::Frontend { enum class SwkbdResult : u32; enum class SwkbdTextCheckResult : u32; @@ -268,11 +268,10 @@ private: void PreventOSSleep(); void AllowOSSleep(); - bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index, - AmLaunchType launch_type); - void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0, - StartGameType with_config = StartGameType::Normal, - AmLaunchType launch_type = AmLaunchType::UserInitiated); + bool LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params); + void BootGame(const QString& filename, Service::AM::FrontendAppletParameters params, + StartGameType with_config = StartGameType::Normal); + void BootGameFromList(const QString& filename, StartGameType with_config); void ShutdownGame(); void ShowTelemetryCallout(); @@ -325,6 +324,10 @@ private: void SetGamemodeEnabled(bool state); #endif + Service::AM::FrontendAppletParameters ApplicationAppletParameters(); + Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id, + Service::AM::AppletId applet_id); + private slots: void OnStartGame(); void OnRestartGame(); diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index c39ace2ec..3b321dad1 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -26,6 +26,7 @@ #include "core/crypto/key_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/vfs/vfs_real.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "core/telemetry_session.h" @@ -366,7 +367,10 @@ int main(int argc, char** argv) { system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); system.GetUserChannel().clear(); - const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath)}; + Service::AM::FrontendAppletParameters load_parameters{ + .applet_id = Service::AM::AppletId::Application, + }; + const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath, load_parameters)}; switch (load_result) { case Core::SystemResultStatus::ErrorGetLoader: -- cgit v1.2.3 From 182137a9a4b09c8188d2cbffa312550c5dc83641 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Jan 2024 18:29:03 -0500 Subject: am: migrate global state to per-applet state structure --- src/core/core.cpp | 9 +- src/core/core.h | 3 +- src/core/hle/kernel/kernel.cpp | 30 +- src/core/hle/service/am/am.cpp | 10 +- src/core/hle/service/am/am_results.h | 1 + src/core/hle/service/am/applet_ae.cpp | 72 +++-- src/core/hle/service/am/applet_ae.h | 10 +- .../hle/service/am/applet_common_functions.cpp | 11 +- src/core/hle/service/am/applet_common_functions.h | 6 +- src/core/hle/service/am/applet_manager.cpp | 2 +- src/core/hle/service/am/applet_message_queue.cpp | 7 +- src/core/hle/service/am/applet_message_queue.h | 1 + src/core/hle/service/am/applet_oe.cpp | 35 ++- src/core/hle/service/am/applet_oe.h | 10 +- src/core/hle/service/am/application_functions.cpp | 156 +++++----- src/core/hle/service/am/application_functions.h | 13 +- src/core/hle/service/am/application_proxy.cpp | 21 +- src/core/hle/service/am/application_proxy.h | 9 +- src/core/hle/service/am/common_state_getter.cpp | 51 ++-- src/core/hle/service/am/common_state_getter.h | 10 +- src/core/hle/service/am/frontend/applets.cpp | 20 +- src/core/hle/service/am/frontend/applets.h | 1 - .../hle/service/am/library_applet_accessor.cpp | 76 ++--- src/core/hle/service/am/library_applet_accessor.h | 13 +- src/core/hle/service/am/library_applet_creator.cpp | 115 ++++++- src/core/hle/service/am/library_applet_creator.h | 6 +- src/core/hle/service/am/library_applet_proxy.cpp | 23 +- src/core/hle/service/am/library_applet_proxy.h | 9 +- .../service/am/library_applet_self_accessor.cpp | 330 +++++++-------------- .../hle/service/am/library_applet_self_accessor.h | 18 +- .../hle/service/am/process_winding_controller.cpp | 35 +-- .../hle/service/am/process_winding_controller.h | 6 +- src/core/hle/service/am/self_controller.cpp | 187 ++++++------ src/core/hle/service/am/self_controller.h | 25 +- src/core/hle/service/am/system_applet_proxy.cpp | 19 +- src/core/hle/service/am/system_applet_proxy.h | 8 +- src/core/hle/service/am/window_controller.cpp | 18 +- src/core/hle/service/am/window_controller.h | 6 +- src/core/hle/service/vi/vi.cpp | 8 + src/yuzu/configuration/configure_input.cpp | 17 +- src/yuzu/main.cpp | 28 +- 41 files changed, 687 insertions(+), 748 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 8c04685a5..435ef6793 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -392,6 +392,7 @@ struct System::Impl { // All threads are started, begin main process execution, now that we're in the clear. main_process->Run(load_parameters->main_thread_priority, load_parameters->main_thread_stack_size); + main_process->Close(); if (Settings::values.gamecard_inserted) { if (Settings::values.gamecard_current_game) { @@ -886,10 +887,6 @@ void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set impl->frontend_applets.SetFrontendAppletSet(std::move(set)); } -void System::SetDefaultAppletFrontendSet() { - impl->frontend_applets.SetDefaultAppletFrontendSet(); -} - Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { return impl->frontend_applets; } @@ -898,6 +895,10 @@ const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHold return impl->frontend_applets; } +Service::AM::AppletManager& System::GetAppletManager() { + return impl->applet_manager; +} + void System::SetContentProvider(std::unique_ptr provider) { impl->content_provider = std::move(provider); } diff --git a/src/core/core.h b/src/core/core.h index 97e2d4b50..90826bd3a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -350,12 +350,13 @@ public: u64 main_region_size); void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); - void SetDefaultAppletFrontendSet(); [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() const; + [[nodiscard]] Service::AM::AppletManager& GetAppletManager(); + void SetContentProvider(std::unique_ptr provider); [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f3683cdcc..34b25be66 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -97,8 +97,14 @@ struct KernelCore::Impl { RegisterHostThread(nullptr); } - void TerminateApplicationProcess() { - application_process.load()->Terminate(); + void TerminateAllProcesses() { + std::scoped_lock lk{process_list_lock}; + for (auto& process : process_list) { + process->Terminate(); + process->Close(); + process = nullptr; + } + process_list.clear(); } void Shutdown() { @@ -107,18 +113,9 @@ struct KernelCore::Impl { CloseServices(); - auto* old_process = application_process.exchange(nullptr); - if (old_process) { - old_process->Close(); - } - - { - std::scoped_lock lk{process_list_lock}; - for (auto* const process : process_list) { - process->Terminate(); - process->Close(); - } - process_list.clear(); + if (application_process) { + application_process->Close(); + application_process = nullptr; } next_object_id = 0; @@ -354,6 +351,7 @@ struct KernelCore::Impl { void MakeApplicationProcess(KProcess* process) { application_process = process; + application_process->Open(); } static inline thread_local u8 host_thread_id = UINT8_MAX; @@ -779,7 +777,7 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::mutex process_list_lock; std::vector process_list; - std::atomic application_process{}; + KProcess* application_process{}; std::unique_ptr global_scheduler_context; std::unique_ptr hardware_timer; @@ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) { } void KernelCore::ShutdownCores() { - impl->TerminateApplicationProcess(); + impl->TerminateAllProcesses(); KScopedSchedulerLock lk{*this}; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 46bc4f703..8f90eba34 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -3,7 +3,6 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" -#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" @@ -13,13 +12,12 @@ namespace Service::AM { void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { - auto message_queue = std::make_shared(system); auto server_manager = std::make_unique(system); - server_manager->RegisterNamedService( - "appletAE", std::make_shared(nvnflinger, message_queue, system)); - server_manager->RegisterNamedService( - "appletOE", std::make_shared(nvnflinger, message_queue, system)); + server_manager->RegisterNamedService("appletAE", + std::make_shared(nvnflinger, system)); + server_manager->RegisterNamedService("appletOE", + std::make_shared(nvnflinger, system)); server_manager->RegisterNamedService("idle:sys", std::make_shared(system)); server_manager->RegisterNamedService("omm", std::make_shared(system)); server_manager->RegisterNamedService("spsm", std::make_shared(system)); diff --git a/src/core/hle/service/am/am_results.h b/src/core/hle/service/am/am_results.h index 528b334ad..e82d391ad 100644 --- a/src/core/hle/service/am/am_results.h +++ b/src/core/hle/service/am/am_results.h @@ -10,5 +10,6 @@ namespace Service::AM { constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; constexpr Result ResultNoMessages{ErrorModule::AM, 3}; constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; +constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512}; } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index bd9e5f505..1b715dea6 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -2,40 +2,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/library_applet_proxy.h" #include "core/hle/service/am/system_applet_proxy.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(nvnflinger, msg_queue, system); -} - -void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(nvnflinger, msg_queue, system); -} - -void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(nvnflinger, msg_queue, system); -} - -AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, - msg_queue{std::move(msg_queue_)} { +AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) + : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} { // clang-format off static const FunctionInfo functions[] = { {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, @@ -54,8 +29,45 @@ AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, AppletAE::~AppletAE() = default; -const std::shared_ptr& AppletAE::GetMessageQueue() const { - return msg_queue; +void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + if (const auto applet = GetAppletFromContext(ctx)) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + } +} + +void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + if (const auto applet = GetAppletFromContext(ctx)) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + } +} + +void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + return OpenLibraryAppletProxy(ctx); +} + +std::shared_ptr AppletAE::GetAppletFromContext(HLERequestContext& ctx) { + const auto aruid = ctx.GetPID(); + return system.GetAppletManager().GetByAppletResourceUserId(aruid); } } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 538ce2903..3d7961fa1 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -18,23 +18,21 @@ class Nvnflinger; namespace AM { -class AppletMessageQueue; +struct Applet; class AppletAE final : public ServiceFramework { public: - explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, Core::System& system_); + explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); ~AppletAE() override; - const std::shared_ptr& GetMessageQueue() const; - private: void OpenSystemAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxyOld(HLERequestContext& ctx); + std::shared_ptr GetAppletFromContext(HLERequestContext& ctx); + Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; }; } // namespace AM diff --git a/src/core/hle/service/am/applet_common_functions.cpp b/src/core/hle/service/am/applet_common_functions.cpp index 81c01a48b..a5c54ce87 100644 --- a/src/core/hle/service/am/applet_common_functions.cpp +++ b/src/core/hle/service/am/applet_common_functions.cpp @@ -1,13 +1,15 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/service/am/applet.h" #include "core/hle/service/am/applet_common_functions.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) - : ServiceFramework{system_, "IAppletCommonFunctions"} { +IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_, + std::shared_ptr applet_) + : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "SetTerminateResult"}, @@ -40,6 +42,11 @@ IAppletCommonFunctions::~IAppletCommonFunctions() = default; void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->cpu_boost_request_priority = rp.Pop(); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } diff --git a/src/core/hle/service/am/applet_common_functions.h b/src/core/hle/service/am/applet_common_functions.h index be87b3820..229555669 100644 --- a/src/core/hle/service/am/applet_common_functions.h +++ b/src/core/hle/service/am/applet_common_functions.h @@ -7,13 +7,17 @@ namespace Service::AM { +struct Applet; + class IAppletCommonFunctions final : public ServiceFramework { public: - explicit IAppletCommonFunctions(Core::System& system_); + explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr applet_); ~IAppletCommonFunctions() override; private: void SetCpuBoostRequestPriority(HLERequestContext& ctx); + + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index 4aac5dba7..efbd0108c 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -294,8 +294,8 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters( } // Applet was started by frontend, so it is foreground. - applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); applet->focus_state = FocusState::InFocus; this->InsertApplet(std::move(applet)); diff --git a/src/core/hle/service/am/applet_message_queue.cpp b/src/core/hle/service/am/applet_message_queue.cpp index e4931031d..5ed996b70 100644 --- a/src/core/hle/service/am/applet_message_queue.cpp +++ b/src/core/hle/service/am/applet_message_queue.cpp @@ -26,11 +26,15 @@ Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { } void AppletMessageQueue::PushMessage(AppletMessage msg) { - messages.push(msg); + { + std::scoped_lock lk{lock}; + messages.push(msg); + } on_new_message->Signal(); } AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { + std::scoped_lock lk{lock}; if (messages.empty()) { on_new_message->Clear(); return AppletMessage::None; @@ -44,6 +48,7 @@ AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { } std::size_t AppletMessageQueue::GetMessageCount() const { + std::scoped_lock lk{lock}; return messages.size(); } diff --git a/src/core/hle/service/am/applet_message_queue.h b/src/core/hle/service/am/applet_message_queue.h index 60145aae9..5cb236d47 100644 --- a/src/core/hle/service/am/applet_message_queue.h +++ b/src/core/hle/service/am/applet_message_queue.h @@ -69,6 +69,7 @@ private: Kernel::KEvent* on_new_message; Kernel::KEvent* on_operation_mode_changed; + mutable std::mutex lock; std::queue messages; }; diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index f373d1136..56bafd162 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -2,24 +2,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/am/am.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/application_proxy.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(nvnflinger, msg_queue, system); -} - -AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, - msg_queue{std::move(msg_queue_)} { +AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) + : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} { static const FunctionInfo functions[] = { {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; @@ -28,8 +19,24 @@ AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, AppletOE::~AppletOE() = default; -const std::shared_ptr& AppletOE::GetMessageQueue() const { - return msg_queue; +void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + if (const auto applet = GetAppletFromContext(ctx)) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + } +} + +std::shared_ptr AppletOE::GetAppletFromContext(HLERequestContext& ctx) { + const auto aruid = ctx.GetPID(); + return system.GetAppletManager().GetByAppletResourceUserId(aruid); } } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 39eccc4ab..f2ba1c924 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -18,21 +18,19 @@ class Nvnflinger; namespace AM { -class AppletMessageQueue; +struct Applet; class AppletOE final : public ServiceFramework { public: - explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, Core::System& system_); + explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); ~AppletOE() override; - const std::shared_ptr& GetMessageQueue() const; - private: void OpenApplicationProxy(HLERequestContext& ctx); + std::shared_ptr GetAppletFromContext(HLERequestContext& ctx); + Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; }; } // namespace AM diff --git a/src/core/hle/service/am/application_functions.cpp b/src/core/hle/service/am/application_functions.cpp index fef45c732..51c5be2d1 100644 --- a/src/core/hle/service/am/application_functions.cpp +++ b/src/core/hle/service/am/application_functions.cpp @@ -9,6 +9,7 @@ #include "core/file_sys/savedata_factory.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" #include "core/hle/service/am/application_functions.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/filesystem/filesystem.h" @@ -24,19 +25,8 @@ enum class LaunchParameterKind : u32 { AccountPreselectedUser = 2, }; -constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; - -struct LaunchParameterAccountPreselectedUser { - u32_le magic; - u32_le is_account_selected; - Common::UUID current_user; - INSERT_PADDING_BYTES(0x70); -}; -static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); - -IApplicationFunctions::IApplicationFunctions(Core::System& system_) - : ServiceFramework{system_, "IApplicationFunctions"}, - service_context{system, "IApplicationFunctions"} { +IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr applet_) + : ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, @@ -105,27 +95,16 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) // clang-format on RegisterHandlers(functions); - - gpu_error_detected_event = - service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); - friend_invitation_storage_channel_event = - service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); - notification_storage_channel_event = - service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); - health_warning_disappeared_system_event = - service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); } -IApplicationFunctions::~IApplicationFunctions() { - service_context.CloseEvent(gpu_error_detected_event); - service_context.CloseEvent(friend_invitation_storage_channel_event); - service_context.CloseEvent(notification_storage_channel_event); - service_context.CloseEvent(health_warning_disappeared_system_event); -} +IApplicationFunctions::~IApplicationFunctions() = default; void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->application_crash_report_enabled = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -157,6 +136,10 @@ void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = true; + applet->home_button_short_pressed_blocked = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -164,6 +147,10 @@ void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLEReques void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = false; + applet->home_button_short_pressed_blocked = false; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -171,6 +158,11 @@ void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestC void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = true; + applet->home_button_short_pressed_blocked = true; + applet->home_button_double_click_enabled = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -178,6 +170,11 @@ void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = false; + applet->home_button_short_pressed_blocked = false; + applet->home_button_double_click_enabled = false; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -188,47 +185,25 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called, kind={:08X}", kind); - if (kind == LaunchParameterKind::UserChannel) { - auto channel = system.GetUserChannel(); - if (channel.empty()) { - LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - auto data = channel.back(); - channel.pop_back(); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(data)); - } else if (kind == LaunchParameterKind::AccountPreselectedUser && - !launch_popped_account_preselect) { - // TODO: Verify this is hw-accurate - LaunchParameterAccountPreselectedUser params{}; - - params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; - params.is_account_selected = 1; - - Account::ProfileManager profile_manager{}; - const auto uuid = profile_manager.GetUser(static_cast(Settings::values.current_user)); - ASSERT(uuid.has_value() && uuid->IsValid()); - params.current_user = *uuid; + std::scoped_lock lk{applet->lock}; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); + auto& channel = kind == LaunchParameterKind::UserChannel + ? applet->user_channel_launch_parameter + : applet->preselected_user_launch_parameter; - std::vector buffer(sizeof(LaunchParameterAccountPreselectedUser)); - std::memcpy(buffer.data(), ¶ms, buffer.size()); - - rb.PushIpcInterface(system, std::move(buffer)); - launch_popped_account_preselect = true; - } else { - LOG_ERROR(Service_AM, "Unknown launch parameter kind."); + if (channel.empty()) { + LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(AM::ResultNoDataInChannel); + return; } + + auto data = channel.back(); + channel.pop_back(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, std::move(data)); } void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { @@ -245,7 +220,7 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); FileSys::SaveDataAttribute attribute{}; - attribute.title_id = system.GetApplicationProcessProgramID(); + attribute.title_id = applet->program_id; attribute.user_id = user_id; attribute.type = FileSys::SaveDataType::SaveData; @@ -267,6 +242,9 @@ void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { u32 result = rp.Pop(); LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); + std::scoped_lock lk{applet->lock}; + applet->terminate_result = Result(result); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -277,16 +255,14 @@ void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { std::array version_string{}; const auto res = [this] { - const auto title_id = system.GetApplicationProcessProgramID(); - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(), system.GetContentProvider()}; auto metadata = pm.GetControlMetadata(); if (metadata.first != nullptr) { return metadata; } - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id), system.GetFileSystemController(), system.GetContentProvider()}; return pm_update.GetControlMetadata(); @@ -314,16 +290,14 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { u32 supported_languages = 0; const auto res = [this] { - const auto title_id = system.GetApplicationProcessProgramID(); - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(), system.GetContentProvider()}; auto metadata = pm.GetControlMetadata(); if (metadata.first != nullptr) { return metadata; } - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id), system.GetFileSystemController(), system.GetContentProvider()}; return pm_update.GetControlMetadata(); @@ -368,11 +342,9 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - constexpr bool gameplay_recording_supported = false; - IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(gameplay_recording_supported); + rb.Push(applet->gameplay_recording_supported); } void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { @@ -385,6 +357,11 @@ void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->gameplay_recording_state = rp.PopRaw(); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -392,6 +369,9 @@ void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->is_running = true; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(0); // Unknown, seems to be ignored by official processes @@ -426,8 +406,7 @@ void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { static_cast(type), user_id[1], user_id[0], new_normal_size, new_journal_size); system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( - type, system.GetApplicationProcessProgramID(), user_id, - {new_normal_size, new_journal_size}); + type, applet->program_id, user_id, {new_normal_size, new_journal_size}); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -451,7 +430,7 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { user_id[0]); const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( - type, system.GetApplicationProcessProgramID(), user_id); + type, applet->program_id, user_id); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); @@ -528,13 +507,15 @@ void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); + // Swap user channel ownership into the system so that it will be preserved + system.GetUserChannel().swap(applet->user_channel_launch_parameter); system.ExecuteProgram(program_index); } void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - system.GetUserChannel().clear(); + applet->user_channel_launch_parameter.clear(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -546,7 +527,7 @@ void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto storage = rp.PopIpcInterface().lock(); if (storage) { - system.GetUserChannel().push_back(storage->GetData()); + applet->user_channel_launch_parameter.push_back(storage->GetData()); } IPC::ResponseBuilder rb{ctx, 2}; @@ -558,7 +539,7 @@ void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(previous_program_index); + rb.Push(applet->previous_program_index); } void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { @@ -566,7 +547,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ct IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); + rb.PushCopyObjects(applet->gpu_error_detected_event.GetHandle()); } void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { @@ -574,7 +555,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestCon IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); + rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle()); } void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { @@ -589,7 +570,7 @@ void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); + rb.PushCopyObjects(applet->notification_storage_channel_event.GetHandle()); } void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { @@ -597,12 +578,15 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestCon IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); + rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle()); } void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->jit_service_launched = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } diff --git a/src/core/hle/service/am/application_functions.h b/src/core/hle/service/am/application_functions.h index 22aab1c8f..55eb21d39 100644 --- a/src/core/hle/service/am/application_functions.h +++ b/src/core/hle/service/am/application_functions.h @@ -8,9 +8,11 @@ namespace Service::AM { +struct Applet; + class IApplicationFunctions final : public ServiceFramework { public: - explicit IApplicationFunctions(Core::System& system_); + explicit IApplicationFunctions(Core::System& system_, std::shared_ptr applet_); ~IApplicationFunctions() override; private: @@ -50,14 +52,7 @@ private: void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); void PrepareForJit(HLERequestContext& ctx); - KernelHelpers::ServiceContext service_context; - - bool launch_popped_account_preselect = false; - s32 previous_program_index{-1}; - Kernel::KEvent* gpu_error_detected_event; - Kernel::KEvent* friend_invitation_storage_channel_event; - Kernel::KEvent* notification_storage_channel_event; - Kernel::KEvent* health_warning_disappeared_system_event; + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/application_proxy.cpp b/src/core/hle/service/am/application_proxy.cpp index e9cd0aa71..99e97f4bc 100644 --- a/src/core/hle/service/am/application_proxy.cpp +++ b/src/core/hle/service/am/application_proxy.cpp @@ -18,10 +18,9 @@ namespace Service::AM { IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, - msg_queue{std::move(msg_queue_)} { + std::shared_ptr applet_, Core::System& system_) + : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -39,6 +38,8 @@ IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, RegisterHandlers(functions); } +IApplicationProxy::~IApplicationProxy() = default; + void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -60,7 +61,7 @@ void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { @@ -76,7 +77,7 @@ void IApplicationProxy::GetWindowController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { @@ -84,7 +85,7 @@ void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nvnflinger); + rb.PushIpcInterface(system, applet, nvnflinger); } void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { @@ -92,7 +93,7 @@ void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, msg_queue); + rb.PushIpcInterface(system, applet); } void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { @@ -100,7 +101,7 @@ void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { @@ -108,7 +109,7 @@ void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } } // namespace Service::AM diff --git a/src/core/hle/service/am/application_proxy.h b/src/core/hle/service/am/application_proxy.h index 4f620242b..eb98b095c 100644 --- a/src/core/hle/service/am/application_proxy.h +++ b/src/core/hle/service/am/application_proxy.h @@ -3,16 +3,17 @@ #pragma once -#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/service.h" namespace Service::AM { +struct Applet; + class IApplicationProxy final : public ServiceFramework { public: explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_); + std::shared_ptr msg_queue_, Core::System& system_); + ~IApplicationProxy(); private: void GetAudioController(HLERequestContext& ctx); @@ -26,7 +27,7 @@ private: void GetApplicationFunctions(HLERequestContext& ctx); Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; + std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/common_state_getter.cpp b/src/core/hle/service/am/common_state_getter.cpp index 0b54b769d..77f3fd868 100644 --- a/src/core/hle/service/am/common_state_getter.cpp +++ b/src/core/hle/service/am/common_state_getter.cpp @@ -3,6 +3,7 @@ #include "common/settings.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" #include "core/hle/service/am/common_state_getter.h" #include "core/hle/service/am/lock_accessor.h" #include "core/hle/service/apm/apm_controller.h" @@ -14,10 +15,8 @@ namespace Service::AM { -ICommonStateGetter::ICommonStateGetter(Core::System& system_, - std::shared_ptr msg_queue_) - : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, - service_context{system_, "ICommonStateGetter"} { +ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr applet_) + : ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, @@ -75,17 +74,9 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, // clang-format on RegisterHandlers(functions); - - sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); - - // Configure applets to be in foreground state - msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); - msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); } -ICommonStateGetter::~ICommonStateGetter() { - service_context.CloseEvent(sleep_lock_event); -}; +ICommonStateGetter::~ICommonStateGetter() = default; void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -96,17 +87,17 @@ void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { } void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + LOG_DEBUG(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); + rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent()); } void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - const auto message = msg_queue->PopMessage(); + const auto message = applet->message_queue.PopMessage(); IPC::ResponseBuilder rb{ctx, 3}; if (message == AppletMessageQueue::AppletMessage::None) { @@ -123,9 +114,11 @@ void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(static_cast(FocusState::InFocus)); + rb.Push(static_cast(applet->focus_state)); } void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { @@ -149,7 +142,7 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); // Sleep lock is acquired immediately. - sleep_lock_event->Signal(); + applet->sleep_lock_event.Signal(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -172,22 +165,25 @@ void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); + rb.PushCopyObjects(applet->sleep_lock_event.GetHandle()); } void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); + std::scoped_lock lk{applet->lock}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(vr_mode_state); + rb.Push(applet->vr_mode_enabled); } void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - vr_mode_state = rp.Pop(); - LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = rp.Pop(); + LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "on" : "off"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -207,6 +203,9 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -214,6 +213,9 @@ void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = false; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -223,7 +225,7 @@ void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContex IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); + rb.PushCopyObjects(applet->message_queue.GetOperationModeChangedEvent()); } void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { @@ -281,6 +283,9 @@ void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnable HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->request_exit_to_library_applet_at_execute_next_program_enabled = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } diff --git a/src/core/hle/service/am/common_state_getter.h b/src/core/hle/service/am/common_state_getter.h index 11d66f10a..643ca4dc5 100644 --- a/src/core/hle/service/am/common_state_getter.h +++ b/src/core/hle/service/am/common_state_getter.h @@ -10,10 +10,11 @@ namespace Service::AM { +struct Applet; + class ICommonStateGetter final : public ServiceFramework { public: - explicit ICommonStateGetter(Core::System& system_, - std::shared_ptr msg_queue_); + explicit ICommonStateGetter(Core::System& system_, std::shared_ptr applet_); ~ICommonStateGetter() override; private: @@ -69,10 +70,7 @@ private: void GetSettingsPlatformRegion(HLERequestContext& ctx); void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); - std::shared_ptr msg_queue; - bool vr_mode_state{}; - Kernel::KEvent* sleep_lock_event; - KernelHelpers::ServiceContext service_context; + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp index 4e8f806d7..38495ee19 100644 --- a/src/core/hle/service/am/frontend/applets.cpp +++ b/src/core/hle/service/am/frontend/applets.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/frontend/applet_cabinet.h" @@ -122,21 +123,11 @@ void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr&& void AppletDataBroker::SignalStateChanged() { state_changed_event->Signal(); + // TODO proper window management switch (applet_mode) { case LibraryAppletMode::AllForeground: case LibraryAppletMode::AllForegroundInitiallyHidden: { - auto applet_oe = system.ServiceManager().GetService("appletOE"); - auto applet_ae = system.ServiceManager().GetService("appletAE"); - - if (applet_oe) { - applet_oe->GetMessageQueue()->FocusStateChanged(); - break; - } - - if (applet_ae) { - applet_ae->GetMessageQueue()->FocusStateChanged(); - break; - } + system.GetAppletManager().FocusStateChanged(); break; } default: @@ -255,11 +246,6 @@ void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) { current_applet_id = applet_id; } -void FrontendAppletHolder::SetDefaultAppletFrontendSet() { - ClearAll(); - SetDefaultAppletsIfMissing(); -} - void FrontendAppletHolder::SetDefaultAppletsIfMissing() { if (frontend.cabinet == nullptr) { frontend.cabinet = std::make_unique(); diff --git a/src/core/hle/service/am/frontend/applets.h b/src/core/hle/service/am/frontend/applets.h index f58147955..dec1d63b2 100644 --- a/src/core/hle/service/am/frontend/applets.h +++ b/src/core/hle/service/am/frontend/applets.h @@ -188,7 +188,6 @@ public: void SetFrontendAppletSet(FrontendAppletSet set); void SetCabinetMode(NFP::CabinetMode mode); void SetCurrentAppletId(AppletId applet_id); - void SetDefaultAppletFrontendSet(); void SetDefaultAppletsIfMissing(); void ClearAll(); diff --git a/src/core/hle/service/am/library_applet_accessor.cpp b/src/core/hle/service/am/library_applet_accessor.cpp index dabbd6dbe..d3be493e6 100644 --- a/src/core/hle/service/am/library_applet_accessor.cpp +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -1,7 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/scope_exit.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/ipc_helpers.h" @@ -9,8 +11,10 @@ namespace Service::AM { ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, - std::shared_ptr applet_) - : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { + std::shared_ptr storage_, + std::shared_ptr applet_) + : ServiceFramework{system_, "ILibraryAppletAccessor"}, storage{std::move(storage_)}, + applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, @@ -38,27 +42,31 @@ ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, RegisterHandlers(functions); } +ILibraryAppletAccessor::~ILibraryAppletAccessor() = default; + void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); + rb.PushCopyObjects(storage->state_changed_event.GetHandle()); } void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); + std::scoped_lock lk{applet->lock}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(applet->TransactionComplete()); + rb.Push(applet->is_completed); } void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(applet->GetStatus()); + rb.Push(applet->terminate_result); } void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { @@ -71,10 +79,7 @@ void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestConte void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - ASSERT(applet != nullptr); - - applet->Initialize(); - applet->Execute(); + applet->process->Run(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -84,16 +89,17 @@ void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); ASSERT(applet != nullptr); + applet->message_queue.RequestExit(); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(applet->RequestExit()); + rb.Push(ResultSuccess); } void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::RequestParser rp{ctx}; - applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface().lock()); + storage->in_data.PushData(rp.PopIpcInterface().lock()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -102,29 +108,24 @@ void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - auto storage = applet->GetBroker().PopNormalDataToGame(); - if (storage == nullptr) { - LOG_DEBUG(Service_AM, - "storage is a nullptr. There is no data in the current normal channel"); + std::shared_ptr data; + const auto res = storage->out_data.PopData(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; + rb.Push(res); } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(std::move(storage)); } void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::RequestParser rp{ctx}; - applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface().lock()); - - ASSERT(applet->IsInitialized()); - applet->ExecuteInteractive(); - applet->Execute(); + storage->interactive_in_data.PushData(rp.PopIpcInterface().lock()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -133,18 +134,17 @@ void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - auto storage = applet->GetBroker().PopInteractiveDataToGame(); - if (storage == nullptr) { - LOG_DEBUG(Service_AM, - "storage is a nullptr. There is no data in the current interactive channel"); + std::shared_ptr data; + const auto res = storage->interactive_out_data.PopData(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; + rb.Push(res); } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(std::move(storage)); } void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { @@ -152,7 +152,7 @@ void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); + rb.PushCopyObjects(storage->out_data.GetEvent()); } void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { @@ -160,7 +160,7 @@ void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ct IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); + rb.PushCopyObjects(storage->interactive_out_data.GetEvent()); } void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/library_applet_accessor.h b/src/core/hle/service/am/library_applet_accessor.h index 77f62906c..c34a1cbca 100644 --- a/src/core/hle/service/am/library_applet_accessor.h +++ b/src/core/hle/service/am/library_applet_accessor.h @@ -3,17 +3,21 @@ #pragma once -#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/service.h" namespace Service::AM { +struct AppletStorageHolder; +struct Applet; + class ILibraryAppletAccessor final : public ServiceFramework { public: explicit ILibraryAppletAccessor(Core::System& system_, - std::shared_ptr applet_); + std::shared_ptr storage_, + std::shared_ptr applet_); + ~ILibraryAppletAccessor(); -private: +protected: void GetAppletStateChangedEvent(HLERequestContext& ctx); void IsCompleted(HLERequestContext& ctx); void GetResult(HLERequestContext& ctx); @@ -28,7 +32,8 @@ private: void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); - std::shared_ptr applet; + const std::shared_ptr storage; + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp index f80887517..e4332e244 100644 --- a/src/core/hle/service/am/library_applet_creator.cpp +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -2,16 +2,112 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" #include "core/hle/service/am/library_applet_creator.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/sm/sm.h" namespace Service::AM { -ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletCreator"} { +namespace { + +AppletProgramId AppletIdToProgramId(AppletId applet_id) { + switch (applet_id) { + case AppletId::OverlayDisplay: + return AppletProgramId::OverlayDisplay; + case AppletId::QLaunch: + return AppletProgramId::QLaunch; + case AppletId::Starter: + return AppletProgramId::Starter; + case AppletId::Auth: + return AppletProgramId::Auth; + case AppletId::Cabinet: + return AppletProgramId::Cabinet; + case AppletId::Controller: + return AppletProgramId::Controller; + case AppletId::DataErase: + return AppletProgramId::DataErase; + case AppletId::Error: + return AppletProgramId::Error; + case AppletId::NetConnect: + return AppletProgramId::NetConnect; + case AppletId::ProfileSelect: + return AppletProgramId::ProfileSelect; + case AppletId::SoftwareKeyboard: + return AppletProgramId::SoftwareKeyboard; + case AppletId::MiiEdit: + return AppletProgramId::MiiEdit; + case AppletId::Web: + return AppletProgramId::Web; + case AppletId::Shop: + return AppletProgramId::Shop; + case AppletId::PhotoViewer: + return AppletProgramId::PhotoViewer; + case AppletId::Settings: + return AppletProgramId::Settings; + case AppletId::OfflineWeb: + return AppletProgramId::OfflineWeb; + case AppletId::LoginShare: + return AppletProgramId::LoginShare; + case AppletId::WebAuth: + return AppletProgramId::WebAuth; + case AppletId::MyPage: + return AppletProgramId::MyPage; + default: + return static_cast(0); + } +} + +std::shared_ptr CreateGuestApplet(Core::System& system, + std::shared_ptr caller_applet, + AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast(AppletIdToProgramId(applet_id)); + if (program_id == 0) { + // Unknown applet + return {}; + } + + auto process = std::make_unique(system); + if (!process->Initialize(program_id)) { + // Couldn't initialize the guest process + return {}; + } + + const auto applet = std::make_shared(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + // Library applet should be foreground + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + applet->focus_state = FocusState::InFocus; + + auto storage = std::make_shared(system); + applet->caller_applet = caller_applet; + applet->caller_applet_storage = storage; + + system.GetAppletManager().InsertApplet(applet); + + return std::make_shared(system, storage, applet); +} + +std::shared_ptr CreateFrontendApplet(Core::System& system, + AppletId applet_id, + LibraryAppletMode mode) { + UNREACHABLE(); + return {}; +} + +} // namespace + +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr applet_) + : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} { static const FunctionInfo functions[] = { {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, {1, nullptr, "TerminateAllLibraryApplets"}, @@ -34,10 +130,11 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, applet_mode); - const auto& holder{system.GetFrontendAppletHolder()}; - const auto applet = holder.GetApplet(applet_id, applet_mode); - - if (applet == nullptr) { + auto library_applet = CreateGuestApplet(system, applet, applet_id, applet_mode); + if (!library_applet) { + library_applet = CreateFrontendApplet(system, applet_id, applet_mode); + } + if (!library_applet) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -45,10 +142,12 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { return; } - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + // Applet is created, can now be launched. + applet->library_applet_launchable_event.Signal(); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, applet); + rb.PushIpcInterface(library_applet); } void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/library_applet_creator.h b/src/core/hle/service/am/library_applet_creator.h index 97f236fbc..551f287bd 100644 --- a/src/core/hle/service/am/library_applet_creator.h +++ b/src/core/hle/service/am/library_applet_creator.h @@ -7,9 +7,11 @@ namespace Service::AM { +struct Applet; + class ILibraryAppletCreator final : public ServiceFramework { public: - explicit ILibraryAppletCreator(Core::System& system_); + explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr applet_); ~ILibraryAppletCreator() override; private: @@ -17,6 +19,8 @@ private: void CreateStorage(HLERequestContext& ctx); void CreateTransferMemoryStorage(HLERequestContext& ctx); void CreateHandleStorage(HLERequestContext& ctx); + + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_proxy.cpp b/src/core/hle/service/am/library_applet_proxy.cpp index 047fc40f4..1d88dd78c 100644 --- a/src/core/hle/service/am/library_applet_proxy.cpp +++ b/src/core/hle/service/am/library_applet_proxy.cpp @@ -19,10 +19,9 @@ namespace Service::AM { ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, - msg_queue{std::move(msg_queue_)} { + std::shared_ptr applet_, Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -43,12 +42,14 @@ ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, RegisterHandlers(functions); } +ILibraryAppletProxy::~ILibraryAppletProxy() = default; + void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, msg_queue); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { @@ -56,7 +57,7 @@ void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nvnflinger); + rb.PushIpcInterface(system, applet, nvnflinger); } void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { @@ -64,7 +65,7 @@ void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { @@ -88,7 +89,7 @@ void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { @@ -96,7 +97,7 @@ void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { @@ -104,7 +105,7 @@ void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { @@ -112,7 +113,7 @@ void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/library_applet_proxy.h b/src/core/hle/service/am/library_applet_proxy.h index cd9e6d02b..8f7a25897 100644 --- a/src/core/hle/service/am/library_applet_proxy.h +++ b/src/core/hle/service/am/library_applet_proxy.h @@ -3,16 +3,17 @@ #pragma once -#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/service.h" namespace Service::AM { +struct Applet; + class ILibraryAppletProxy final : public ServiceFramework { public: explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_); + std::shared_ptr applet_, Core::System& system_); + ~ILibraryAppletProxy(); private: void GetCommonStateGetter(HLERequestContext& ctx); @@ -29,7 +30,7 @@ private: void GetDebugFunctions(HLERequestContext& ctx); Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; + std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp index c36f141f4..74ee33213 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -1,9 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/scope_exit.h" #include "core/core_timing.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/frontend/applet_cabinet.h" #include "core/hle/service/am/frontend/applet_controller.h" #include "core/hle/service/am/frontend/applet_mii_edit_types.h" @@ -16,16 +18,44 @@ namespace Service::AM { -ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { +namespace { + +struct AppletIdentityInfo { + AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; +}; +static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + +AppletIdentityInfo GetCallerIdentity(std::shared_ptr applet) { + if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) { + // TODO: is this actually the application ID? + return { + .applet_id = applet->applet_id, + .application_id = applet->program_id, + }; + } else { + return { + .applet_id = AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + } +} + +} // namespace + +ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, + std::shared_ptr applet_) + : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)}, + storage{applet->caller_applet_storage} { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, - {2, nullptr, "PopInteractiveInData"}, - {3, nullptr, "PushInteractiveOutData"}, - {5, nullptr, "GetPopInDataEvent"}, - {6, nullptr, "GetPopInteractiveInDataEvent"}, + {2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"}, + {3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"}, + {5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"}, + {6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"}, {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, @@ -58,26 +88,6 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) }; // clang-format on RegisterHandlers(functions); - - switch (system.GetFrontendAppletHolder().GetCurrentAppletId()) { - case AppletId::Cabinet: - PushInShowCabinetData(); - break; - case AppletId::MiiEdit: - PushInShowMiiEditData(); - break; - case AppletId::PhotoViewer: - PushInShowAlbum(); - break; - case AppletId::SoftwareKeyboard: - PushInShowSoftwareKeyboard(); - break; - case AppletId::Controller: - PushInShowController(); - break; - default: - break; - } } ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; @@ -85,31 +95,81 @@ ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called"); - if (queue_data.empty()) { + std::shared_ptr data; + const auto res = storage->in_data.PopData(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; + rb.Push(res); } +} + +void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); - auto data = queue_data.front(); - queue_data.pop_front(); + IPC::RequestParser rp{ctx}; + storage->out_data.PushData(rp.PopIpcInterface().lock()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(data)); } -void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); +void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr data; + const auto res = storage->interactive_in_data.PopData(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + } +} + +void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + storage->interactive_out_data.PushData(rp.PopIpcInterface().lock()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } +void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(storage->in_data.GetEvent()); +} + +void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(storage->interactive_in_data.GetEvent()); +} + void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_INFO(Service_AM, "called"); + + system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid); - system.Exit(); + { + std::scoped_lock lk{applet->lock}; + applet->is_completed = true; + storage->state_changed_event.Signal(); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -124,8 +184,8 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); const LibraryAppletInfo applet_info{ - .applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(), - .library_applet_mode = LibraryAppletMode::AllForeground, + .applet_id = applet->applet_id, + .library_applet_mode = applet->library_applet_mode, }; IPC::ResponseBuilder rb{ctx, 4}; @@ -134,13 +194,6 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { } void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { - struct AppletIdentityInfo { - AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; - }; - static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); - LOG_WARNING(Service_AM, "(STUBBED) called"); const AppletIdentityInfo applet_info{ @@ -154,22 +207,11 @@ void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ct } void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { - struct AppletIdentityInfo { - AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; - }; - static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); LOG_WARNING(Service_AM, "(STUBBED) called"); - const AppletIdentityInfo applet_info{ - .applet_id = AppletId::QLaunch, - .application_id = 0x0100000000001000ull, - }; - IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - rb.PushRaw(applet_info); + rb.PushRaw(GetCallerIdentity(applet)); } void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { @@ -207,176 +249,4 @@ void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext rb.Push(0); } -void ILibraryAppletSelfAccessor::PushInShowAlbum() { - const CommonArguments arguments{ - .arguments_version = CommonArgumentVersion::Version3, - .size = CommonArgumentSize::Version3, - .library_version = 1, - .theme_color = ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector argument_data(sizeof(arguments)); - std::vector settings_data{2}; - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(settings_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowController() { - const CommonArguments common_args = { - .arguments_version = CommonArgumentVersion::Version3, - .size = CommonArgumentSize::Version3, - .library_version = static_cast(Frontend::ControllerAppletVersion::Version8), - .theme_color = ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - Frontend::ControllerSupportArgNew user_args = { - .header = {.player_count_min = 1, - .player_count_max = 4, - .enable_take_over_connection = true, - .enable_left_justify = false, - .enable_permit_joy_dual = true, - .enable_single_mode = false, - .enable_identification_color = false}, - .identification_colors = {}, - .enable_explain_text = false, - .explain_text = {}, - }; - - Frontend::ControllerSupportArgPrivate private_args = { - .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate), - .arg_size = sizeof(Frontend::ControllerSupportArgNew), - .is_home_menu = true, - .flag_1 = true, - .mode = Frontend::ControllerSupportMode::ShowControllerSupport, - .caller = Frontend::ControllerSupportCaller:: - Application, // switchbrew: Always zero except with - // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, - // which sets this to the input param - .style_set = Core::HID::NpadStyleSet::None, - .joy_hold_type = 0, - }; - std::vector common_args_data(sizeof(common_args)); - std::vector private_args_data(sizeof(private_args)); - std::vector user_args_data(sizeof(user_args)); - - std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); - std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); - std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); - - queue_data.emplace_back(std::move(common_args_data)); - queue_data.emplace_back(std::move(private_args_data)); - queue_data.emplace_back(std::move(user_args_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowCabinetData() { - const CommonArguments arguments{ - .arguments_version = CommonArgumentVersion::Version3, - .size = CommonArgumentSize::Version3, - .library_version = static_cast(Frontend::CabinetAppletVersion::Version1), - .theme_color = ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - const Frontend::StartParamForAmiiboSettings amiibo_settings{ - .param_1 = 0, - .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(), - .flags = Frontend::CabinetFlags::None, - .amiibo_settings_1 = 0, - .device_handle = 0, - .tag_info{}, - .register_info{}, - .amiibo_settings_3{}, - }; - - std::vector argument_data(sizeof(arguments)); - std::vector settings_data(sizeof(amiibo_settings)); - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(settings_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { - struct MiiEditV3 { - Frontend::MiiEditAppletInputCommon common; - Frontend::MiiEditAppletInputV3 input; - }; - static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); - - MiiEditV3 mii_arguments{ - .common = - { - .version = Frontend::MiiEditAppletVersion::Version3, - .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit, - }, - .input{}, - }; - - std::vector argument_data(sizeof(mii_arguments)); - std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); - - queue_data.emplace_back(std::move(argument_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { - const CommonArguments arguments{ - .arguments_version = CommonArgumentVersion::Version3, - .size = CommonArgumentSize::Version3, - .library_version = static_cast(Frontend::SwkbdAppletVersion::Version524301), - .theme_color = ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector initial_string(0); - - const Frontend::SwkbdConfigCommon swkbd_config{ - .type = Frontend::SwkbdType::Qwerty, - .ok_text{}, - .left_optional_symbol_key{}, - .right_optional_symbol_key{}, - .use_prediction = false, - .key_disable_flags{}, - .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start, - .header_text{}, - .sub_text{}, - .guide_text{}, - .max_text_length = 500, - .min_text_length = 0, - .password_mode = Frontend::SwkbdPasswordMode::Disabled, - .text_draw_type = Frontend::SwkbdTextDrawType::Box, - .enable_return_button = true, - .use_utf8 = false, - .use_blur_background = true, - .initial_string_offset{}, - .initial_string_length = static_cast(initial_string.size()), - .user_dictionary_offset{}, - .user_dictionary_entries{}, - .use_text_check = false, - }; - - Frontend::SwkbdConfigNew swkbd_config_new{}; - - std::vector argument_data(sizeof(arguments)); - std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); - std::vector work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); - - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); - std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, - sizeof(Frontend::SwkbdConfigNew)); - std::memcpy(work_buffer.data(), initial_string.data(), - swkbd_config.initial_string_length * sizeof(char16_t)); - - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(swkbd_data)); - queue_data.emplace_back(std::move(work_buffer)); -} - } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.h b/src/core/hle/service/am/library_applet_self_accessor.h index 45b325b77..b15040539 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.h +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -10,14 +10,21 @@ namespace Service::AM { +struct AppletStorageHolder; +struct Applet; + class ILibraryAppletSelfAccessor final : public ServiceFramework { public: - explicit ILibraryAppletSelfAccessor(Core::System& system_); + explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr applet_); ~ILibraryAppletSelfAccessor() override; private: void PopInData(HLERequestContext& ctx); void PushOutData(HLERequestContext& ctx); + void PopInteractiveInData(HLERequestContext& ctx); + void PushInteractiveOutData(HLERequestContext& ctx); + void GetPopInDataEvent(HLERequestContext& ctx); + void GetPopInteractiveInDataEvent(HLERequestContext& ctx); void GetLibraryAppletInfo(HLERequestContext& ctx); void GetMainAppletIdentityInfo(HLERequestContext& ctx); void ExitProcessAndReturn(HLERequestContext& ctx); @@ -26,13 +33,8 @@ private: void GetMainAppletAvailableUsers(HLERequestContext& ctx); void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); - void PushInShowAlbum(); - void PushInShowCabinetData(); - void PushInShowMiiEditData(); - void PushInShowSoftwareKeyboard(); - void PushInShowController(); - - std::deque> queue_data; + const std::shared_ptr applet; + const std::shared_ptr storage; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp index 7954abd7a..f5ccc4643 100644 --- a/src/core/hle/service/am/process_winding_controller.cpp +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -8,8 +8,9 @@ namespace Service::AM { -IProcessWindingController::IProcessWindingController(Core::System& system_) - : ServiceFramework{system_, "IProcessWindingController"} { +IProcessWindingController::IProcessWindingController(Core::System& system_, + std::shared_ptr applet_) + : ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, @@ -31,34 +32,15 @@ IProcessWindingController::~IProcessWindingController() = default; void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - struct AppletProcessLaunchReason { - u8 flag; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(AppletProcessLaunchReason) == 0x4, - "AppletProcessLaunchReason is an invalid size"); - - AppletProcessLaunchReason reason{ - .flag = 0, - }; - IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushRaw(reason); + rb.PushRaw(applet->launch_reason); } void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { - const auto applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(); - const auto applet_mode = LibraryAppletMode::AllForeground; - - LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, - applet_mode); - - const auto& holder{system.GetFrontendAppletHolder()}; - const auto applet = holder.GetApplet(applet_id, applet_mode); - - if (applet == nullptr) { - LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + const auto caller_applet = applet->caller_applet.lock(); + if (caller_applet == nullptr) { + LOG_ERROR(Service_AM, "No calling applet available"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); @@ -67,7 +49,8 @@ void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, applet); + rb.PushIpcInterface(system, applet->caller_applet_storage, + caller_applet); } } // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.h b/src/core/hle/service/am/process_winding_controller.h index 9b9704201..71ae4c4f5 100644 --- a/src/core/hle/service/am/process_winding_controller.h +++ b/src/core/hle/service/am/process_winding_controller.h @@ -7,14 +7,18 @@ namespace Service::AM { +struct Applet; + class IProcessWindingController final : public ServiceFramework { public: - explicit IProcessWindingController(Core::System& system_); + explicit IProcessWindingController(Core::System& system_, std::shared_ptr applet_); ~IProcessWindingController() override; private: void GetLaunchReason(HLERequestContext& ctx); void OpenCallingLibraryApplet(HLERequestContext& ctx); + + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp index d5de1bb2f..3ac967b4d 100644 --- a/src/core/hle/service/am/self_controller.cpp +++ b/src/core/hle/service/am/self_controller.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/service/am/am_results.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/self_controller.h" #include "core/hle/service/caps/caps_su.h" @@ -12,9 +13,10 @@ namespace Service::AM { -ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) - : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, - service_context{system, "ISelfController"} { +ISelfController::ISelfController(Core::System& system_, std::shared_ptr applet_, + Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &ISelfController::Exit, "Exit"}, @@ -69,24 +71,9 @@ ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& // clang-format on RegisterHandlers(functions); - - launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); - - // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is - // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple - // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not - // suspended if the event has previously been created by a call to - // GetAccumulatedSuspendedTickChangedEvent. - - accumulated_suspended_tick_changed_event = - service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); - accumulated_suspended_tick_changed_event->Signal(); } -ISelfController::~ISelfController() { - service_context.CloseEvent(launchable_event); - service_context.CloseEvent(accumulated_suspended_tick_changed_event); -} +ISelfController::~ISelfController() = default; void ISelfController::Exit(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -94,6 +81,7 @@ void ISelfController::Exit(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); + // TODO system.Exit(); } @@ -120,8 +108,10 @@ void ISelfController::UnlockExit(HLERequestContext& ctx) { } void ISelfController::EnterFatalSection(HLERequestContext& ctx) { - ++num_fatal_sections_entered; - LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); + + std::scoped_lock lk{applet->lock}; + applet->fatal_section_count++; + LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", applet->fatal_section_count); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -131,13 +121,14 @@ void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called."); // Entry and exit of fatal sections must be balanced. - if (num_fatal_sections_entered == 0) { + std::scoped_lock lk{applet->lock}; + if (applet->fatal_section_count == 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(Result{ErrorModule::AM, 512}); + rb.Push(AM::ResultFatalSectionCountImbalance); return; } - --num_fatal_sections_entered; + applet->fatal_section_count--; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -146,11 +137,11 @@ void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - launchable_event->Signal(); + applet->library_applet_launchable_event.Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(launchable_event->GetReadableEvent()); + rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle()); } void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { @@ -158,7 +149,8 @@ void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { const auto permission = rp.PopEnum(); LOG_DEBUG(Service_AM, "called, permission={}", permission); - screenshot_permission = permission; + std::scoped_lock lk{applet->lock}; + applet->screenshot_permission = permission; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -167,8 +159,11 @@ void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - bool flag = rp.Pop(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + const bool notification_enabled = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled); + + std::scoped_lock lk{applet->lock}; + applet->operation_mode_changed_notification_enabled = notification_enabled; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -177,28 +172,27 @@ void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - bool flag = rp.Pop(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + const bool notification_enabled = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled); + + std::scoped_lock lk{applet->lock}; + applet->performance_mode_changed_notification_enabled = notification_enabled; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. IPC::RequestParser rp{ctx}; - struct FocusHandlingModeParams { - u8 unknown0; - u8 unknown1; - u8 unknown2; - }; - const auto flags = rp.PopRaw(); + const auto flags = rp.PopRaw(); LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", flags.unknown0, flags.unknown1, flags.unknown2); + std::scoped_lock lk{applet->lock}; + applet->focus_handling_mode = flags; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -206,24 +200,35 @@ void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->restart_message_enabled = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. IPC::RequestParser rp{ctx}; - bool enabled = rp.Pop(); + const bool enabled = rp.Pop(); LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); + std::scoped_lock lk{applet->lock}; + ASSERT(applet->type == AppletType::Application); + applet->out_of_focus_suspension_enabled = enabled; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + + const auto orientation = rp.PopRaw(); + LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast(orientation)); + + std::scoped_lock lk{applet->lock}; + applet->album_image_orientation = orientation; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -232,14 +237,13 @@ void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - // TODO(Subv): Find out how AM determines the display to use, for now just - // create the layer in the Default display. - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto layer_id = nvnflinger.CreateLayer(*display_id); + u64 layer_id{}; + applet->managed_layer_holder.Initialize(&nvnflinger); + applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_id); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(*layer_id); + rb.Push(layer_id); } void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { @@ -252,56 +256,46 @@ void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + u64 buffer_id, layer_id; + applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id); + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); - rb.Push(system_shared_buffer_id); - rb.Push(system_shared_layer_id); + rb.Push(buffer_id); + rb.Push(layer_id); } void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + u64 buffer_id, layer_id; + applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); - rb.Push(system_shared_buffer_id); + rb.Push(buffer_id); } Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { - if (buffer_sharing_enabled) { + if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) { return ResultSuccess; } - if (system.GetFrontendAppletHolder().GetCurrentAppletId() <= AppletId::Application) { - return VI::ResultOperationFailed; - } - - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto result = nvnflinger.GetSystemBufferManager().Initialize( - &system_shared_buffer_id, &system_shared_layer_id, *display_id); - - if (result.IsSuccess()) { - buffer_sharing_enabled = true; - } - - return result; + return VI::ResultOperationFailed; } void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - // TODO(Subv): Find out how AM determines the display to use, for now just - // create the layer in the Default display. - // This calls nn::vi::CreateRecordingLayer() which creates another layer. - // Currently we do not support more than 1 layer per display, output 1 layer id for now. - // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse - // side effects. - // TODO: Support multiple layers - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto layer_id = nvnflinger.CreateLayer(*display_id); + u64 layer_id{}; + u64 recording_layer_id{}; + applet->managed_layer_holder.Initialize(&nvnflinger); + applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id); - IPC::ResponseBuilder rb{ctx, 4}; + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - rb.Push(*layer_id); + rb.Push(layer_id); + rb.Push(recording_layer_id); } void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { @@ -320,9 +314,12 @@ void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - idle_time_detection_extension = rp.Pop(); - LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", - idle_time_detection_extension); + + const auto extension = rp.PopRaw(); + LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", extension); + + std::scoped_lock lk{applet->lock}; + applet->idle_time_detection_extension = extension; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -331,9 +328,11 @@ void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(idle_time_detection_extension); + rb.PushRaw(applet->idle_time_detection_extension); } void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { @@ -345,7 +344,9 @@ void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - is_auto_sleep_disabled = rp.Pop(); + + std::scoped_lock lk{applet->lock}; + applet->auto_sleep_disabled = rp.Pop(); // On the system itself, if the previous state of is_auto_sleep_disabled // differed from the current value passed in, it'd signify the internal @@ -357,7 +358,7 @@ void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { // and it's sufficient to simply set the member variable for querying via // IsAutoSleepDisabled(). - LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); + LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", applet->auto_sleep_disabled); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -366,20 +367,23 @@ void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called."); + std::scoped_lock lk{applet->lock}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(is_auto_sleep_disabled); + rb.Push(applet->auto_sleep_disabled); } void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called."); + std::scoped_lock lk{applet->lock}; // This command returns the total number of system ticks since ISelfController creation // where the game was suspended. Since Yuzu doesn't implement game suspension, this command // can just always return 0 ticks. IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(0); + rb.Push(applet->suspended_ticks); } void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { @@ -387,7 +391,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); + rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle()); } void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { @@ -396,10 +400,11 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& c // This service call sets an internal flag whether a notification is shown when an image is // captured. Currently we do not support capturing images via the capture button, so this can be // stubbed for now. - const bool album_image_taken_notification_enabled = rp.Pop(); + const bool enabled = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); - LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", - album_image_taken_notification_enabled); + std::scoped_lock lk{applet->lock}; + applet->album_image_taken_notification_enabled = enabled; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -427,9 +432,11 @@ void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto is_record_volume_muted = rp.Pop(); + const auto enabled = rp.Pop(); + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); - LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); + std::scoped_lock lk{applet->lock}; + applet->record_volume_muted = enabled; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/am/self_controller.h b/src/core/hle/service/am/self_controller.h index f157bb826..6e6975264 100644 --- a/src/core/hle/service/am/self_controller.h +++ b/src/core/hle/service/am/self_controller.h @@ -8,9 +8,12 @@ namespace Service::AM { +struct Applet; + class ISelfController final : public ServiceFramework { public: - explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); + explicit ISelfController(Core::System& system_, std::shared_ptr applet_, + Nvnflinger::Nvnflinger& nvnflinger_); ~ISelfController() override; private: @@ -47,26 +50,8 @@ private: Result EnsureBufferSharingEnabled(Kernel::KProcess* process); - enum class ScreenshotPermission : u32 { - Inherit = 0, - Enable = 1, - Disable = 2, - }; - Nvnflinger::Nvnflinger& nvnflinger; - - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* launchable_event; - Kernel::KEvent* accumulated_suspended_tick_changed_event; - - u32 idle_time_detection_extension = 0; - u64 num_fatal_sections_entered = 0; - u64 system_shared_buffer_id = 0; - u64 system_shared_layer_id = 0; - bool is_auto_sleep_disabled = false; - bool buffer_sharing_enabled = false; - ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/system_applet_proxy.cpp b/src/core/hle/service/am/system_applet_proxy.cpp index d51a2c8db..e3013271b 100644 --- a/src/core/hle/service/am/system_applet_proxy.cpp +++ b/src/core/hle/service/am/system_applet_proxy.cpp @@ -20,10 +20,9 @@ namespace Service::AM { ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, - msg_queue{std::move(msg_queue_)} { + std::shared_ptr applet_, Core::System& system_) + : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -44,12 +43,14 @@ ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, RegisterHandlers(functions); } +ISystemAppletProxy::~ISystemAppletProxy() = default; + void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, msg_queue); + rb.PushIpcInterface(system, applet); } void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { @@ -57,7 +58,7 @@ void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nvnflinger); + rb.PushIpcInterface(system, applet, nvnflinger); } void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { @@ -65,7 +66,7 @@ void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { @@ -89,7 +90,7 @@ void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { @@ -121,7 +122,7 @@ void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/system_applet_proxy.h b/src/core/hle/service/am/system_applet_proxy.h index b8855b1d6..0390cd1e5 100644 --- a/src/core/hle/service/am/system_applet_proxy.h +++ b/src/core/hle/service/am/system_applet_proxy.h @@ -8,11 +8,13 @@ namespace Service::AM { +struct Applet; + class ISystemAppletProxy final : public ServiceFramework { public: explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr msg_queue_, - Core::System& system_); + std::shared_ptr applet_, Core::System& system_); + ~ISystemAppletProxy(); private: void GetCommonStateGetter(HLERequestContext& ctx); @@ -28,7 +30,7 @@ private: void GetDebugFunctions(HLERequestContext& ctx); Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr msg_queue; + std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/window_controller.cpp b/src/core/hle/service/am/window_controller.cpp index f2ba3c134..430ca180b 100644 --- a/src/core/hle/service/am/window_controller.cpp +++ b/src/core/hle/service/am/window_controller.cpp @@ -1,13 +1,14 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/service/am/applet.h" #include "core/hle/service/am/window_controller.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -IWindowController::IWindowController(Core::System& system_) - : ServiceFramework{system_, "IWindowController"} { +IWindowController::IWindowController(Core::System& system_, std::shared_ptr applet_) + : ServiceFramework{system_, "IWindowController"}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "CreateWindow"}, @@ -27,23 +28,22 @@ IWindowController::IWindowController(Core::System& system_) IWindowController::~IWindowController() = default; void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { - const u64 process_id = system.ApplicationProcess()->GetProcessId(); - - LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); - IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(process_id); + rb.Push(applet->aruid); } void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { - const u64 process_id = 0; + u64 aruid = 0; + if (auto caller = applet->caller_applet.lock(); caller) { + aruid = caller->aruid; + } LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(process_id); + rb.Push(aruid); } void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/window_controller.h b/src/core/hle/service/am/window_controller.h index 07b0e0e17..d97f93737 100644 --- a/src/core/hle/service/am/window_controller.h +++ b/src/core/hle/service/am/window_controller.h @@ -7,15 +7,19 @@ namespace Service::AM { +struct Applet; + class IWindowController final : public ServiceFramework { public: - explicit IWindowController(Core::System& system_); + explicit IWindowController(Core::System& system_, std::shared_ptr applet_); ~IWindowController() override; private: void GetAppletResourceUserId(HLERequestContext& ctx); void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); void AcquireForegroundRights(HLERequestContext& ctx); + + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 1f3d82c57..73058db9a 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -535,6 +535,12 @@ public: RegisterHandlers(functions); } + ~IApplicationDisplayService() { + for (const auto layer_id : stray_layer_ids) { + nvnflinger.DestroyLayer(layer_id); + } + } + private: enum class ConvertedScaleMode : u64 { Freeze = 0, @@ -770,6 +776,7 @@ private: return; } + stray_layer_ids.push_back(*layer_id); const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); if (!buffer_queue_id) { LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); @@ -916,6 +923,7 @@ private: Nvnflinger::Nvnflinger& nvnflinger; Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; + std::vector stray_layer_ids; bool vsync_event_fetched{false}; }; diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 718534ba1..e28df10bd 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/sm/sm.h" @@ -48,22 +49,8 @@ void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system) if (!system.IsPoweredOn()) { return; } - Service::SM::ServiceManager& sm = system.ServiceManager(); - // Message queue is shared between these services, we just need to signal an operation - // change to one and it will handle both automatically - auto applet_oe = sm.GetService("appletOE"); - auto applet_ae = sm.GetService("appletAE"); - bool has_signalled = false; - - if (applet_oe != nullptr) { - applet_oe->GetMessageQueue()->OperationModeChanged(); - has_signalled = true; - } - - if (applet_ae != nullptr && !has_signalled) { - applet_ae->GetMessageQueue()->OperationModeChanged(); - } + system.GetAppletManager().OperationModeChanged(); } ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 02508b20d..4e5c4da53 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4783,36 +4783,12 @@ void GMainWindow::RequestGameExit() { return; } - auto& sm{system->ServiceManager()}; - auto applet_oe = sm.GetService("appletOE"); - auto applet_ae = sm.GetService("appletAE"); - bool has_signalled = false; - system->SetExitRequested(true); - - if (applet_oe != nullptr) { - applet_oe->GetMessageQueue()->RequestExit(); - has_signalled = true; - } - - if (applet_ae != nullptr && !has_signalled) { - applet_ae->GetMessageQueue()->RequestExit(); - } + system->GetAppletManager().RequestExit(); } void GMainWindow::RequestGameResume() { - auto& sm{system->ServiceManager()}; - auto applet_oe = sm.GetService("appletOE"); - auto applet_ae = sm.GetService("appletAE"); - - if (applet_oe != nullptr) { - applet_oe->GetMessageQueue()->RequestResume(); - return; - } - - if (applet_ae != nullptr) { - applet_ae->GetMessageQueue()->RequestResume(); - } + system->GetAppletManager().RequestResume(); } void GMainWindow::filterBarSetChecked(bool state) { -- cgit v1.2.3 From b1c2f791af08b3eaba53c1ce1673fe0729fc5d26 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Jan 2024 21:58:56 -0500 Subject: am: rework IStorage for transfer storage --- src/core/hle/service/am/am_results.h | 1 + src/core/hle/service/am/library_applet_creator.cpp | 28 ++++---- src/core/hle/service/am/storage.cpp | 71 +++++++++--------- src/core/hle/service/am/storage.h | 25 ++----- src/core/hle/service/am/storage_accessor.cpp | 84 ++++++++++++---------- src/core/hle/service/am/storage_accessor.h | 17 ++++- 6 files changed, 117 insertions(+), 109 deletions(-) diff --git a/src/core/hle/service/am/am_results.h b/src/core/hle/service/am/am_results.h index e82d391ad..a2afc9eec 100644 --- a/src/core/hle/service/am/am_results.h +++ b/src/core/hle/service/am/am_results.h @@ -10,6 +10,7 @@ namespace Service::AM { constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; constexpr Result ResultNoMessages{ErrorModule::AM, 3}; constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; +constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511}; constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512}; } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp index e4332e244..888b8b44b 100644 --- a/src/core/hle/service/am/library_applet_creator.cpp +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -6,6 +6,7 @@ #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" #include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_storage.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/sm/sm.h" @@ -164,28 +165,28 @@ void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { return; } - std::vector buffer(size); + std::vector data(size); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(buffer)); + rb.PushIpcInterface(system, AM::CreateStorage(std::move(data))); } void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u8 permissions; + bool is_writable; s64 size; }; - const auto parameters{rp.PopRaw()}; + const auto params{rp.PopRaw()}; const auto handle{ctx.GetCopyHandle(0)}; - LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, - parameters.size, handle); + LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable, + params.size, handle); - if (parameters.size <= 0) { + if (params.size <= 0) { LOG_ERROR(Service_AM, "size is less than or equal to 0"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); @@ -201,12 +202,11 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) return; } - std::vector memory(transfer_mem->GetSize()); - ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(memory)); + rb.PushIpcInterface( + system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), + params.is_writable, params.size)); } void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { @@ -233,12 +233,10 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { return; } - std::vector memory(transfer_mem->GetSize()); - ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, std::move(memory)); + rb.PushIpcInterface( + system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size)); } } // namespace Service::AM diff --git a/src/core/hle/service/am/storage.cpp b/src/core/hle/service/am/storage.cpp index 9a86c867a..4e82afd1c 100644 --- a/src/core/hle/service/am/storage.cpp +++ b/src/core/hle/service/am/storage.cpp @@ -1,60 +1,59 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/am/storage_accessor.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -IStorageImpl::~IStorageImpl() = default; - -class StorageDataImpl final : public IStorageImpl { -public: - explicit StorageDataImpl(std::vector&& buffer_) : buffer{std::move(buffer_)} {} - - std::vector& GetData() override { - return buffer; - } - - const std::vector& GetData() const override { - return buffer; - } - - std::size_t GetSize() const override { - return buffer.size(); - } - -private: - std::vector buffer; -}; - -IStorage::IStorage(Core::System& system_, std::vector&& buffer) - : ServiceFramework{system_, "IStorage"}, - impl{std::make_shared(std::move(buffer))} { - Register(); -} - -void IStorage::Register() { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorage::Open, "Open"}, - {1, nullptr, "OpenTransferStorage"}, - }; - // clang-format on +IStorage::IStorage(Core::System& system_, std::shared_ptr impl_) + : ServiceFramework{system_, "IStorage"}, impl{std::move(impl_)} { + static const FunctionInfo functions[] = { + {0, &IStorage::Open, "Open"}, + {1, &IStorage::OpenTransferStorage, "OpenTransferStorage"}, + }; RegisterHandlers(functions); } +IStorage::IStorage(Core::System& system_, std::vector&& data) + : IStorage(system_, CreateStorage(std::move(data))) {} + IStorage::~IStorage() = default; void IStorage::Open(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); + if (impl->GetHandle() != nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidStorageType); + return; + } + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, impl); +} + +void IStorage::OpenTransferStorage(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + if (impl->GetHandle() == nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidStorageType); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, *this); + rb.PushIpcInterface(system, impl); +} + +std::vector IStorage::GetData() const { + return impl->GetData(); } } // namespace Service::AM diff --git a/src/core/hle/service/am/storage.h b/src/core/hle/service/am/storage.h index d47a8d89f..10d00b141 100644 --- a/src/core/hle/service/am/storage.h +++ b/src/core/hle/service/am/storage.h @@ -7,36 +7,25 @@ namespace Service::AM { -class IStorageImpl { -public: - virtual ~IStorageImpl(); - virtual std::vector& GetData() = 0; - virtual const std::vector& GetData() const = 0; - virtual std::size_t GetSize() const = 0; -}; +class LibraryAppletStorage; class IStorage final : public ServiceFramework { public: + explicit IStorage(Core::System& system_, std::shared_ptr impl_); explicit IStorage(Core::System& system_, std::vector&& buffer); ~IStorage() override; - std::vector& GetData() { - return impl->GetData(); + std::shared_ptr GetImpl() const { + return impl; } - const std::vector& GetData() const { - return impl->GetData(); - } - - std::size_t GetSize() const { - return impl->GetSize(); - } + std::vector GetData() const; private: - void Register(); void Open(HLERequestContext& ctx); + void OpenTransferStorage(HLERequestContext& ctx); - std::shared_ptr impl; + const std::shared_ptr impl; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/storage_accessor.cpp b/src/core/hle/service/am/storage_accessor.cpp index 7d8c82de3..a1184b065 100644 --- a/src/core/hle/service/am/storage_accessor.cpp +++ b/src/core/hle/service/am/storage_accessor.cpp @@ -1,21 +1,22 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" #include "core/hle/service/am/storage_accessor.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) - : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorageAccessor::GetSize, "GetSize"}, - {10, &IStorageAccessor::Write, "Write"}, - {11, &IStorageAccessor::Read, "Read"}, - }; - // clang-format on +IStorageAccessor::IStorageAccessor(Core::System& system_, + std::shared_ptr impl_) + : ServiceFramework{system_, "IStorageAccessor"}, impl{std::move(impl_)} { + static const FunctionInfo functions[] = { + {0, &IStorageAccessor::GetSize, "GetSize"}, + {10, &IStorageAccessor::Write, "Write"}, + {11, &IStorageAccessor::Read, "Read"}, + }; RegisterHandlers(functions); } @@ -28,55 +29,62 @@ void IStorageAccessor::GetSize(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(static_cast(backing.GetSize())); + rb.Push(impl->GetSize()); } void IStorageAccessor::Write(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const u64 offset{rp.Pop()}; + const s64 offset{rp.Pop()}; const auto data{ctx.ReadBuffer()}; - const std::size_t size{std::min(data.size(), backing.GetSize() - offset)}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); - LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - - if (offset > backing.GetSize()) { - LOG_ERROR(Service_AM, - "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", - backing.GetSize(), size, offset); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultInvalidOffset); - return; - } - - std::memcpy(backing.GetData().data() + offset, data.data(), size); + const auto res{impl->Write(offset, data.data(), data.size())}; IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(res); } void IStorageAccessor::Read(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const u64 offset{rp.Pop()}; - const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; + const s64 offset{rp.Pop()}; + std::vector data(ctx.GetWriteBufferSize()); - LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); - if (offset > backing.GetSize()) { - LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", - backing.GetSize(), size, offset); + const auto res{impl->Read(offset, data.data(), data.size())}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultInvalidOffset); - return; - } - - ctx.WriteBuffer(backing.GetData().data() + offset, size); + ctx.WriteBuffer(data); IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_, + std::shared_ptr impl_) + : ServiceFramework{system_, "ITransferStorageAccessor"}, impl{std::move(impl_)} { + static const FunctionInfo functions[] = { + {0, &ITransferStorageAccessor::GetSize, "GetSize"}, + {1, &ITransferStorageAccessor::GetHandle, "GetHandle"}, + }; + + RegisterHandlers(functions); +} + +ITransferStorageAccessor::~ITransferStorageAccessor() = default; + +void ITransferStorageAccessor::GetSize(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(impl->GetSize()); +} + +void ITransferStorageAccessor::GetHandle(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4, 1}; rb.Push(ResultSuccess); + rb.Push(impl->GetSize()); + rb.PushCopyObjects(impl->GetHandle()); } } // namespace Service::AM diff --git a/src/core/hle/service/am/storage_accessor.h b/src/core/hle/service/am/storage_accessor.h index 8648bfc13..b9aa85a66 100644 --- a/src/core/hle/service/am/storage_accessor.h +++ b/src/core/hle/service/am/storage_accessor.h @@ -10,7 +10,7 @@ namespace Service::AM { class IStorageAccessor final : public ServiceFramework { public: - explicit IStorageAccessor(Core::System& system_, IStorage& backing_); + explicit IStorageAccessor(Core::System& system_, std::shared_ptr impl_); ~IStorageAccessor() override; private: @@ -18,7 +18,20 @@ private: void Write(HLERequestContext& ctx); void Read(HLERequestContext& ctx); - IStorage& backing; + const std::shared_ptr impl; +}; + +class ITransferStorageAccessor final : public ServiceFramework { +public: + explicit ITransferStorageAccessor(Core::System& system_, + std::shared_ptr impl_); + ~ITransferStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void GetHandle(HLERequestContext& ctx); + + const std::shared_ptr impl; }; } // namespace Service::AM -- cgit v1.2.3 From 8a146469c0639ff402e77da8843072ce1f2bce0c Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jan 2024 01:16:27 -0500 Subject: am: return AppletDataBroker and use for frontend applets --- src/core/CMakeLists.txt | 2 + src/core/hle/service/am/am_types.h | 2 +- src/core/hle/service/am/applet.cpp | 40 +---- src/core/hle/service/am/applet.h | 36 +---- src/core/hle/service/am/applet_data_broker.cpp | 67 +++++++++ src/core/hle/service/am/applet_data_broker.h | 80 ++++++++++ src/core/hle/service/am/applet_manager.cpp | 27 ++-- .../hle/service/am/frontend/applet_cabinet.cpp | 23 ++- src/core/hle/service/am/frontend/applet_cabinet.h | 5 +- .../hle/service/am/frontend/applet_controller.cpp | 22 ++- .../hle/service/am/frontend/applet_controller.h | 5 +- src/core/hle/service/am/frontend/applet_error.cpp | 14 +- src/core/hle/service/am/frontend/applet_error.h | 6 +- .../hle/service/am/frontend/applet_general.cpp | 75 ++++------ src/core/hle/service/am/frontend/applet_general.h | 15 +- .../hle/service/am/frontend/applet_mii_edit.cpp | 20 +-- src/core/hle/service/am/frontend/applet_mii_edit.h | 5 +- .../service/am/frontend/applet_profile_select.cpp | 19 ++- .../service/am/frontend/applet_profile_select.h | 5 +- .../am/frontend/applet_software_keyboard.cpp | 59 ++++---- .../service/am/frontend/applet_software_keyboard.h | 5 +- .../hle/service/am/frontend/applet_web_browser.cpp | 15 +- .../hle/service/am/frontend/applet_web_browser.h | 7 +- src/core/hle/service/am/frontend/applets.cpp | 165 +++++---------------- src/core/hle/service/am/frontend/applets.h | 89 ++--------- .../hle/service/am/library_applet_accessor.cpp | 44 ++++-- src/core/hle/service/am/library_applet_accessor.h | 10 +- src/core/hle/service/am/library_applet_creator.cpp | 42 ++++-- .../service/am/library_applet_self_accessor.cpp | 22 ++- .../hle/service/am/library_applet_self_accessor.h | 4 +- .../hle/service/am/process_winding_controller.cpp | 2 +- 31 files changed, 424 insertions(+), 508 deletions(-) create mode 100644 src/core/hle/service/am/applet_data_broker.cpp create mode 100644 src/core/hle/service/am/applet_data_broker.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5fb0ad822..570acb193 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -420,6 +420,8 @@ add_library(core STATIC hle/service/am/applet_ae.cpp hle/service/am/applet_ae.h hle/service/am/applet_manager.cpp + hle/service/am/applet_data_broker.cpp + hle/service/am/applet_data_broker.h hle/service/am/applet_manager.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h index d0a237a7e..d47028b80 100644 --- a/src/core/hle/service/am/am_types.h +++ b/src/core/hle/service/am/am_types.h @@ -166,6 +166,6 @@ using AppletResourceUserId = u64; using ProgramId = u64; struct Applet; -struct AppletStorageHolder; +class AppletDataBroker; } // namespace Service::AM diff --git a/src/core/hle/service/am/applet.cpp b/src/core/hle/service/am/applet.cpp index 8f44fab33..5b9056c12 100644 --- a/src/core/hle/service/am/applet.cpp +++ b/src/core/hle/service/am/applet.cpp @@ -3,49 +3,13 @@ #include "common/scope_exit.h" +#include "core/core.h" #include "core/hle/service/am/am_results.h" #include "core/hle/service/am/applet.h" +#include "core/hle/service/am/applet_manager.h" namespace Service::AM { -AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context) - : m_event(context) {} -AppletStorageChannel::~AppletStorageChannel() = default; - -void AppletStorageChannel::PushData(std::shared_ptr storage) { - std::scoped_lock lk{m_lock}; - - m_data.emplace_back(std::move(storage)); - m_event.Signal(); -} - -Result AppletStorageChannel::PopData(std::shared_ptr* out_storage) { - std::scoped_lock lk{m_lock}; - - SCOPE_EXIT({ - if (m_data.empty()) { - m_event.Clear(); - } - }); - - R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); - - *out_storage = std::move(m_data.front()); - m_data.pop_front(); - - R_SUCCEED(); -} - -Kernel::KReadableEvent* AppletStorageChannel::GetEvent() { - return m_event.GetHandle(); -} - -AppletStorageHolder::AppletStorageHolder(Core::System& system) - : context(system, "AppletStorageHolder"), in_data(context), interactive_in_data(context), - out_data(context), interactive_out_data(context), state_changed_event(context) {} - -AppletStorageHolder::~AppletStorageHolder() = default; - Applet::Applet(Core::System& system, std::unique_ptr process_) : context(system, "Applet"), message_queue(system), process(std::move(process_)), hid_registration(system, *process), gpu_error_detected_event(context), diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index 9650a2615..65bfbc250 100644 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h @@ -21,41 +21,8 @@ #include "core/hle/service/am/storage.h" #include "core/hle/service/am/system_buffer_manager.h" -namespace Service::Nvnflinger { -class FbShareBufferManager; -class Nvnflinger; -} // namespace Service::Nvnflinger - namespace Service::AM { -class AppletStorageChannel { -public: - explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx); - ~AppletStorageChannel(); - - void PushData(std::shared_ptr storage); - Result PopData(std::shared_ptr* out_storage); - Kernel::KReadableEvent* GetEvent(); - -private: - std::mutex m_lock{}; - std::deque> m_data{}; - Event m_event; -}; - -struct AppletStorageHolder { - explicit AppletStorageHolder(Core::System& system); - ~AppletStorageHolder(); - - KernelHelpers::ServiceContext context; - - AppletStorageChannel in_data; - AppletStorageChannel interactive_in_data; - AppletStorageChannel out_data; - AppletStorageChannel interactive_out_data; - Event state_changed_event; -}; - struct Applet { explicit Applet(Core::System& system, std::unique_ptr process_); ~Applet(); @@ -126,8 +93,7 @@ struct Applet { // Caller applet std::weak_ptr caller_applet{}; - std::shared_ptr caller_applet_storage{}; - bool is_completed{}; + std::shared_ptr caller_applet_broker{}; // Self state bool exit_locked{}; diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp new file mode 100644 index 000000000..4d58c4db5 --- /dev/null +++ b/src/core/hle/service/am/applet_data_broker.cpp @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" + +#include "core/core.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" + +namespace Service::AM { + +AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context) + : m_event(context) {} +AppletStorageChannel::~AppletStorageChannel() = default; + +void AppletStorageChannel::Push(std::shared_ptr storage) { + std::scoped_lock lk{m_lock}; + + m_data.emplace_back(std::move(storage)); + m_event.Signal(); +} + +Result AppletStorageChannel::Pop(std::shared_ptr* out_storage) { + std::scoped_lock lk{m_lock}; + + SCOPE_EXIT({ + if (m_data.empty()) { + m_event.Clear(); + } + }); + + R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); + + *out_storage = std::move(m_data.front()); + m_data.pop_front(); + + R_SUCCEED(); +} + +Kernel::KReadableEvent* AppletStorageChannel::GetEvent() { + return m_event.GetHandle(); +} + +AppletDataBroker::AppletDataBroker(Core::System& system_) + : system(system_), context(system_, "AppletDataBroker"), in_data(context), + interactive_in_data(context), out_data(context), interactive_out_data(context), + state_changed_event(context), is_completed(false) {} + +AppletDataBroker::~AppletDataBroker() = default; + +void AppletDataBroker::SignalCompletion() { + { + std::scoped_lock lk{lock}; + + if (is_completed) { + return; + } + + is_completed = true; + state_changed_event.Signal(); + } + + system.GetAppletManager().FocusStateChanged(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h new file mode 100644 index 000000000..12326fd04 --- /dev/null +++ b/src/core/hle/service/am/applet_data_broker.h @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +#include "core/hle/service/event.h" +#include "core/hle/service/kernel_helpers.h" + +union Result; + +namespace Service::AM { + +struct Applet; +class IStorage; + +class AppletStorageChannel { +public: + explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx); + ~AppletStorageChannel(); + + void Push(std::shared_ptr storage); + Result Pop(std::shared_ptr* out_storage); + Kernel::KReadableEvent* GetEvent(); + +private: + std::mutex m_lock{}; + std::deque> m_data{}; + Event m_event; +}; + +class AppletDataBroker { +public: + explicit AppletDataBroker(Core::System& system_); + ~AppletDataBroker(); + + AppletStorageChannel& GetInData() { + return in_data; + } + + AppletStorageChannel& GetInteractiveInData() { + return interactive_in_data; + } + + AppletStorageChannel& GetOutData() { + return out_data; + } + + AppletStorageChannel& GetInteractiveOutData() { + return interactive_out_data; + } + + Event& GetStateChangedEvent() { + return state_changed_event; + } + + bool IsCompleted() const { + return is_completed; + } + + void SignalCompletion(); + +private: + Core::System& system; + KernelHelpers::ServiceContext context; + + AppletStorageChannel in_data; + AppletStorageChannel interactive_in_data; + AppletStorageChannel out_data; + AppletStorageChannel interactive_out_data; + Event state_changed_event; + + std::mutex lock; + bool is_completed; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index efbd0108c..a733525a2 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -6,6 +6,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/frontend/applet_cabinet.h" #include "core/hle/service/am/frontend/applet_controller.h" @@ -29,8 +30,8 @@ static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system, std::shared_ptr& applet) { - applet->caller_applet_storage = std::make_shared(system); - return applet->caller_applet_storage->in_data; + applet->caller_applet_broker = std::make_shared(system); + return applet->caller_applet_broker->GetInData(); } void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { @@ -46,8 +47,8 @@ void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { std::vector argument_data(sizeof(arguments)); std::vector settings_data{2}; std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - channel.PushData(std::make_shared(system, std::move(argument_data))); - channel.PushData(std::make_shared(system, std::move(settings_data))); + channel.Push(std::make_shared(system, std::move(argument_data))); + channel.Push(std::make_shared(system, std::move(settings_data))); } void PushInShowController(Core::System& system, AppletStorageChannel& channel) { @@ -94,9 +95,9 @@ void PushInShowController(Core::System& system, AppletStorageChannel& channel) { std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); - channel.PushData(std::make_shared(system, std::move(common_args_data))); - channel.PushData(std::make_shared(system, std::move(private_args_data))); - channel.PushData(std::make_shared(system, std::move(user_args_data))); + channel.Push(std::make_shared(system, std::move(common_args_data))); + channel.Push(std::make_shared(system, std::move(private_args_data))); + channel.Push(std::make_shared(system, std::move(user_args_data))); } void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) { @@ -124,8 +125,8 @@ void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) std::vector settings_data(sizeof(amiibo_settings)); std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); - channel.PushData(std::make_shared(system, std::move(argument_data))); - channel.PushData(std::make_shared(system, std::move(settings_data))); + channel.Push(std::make_shared(system, std::move(argument_data))); + channel.Push(std::make_shared(system, std::move(settings_data))); } void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { @@ -147,7 +148,7 @@ void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) std::vector argument_data(sizeof(mii_arguments)); std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); - channel.PushData(std::make_shared(system, std::move(argument_data))); + channel.Push(std::make_shared(system, std::move(argument_data))); } void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) { @@ -200,9 +201,9 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan std::memcpy(work_buffer.data(), initial_string.data(), swkbd_config.initial_string_length * sizeof(char16_t)); - channel.PushData(std::make_shared(system, std::move(argument_data))); - channel.PushData(std::make_shared(system, std::move(swkbd_data))); - channel.PushData(std::make_shared(system, std::move(work_buffer))); + channel.Push(std::make_shared(system, std::move(argument_data))); + channel.Push(std::make_shared(system, std::move(swkbd_data))); + channel.Push(std::make_shared(system, std::move(work_buffer))); } } // namespace diff --git a/src/core/hle/service/am/frontend/applet_cabinet.cpp b/src/core/hle/service/am/frontend/applet_cabinet.cpp index f1f49e83b..0862c81b6 100644 --- a/src/core/hle/service/am/frontend/applet_cabinet.cpp +++ b/src/core/hle/service/am/frontend/applet_cabinet.cpp @@ -16,10 +16,11 @@ namespace Service::AM::Frontend { -Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::CabinetApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, - system{system_}, service_context{system_, "CabinetApplet"} { +Cabinet::Cabinet(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_) + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{ + system_, + "CabinetApplet"} { availability_change_event = service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); @@ -41,7 +42,7 @@ void Cabinet::Initialize() { common_args.play_startup_sound, common_args.size, common_args.system_tick, common_args.theme_color); - const auto storage = broker.PopNormalDataToApplet(); + std::shared_ptr storage = PopInData(); ASSERT(storage != nullptr); const auto applet_input_data = storage->GetData(); @@ -51,10 +52,6 @@ void Cabinet::Initialize() { sizeof(StartParamForAmiiboSettings)); } -bool Cabinet::TransactionComplete() const { - return is_complete; -} - Result Cabinet::GetStatus() const { return ResultSuccess; } @@ -160,8 +157,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::move(out_data))); + Exit(); } void Cabinet::Cancel() { @@ -175,8 +172,8 @@ void Cabinet::Cancel() { is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::move(out_data))); + Exit(); } Result Cabinet::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_cabinet.h b/src/core/hle/service/am/frontend/applet_cabinet.h index 85d25bcb3..3a211ed37 100644 --- a/src/core/hle/service/am/frontend/applet_cabinet.h +++ b/src/core/hle/service/am/frontend/applet_cabinet.h @@ -86,13 +86,13 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, class Cabinet final : public FrontendApplet { public: - explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Cabinet(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_); ~Cabinet() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -102,7 +102,6 @@ public: private: const Core::Frontend::CabinetApplet& frontend; - Core::System& system; bool is_complete{false}; std::shared_ptr nfp_device; diff --git a/src/core/hle/service/am/frontend/applet_controller.cpp b/src/core/hle/service/am/frontend/applet_controller.cpp index b4114f6a3..bd3e49fc4 100644 --- a/src/core/hle/service/am/frontend/applet_controller.cpp +++ b/src/core/hle/service/am/frontend/applet_controller.cpp @@ -47,9 +47,10 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters( }; } -Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, +Controller::Controller(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ControllerApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Controller::~Controller() = default; @@ -67,7 +68,7 @@ void Controller::Initialize() { controller_applet_version = ControllerAppletVersion{common_args.library_version}; - const auto private_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr private_arg_storage = PopInData(); ASSERT(private_arg_storage != nullptr); const auto& private_arg = private_arg_storage->GetData(); @@ -117,7 +118,7 @@ void Controller::Initialize() { switch (controller_private_arg.mode) { case ControllerSupportMode::ShowControllerSupport: case ControllerSupportMode::ShowControllerStrapGuide: { - const auto user_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr user_arg_storage = PopInData(); ASSERT(user_arg_storage != nullptr); const auto& user_arg = user_arg_storage->GetData(); @@ -143,7 +144,7 @@ void Controller::Initialize() { break; } case ControllerSupportMode::ShowControllerFirmwareUpdate: { - const auto update_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr update_arg_storage = PopInData(); ASSERT(update_arg_storage != nullptr); const auto& update_arg = update_arg_storage->GetData(); @@ -153,7 +154,7 @@ void Controller::Initialize() { break; } case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { - const auto remapping_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr remapping_arg_storage = PopInData(); ASSERT(remapping_arg_storage != nullptr); const auto& remapping_arg = remapping_arg_storage->GetData(); @@ -169,10 +170,6 @@ void Controller::Initialize() { } } -bool Controller::TransactionComplete() const { - return complete; -} - Result Controller::GetStatus() const { return status; } @@ -261,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) { complete = true; out_data = std::vector(sizeof(ControllerSupportResultInfo)); std::memcpy(out_data.data(), &result_info, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); + + PushOutData(std::make_shared(system, std::move(out_data))); + Exit(); } Result Controller::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_controller.h b/src/core/hle/service/am/frontend/applet_controller.h index bf2bed332..2f219429c 100644 --- a/src/core/hle/service/am/frontend/applet_controller.h +++ b/src/core/hle/service/am/frontend/applet_controller.h @@ -124,13 +124,13 @@ static_assert(sizeof(ControllerSupportResultInfo) == 0xC, class Controller final : public FrontendApplet { public: - explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Controller(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ControllerApplet& frontend_); ~Controller() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -140,7 +140,6 @@ public: private: const Core::Frontend::ControllerApplet& frontend; - Core::System& system; ControllerAppletVersion controller_applet_version; ControllerSupportArgPrivate controller_private_arg; diff --git a/src/core/hle/service/am/frontend/applet_error.cpp b/src/core/hle/service/am/frontend/applet_error.cpp index 48be77da2..d6db345b6 100644 --- a/src/core/hle/service/am/frontend/applet_error.cpp +++ b/src/core/hle/service/am/frontend/applet_error.cpp @@ -104,9 +104,9 @@ Result Decode64BitError(u64 error) { } // Anonymous namespace -Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, +Error::Error(Core::System& system_, std::shared_ptr applet_, LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Error::~Error() = default; @@ -115,7 +115,7 @@ void Error::Initialize() { args = std::make_unique(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); @@ -153,10 +153,6 @@ void Error::Initialize() { } } -bool Error::TransactionComplete() const { - return complete; -} - Result Error::GetStatus() const { return ResultSuccess; } @@ -211,8 +207,8 @@ void Error::Execute() { void Error::DisplayCompleted() { complete = true; - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector{})); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::vector())); + Exit(); } Result Error::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_error.h b/src/core/hle/service/am/frontend/applet_error.h index 639e3c224..678bf33fa 100644 --- a/src/core/hle/service/am/frontend/applet_error.h +++ b/src/core/hle/service/am/frontend/applet_error.h @@ -24,13 +24,12 @@ enum class ErrorAppletMode : u8 { class Error final : public FrontendApplet { public: - explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ErrorApplet& frontend_); + explicit Error(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_); ~Error() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -47,7 +46,6 @@ private: std::unique_ptr args; bool complete = false; - Core::System& system; }; } // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_general.cpp b/src/core/hle/service/am/frontend/applet_general.cpp index e51171525..3c091a602 100644 --- a/src/core/hle/service/am/frontend/applet_general.cpp +++ b/src/core/hle/service/am/frontend/applet_general.cpp @@ -8,6 +8,7 @@ #include "core/frontend/applets/general.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" +#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/frontend/applet_general.h" #include "core/hle/service/am/storage.h" #include "core/reporter.h" @@ -16,17 +17,16 @@ namespace Service::AM::Frontend { constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; -static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { - std::shared_ptr storage = broker.PopNormalDataToApplet(); - for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { +static void LogCurrentStorage(std::shared_ptr applet, std::string_view prefix) { + std::shared_ptr storage; + while (R_SUCCEEDED(applet->caller_applet_broker->GetInData().Pop(&storage))) { const auto data = storage->GetData(); LOG_INFO(Service_AM, "called (STUBBED), during {} received normal data with size={:08X}, data={}", prefix, data.size(), Common::HexToString(data)); } - storage = broker.PopInteractiveDataToApplet(); - for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) { + while (R_SUCCEEDED(applet->caller_applet_broker->GetInteractiveInData().Pop(&storage))) { const auto data = storage->GetData(); LOG_INFO(Service_AM, "called (STUBBED), during {} received interactive data with size={:08X}, data={}", @@ -34,9 +34,9 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) } } -Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, +Auth::Auth(Core::System& system_, std::shared_ptr applet_, LibraryAppletMode applet_mode_, Core::Frontend::ParentalControlsApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Auth::~Auth() = default; @@ -44,7 +44,7 @@ void Auth::Initialize() { FrontendApplet::Initialize(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); ASSERT(data.size() >= 0xC); @@ -68,10 +68,6 @@ void Auth::Initialize() { arg2 = arg.arg2; } -bool Auth::TransactionComplete() const { - return complete; -} - Result Auth::GetStatus() const { return successful ? ResultSuccess : ERROR_INVALID_PIN; } @@ -147,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) { std::vector out(sizeof(Return)); std::memcpy(out.data(), &return_, sizeof(Return)); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::move(out))); + Exit(); } Result Auth::RequestExit() { @@ -156,9 +152,10 @@ Result Auth::RequestExit() { R_SUCCEED(); } -PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, +PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::PhotoViewerApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} PhotoViewer::~PhotoViewer() = default; @@ -166,17 +163,13 @@ void PhotoViewer::Initialize() { FrontendApplet::Initialize(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); ASSERT(!data.empty()); mode = static_cast(data[0]); } -bool PhotoViewer::TransactionComplete() const { - return complete; -} - Result PhotoViewer::GetStatus() const { return ResultSuccess; } @@ -204,8 +197,8 @@ void PhotoViewer::Execute() { } void PhotoViewer::ViewFinished() { - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector{})); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::vector{})); + Exit(); } Result PhotoViewer::RequestExit() { @@ -213,8 +206,9 @@ Result PhotoViewer::RequestExit() { R_SUCCEED(); } -StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) - : FrontendApplet{system_, applet_mode_}, id{id_}, system{system_} {} +StubApplet::StubApplet(Core::System& system_, std::shared_ptr applet_, AppletId id_, + LibraryAppletMode applet_mode_) + : FrontendApplet{system_, applet_, applet_mode_}, id{id_} {} StubApplet::~StubApplet() = default; @@ -222,18 +216,7 @@ void StubApplet::Initialize() { LOG_WARNING(Service_AM, "called (STUBBED)"); FrontendApplet::Initialize(); - const auto data = broker.PeekDataToAppletForDebug(); - system.GetReporter().SaveUnimplementedAppletReport( - static_cast(id), static_cast(common_args.arguments_version), - common_args.library_version, static_cast(common_args.theme_color), - common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive); - - LogCurrentStorage(broker, "Initialize"); -} - -bool StubApplet::TransactionComplete() const { - LOG_WARNING(Service_AM, "called (STUBBED)"); - return true; + LogCurrentStorage(applet.lock(), "Initialize"); } Result StubApplet::GetStatus() const { @@ -243,22 +226,20 @@ Result StubApplet::GetStatus() const { void StubApplet::ExecuteInteractive() { LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "ExecuteInteractive"); + LogCurrentStorage(applet.lock(), "ExecuteInteractive"); - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared(system, std::vector(0x1000))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::vector(0x1000))); + PushInteractiveOutData(std::make_shared(system, std::vector(0x1000))); + Exit(); } void StubApplet::Execute() { LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "Execute"); + LogCurrentStorage(applet.lock(), "Execute"); - broker.PushNormalDataFromApplet(std::make_shared(system, std::vector(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared(system, std::vector(0x1000))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::vector(0x1000))); + PushInteractiveOutData(std::make_shared(system, std::vector(0x1000))); + Exit(); } Result StubApplet::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_general.h b/src/core/hle/service/am/frontend/applet_general.h index b39a9a3f1..eaa7ae25f 100644 --- a/src/core/hle/service/am/frontend/applet_general.h +++ b/src/core/hle/service/am/frontend/applet_general.h @@ -19,12 +19,12 @@ enum class AuthAppletType : u32 { class Auth final : public FrontendApplet { public: - explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Auth(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, Core::Frontend::ParentalControlsApplet& frontend_); ~Auth() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -34,7 +34,6 @@ public: private: Core::Frontend::ParentalControlsApplet& frontend; - Core::System& system; bool complete = false; bool successful = false; @@ -51,12 +50,12 @@ enum class PhotoViewerAppletMode : u8 { class PhotoViewer final : public FrontendApplet { public: - explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, + explicit PhotoViewer(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::PhotoViewerApplet& frontend_); ~PhotoViewer() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -68,17 +67,16 @@ private: const Core::Frontend::PhotoViewerApplet& frontend; bool complete = false; PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; - Core::System& system; }; class StubApplet final : public FrontendApplet { public: - explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); + explicit StubApplet(Core::System& system_, std::shared_ptr applet_, AppletId id_, + LibraryAppletMode applet_mode_); ~StubApplet() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -86,7 +84,6 @@ public: private: AppletId id; - Core::System& system; }; } // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_mii_edit.cpp b/src/core/hle/service/am/frontend/applet_mii_edit.cpp index 6203ebd2e..e3d19fb3d 100644 --- a/src/core/hle/service/am/frontend/applet_mii_edit.cpp +++ b/src/core/hle/service/am/frontend/applet_mii_edit.cpp @@ -14,9 +14,9 @@ namespace Service::AM::Frontend { -MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::MiiEditApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} +MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_) + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} MiiEdit::~MiiEdit() = default; @@ -25,7 +25,7 @@ void MiiEdit::Initialize() { // Instead, it is initialized by an AppletInput storage with size 0x100 bytes. // Do NOT call Applet::Initialize() here. - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr storage = PopInData(); ASSERT(storage != nullptr); const auto applet_input_data = storage->GetData(); @@ -67,10 +67,6 @@ void MiiEdit::Initialize() { manager->Initialize(metadata); } -bool MiiEdit::TransactionComplete() const { - return is_complete; -} - Result MiiEdit::GetStatus() const { return ResultSuccess; } @@ -153,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) { is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::move(out_data))); + Exit(); } void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, @@ -169,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::move(out_data))); + Exit(); } Result MiiEdit::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_mii_edit.h b/src/core/hle/service/am/frontend/applet_mii_edit.h index ebde37028..5db792f7d 100644 --- a/src/core/hle/service/am/frontend/applet_mii_edit.h +++ b/src/core/hle/service/am/frontend/applet_mii_edit.h @@ -20,13 +20,13 @@ namespace Service::AM::Frontend { class MiiEdit final : public FrontendApplet { public: - explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, + explicit MiiEdit(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_); ~MiiEdit() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -38,7 +38,6 @@ public: private: const Core::Frontend::MiiEditApplet& frontend; - Core::System& system; MiiEditAppletInputCommon applet_input_common{}; MiiEditAppletInputV3 applet_input_v3{}; diff --git a/src/core/hle/service/am/frontend/applet_profile_select.cpp b/src/core/hle/service/am/frontend/applet_profile_select.cpp index 5d71f985e..efb4053b8 100644 --- a/src/core/hle/service/am/frontend/applet_profile_select.cpp +++ b/src/core/hle/service/am/frontend/applet_profile_select.cpp @@ -14,9 +14,10 @@ namespace Service::AM::Frontend { -ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, +ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ProfileSelectApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} ProfileSelect::~ProfileSelect() = default; @@ -28,7 +29,7 @@ void ProfileSelect::Initialize() { FrontendApplet::Initialize(); profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; - const auto user_config_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr user_config_storage = PopInData(); ASSERT(user_config_storage != nullptr); const auto& user_config = user_config_storage->GetData(); @@ -51,10 +52,6 @@ void ProfileSelect::Initialize() { } } -bool ProfileSelect::TransactionComplete() const { - return complete; -} - Result ProfileSelect::GetStatus() const { return status; } @@ -65,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() { void ProfileSelect::Execute() { if (complete) { - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(final_data))); + PushOutData(std::make_shared(system, std::move(final_data))); + Exit(); return; } @@ -112,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional uuid) { final_data = std::vector(sizeof(UiReturnArg)); std::memcpy(final_data.data(), &output, final_data.size()); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(final_data))); - broker.SignalStateChanged(); + + PushOutData(std::make_shared(system, std::move(final_data))); + Exit(); } Result ProfileSelect::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_profile_select.h b/src/core/hle/service/am/frontend/applet_profile_select.h index 43ec67c8e..674e7afe1 100644 --- a/src/core/hle/service/am/frontend/applet_profile_select.h +++ b/src/core/hle/service/am/frontend/applet_profile_select.h @@ -113,13 +113,13 @@ static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); class ProfileSelect final : public FrontendApplet { public: - explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, + explicit ProfileSelect(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ProfileSelectApplet& frontend_); ~ProfileSelect() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -137,7 +137,6 @@ private: bool complete = false; Result status = ResultSuccess; std::vector final_data; - Core::System& system; }; } // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard.cpp b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp index 7974995cc..fbf75d379 100644 --- a/src/core/hle/service/am/frontend/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp @@ -42,9 +42,10 @@ void SetReplyBase(std::vector& reply, SwkbdState state, SwkbdReplyType reply } // Anonymous namespace -SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, +SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, Core::Frontend::SoftwareKeyboardApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} SoftwareKeyboard::~SoftwareKeyboard() = default; @@ -77,10 +78,6 @@ void SoftwareKeyboard::Initialize() { } } -bool SoftwareKeyboard::TransactionComplete() const { - return complete; -} - Result SoftwareKeyboard::GetStatus() const { return status; } @@ -185,7 +182,7 @@ void SoftwareKeyboard::InitializeForeground() { is_background = false; - const auto swkbd_config_storage = broker.PopNormalDataToApplet(); + const auto swkbd_config_storage = PopInData(); ASSERT(swkbd_config_storage != nullptr); const auto& swkbd_config_data = swkbd_config_storage->GetData(); @@ -222,7 +219,7 @@ void SoftwareKeyboard::InitializeForeground() { break; } - const auto work_buffer_storage = broker.PopNormalDataToApplet(); + const auto work_buffer_storage = PopInData(); ASSERT(work_buffer_storage != nullptr); if (swkbd_config_common.initial_string_length == 0) { @@ -251,7 +248,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod is_background = true; - const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); + const auto swkbd_inline_initialize_arg_storage = PopInData(); ASSERT(swkbd_inline_initialize_arg_storage != nullptr); const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); @@ -268,7 +265,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod } void SoftwareKeyboard::ProcessTextCheck() { - const auto text_check_storage = broker.PopInteractiveDataToApplet(); + const auto text_check_storage = PopInteractiveInData(); ASSERT(text_check_storage != nullptr); const auto& text_check_data = text_check_storage->GetData(); @@ -315,7 +312,7 @@ void SoftwareKeyboard::ProcessTextCheck() { } void SoftwareKeyboard::ProcessInlineKeyboardRequest() { - const auto request_data_storage = broker.PopInteractiveDataToApplet(); + const auto request_data_storage = PopInteractiveInData(); ASSERT(request_data_storage != nullptr); const auto& request_data = request_data_storage->GetData(); @@ -378,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, submitted_text.size() * sizeof(char16_t)); } - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + PushOutData(std::make_shared(system, std::move(out_data))); ExitKeyboard(); } @@ -411,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { current_text.size() * sizeof(char16_t)); } - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(out_data))); + PushInteractiveOutData(std::make_shared(system, std::move(out_data))); } void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { @@ -768,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() { frontend.ExitKeyboard(); - broker.SignalStateChanged(); + Exit(); } Result SoftwareKeyboard::RequestExit() { @@ -968,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyDefault() { @@ -978,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedString() { @@ -1000,7 +997,7 @@ void SoftwareKeyboard::ReplyChangedString() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, sizeof(SwkbdChangedStringArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursor() { @@ -1020,7 +1017,7 @@ void SoftwareKeyboard::ReplyMovedCursor() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, sizeof(SwkbdMovedCursorArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedTab() { @@ -1040,7 +1037,7 @@ void SoftwareKeyboard::ReplyMovedTab() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, sizeof(SwkbdMovedTabArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyDecidedEnter() { @@ -1059,7 +1056,7 @@ void SoftwareKeyboard::ReplyDecidedEnter() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, sizeof(SwkbdDecidedEnterArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); HideInlineKeyboard(); } @@ -1071,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); HideInlineKeyboard(); } @@ -1096,7 +1093,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, sizeof(SwkbdChangedStringArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorUtf8() { @@ -1117,7 +1114,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, sizeof(SwkbdMovedCursorArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyDecidedEnterUtf8() { @@ -1137,7 +1134,7 @@ void SoftwareKeyboard::ReplyDecidedEnterUtf8() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, sizeof(SwkbdDecidedEnterArg)); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); HideInlineKeyboard(); } @@ -1149,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyReleasedUserWordInfo() { @@ -1159,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { @@ -1169,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedStringV2() { @@ -1195,7 +1192,7 @@ void SoftwareKeyboard::ReplyChangedStringV2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorV2() { @@ -1219,7 +1216,7 @@ void SoftwareKeyboard::ReplyMovedCursorV2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedStringUtf8V2() { @@ -1246,7 +1243,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8V2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { @@ -1271,7 +1268,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared(system, std::move(reply))); + PushInteractiveOutData(std::make_shared(system, std::move(reply))); } } // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applet_software_keyboard.h b/src/core/hle/service/am/frontend/applet_software_keyboard.h index 00ad0add3..f464b7e15 100644 --- a/src/core/hle/service/am/frontend/applet_software_keyboard.h +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.h @@ -21,13 +21,13 @@ namespace Service::AM::Frontend { class SoftwareKeyboard final : public FrontendApplet { public: - explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, + explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, Core::Frontend::SoftwareKeyboardApplet& frontend_); ~SoftwareKeyboard() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -156,7 +156,6 @@ private: void ReplyMovedCursorUtf8V2(); Core::Frontend::SoftwareKeyboardApplet& frontend; - Core::System& system; SwkbdAppletVersion swkbd_applet_version; diff --git a/src/core/hle/service/am/frontend/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp index 28a20c72b..6ee4caf34 100644 --- a/src/core/hle/service/am/frontend/applet_web_browser.cpp +++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp @@ -224,9 +224,10 @@ void ExtractSharedFonts(Core::System& system) { } // namespace -WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, +WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_) - : FrontendApplet{system_, applet_mode_}, frontend(frontend_), system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {} WebBrowser::~WebBrowser() = default; @@ -244,7 +245,7 @@ void WebBrowser::Initialize() { web_applet_version = WebAppletVersion{common_args.library_version}; - const auto web_arg_storage = broker.PopNormalDataToApplet(); + const auto web_arg_storage = PopInData(); ASSERT(web_arg_storage != nullptr); const auto& web_arg = web_arg_storage->GetData(); @@ -285,10 +286,6 @@ void WebBrowser::Initialize() { } } -bool WebBrowser::TransactionComplete() const { - return complete; -} - Result WebBrowser::GetStatus() const { return status; } @@ -359,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) complete = true; std::vector out_data(sizeof(WebCommonReturnValue)); std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared(system, std::move(out_data))); + Exit(); } Result WebBrowser::RequestExit() { diff --git a/src/core/hle/service/am/frontend/applet_web_browser.h b/src/core/hle/service/am/frontend/applet_web_browser.h index 613d8e9ea..ba20b7a4c 100644 --- a/src/core/hle/service/am/frontend/applet_web_browser.h +++ b/src/core/hle/service/am/frontend/applet_web_browser.h @@ -24,14 +24,13 @@ namespace Service::AM::Frontend { class WebBrowser final : public FrontendApplet { public: - WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::WebBrowserApplet& frontend_); + WebBrowser(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_); ~WebBrowser() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -80,8 +79,6 @@ private: FileSys::VirtualFile offline_romfs; std::string external_url; - - Core::System& system; }; } // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp index 38495ee19..db2b04575 100644 --- a/src/core/hle/service/am/frontend/applets.cpp +++ b/src/core/hle/service/am/frontend/applets.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" @@ -33,135 +34,45 @@ namespace Service::AM::Frontend { -AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) - : system{system_}, applet_mode{applet_mode_}, - service_context{system, "ILibraryAppletAccessor"} { - state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent"); - pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent"); - pop_interactive_out_data_event = - service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent"); -} - -AppletDataBroker::~AppletDataBroker() { - service_context.CloseEvent(state_changed_event); - service_context.CloseEvent(pop_out_data_event); - service_context.CloseEvent(pop_interactive_out_data_event); -} - -AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const { - std::vector> out_normal; - - for (const auto& storage : in_channel) { - out_normal.push_back(storage->GetData()); - } - - std::vector> out_interactive; +FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_) + : system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {} - for (const auto& storage : in_interactive_channel) { - out_interactive.push_back(storage->GetData()); - } - - return {std::move(out_normal), std::move(out_interactive)}; -} - -std::shared_ptr AppletDataBroker::PopNormalDataToGame() { - if (out_channel.empty()) - return nullptr; - - auto out = std::move(out_channel.front()); - out_channel.pop_front(); - pop_out_data_event->Clear(); - return out; -} - -std::shared_ptr AppletDataBroker::PopNormalDataToApplet() { - if (in_channel.empty()) - return nullptr; - - auto out = std::move(in_channel.front()); - in_channel.pop_front(); - return out; -} - -std::shared_ptr AppletDataBroker::PopInteractiveDataToGame() { - if (out_interactive_channel.empty()) - return nullptr; - - auto out = std::move(out_interactive_channel.front()); - out_interactive_channel.pop_front(); - pop_interactive_out_data_event->Clear(); - return out; -} - -std::shared_ptr AppletDataBroker::PopInteractiveDataToApplet() { - if (in_interactive_channel.empty()) - return nullptr; - - auto out = std::move(in_interactive_channel.front()); - in_interactive_channel.pop_front(); - return out; -} - -void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr&& storage) { - in_channel.emplace_back(std::move(storage)); -} +FrontendApplet::~FrontendApplet() = default; -void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr&& storage) { - out_channel.emplace_back(std::move(storage)); - pop_out_data_event->Signal(); -} +void FrontendApplet::Initialize() { + std::shared_ptr common = PopInData(); + ASSERT(common != nullptr); + const auto common_data = common->GetData(); -void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr&& storage) { - in_interactive_channel.emplace_back(std::move(storage)); -} + ASSERT(common_data.size() >= sizeof(CommonArguments)); + std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); -void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr&& storage) { - out_interactive_channel.emplace_back(std::move(storage)); - pop_interactive_out_data_event->Signal(); + initialized = true; } -void AppletDataBroker::SignalStateChanged() { - state_changed_event->Signal(); - - // TODO proper window management - switch (applet_mode) { - case LibraryAppletMode::AllForeground: - case LibraryAppletMode::AllForegroundInitiallyHidden: { - system.GetAppletManager().FocusStateChanged(); - break; - } - default: - break; - } +std::shared_ptr FrontendApplet::PopInData() { + std::shared_ptr ret; + applet.lock()->caller_applet_broker->GetInData().Pop(&ret); + return ret; } -Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() { - return pop_out_data_event->GetReadableEvent(); +std::shared_ptr FrontendApplet::PopInteractiveInData() { + std::shared_ptr ret; + applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret); + return ret; } -Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() { - return pop_interactive_out_data_event->GetReadableEvent(); +void FrontendApplet::PushOutData(std::shared_ptr storage) { + applet.lock()->caller_applet_broker->GetOutData().Push(storage); } -Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() { - return state_changed_event->GetReadableEvent(); +void FrontendApplet::PushInteractiveOutData(std::shared_ptr storage) { + applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage); } -FrontendApplet::FrontendApplet(Core::System& system_, LibraryAppletMode applet_mode_) - : broker{system_, applet_mode_}, applet_mode{applet_mode_} {} - -FrontendApplet::~FrontendApplet() = default; - -void FrontendApplet::Initialize() { - const auto common = broker.PopNormalDataToApplet(); - ASSERT(common != nullptr); - - const auto common_data = common->GetData(); - - ASSERT(common_data.size() >= sizeof(CommonArguments)); - std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); - - initialized = true; +void FrontendApplet::Exit() { + applet.lock()->caller_applet_broker->SignalCompletion(); } FrontendAppletSet::FrontendAppletSet() = default; @@ -291,36 +202,38 @@ void FrontendAppletHolder::ClearAll() { frontend = {}; } -std::shared_ptr FrontendAppletHolder::GetApplet(AppletId id, +std::shared_ptr FrontendAppletHolder::GetApplet(std::shared_ptr applet, + AppletId id, LibraryAppletMode mode) const { switch (id) { case AppletId::Auth: - return std::make_shared(system, mode, *frontend.parental_controls); + return std::make_shared(system, applet, mode, *frontend.parental_controls); case AppletId::Cabinet: - return std::make_shared(system, mode, *frontend.cabinet); + return std::make_shared(system, applet, mode, *frontend.cabinet); case AppletId::Controller: - return std::make_shared(system, mode, *frontend.controller); + return std::make_shared(system, applet, mode, *frontend.controller); case AppletId::Error: - return std::make_shared(system, mode, *frontend.error); + return std::make_shared(system, applet, mode, *frontend.error); case AppletId::ProfileSelect: - return std::make_shared(system, mode, *frontend.profile_select); + return std::make_shared(system, applet, mode, *frontend.profile_select); case AppletId::SoftwareKeyboard: - return std::make_shared(system, mode, *frontend.software_keyboard); + return std::make_shared(system, applet, mode, + *frontend.software_keyboard); case AppletId::MiiEdit: - return std::make_shared(system, mode, *frontend.mii_edit); + return std::make_shared(system, applet, mode, *frontend.mii_edit); case AppletId::Web: case AppletId::Shop: case AppletId::OfflineWeb: case AppletId::LoginShare: case AppletId::WebAuth: - return std::make_shared(system, mode, *frontend.web_browser); + return std::make_shared(system, applet, mode, *frontend.web_browser); case AppletId::PhotoViewer: - return std::make_shared(system, mode, *frontend.photo_viewer); + return std::make_shared(system, applet, mode, *frontend.photo_viewer); default: UNIMPLEMENTED_MSG( "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", static_cast(id)); - return std::make_shared(system, id, mode); + return std::make_shared(system, applet, id, mode); } } diff --git a/src/core/hle/service/am/frontend/applets.h b/src/core/hle/service/am/frontend/applets.h index dec1d63b2..1e1fd28b8 100644 --- a/src/core/hle/service/am/frontend/applets.h +++ b/src/core/hle/service/am/frontend/applets.h @@ -44,87 +44,19 @@ class IStorage; namespace Frontend { -class AppletDataBroker final { -public: - explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_); - ~AppletDataBroker(); - - struct RawChannelData { - std::vector> normal; - std::vector> interactive; - }; - - // Retrieves but does not pop the data sent to applet. - RawChannelData PeekDataToAppletForDebug() const; - - std::shared_ptr PopNormalDataToGame(); - std::shared_ptr PopNormalDataToApplet(); - - std::shared_ptr PopInteractiveDataToGame(); - std::shared_ptr PopInteractiveDataToApplet(); - - void PushNormalDataFromGame(std::shared_ptr&& storage); - void PushNormalDataFromApplet(std::shared_ptr&& storage); - - void PushInteractiveDataFromGame(std::shared_ptr&& storage); - void PushInteractiveDataFromApplet(std::shared_ptr&& storage); - - void SignalStateChanged(); - - Kernel::KReadableEvent& GetNormalDataEvent(); - Kernel::KReadableEvent& GetInteractiveDataEvent(); - Kernel::KReadableEvent& GetStateChangedEvent(); - -private: - Core::System& system; - LibraryAppletMode applet_mode; - - KernelHelpers::ServiceContext service_context; - - // Queues are named from applet's perspective - - // PopNormalDataToApplet and PushNormalDataFromGame - std::deque> in_channel; - - // PopNormalDataToGame and PushNormalDataFromApplet - std::deque> out_channel; - - // PopInteractiveDataToApplet and PushInteractiveDataFromGame - std::deque> in_interactive_channel; - - // PopInteractiveDataToGame and PushInteractiveDataFromApplet - std::deque> out_interactive_channel; - - Kernel::KEvent* state_changed_event; - - // Signaled on PushNormalDataFromApplet - Kernel::KEvent* pop_out_data_event; - - // Signaled on PushInteractiveDataFromApplet - Kernel::KEvent* pop_interactive_out_data_event; -}; - class FrontendApplet { public: - explicit FrontendApplet(Core::System& system_, LibraryAppletMode applet_mode_); + explicit FrontendApplet(Core::System& system_, std::shared_ptr applet_, + LibraryAppletMode applet_mode_); virtual ~FrontendApplet(); virtual void Initialize(); - virtual bool TransactionComplete() const = 0; virtual Result GetStatus() const = 0; virtual void ExecuteInteractive() = 0; virtual void Execute() = 0; virtual Result RequestExit() = 0; - AppletDataBroker& GetBroker() { - return broker; - } - - const AppletDataBroker& GetBroker() const { - return broker; - } - LibraryAppletMode GetLibraryAppletMode() const { return applet_mode; } @@ -134,10 +66,18 @@ public: } protected: + std::shared_ptr PopInData(); + std::shared_ptr PopInteractiveInData(); + void PushOutData(std::shared_ptr storage); + void PushInteractiveOutData(std::shared_ptr storage); + void Exit(); + +protected: + Core::System& system; CommonArguments common_args{}; - AppletDataBroker broker; - LibraryAppletMode applet_mode; - bool initialized = false; + std::weak_ptr applet{}; + LibraryAppletMode applet_mode{}; + bool initialized{false}; }; struct FrontendAppletSet { @@ -191,7 +131,8 @@ public: void SetDefaultAppletsIfMissing(); void ClearAll(); - std::shared_ptr GetApplet(AppletId id, LibraryAppletMode mode) const; + std::shared_ptr GetApplet(std::shared_ptr applet, AppletId id, + LibraryAppletMode mode) const; private: AppletId current_applet_id{}; diff --git a/src/core/hle/service/am/library_applet_accessor.cpp b/src/core/hle/service/am/library_applet_accessor.cpp index d3be493e6..6b20814f8 100644 --- a/src/core/hle/service/am/library_applet_accessor.cpp +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -3,6 +3,7 @@ #include "common/scope_exit.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" #include "core/hle/service/am/storage.h" @@ -11,9 +12,9 @@ namespace Service::AM { ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, - std::shared_ptr storage_, + std::shared_ptr broker_, std::shared_ptr applet_) - : ServiceFramework{system_, "ILibraryAppletAccessor"}, storage{std::move(storage_)}, + : ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)}, applet{std::move(applet_)} { // clang-format off static const FunctionInfo functions[] = { @@ -49,7 +50,7 @@ void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(storage->state_changed_event.GetHandle()); + rb.PushCopyObjects(broker->GetStateChangedEvent().GetHandle()); } void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { @@ -59,7 +60,7 @@ void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(applet->is_completed); + rb.Push(broker->IsCompleted()); } void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { @@ -80,6 +81,7 @@ void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); applet->process->Run(); + FrontendExecute(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -90,6 +92,7 @@ void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { ASSERT(applet != nullptr); applet->message_queue.RequestExit(); + FrontendRequestExit(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -99,7 +102,7 @@ void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::RequestParser rp{ctx}; - storage->in_data.PushData(rp.PopIpcInterface().lock()); + broker->GetInData().Push(rp.PopIpcInterface().lock()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -109,7 +112,7 @@ void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); std::shared_ptr data; - const auto res = storage->out_data.PopData(&data); + const auto res = broker->GetOutData().Pop(&data); if (res.IsSuccess()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -125,7 +128,8 @@ void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); IPC::RequestParser rp{ctx}; - storage->interactive_in_data.PushData(rp.PopIpcInterface().lock()); + broker->GetInteractiveInData().Push(rp.PopIpcInterface().lock()); + FrontendExecuteInteractive(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -135,7 +139,7 @@ void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); std::shared_ptr data; - const auto res = storage->interactive_out_data.PopData(&data); + const auto res = broker->GetInteractiveOutData().Pop(&data); if (res.IsSuccess()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -152,7 +156,7 @@ void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(storage->out_data.GetEvent()); + rb.PushCopyObjects(broker->GetOutData().GetEvent()); } void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { @@ -160,7 +164,7 @@ void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ct IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(storage->interactive_out_data.GetEvent()); + rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent()); } void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { @@ -175,4 +179,24 @@ void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& c rb.Push(handle); } +void ILibraryAppletAccessor::FrontendExecute() { + if (applet->frontend) { + applet->frontend->Initialize(); + applet->frontend->Execute(); + } +} + +void ILibraryAppletAccessor::FrontendExecuteInteractive() { + if (applet->frontend) { + applet->frontend->ExecuteInteractive(); + applet->frontend->Execute(); + } +} + +void ILibraryAppletAccessor::FrontendRequestExit() { + if (applet->frontend) { + applet->frontend->RequestExit(); + } +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_accessor.h b/src/core/hle/service/am/library_applet_accessor.h index c34a1cbca..8be29e003 100644 --- a/src/core/hle/service/am/library_applet_accessor.h +++ b/src/core/hle/service/am/library_applet_accessor.h @@ -7,13 +7,13 @@ namespace Service::AM { -struct AppletStorageHolder; +class AppletDataBroker; struct Applet; class ILibraryAppletAccessor final : public ServiceFramework { public: explicit ILibraryAppletAccessor(Core::System& system_, - std::shared_ptr storage_, + std::shared_ptr broker_, std::shared_ptr applet_); ~ILibraryAppletAccessor(); @@ -32,7 +32,11 @@ protected: void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); - const std::shared_ptr storage; + void FrontendExecute(); + void FrontendExecuteInteractive(); + void FrontendRequestExit(); + + const std::shared_ptr broker; const std::shared_ptr applet; }; diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp index 888b8b44b..e69764670 100644 --- a/src/core/hle/service/am/library_applet_creator.cpp +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_accessor.h" @@ -62,10 +63,9 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) { } } -std::shared_ptr CreateGuestApplet(Core::System& system, - std::shared_ptr caller_applet, - AppletId applet_id, - LibraryAppletMode mode) { +[[maybe_unused]] std::shared_ptr CreateGuestApplet( + Core::System& system, std::shared_ptr caller_applet, AppletId applet_id, + LibraryAppletMode mode) { const auto program_id = static_cast(AppletIdToProgramId(applet_id)); if (program_id == 0) { // Unknown applet @@ -89,20 +89,33 @@ std::shared_ptr CreateGuestApplet(Core::System& system, applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); applet->focus_state = FocusState::InFocus; - auto storage = std::make_shared(system); + auto broker = std::make_shared(system); applet->caller_applet = caller_applet; - applet->caller_applet_storage = storage; + applet->caller_applet_broker = broker; system.GetAppletManager().InsertApplet(applet); - return std::make_shared(system, storage, applet); + return std::make_shared(system, broker, applet); } -std::shared_ptr CreateFrontendApplet(Core::System& system, - AppletId applet_id, - LibraryAppletMode mode) { - UNREACHABLE(); - return {}; +[[maybe_unused]] std::shared_ptr CreateFrontendApplet( + Core::System& system, std::shared_ptr caller_applet, AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast(AppletIdToProgramId(applet_id)); + + auto process = std::make_unique(system); + auto applet = std::make_shared(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + auto storage = std::make_shared(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = storage; + applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); + + return std::make_shared(system, storage, applet); } } // namespace @@ -131,10 +144,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, applet_mode); - auto library_applet = CreateGuestApplet(system, applet, applet_id, applet_mode); - if (!library_applet) { - library_applet = CreateFrontendApplet(system, applet_id, applet_mode); - } + auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode); if (!library_applet) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp index 74ee33213..bc66bcb6b 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -5,6 +5,7 @@ #include "core/core_timing.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/frontend/applet_cabinet.h" #include "core/hle/service/am/frontend/applet_controller.h" @@ -47,7 +48,7 @@ AppletIdentityInfo GetCallerIdentity(std::shared_ptr applet) { ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr applet_) : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)}, - storage{applet->caller_applet_storage} { + broker{applet->caller_applet_broker} { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, @@ -96,7 +97,7 @@ void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called"); std::shared_ptr data; - const auto res = storage->in_data.PopData(&data); + const auto res = broker->GetInData().Pop(&data); if (res.IsSuccess()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -112,7 +113,7 @@ void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called"); IPC::RequestParser rp{ctx}; - storage->out_data.PushData(rp.PopIpcInterface().lock()); + broker->GetOutData().Push(rp.PopIpcInterface().lock()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -122,7 +123,7 @@ void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called"); std::shared_ptr data; - const auto res = storage->interactive_in_data.PopData(&data); + const auto res = broker->GetInteractiveInData().Pop(&data); if (res.IsSuccess()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -138,7 +139,7 @@ void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) LOG_INFO(Service_AM, "called"); IPC::RequestParser rp{ctx}; - storage->interactive_out_data.PushData(rp.PopIpcInterface().lock()); + broker->GetInteractiveOutData().Push(rp.PopIpcInterface().lock()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -149,7 +150,7 @@ void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(storage->in_data.GetEvent()); + rb.PushCopyObjects(broker->GetInData().GetEvent()); } void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) { @@ -157,19 +158,14 @@ void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(storage->interactive_in_data.GetEvent()); + rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent()); } void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called"); system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid); - - { - std::scoped_lock lk{applet->lock}; - applet->is_completed = true; - storage->state_changed_event.Signal(); - } + broker->SignalCompletion(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/am/library_applet_self_accessor.h b/src/core/hle/service/am/library_applet_self_accessor.h index b15040539..596cea0df 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.h +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -10,7 +10,7 @@ namespace Service::AM { -struct AppletStorageHolder; +class AppletDataBroker; struct Applet; class ILibraryAppletSelfAccessor final : public ServiceFramework { @@ -34,7 +34,7 @@ private: void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); const std::shared_ptr applet; - const std::shared_ptr storage; + const std::shared_ptr broker; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp index f5ccc4643..b48b52797 100644 --- a/src/core/hle/service/am/process_winding_controller.cpp +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -49,7 +49,7 @@ void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, applet->caller_applet_storage, + rb.PushIpcInterface(system, applet->caller_applet_broker, caller_applet); } -- cgit v1.2.3 From 68303ed6016da0926df8b62e5a0c55c9b914f927 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 6 Jan 2024 21:21:01 -0500 Subject: core: support offline web applet --- src/core/hle/service/am/am_types.h | 7 ++ src/core/hle/service/am/applet.h | 3 + .../hle/service/am/applet_common_functions.cpp | 9 ++ src/core/hle/service/am/applet_common_functions.h | 1 + src/core/hle/service/am/application_proxy.cpp | 2 +- src/core/hle/service/am/common_state_getter.cpp | 23 ++++- src/core/hle/service/am/common_state_getter.h | 1 + src/core/hle/service/am/display_controller.cpp | 64 +++++++++--- src/core/hle/service/am/display_controller.h | 8 +- src/core/hle/service/am/hid_registration.cpp | 6 ++ src/core/hle/service/am/hid_registration.h | 2 + src/core/hle/service/am/library_applet_creator.cpp | 27 ++++- src/core/hle/service/am/library_applet_proxy.cpp | 2 +- .../service/am/library_applet_self_accessor.cpp | 114 ++++++++++++++++++--- .../hle/service/am/library_applet_self_accessor.h | 4 + src/core/hle/service/am/self_controller.cpp | 13 ++- src/core/hle/service/am/self_controller.h | 1 + src/core/hle/service/am/system_applet_proxy.cpp | 2 +- src/core/hle/service/am/system_buffer_manager.cpp | 20 ++++ src/core/hle/service/am/system_buffer_manager.h | 7 ++ src/core/hle/service/am/window_controller.cpp | 35 ++++++- src/core/hle/service/am/window_controller.h | 2 + src/core/hle/service/filesystem/fsp/fsp_srv.cpp | 48 ++++++--- src/core/hle/service/nifm/nifm.cpp | 12 ++- src/core/hle/service/ns/ns.cpp | 67 +++++++++++- src/core/hle/service/ns/ns.h | 15 +++ src/core/hle/service/nvnflinger/nvnflinger.cpp | 10 ++ src/core/hle/service/nvnflinger/nvnflinger.h | 3 + src/core/hle/service/vi/display/vi_display.cpp | 4 +- src/core/hle/service/vi/layer/vi_layer.cpp | 2 +- src/core/hle/service/vi/layer/vi_layer.h | 9 ++ src/yuzu/main.cpp | 5 +- 32 files changed, 470 insertions(+), 58 deletions(-) diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h index d47028b80..a2b852b12 100644 --- a/src/core/hle/service/am/am_types.h +++ b/src/core/hle/service/am/am_types.h @@ -162,6 +162,13 @@ struct CommonArguments { }; static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); +struct AppletIdentityInfo { + AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; +}; +static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + using AppletResourceUserId = u64; using ProgramId = u64; diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index 65bfbc250..bce6f9050 100644 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h @@ -49,6 +49,9 @@ struct Applet { s32 previous_program_index{-1}; ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable}; + // TODO: some fields above can be AppletIdentityInfo + AppletIdentityInfo screen_shot_identity; + // hid state HidRegistration hid_registration; diff --git a/src/core/hle/service/am/applet_common_functions.cpp b/src/core/hle/service/am/applet_common_functions.cpp index a5c54ce87..130614ae5 100644 --- a/src/core/hle/service/am/applet_common_functions.cpp +++ b/src/core/hle/service/am/applet_common_functions.cpp @@ -31,6 +31,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_, {90, nullptr, "OpenNamedChannelAsParent"}, {91, nullptr, "OpenNamedChannelAsChild"}, {100, nullptr, "SetApplicationCoreUsageMode"}, + {300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"}, }; // clang-format on @@ -51,4 +52,12 @@ void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) rb.Push(ResultSuccess); } +void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(system.GetApplicationProcessProgramID() & ~0xFFFULL); +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_common_functions.h b/src/core/hle/service/am/applet_common_functions.h index 229555669..b86adf5cb 100644 --- a/src/core/hle/service/am/applet_common_functions.h +++ b/src/core/hle/service/am/applet_common_functions.h @@ -16,6 +16,7 @@ public: private: void SetCpuBoostRequestPriority(HLERequestContext& ctx); + void GetCurrentApplicationId(HLERequestContext& ctx); const std::shared_ptr applet; }; diff --git a/src/core/hle/service/am/application_proxy.cpp b/src/core/hle/service/am/application_proxy.cpp index 99e97f4bc..a6fd6d37f 100644 --- a/src/core/hle/service/am/application_proxy.cpp +++ b/src/core/hle/service/am/application_proxy.cpp @@ -53,7 +53,7 @@ void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/common_state_getter.cpp b/src/core/hle/service/am/common_state_getter.cpp index 77f3fd868..937ac0beb 100644 --- a/src/core/hle/service/am/common_state_getter.cpp +++ b/src/core/hle/service/am/common_state_getter.cpp @@ -60,7 +60,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr current_applet = applet; + std::vector result; + + const size_t count = ctx.GetWriteBufferNumElements(); + size_t i; + + for (i = 0; i < count && current_applet != nullptr; i++) { + result.push_back(current_applet->applet_id); + current_applet = current_applet->caller_applet.lock(); + } + + ctx.WriteBuffer(result); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(i)); +} + void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); diff --git a/src/core/hle/service/am/common_state_getter.h b/src/core/hle/service/am/common_state_getter.h index 643ca4dc5..bf652790c 100644 --- a/src/core/hle/service/am/common_state_getter.h +++ b/src/core/hle/service/am/common_state_getter.h @@ -67,6 +67,7 @@ private: void SetCpuBoostMode(HLERequestContext& ctx); void GetBuiltInDisplayType(HLERequestContext& ctx); void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); + void GetAppletLaunchedHistory(HLERequestContext& ctx); void GetSettingsPlatformRegion(HLERequestContext& ctx); void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); diff --git a/src/core/hle/service/am/display_controller.cpp b/src/core/hle/service/am/display_controller.cpp index d4d3d60e7..4d6858348 100644 --- a/src/core/hle/service/am/display_controller.cpp +++ b/src/core/hle/service/am/display_controller.cpp @@ -1,13 +1,23 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/service/am/applet.h" #include "core/hle/service/am/display_controller.h" #include "core/hle/service/ipc_helpers.h" namespace Service::AM { -IDisplayController::IDisplayController(Core::System& system_) - : ServiceFramework{system_, "IDisplayController"} { +namespace { +struct OutputParameters { + bool was_written; + s32 fbshare_layer_index; +}; + +static_assert(sizeof(OutputParameters) == 8, "OutputParameters has wrong size"); +} // namespace + +IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr applet_) + : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetLastForegroundCaptureImage"}, @@ -31,8 +41,8 @@ IDisplayController::IDisplayController(Core::System& system_) {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, {20, nullptr, "ClearCaptureBuffer"}, {21, nullptr, "ClearAppletTransitionBuffer"}, - {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, - {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, + {22, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "ReleaseLastApplicationCaptureSharedBuffer"}, {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"}, {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"}, {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"}, @@ -49,10 +59,13 @@ IDisplayController::~IDisplayController() = default; void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1u); - rb.Push(1); + rb.Push(res); + rb.PushRaw(params); } void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { @@ -62,13 +75,35 @@ void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { rb.Push(ResultSuccess); } -void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { +void IDisplayController::AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw(params); +} + +void IDisplayController::ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); - rb.Push(1U); - rb.Push(1); +} + +void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw(params); } void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { @@ -81,10 +116,13 @@ void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestCont void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1U); - rb.Push(1); + rb.Push(res); + rb.PushRaw(params); } void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/display_controller.h b/src/core/hle/service/am/display_controller.h index 32f819294..75172580c 100644 --- a/src/core/hle/service/am/display_controller.h +++ b/src/core/hle/service/am/display_controller.h @@ -7,9 +7,11 @@ namespace Service::AM { +struct Applet; + class IDisplayController final : public ServiceFramework { public: - explicit IDisplayController(Core::System& system_); + explicit IDisplayController(Core::System& system_, std::shared_ptr applet_); ~IDisplayController() override; private: @@ -19,6 +21,10 @@ private: void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); + void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx); + + const std::shared_ptr applet; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp index b9426f7b6..8ed49bac1 100644 --- a/src/core/hle/service/am/hid_registration.cpp +++ b/src/core/hle/service/am/hid_registration.cpp @@ -26,4 +26,10 @@ HidRegistration::~HidRegistration() { } } +void HidRegistration::EnableAppletToGetInput(bool enable) { + if (m_process.IsInitialized()) { + m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable); + } +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/hid_registration.h b/src/core/hle/service/am/hid_registration.h index 8a732349c..67cd84961 100644 --- a/src/core/hle/service/am/hid_registration.h +++ b/src/core/hle/service/am/hid_registration.h @@ -22,6 +22,8 @@ public: explicit HidRegistration(Core::System& system, Process& process); ~HidRegistration(); + void EnableAppletToGetInput(bool enable); + private: Process& m_process; std::shared_ptr m_hid_server; diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp index e69764670..47bab7528 100644 --- a/src/core/hle/service/am/library_applet_creator.cpp +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -84,10 +84,29 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) { applet->type = AppletType::LibraryApplet; applet->library_applet_mode = mode; - // Library applet should be foreground - applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); - applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); - applet->focus_state = FocusState::InFocus; + // Set focus state + switch (mode) { + case LibraryAppletMode::AllForeground: + case LibraryAppletMode::NoUI: + applet->focus_state = FocusState::InFocus; + applet->hid_registration.EnableAppletToGetInput(true); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + break; + case LibraryAppletMode::AllForegroundInitiallyHidden: + applet->system_buffer_manager.SetWindowVisibility(false); + applet->focus_state = FocusState::NotInFocus; + applet->hid_registration.EnableAppletToGetInput(false); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + break; + case LibraryAppletMode::Background: + case LibraryAppletMode::BackgroundIndirectDisplay: + default: + applet->focus_state = FocusState::Background; + applet->hid_registration.EnableAppletToGetInput(true); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + break; + } auto broker = std::make_shared(system); applet->caller_applet = caller_applet; diff --git a/src/core/hle/service/am/library_applet_proxy.cpp b/src/core/hle/service/am/library_applet_proxy.cpp index 1d88dd78c..d6108fba3 100644 --- a/src/core/hle/service/am/library_applet_proxy.cpp +++ b/src/core/hle/service/am/library_applet_proxy.cpp @@ -81,7 +81,7 @@ void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp index bc66bcb6b..b560f580b 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -3,6 +3,9 @@ #include "common/scope_exit.h" #include "core/core_timing.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am_results.h" #include "core/hle/service/am/applet_data_broker.h" @@ -15,25 +18,20 @@ #include "core/hle/service/am/library_applet_self_accessor.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" #include "hid_core/hid_types.h" namespace Service::AM { namespace { -struct AppletIdentityInfo { - AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; -}; -static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); - AppletIdentityInfo GetCallerIdentity(std::shared_ptr applet) { if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) { // TODO: is this actually the application ID? return { - .applet_id = applet->applet_id, - .application_id = applet->program_id, + .applet_id = caller_applet->applet_id, + .application_id = caller_applet->program_id, }; } else { return { @@ -60,7 +58,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, - {13, nullptr, "CanUseApplicationCore"}, + {13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "CanUseApplicationCore"}, {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, {15, nullptr, "GetMainAppletApplicationControlProperty"}, {16, nullptr, "GetMainAppletStorageId"}, @@ -74,8 +72,8 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, {40, nullptr, "GetIndirectLayerProducerHandle"}, {50, nullptr, "ReportVisibleError"}, {51, nullptr, "ReportVisibleErrorWithErrorContext"}, - {60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, - {70, nullptr, "GetCurrentApplicationId"}, + {60, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"}, + {70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "GetCurrentApplicationId"}, {80, nullptr, "RequestExitToSelf"}, {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, {100, nullptr, "CreateGameMovieTrimmer"}, @@ -86,6 +84,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, {140, nullptr, "SetApplicationMemoryReservation"}, {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, + {160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"}, }; // clang-format on RegisterHandlers(functions); @@ -202,6 +201,15 @@ void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ct rb.PushRaw(applet_info); } +void ILibraryAppletSelfAccessor::CanUseApplicationCore(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO: This appears to read the NPDM from state and check the core mask of the applet. + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -218,6 +226,80 @@ void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& c rb.Push(0); } +void ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx) { + // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage + auto identity = GetCallerIdentity(applet); + + // TODO(bunnei): This should be configurable + LOG_DEBUG(Service_AM, "called"); + + // Get supported languages from NACP, if possible + // Default to 0 (all languages supported) + u32 supported_languages = 0; + + const auto res = [this, identity] { + const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + u8 desired_language{}; + const auto res_lang = + app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages); + if (res_lang != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_lang); + return; + } + + // Convert to settings language code. + u64 language_code{}; + const auto res_code = + app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language); + if (res_code != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_code); + return; + } + + LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(language_code); +} + +void ILibraryAppletSelfAccessor::GetCurrentApplicationId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + u64 application_id = 0; + if (auto caller_applet = applet->caller_applet.lock(); caller_applet) { + application_id = caller_applet->program_id; + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(application_id); +} + void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { const Service::Account::ProfileManager manager{}; bool is_empty{true}; @@ -245,4 +327,12 @@ void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext rb.Push(0); } +void ILibraryAppletSelfAccessor::Cmd160(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(0); +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.h b/src/core/hle/service/am/library_applet_self_accessor.h index 596cea0df..8717a989a 100644 --- a/src/core/hle/service/am/library_applet_self_accessor.h +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -27,11 +27,15 @@ private: void GetPopInteractiveInDataEvent(HLERequestContext& ctx); void GetLibraryAppletInfo(HLERequestContext& ctx); void GetMainAppletIdentityInfo(HLERequestContext& ctx); + void CanUseApplicationCore(HLERequestContext& ctx); void ExitProcessAndReturn(HLERequestContext& ctx); void GetCallerAppletIdentityInfo(HLERequestContext& ctx); void GetDesirableKeyboardLayout(HLERequestContext& ctx); + void GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx); + void GetCurrentApplicationId(HLERequestContext& ctx); void GetMainAppletAvailableUsers(HLERequestContext& ctx); void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); + void Cmd160(HLERequestContext& ctx); const std::shared_ptr applet; const std::shared_ptr broker; diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp index 3ac967b4d..0289f5cf1 100644 --- a/src/core/hle/service/am/self_controller.cpp +++ b/src/core/hle/service/am/self_controller.cpp @@ -30,7 +30,7 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"}, {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, - {15, nullptr, "SetScreenShotAppletIdentityInfo"}, + {15, &ISelfController::SetScreenShotAppletIdentityInfo, "SetScreenShotAppletIdentityInfo"}, {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, {17, nullptr, "SetControllerFirmwareUpdateSection"}, {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, @@ -207,6 +207,17 @@ void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void ISelfController::SetScreenShotAppletIdentityInfo(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + std::scoped_lock lk{applet->lock}; + applet->screen_shot_identity = rp.PopRaw(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; diff --git a/src/core/hle/service/am/self_controller.h b/src/core/hle/service/am/self_controller.h index 6e6975264..a63bc2e74 100644 --- a/src/core/hle/service/am/self_controller.h +++ b/src/core/hle/service/am/self_controller.h @@ -28,6 +28,7 @@ private: void SetPerformanceModeChangedNotification(HLERequestContext& ctx); void SetFocusHandlingMode(HLERequestContext& ctx); void SetRestartMessageEnabled(HLERequestContext& ctx); + void SetScreenShotAppletIdentityInfo(HLERequestContext& ctx); void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx); void SetAlbumImageOrientation(HLERequestContext& ctx); void IsSystemBufferSharingEnabled(HLERequestContext& ctx); diff --git a/src/core/hle/service/am/system_applet_proxy.cpp b/src/core/hle/service/am/system_applet_proxy.cpp index e3013271b..38643408e 100644 --- a/src/core/hle/service/am/system_applet_proxy.cpp +++ b/src/core/hle/service/am/system_applet_proxy.cpp @@ -82,7 +82,7 @@ void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, applet); } void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp index 7211ef488..60a9afc9d 100644 --- a/src/core/hle/service/am/system_buffer_manager.cpp +++ b/src/core/hle/service/am/system_buffer_manager.cpp @@ -4,6 +4,7 @@ #include "core/hle/service/am/system_buffer_manager.h" #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" #include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/vi/vi_results.h" namespace Service::AM { @@ -41,9 +42,28 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel: if (res.IsSuccess()) { m_buffer_sharing_enabled = true; + m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible); } return m_buffer_sharing_enabled; } +void SystemBufferManager::SetWindowVisibility(bool visible) { + if (m_visible == visible) { + return; + } + + m_visible = visible; + + if (m_nvnflinger) { + m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible); + } +} + +Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, + s32* out_fbshare_layer_index) { + // TODO + R_SUCCEED(); +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h index c60d73416..98c3cf055 100644 --- a/src/core/hle/service/am/system_buffer_manager.h +++ b/src/core/hle/service/am/system_buffer_manager.h @@ -18,6 +18,8 @@ namespace Service::Nvnflinger { class Nvnflinger; } +union Result; + namespace Service::AM { class SystemBufferManager { @@ -33,10 +35,15 @@ public: *out_system_shared_layer_id = m_system_shared_layer_id; } + void SetWindowVisibility(bool visible); + + Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index); + private: Kernel::KProcess* m_process{}; Nvnflinger::Nvnflinger* m_nvnflinger{}; bool m_buffer_sharing_enabled{}; + bool m_visible{true}; u64 m_system_shared_buffer_id{}; u64 m_system_shared_layer_id{}; }; diff --git a/src/core/hle/service/am/window_controller.cpp b/src/core/hle/service/am/window_controller.cpp index 430ca180b..f00957f83 100644 --- a/src/core/hle/service/am/window_controller.cpp +++ b/src/core/hle/service/am/window_controller.cpp @@ -17,8 +17,8 @@ IWindowController::IWindowController(Core::System& system_, std::shared_ptr(); + + applet->system_buffer_manager.SetWindowVisibility(visible); + applet->hid_registration.EnableAppletToGetInput(visible); + + if (visible) { + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->focus_state = FocusState::InFocus; + } else { + applet->focus_state = FocusState::NotInFocus; + } + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IWindowController::SetAppletGpuTimeSlice(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto time_slice = rp.Pop(); + + LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/window_controller.h b/src/core/hle/service/am/window_controller.h index d97f93737..a28219abe 100644 --- a/src/core/hle/service/am/window_controller.h +++ b/src/core/hle/service/am/window_controller.h @@ -18,6 +18,8 @@ private: void GetAppletResourceUserId(HLERequestContext& ctx); void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); void AcquireForegroundRights(HLERequestContext& ctx); + void SetAppletWindowVisibility(HLERequestContext& ctx); + void SetAppletGpuTimeSlice(HLERequestContext& ctx); const std::shared_ptr applet; }; diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp index 2be72b021..5fe534c73 100644 --- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp @@ -15,11 +15,13 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/errors.h" #include "core/file_sys/fs_directory.h" #include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" +#include "core/file_sys/romfs.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/system_archive/system_archive.h" @@ -33,18 +35,20 @@ #include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/hle_ipc.h" #include "core/hle/service/ipc_helpers.h" +#include "core/loader/loader.h" #include "core/reporter.h" namespace Service::FileSystem { -enum class FileSystemType : u8 { - Invalid0 = 0, - Invalid1 = 1, +enum class FileSystemProxyType : u8 { + Code = 0, + Rom = 1, Logo = 2, - ContentControl = 3, - ContentManual = 4, - ContentMeta = 5, - ContentData = 6, - ApplicationPackage = 7, + Control = 3, + Manual = 4, + Meta = 5, + Data = 6, + Package = 7, + RegisteredUpdate = 8, }; class ISaveDataInfoReader final : public ServiceFramework { @@ -357,12 +361,30 @@ void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto type = rp.PopRaw(); - const auto title_id = rp.PopRaw(); - LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); + struct InputParameters { + FileSystemProxyType type; + u64 program_id; + }; + static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size"); + + const auto params = rp.PopRaw(); + LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type, + params.program_id); + + // FIXME: many issues with this + ASSERT(params.type == FileSystemProxyType::Manual); + const auto manual_romfs = romfs_controller->OpenPatchedRomFS( + params.program_id, FileSys::ContentRecordType::HtmlDocument); - IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(ResultUnknown); + ASSERT(manual_romfs != nullptr); + + const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs); + ASSERT(extracted_romfs != nullptr); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, extracted_romfs, + SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser)); } void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 22dc55a6d..8e3224f73 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -185,7 +185,7 @@ public: {3, &IRequest::Cancel, "Cancel"}, {4, &IRequest::Submit, "Submit"}, {5, nullptr, "SetRequirement"}, - {6, nullptr, "SetRequirementPreset"}, + {6, &IRequest::SetRequirementPreset, "SetRequirementPreset"}, {8, nullptr, "SetPriority"}, {9, nullptr, "SetNetworkProfileId"}, {10, nullptr, "SetRejectable"}, @@ -237,6 +237,16 @@ private: rb.PushEnum(state); } + void SetRequirementPreset(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto param_1 = rp.Pop(); + + LOG_WARNING(Service_NIFM, "(STUBBED) called, param_1={}", param_1); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + void GetResult(HLERequestContext& ctx) { LOG_DEBUG(Service_NIFM, "(STUBBED) called"); diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 2258ee609..19c3ff01b 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -3,6 +3,7 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "core/arm/debug.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" @@ -544,8 +545,8 @@ IDocumentInterface::IDocumentInterface(Core::System& system_) // clang-format off static const FunctionInfo functions[] = { {21, nullptr, "GetApplicationContentPath"}, - {23, nullptr, "ResolveApplicationContentPath"}, - {93, nullptr, "GetRunningApplicationProgramId"}, + {23, &IDocumentInterface::ResolveApplicationContentPath, "ResolveApplicationContentPath"}, + {92, &IDocumentInterface::GetRunningApplicationProgramId, "GetRunningApplicationProgramId"}, }; // clang-format on @@ -554,6 +555,32 @@ IDocumentInterface::IDocumentInterface(Core::System& system_) IDocumentInterface::~IDocumentInterface() = default; +void IDocumentInterface::ResolveApplicationContentPath(HLERequestContext& ctx) { + struct ContentPath { + u8 file_system_proxy_type; + u64 program_id; + }; + static_assert(sizeof(ContentPath) == 0x10, "ContentPath has wrong size"); + + IPC::RequestParser rp{ctx}; + auto content_path = rp.PopRaw(); + LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}", + content_path.file_system_proxy_type, content_path.program_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDocumentInterface::GetRunningApplicationProgramId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto caller_program_id = rp.PopRaw(); + LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(system.GetApplicationProcessProgramID()); +} + IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) : ServiceFramework{system_, "IDownloadTaskInterface"} { // clang-format off @@ -613,6 +640,40 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) IFactoryResetInterface::~IFactoryResetInterface() = default; +IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_) + : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} { + static const FunctionInfo functions[] = { + {0, &IReadOnlyApplicationRecordInterface::HasApplicationRecord, "HasApplicationRecord"}, + {1, nullptr, "NotifyApplicationFailure"}, + {2, &IReadOnlyApplicationRecordInterface::IsDataCorruptedResult, "IsDataCorruptedResult"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default; + +void IReadOnlyApplicationRecordInterface::HasApplicationRecord(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 program_id = rp.PopRaw(); + LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(1); +} + +void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto result = rp.PopRaw(); + LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue()); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( Core::System& system_) : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { @@ -663,7 +724,7 @@ NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name static const FunctionInfo functions[] = { {7988, nullptr, "GetDynamicRightsInterface"}, {7989, &NS::PushInterface, "GetReadOnlyApplicationControlDataInterface"}, - {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, + {7991, &NS::PushInterface, "GetReadOnlyApplicationRecordInterface"}, {7992, &NS::PushInterface, "GetECommerceInterface"}, {7993, &NS::PushInterface, "GetApplicationVersionInterface"}, {7994, &NS::PushInterface, "GetFactoryResetInterface"}, diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 34d2a45dc..9ee306ef9 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -58,6 +58,10 @@ class IDocumentInterface final : public ServiceFramework { public: explicit IDocumentInterface(Core::System& system_); ~IDocumentInterface() override; + +private: + void ResolveApplicationContentPath(HLERequestContext& ctx); + void GetRunningApplicationProgramId(HLERequestContext& ctx); }; class IDownloadTaskInterface final : public ServiceFramework { @@ -78,6 +82,17 @@ public: ~IFactoryResetInterface() override; }; +class IReadOnlyApplicationRecordInterface final + : public ServiceFramework { +public: + explicit IReadOnlyApplicationRecordInterface(Core::System& system_); + ~IReadOnlyApplicationRecordInterface() override; + +private: + void HasApplicationRecord(HLERequestContext& ctx); + void IsDataCorruptedResult(HLERequestContext& ctx); +}; + class IReadOnlyApplicationControlDataInterface final : public ServiceFramework { public: diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 71d6fdb0c..51133853c 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -198,6 +198,16 @@ bool Nvnflinger::CloseLayer(u64 layer_id) { return false; } +void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) { + const auto lock_guard = Lock(); + + for (auto& display : displays) { + if (auto* layer = display.FindLayer(layer_id); layer) { + layer->SetVisibility(visible); + } + } +} + void Nvnflinger::DestroyLayer(u64 layer_id) { const auto lock_guard = Lock(); diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index a60e0ae6b..369439142 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -79,6 +79,9 @@ public: /// Closes a layer on all displays for the given layer ID. bool CloseLayer(u64 layer_id); + /// Makes a layer visible on all displays for the given layer ID. + void SetLayerVisibility(u64 layer_id, bool visible); + /// Destroys the given layer ID. void DestroyLayer(u64 layer_id); diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 725311c53..dab1905cc 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -53,7 +53,7 @@ Display::~Display() { Layer& Display::GetLayer(std::size_t index) { size_t i = 0; for (auto& layer : layers) { - if (!layer->IsOpen()) { + if (!layer->IsOpen() || !layer->IsVisible()) { continue; } @@ -68,7 +68,7 @@ Layer& Display::GetLayer(std::size_t index) { } size_t Display::GetNumLayers() const { - return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); + return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); }); } Kernel::KReadableEvent* Display::GetVSyncEvent() { diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp index 04e52a23b..493bd6e9e 100644 --- a/src/core/hle/service/vi/layer/vi_layer.cpp +++ b/src/core/hle/service/vi/layer/vi_layer.cpp @@ -9,7 +9,7 @@ Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, android::BufferQueueProducer& binder_, std::shared_ptr&& consumer_) : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, - consumer{std::move(consumer_)}, open{false} {} + consumer{std::move(consumer_)}, open{false}, visible{true} {} Layer::~Layer() = default; diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index f95e2dc71..b4b031ee7 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h @@ -72,6 +72,14 @@ public: return core; } + bool IsVisible() const { + return visible; + } + + void SetVisibility(bool v) { + visible = v; + } + bool IsOpen() const { return open; } @@ -91,6 +99,7 @@ private: android::BufferQueueProducer& binder; std::shared_ptr consumer; bool open; + bool visible; }; } // namespace Service::VI diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4e5c4da53..303d84a1f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4931,7 +4931,10 @@ void GMainWindow::changeEvent(QEvent* event) { } Service::AM::FrontendAppletParameters GMainWindow::ApplicationAppletParameters() { - return Service::AM::FrontendAppletParameters{}; + return Service::AM::FrontendAppletParameters{ + .applet_id = Service::AM::AppletId::Application, + .applet_type = Service::AM::AppletType::Application, + }; } Service::AM::FrontendAppletParameters GMainWindow::LibraryAppletParameters( -- cgit v1.2.3 From 8e0a40434c8cc1de7b7262c0439380e5eca3e42a Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 27 Jan 2024 14:39:55 -0500 Subject: am: stop emulation when all applets are closed --- src/core/hle/service/am/applet_manager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index a733525a2..52200d5b2 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -221,6 +221,7 @@ void AppletManager::InsertApplet(std::shared_ptr applet) { void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { std::shared_ptr applet; + bool should_stop = false; { std::scoped_lock lk{m_lock}; @@ -231,10 +232,17 @@ void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { applet = it->second; m_applets.erase(it); + + should_stop = m_applets.empty(); } // Terminate process. applet->process->Terminate(); + + // If there were no applets left, stop emulation. + if (should_stop) { + m_system.Exit(); + } } void AppletManager::CreateAndInsertByFrontendAppletParameters( -- cgit v1.2.3 From 817d916233adcfb26814fde677e71d9825ce614c Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 30 Jan 2024 20:13:48 -0500 Subject: am: push storage from error applet with non-zero size --- src/core/hle/service/am/frontend/applet_error.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/service/am/frontend/applet_error.cpp b/src/core/hle/service/am/frontend/applet_error.cpp index d6db345b6..b97a5f3ea 100644 --- a/src/core/hle/service/am/frontend/applet_error.cpp +++ b/src/core/hle/service/am/frontend/applet_error.cpp @@ -207,7 +207,7 @@ void Error::Execute() { void Error::DisplayCompleted() { complete = true; - PushOutData(std::make_shared(system, std::vector())); + PushOutData(std::make_shared(system, std::vector(0x1000))); Exit(); } -- cgit v1.2.3