diff options
Diffstat (limited to '')
132 files changed, 7084 insertions, 4710 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/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<jstring>(env->GetObjectField( object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;"))); return ResultData{GetJString(env, string), - static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField( + static_cast<Service::AM::Frontend::SwkbdResult>(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<s32>(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..654510129 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -42,14 +42,15 @@ #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_manager.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" @@ -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<Service::AM::AppletId>(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. @@ -226,7 +234,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 @@ -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<Service::AM::AppletId>(m_applet_id), + .launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated + : Service::AM::LaunchType::ApplicationInitiated, + .program_index = static_cast<s32>(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<int>(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<int>(result)); @@ -809,13 +829,12 @@ 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<Service::AM::Applets::AppletId>(jappletId)); + EmulationSession::GetInstance().SetAppletId(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<Service::NFP::CabinetMode>(jcabinetMode)); } 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<bool> m_is_paused = false; SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; + int m_applet_id{1}; // GPU driver parameters std::shared_ptr<Common::DynamicLibrary> m_vulkan_library; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ea6b2c285..570acb193 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,39 +390,101 @@ 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 + 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_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 - 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 + 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/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 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/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 + 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 @@ -486,6 +548,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/core.cpp b/src/core/core.cpp index 11bf8d2f6..435ef6793 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -36,7 +36,8 @@ #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/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" #include "core/hle/service/glue/glue_manager.h" @@ -135,8 +136,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}, applet_manager{system}, frontend_applets{system}, profile_manager{} {} void Initialize(System& system) { device_memory = std::make_unique<Core::DeviceMemory>(); @@ -157,7 +158,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(); @@ -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,9 +385,14 @@ 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); + main_process->Close(); if (Settings::values.gamecard_inserted) { if (Settings::values.gamecard_current_game) { @@ -386,21 +403,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<PerfStats>(program_id); + perf_stats = std::make_unique<PerfStats>(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 +418,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 +465,7 @@ struct System::Impl { } kernel.CloseServices(); kernel.ShutdownCores(); + applet_manager.Reset(); services.reset(); service_manager.reset(); fs_controller.Reset(); @@ -566,8 +577,9 @@ struct System::Impl { std::unique_ptr<Tools::RenderdocAPI> renderdoc_api; - /// Frontend applets - Service::AM::Applets::AppletManager applet_manager; + /// Applets + Service::AM::AppletManager applet_manager; + Service::AM::Frontend::FrontendAppletHolder frontend_applets; /// APM (Performance) services Service::APM::Controller apm_controller{core_timing}; @@ -680,8 +692,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 { @@ -871,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& 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(); +Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { + return impl->frontend_applets; } -Service::AM::Applets::AppletManager& System::GetAppletManager() { - return impl->applet_manager; +const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const { + return impl->frontend_applets; } -const Service::AM::Applets::AppletManager& System::GetAppletManager() const { +Service::AM::AppletManager& System::GetAppletManager() { return impl->applet_manager; } diff --git a/src/core/core.h b/src/core/core.h index d8862e9ce..90826bd3a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -50,10 +50,15 @@ namespace Account { class ProfileManager; } // namespace Account -namespace AM::Applets { -struct AppletFrontendSet; +namespace AM { +struct FrontendAppletParameters; class AppletManager; -} // namespace AM::Applets +} // namespace AM + +namespace AM::Frontend { +struct FrontendAppletSet; +class FrontendAppletHolder; +} // namespace AM::Frontend namespace APM { class Controller; @@ -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 @@ -344,11 +349,13 @@ public: const std::array<u8, 0x20>& build_id, u64 main_region_begin, u64 main_region_size); - void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); - void SetDefaultAppletFrontendSet(); + void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); + + [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); + [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() + const; - [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); - [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const; + [[nodiscard]] Service::AM::AppletManager& GetAppletManager(); void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general.cpp index b4b213a31..4c299ee9c 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" -#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/general.h" namespace Core::Frontend { diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general.h index 319838ac7..319838ac7 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general.h 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<Common::UUID, 8> 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<s32>(index) + 1); std::this_thread::sleep_for(std::chrono::milliseconds(250)); } - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text), - static_cast<s32>(text.size())); + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, + std::u16string(text), static_cast<s32>(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<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; + std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>; using SubmitNormalCallback = - std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>; + std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>; 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 <functional> #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<void()>; using OpenWebPageCallback = - std::function<void(Service::AM::Applets::WebExitReason, std::string)>; + std::function<void(Service::AM::Frontend::WebExitReason, std::string)>; virtual ~WebBrowserApplet(); 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<KProcess*> process_list; - std::atomic<KProcess*> application_process{}; + KProcess* application_process{}; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; std::unique_ptr<Kernel::KHardwareTimer> 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 38f67adcd..8f90eba34 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1,2704 +1,27 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <algorithm> -#include <array> -#include <cinttypes> -#include <cstring> -#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_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<u64>(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<u64>(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<float>(); - const float library_applet_volume_tmp = rp.Pop<float>(); - - 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<Parameters>(); - - 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<float>(); - - 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<ScreenshotPermission>(); - 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<bool>(); - 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<bool>(); - 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<FocusHandlingModeParams>(); - - 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<bool>(); - 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<s64>(system_shared_buffer_id); - rb.Push<s64>(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<s64>(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<u32>(); - 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<u32>(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<bool>(); - - // 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<u64>(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<bool>(); - - 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<Capture::AlbumReportOption>(); - - LOG_INFO(Service_AM, "called, report_option={}", report_option); - - const auto screenshot_service = - system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( - "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<bool>(); - - 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<bool>(); - - 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<u8>(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<u8>(is_locked); -} - -ICommonStateGetter::ICommonStateGetter(Core::System& system_, - std::shared_ptr<AppletMessageQueue> 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<u8>(static_cast<u8>(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<AppletMessageQueue::AppletMessage>(message); - return; - } - - rb.Push(ResultSuccess); - rb.PushEnum<AppletMessageQueue::AppletMessage>(message); -} - -void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u8>(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<u32>(); - - LOG_INFO(Service_AM, "called, unknown={}", unknown); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILockAccessor>(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<bool>(); - - 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<bool>(); - - 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<u32>(Service::VI::DisplayResolution::DockedWidth)); - rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); - } else { - rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); - rb.Push(static_cast<u32>(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::APM_Sys>("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<SystemButtonType>()}; - - 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<u8>&& buffer_) : buffer{std::move(buffer_)} {} - - std::vector<u8>& GetData() override { - return buffer; - } - - const std::vector<u8>& GetData() const override { - return buffer; - } - - std::size_t GetSize() const override { - return buffer.size(); - } - -private: - std::vector<u8> buffer; -}; - -IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer) - : ServiceFramework{system_, "IStorage"}, impl{std::make_shared<StorageDataImpl>( - 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<IStorageAccessor>(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<u8>(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<ILibraryAppletAccessor> { -public: - explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<Applets::Applet> 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<u32>(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<IStorage>().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<IStorage>(std::move(storage)); - } - - void PushInteractiveInData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().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<IStorage>(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<Applets::Applet> 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<u64>(backing.GetSize())); -} - -void IStorageAccessor::Write(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const u64 offset{rp.Pop<u64>()}; - const auto data{ctx.ReadBuffer()}; - const std::size_t size{std::min<u64>(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<u64>()}; - const std::size_t size{std::min<u64>(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<Applets::AppletId>(); - const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>(); - - 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<ILibraryAppletAccessor>(system, applet); -} - -void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const s64 size{rp.Pop<s64>()}; - - 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<u8> buffer(size); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(system, std::move(buffer)); -} - -void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - struct Parameters { - u8 permissions; - s64 size; - }; - - const auto parameters{rp.PopRaw<Parameters>()}; - 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<Kernel::KTransferMemory>(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<u8> 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<IStorage>(system, std::move(memory)); -} - -void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const s64 size{rp.Pop<s64>()}; - 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<Kernel::KTransferMemory>(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<u8> 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<IStorage>(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<IStorage>(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<u32>(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<s32>(manager.GetUserCount()); - ctx.WriteBuffer(manager.GetAllUsers()); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u8>(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<u8>(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<u8> argument_data(sizeof(arguments)); - std::vector<u8> 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<u32>(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<u8> common_args_data(sizeof(common_args)); - std::vector<u8> private_args_data(sizeof(private_args)); - std::vector<u8> 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<u32>(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<u8> argument_data(sizeof(arguments)); - std::vector<u8> 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<u8> 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<u32>(Applets::SwkbdAppletVersion::Version524301), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector<char16_t> 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<u32>(initial_string.size()), - .user_dictionary_offset{}, - .user_dictionary_entries{}, - .use_text_check = false, - }; - - Applets::SwkbdConfigNew swkbd_config_new{}; - - std::vector<u8> argument_data(sizeof(arguments)); - std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); - std::vector<u8> 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<bool>(); - - 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<LaunchParameterKind>(); - - 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<IStorage>(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<s32>(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<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); - std::memcpy(buffer.data(), ¶ms, buffer.size()); - - rb.PushIpcInterface<IStorage>(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<u128>(); - - 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<u64>(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<u32>(); - 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<u8, 0x10> 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::NS>("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<u8>(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<u64>(0); - rb.Push<u64>(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<Parameters>(); - - LOG_DEBUG(Service_AM, - "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " - "new_journal={:016X}", - static_cast<u8>(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<u64>(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<Parameters>(); - - 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<InputParameters>(); - - 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<u32>(0); -} - -void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); -} - -void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::RequestParser rp{ctx}; - [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); - [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); - const auto program_index = rp.Pop<u64>(); - - 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<IStorage>().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<s32>(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<AppletMessageQueue>(system); auto server_manager = std::make_unique<ServerManager>(system); - server_manager->RegisterNamedService( - "appletAE", std::make_shared<AppletAE>(nvnflinger, message_queue, system)); - server_manager->RegisterNamedService( - "appletOE", std::make_shared<AppletOE>(nvnflinger, message_queue, system)); + server_manager->RegisterNamedService("appletAE", + std::make_shared<AppletAE>(nvnflinger, system)); + server_manager->RegisterNamedService("appletOE", + std::make_shared<AppletOE>(nvnflinger, system)); server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system)); server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system)); server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(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<ILibraryAppletAccessor>(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 <chrono> -#include <memory> -#include <queue> - -#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<AppletMessage> messages; -}; - -class IWindowController final : public ServiceFramework<IWindowController> { -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<IAudioController> { -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<IDisplayController> { -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<IDebugFunctions> { -public: - explicit IDebugFunctions(Core::System& system_); - ~IDebugFunctions() override; -}; - -class ISelfController final : public ServiceFramework<ISelfController> { -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<ILockAccessor> { -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<ICommonStateGetter> { -public: - explicit ICommonStateGetter(Core::System& system_, - std::shared_ptr<AppletMessageQueue> 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<AppletMessageQueue> msg_queue; - bool vr_mode_state{}; - Kernel::KEvent* sleep_lock_event; - KernelHelpers::ServiceContext service_context; -}; - -class IStorageImpl { -public: - virtual ~IStorageImpl(); - virtual std::vector<u8>& GetData() = 0; - virtual const std::vector<u8>& GetData() const = 0; - virtual std::size_t GetSize() const = 0; -}; - -class IStorage final : public ServiceFramework<IStorage> { -public: - explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); - ~IStorage() override; - - std::vector<u8>& GetData() { - return impl->GetData(); - } - - const std::vector<u8>& GetData() const { - return impl->GetData(); - } - - std::size_t GetSize() const { - return impl->GetSize(); - } - -private: - void Register(); - void Open(HLERequestContext& ctx); - - std::shared_ptr<IStorageImpl> impl; -}; - -class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { -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<ILibraryAppletCreator> { -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<ILibraryAppletSelfAccessor> { -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<std::vector<u8>> queue_data; -}; - -class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { -public: - explicit IAppletCommonFunctions(Core::System& system_); - ~IAppletCommonFunctions() override; - -private: - void SetCpuBoostRequestPriority(HLERequestContext& ctx); -}; - -class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { -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<IHomeMenuFunctions> { -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<IGlobalStateController> { -public: - explicit IGlobalStateController(Core::System& system_); - ~IGlobalStateController() override; -}; - -class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { -public: - explicit IApplicationCreator(Core::System& system_); - ~IApplicationCreator() override; -}; - -class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { -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..a2afc9eec --- /dev/null +++ b/src/core/hle/service/am/am_results.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/result.h" + +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/am_types.h b/src/core/hle/service/am/am_types.h new file mode 100644 index 000000000..a2b852b12 --- /dev/null +++ b/src/core/hle/service/am/am_types.h @@ -0,0 +1,178 @@ +// 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."); + +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; + +struct Applet; +class AppletDataBroker; + +} // 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..5b9056c12 --- /dev/null +++ b/src/core/hle/service/am/applet.cpp @@ -0,0 +1,27 @@ +// 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.h" +#include "core/hle/service/am/applet_manager.h" + +namespace Service::AM { + +Applet::Applet(Core::System& system, std::unique_ptr<Process> 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..bce6f9050 --- /dev/null +++ b/src/core/hle/service/am/applet.h @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <list> +#include <mutex> + +#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::AM { + +struct Applet { + explicit Applet(Core::System& system, std::unique_ptr<Process> process_); + ~Applet(); + + // Lock + std::mutex lock{}; + + // Event creation helper + KernelHelpers::ServiceContext context; + + // Applet message queue + AppletMessageQueue message_queue; + + // Process + std::unique_ptr<Process> 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}; + + // TODO: some fields above can be AppletIdentityInfo + AppletIdentityInfo screen_shot_identity; + + // 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<f32> 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<std::vector<u8>> user_channel_launch_parameter{}; + std::deque<std::vector<u8>> preselected_user_launch_parameter{}; + + // Caller applet + std::weak_ptr<Applet> caller_applet{}; + std::shared_ptr<AppletDataBroker> caller_applet_broker{}; + + // 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::FrontendApplet> frontend{}; +}; + +} // 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..1b715dea6 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -1,311 +1,73 @@ // 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/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" -#include "core/hle/service/nvnflinger/nvnflinger.h" namespace Service::AM { -class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { -public: - explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> 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<ICommonStateGetter>(system, msg_queue); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISelfController>(system, nvnflinger); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IWindowController>(system); - } - - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAudioController>(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDisplayController>(system); - } - - void GetProcessWindingController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IProcessWindingController>(system); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } - - void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system); - } - - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAppletCommonFunctions>(system); - } - - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IHomeMenuFunctions>(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IGlobalStateController>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - -class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { -public: - explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> 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<ICommonStateGetter>(system, msg_queue); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISelfController>(system, nvnflinger); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IWindowController>(system); - } - - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAudioController>(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDisplayController>(system); - } +AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) + : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} { + // clang-format off + static const FunctionInfo functions[] = { + {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, + {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"}, + {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"}, + {300, nullptr, "OpenOverlayAppletProxy"}, + {350, nullptr, "OpenSystemApplicationProxy"}, + {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, + {410, nullptr, "GetSystemAppletControllerForDebug"}, + {1000, nullptr, "GetDebugFunctions"}, + }; + // clang-format on - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + RegisterHandlers(functions); +} - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } +AppletAE::~AppletAE() = default; - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +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<IHomeMenuFunctions>(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IGlobalStateController>(system); - } - - void GetApplicationCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationCreator>(system); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); } +} - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +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<IAppletCommonFunctions>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - -void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemAppletProxy>(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<ILibraryAppletProxy>(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<ILibraryAppletProxy>(nvnflinger, msg_queue, system); + return OpenLibraryAppletProxy(ctx); } -AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{ - std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, - {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"}, - {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"}, - {300, nullptr, "OpenOverlayAppletProxy"}, - {350, nullptr, "OpenSystemApplicationProxy"}, - {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, - {410, nullptr, "GetSystemAppletControllerForDebug"}, - {1000, nullptr, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -AppletAE::~AppletAE() = default; - -const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const { - return msg_queue; +std::shared_ptr<Applet> 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<AppletAE> { public: - explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); + explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); ~AppletAE() override; - const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; - private: void OpenSystemAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxyOld(HLERequestContext& ctx); + std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); + Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> 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 new file mode 100644 index 000000000..130614ae5 --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.cpp @@ -0,0 +1,63 @@ +// 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_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} { + // 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"}, + {300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +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<s32>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(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 new file mode 100644 index 000000000..b86adf5cb --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.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 { + +struct Applet; + +class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { +public: + explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IAppletCommonFunctions() override; + +private: + void SetCpuBoostRequestPriority(HLERequestContext& ctx); + void GetCurrentApplicationId(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM 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<IStorage> storage) { + std::scoped_lock lk{m_lock}; + + m_data.emplace_back(std::move(storage)); + m_event.Signal(); +} + +Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* 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 <deque> +#include <memory> +#include <mutex> + +#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<IStorage> storage); + Result Pop(std::shared_ptr<IStorage>* out_storage); + Kernel::KReadableEvent* GetEvent(); + +private: + std::mutex m_lock{}; + std::deque<std::shared_ptr<IStorage>> 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 new file mode 100644 index 000000000..52200d5b2 --- /dev/null +++ b/src/core/hle/service/am/applet_manager.cpp @@ -0,0 +1,361 @@ +// 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_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" +#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 { + +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) { + applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system); + return applet->caller_applet_broker->GetInData(); +} + +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<u8> argument_data(sizeof(arguments)); + std::vector<u8> settings_data{2}; + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); + channel.Push(std::make_shared<IStorage>(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<u32>(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<u8> common_args_data(sizeof(common_args)); + std::vector<u8> private_args_data(sizeof(private_args)); + std::vector<u8> 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.Push(std::make_shared<IStorage>(system, std::move(common_args_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(private_args_data))); + channel.Push(std::make_shared<IStorage>(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<u32>(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<u8> argument_data(sizeof(arguments)); + std::vector<u8> settings_data(sizeof(amiibo_settings)); + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(settings_data))); +} + +void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { + 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<u8> argument_data(sizeof(mii_arguments)); + std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); + + channel.Push(std::make_shared<IStorage>(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<u32>(Frontend::SwkbdAppletVersion::Version524301), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector<char16_t> 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<u32>(initial_string.size()), + .user_dictionary_offset{}, + .user_dictionary_entries{}, + .use_text_check = false, + }; + + Frontend::SwkbdConfigNew swkbd_config_new{}; + + std::vector<u8> argument_data(sizeof(arguments)); + std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); + std::vector<u8> 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)); + + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(swkbd_data))); + channel.Push(std::make_shared<IStorage>(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> applet) { + std::scoped_lock lk{m_lock}; + + m_applets.emplace(applet->aruid, std::move(applet)); +} + +void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { + std::shared_ptr<Applet> applet; + bool should_stop = false; + { + 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); + + 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( + 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<Applet>(m_system, std::make_unique<Process>(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<s32>(Settings::values.current_user)); + ASSERT(uuid.has_value() && uuid->IsValid()); + lp.current_user = *uuid; + + std::vector<u8> 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::ChangeIntoForeground); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + applet->focus_state = FocusState::InFocus; + + this->InsertApplet(std::move(applet)); +} + +std::shared_ptr<Applet> 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 <map> +#include <mutex> + +#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> applet); + void TerminateAndRemoveApplet(AppletResourceUserId aruid); + + void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid, + const FrontendAppletParameters& params); + std::shared_ptr<Applet> 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<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{}; + + // AudioController state goes here +}; + +} // 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..5ed996b70 --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.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/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) { + { + 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; + } + auto msg = messages.front(); + messages.pop(); + if (messages.empty()) { + on_new_message->Clear(); + } + return msg; +} + +std::size_t AppletMessageQueue::GetMessageCount() const { + std::scoped_lock lk{lock}; + 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..5cb236d47 --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.h @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <queue> + +#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; + + mutable std::mutex lock; + std::queue<AppletMessage> 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..56bafd162 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -1,129 +1,42 @@ // 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_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" -#include "core/hle/service/nvnflinger/nvnflinger.h" namespace Service::AM { -class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { -public: - explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> 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<IAudioController>(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDisplayController>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IWindowController>(system); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISelfController>(system, nvnflinger); - } - - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) + : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} { + static const FunctionInfo functions[] = { + {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, + }; + RegisterHandlers(functions); +} - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); - } +AppletOE::~AppletOE() = default; - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +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<ILibraryAppletCreator>(system); - } - - void GetApplicationFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationFunctions>(system); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - -void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system); -} - -AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{ - std::move(msg_queue_)} { - static const FunctionInfo functions[] = { - {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, - }; - RegisterHandlers(functions); } -AppletOE::~AppletOE() = default; - -const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const { - return msg_queue; +std::shared_ptr<Applet> 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<AppletOE> { public: - explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); + explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); ~AppletOE() override; - const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; - private: void OpenApplicationProxy(HLERequestContext& ctx); + std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); + Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; }; } // namespace AM 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 89d5434af..000000000 --- a/src/core/hle/service/am/applets/applets.cpp +++ /dev/null @@ -1,338 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <cstring> - -#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_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/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<std::vector<u8>> out_normal; - - for (const auto& storage : in_channel) { - out_normal.push_back(storage->GetData()); - } - - std::vector<std::vector<u8>> 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<IStorage> 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<IStorage> AppletDataBroker::PopNormalDataToApplet() { - if (in_channel.empty()) - return nullptr; - - auto out = std::move(in_channel.front()); - in_channel.pop_front(); - return out; -} - -std::shared_ptr<IStorage> 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<IStorage> 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<IStorage>&& storage) { - in_channel.emplace_back(std::move(storage)); -} - -void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { - out_channel.emplace_back(std::move(storage)); - pop_out_data_event->Signal(); -} - -void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { - in_interactive_channel.emplace_back(std::move(storage)); -} - -void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& 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>("appletOE"); - auto applet_ae = system.ServiceManager().GetService<AppletAE>("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<Core::Frontend::DefaultCabinetApplet>(); - } - - if (frontend.controller == nullptr) { - frontend.controller = - std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); - } - - if (frontend.error == nullptr) { - frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); - } - - if (frontend.mii_edit == nullptr) { - frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>(); - } - - if (frontend.parental_controls == nullptr) { - frontend.parental_controls = - std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); - } - - if (frontend.photo_viewer == nullptr) { - frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); - } - - if (frontend.profile_select == nullptr) { - frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); - } - - if (frontend.software_keyboard == nullptr) { - frontend.software_keyboard = - std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); - } - - if (frontend.web_browser == nullptr) { - frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); - } -} - -void AppletManager::ClearAll() { - frontend = {}; -} - -std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const { - switch (id) { - case AppletId::Auth: - return std::make_shared<Auth>(system, mode, *frontend.parental_controls); - case AppletId::Cabinet: - return std::make_shared<Cabinet>(system, mode, *frontend.cabinet); - case AppletId::Controller: - return std::make_shared<Controller>(system, mode, *frontend.controller); - case AppletId::Error: - return std::make_shared<Error>(system, mode, *frontend.error); - case AppletId::ProfileSelect: - return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select); - case AppletId::SoftwareKeyboard: - return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard); - case AppletId::MiiEdit: - return std::make_shared<MiiEdit>(system, mode, *frontend.mii_edit); - case AppletId::Web: - case AppletId::Shop: - case AppletId::OfflineWeb: - case AppletId::LoginShare: - case AppletId::WebAuth: - return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser); - case AppletId::PhotoViewer: - return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer); - default: - UNIMPLEMENTED_MSG( - "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", - static_cast<u8>(id)); - return std::make_shared<StubApplet>(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 <memory> -#include <queue> - -#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<std::vector<u8>> normal; - std::vector<std::vector<u8>> interactive; - }; - - // Retrieves but does not pop the data sent to applet. - RawChannelData PeekDataToAppletForDebug() const; - - std::shared_ptr<IStorage> PopNormalDataToGame(); - std::shared_ptr<IStorage> PopNormalDataToApplet(); - - std::shared_ptr<IStorage> PopInteractiveDataToGame(); - std::shared_ptr<IStorage> PopInteractiveDataToApplet(); - - void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage); - void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage); - - void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage); - void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& 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<std::shared_ptr<IStorage>> in_channel; - - // PopNormalDataToGame and PushNormalDataFromApplet - std::deque<std::shared_ptr<IStorage>> out_channel; - - // PopInteractiveDataToApplet and PushInteractiveDataFromGame - std::deque<std::shared_ptr<IStorage>> in_interactive_channel; - - // PopInteractiveDataToGame and PushInteractiveDataFromApplet - std::deque<std::shared_ptr<IStorage>> 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<Core::Frontend::CabinetApplet>; - using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; - using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; - using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; - using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; - using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; - using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; - using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; - using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; - - 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<Applet> 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/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<IApplicationCreator> { +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..51c5be2d1 --- /dev/null +++ b/src/core/hle/service/am/application_functions.cpp @@ -0,0 +1,594 @@ +// 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/applet.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, +}; + +IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} { + // 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); +} + +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); +} + +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<bool>(); + + 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"); + + 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); +} + +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); +} + +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); +} + +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); +} + +void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto kind = rp.PopEnum<LaunchParameterKind>(); + + LOG_INFO(Service_AM, "called, kind={:08X}", kind); + + std::scoped_lock lk{applet->lock}; + + auto& channel = kind == LaunchParameterKind::UserChannel + ? applet->user_channel_launch_parameter + : applet->preselected_user_launch_parameter; + + 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<IStorage>(system, std::move(data)); +} + +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<u128>(); + + LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); + + FileSys::SaveDataAttribute attribute{}; + attribute.title_id = applet->program_id; + 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<u64>(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<u32>(); + 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); +} + +void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::array<u8, 0x10> version_string{}; + + const auto res = [this] { + 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(applet->program_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 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(applet->program_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::NS>("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"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(applet->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::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->gameplay_recording_state = rp.PopRaw<GameplayRecordingState>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +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<u8>(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<u64>(0); + rb.Push<u64>(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<Parameters>(); + + LOG_DEBUG(Service_AM, + "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " + "new_journal={:016X}", + static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); + + system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( + type, applet->program_id, 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<u64>(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<Parameters>(); + + 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, applet->program_id, 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<InputParameters>(); + + 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<u32>(0); +} + +void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); +} + +void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); + [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); + const auto program_index = rp.Pop<u64>(); + + 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"); + + applet->user_channel_launch_parameter.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<IStorage>().lock(); + if (storage) { + applet->user_channel_launch_parameter.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<s32>(applet->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(applet->gpu_error_detected_event.GetHandle()); +} + +void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle()); +} + +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(applet->notification_storage_channel_event.GetHandle()); +} + +void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + 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); +} + +} // 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..55eb21d39 --- /dev/null +++ b/src/core/hle/service/am/application_functions.h @@ -0,0 +1,58 @@ +// 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 { + +struct Applet; + +class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { +public: + explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); + ~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); + + const std::shared_ptr<Applet> applet; +}; + +} // 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..a6fd6d37f --- /dev/null +++ b/src/core/hle/service/am/application_proxy.cpp @@ -0,0 +1,115 @@ +// 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<Applet> applet_, Core::System& system_) + : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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); +} + +IApplicationProxy::~IApplicationProxy() = default; + +void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAudioController>(system); +} + +void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDisplayController>(system, applet); +} + +void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IProcessWindingController>(system, applet); +} + +void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDebugFunctions>(system); +} + +void IApplicationProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IWindowController>(system, applet); +} + +void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger); +} + +void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ICommonStateGetter>(system, applet); +} + +void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); +} + +void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IApplicationFunctions>(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 new file mode 100644 index 000000000..eb98b095c --- /dev/null +++ b/src/core/hle/service/am/application_proxy.h @@ -0,0 +1,33 @@ +// 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 { + +struct Applet; + +class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { +public: + explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<Applet> msg_queue_, Core::System& system_); + ~IApplicationProxy(); + +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<Applet> applet; +}; + +} // 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<float>(); + const float library_applet_volume_tmp = rp.Pop<float>(); + + 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<Parameters>(); + + 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<float>(); + + 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<IAudioController> { +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..937ac0beb --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.cpp @@ -0,0 +1,314 @@ +// 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/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" +#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<Applet> applet_) + : ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} { + // 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, &ICommonStateGetter::GetAppletLaunchedHistory, "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); +} + +ICommonStateGetter::~ICommonStateGetter() = default; + +void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode +} + +void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent()); +} + +void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + const auto message = applet->message_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<AppletMessageQueue::AppletMessage>(message); + return; + } + + rb.Push(ResultSuccess); + rb.PushEnum<AppletMessageQueue::AppletMessage>(message); +} + +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<u8>(applet->focus_state)); +} + +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<u8>(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. + applet->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<u32>(); + + LOG_INFO(Service_AM, "called, unknown={}", unknown); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILockAccessor>(system); +} + +void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + 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(applet->vr_mode_enabled); +} + +void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "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<bool>(); + + 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"); + + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = true; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +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); +} + +void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->message_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<u32>(Service::VI::DisplayResolution::DockedWidth)); + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); + } else { + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); + rb.Push(static_cast<u32>(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::APM_Sys>("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<SystemButtonType>()}; + + LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::shared_ptr<Applet> current_applet = applet; + std::vector<AppletId> result; + + const size_t count = ctx.GetWriteBufferNumElements<AppletId>(); + 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<u32>(i)); +} + +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"); + + 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); +} + +} // 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..bf652790c --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.h @@ -0,0 +1,77 @@ +// 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 { + +struct Applet; + +class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { +public: + explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_); + ~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 GetAppletLaunchedHistory(HLERequestContext& ctx); + void GetSettingsPlatformRegion(HLERequestContext& ctx); + void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // 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<IDebugFunctions> { +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..4d6858348 --- /dev/null +++ b/src/core/hle/service/am/display_controller.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.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +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> applet_) + : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) { + // 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, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "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"); + + 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::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +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); +} + +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) { + 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"); + + 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::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..75172580c --- /dev/null +++ b/src/core/hle/service/am/display_controller.h @@ -0,0 +1,30 @@ +// 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 { + +struct Applet; + +class IDisplayController final : public ServiceFramework<IDisplayController> { +public: + explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~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); + void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/frontend/applet_cabinet.cpp index c2ff444a6..0862c81b6 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/frontend/applet_cabinet.cpp @@ -8,16 +8,17 @@ #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/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::Applets { +namespace Service::AM::Frontend { -Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::CabinetApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ +Cabinet::Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_) + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{ system_, "CabinetApplet"} { @@ -30,7 +31,7 @@ Cabinet::~Cabinet() { }; void Cabinet::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_HID, "Initializing Cabinet Applet."); @@ -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<IStorage> 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<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } void Cabinet::Cancel() { @@ -175,8 +172,8 @@ void Cabinet::Cancel() { is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result Cabinet::RequestExit() { @@ -184,4 +181,4 @@ Result Cabinet::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/frontend/applet_cabinet.h index f498796f7..3a211ed37 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/frontend/applet_cabinet.h @@ -6,7 +6,7 @@ #include <array> #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nfp/nfp_types.h" @@ -23,7 +23,7 @@ namespace Service::NFC { class NfcDevice; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class CabinetAppletVersion : u32 { Version1 = 0x1, @@ -84,15 +84,15 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, "ReturnValueForAmiiboSettings is an invalid size"); #pragma pack(pop) -class Cabinet final : public Applet { +class Cabinet final : public FrontendApplet { public: - explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Cabinet(Core::System& system_, std::shared_ptr<Applet> 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<Service::NFC::NfcDevice> nfp_device; @@ -111,4 +110,4 @@ private: StartParamForAmiiboSettings applet_input_common{}; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/frontend/applet_controller.cpp index 0e4d9cc39..bd3e49fc4 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/frontend/applet_controller.cpp @@ -11,13 +11,14 @@ #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/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::Applets { +namespace Service::AM::Frontend { [[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101}; [[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID, @@ -46,14 +47,15 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters( }; } -Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, +Controller::Controller(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ControllerApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Controller::~Controller() = default; void Controller::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_HID, "Initializing Controller Applet."); @@ -66,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<IStorage> private_arg_storage = PopInData(); ASSERT(private_arg_storage != nullptr); const auto& private_arg = private_arg_storage->GetData(); @@ -116,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<IStorage> user_arg_storage = PopInData(); ASSERT(user_arg_storage != nullptr); const auto& user_arg = user_arg_storage->GetData(); @@ -142,7 +144,7 @@ void Controller::Initialize() { break; } case ControllerSupportMode::ShowControllerFirmwareUpdate: { - const auto update_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> update_arg_storage = PopInData(); ASSERT(update_arg_storage != nullptr); const auto& update_arg = update_arg_storage->GetData(); @@ -152,7 +154,7 @@ void Controller::Initialize() { break; } case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { - const auto remapping_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> remapping_arg_storage = PopInData(); ASSERT(remapping_arg_storage != nullptr); const auto& remapping_arg = remapping_arg_storage->GetData(); @@ -168,10 +170,6 @@ void Controller::Initialize() { } } -bool Controller::TransactionComplete() const { - return complete; -} - Result Controller::GetStatus() const { return status; } @@ -260,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) { complete = true; out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); std::memcpy(out_data.data(), &result_info, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result Controller::RequestExit() { @@ -269,4 +268,4 @@ Result Controller::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/frontend/applet_controller.h index 9f839f3d7..2f219429c 100644 --- a/src/core/hle/service/am/applets/applet_controller.h +++ b/src/core/hle/service/am/frontend/applet_controller.h @@ -9,7 +9,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -19,7 +19,7 @@ namespace Core::HID { enum class NpadStyleSet : u32; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { using IdentificationColor = std::array<u8, 4>; using ExplainText = std::array<char, 0x81>; @@ -122,15 +122,15 @@ struct ControllerSupportResultInfo { static_assert(sizeof(ControllerSupportResultInfo) == 0xC, "ControllerSupportResultInfo has incorrect size."); -class Controller final : public Applet { +class Controller final : public FrontendApplet { public: - explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Controller(Core::System& system_, std::shared_ptr<Applet> 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; @@ -154,4 +153,4 @@ private: std::vector<u8> out_data; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/frontend/applet_error.cpp index 084bc138c..b97a5f3ea 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/frontend/applet_error.cpp @@ -9,10 +9,11 @@ #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/frontend/applet_error.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { struct ErrorCode { u32 error_category{}; @@ -103,18 +104,18 @@ Result Decode64BitError(u64 error) { } // Anonymous namespace -Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, +Error::Error(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Error::~Error() = default; void Error::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); args = std::make_unique<ErrorArguments>(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); @@ -152,10 +153,6 @@ void Error::Initialize() { } } -bool Error::TransactionComplete() const { - return complete; -} - Result Error::GetStatus() const { return ResultSuccess; } @@ -210,8 +207,8 @@ void Error::Execute() { void Error::DisplayCompleted() { complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + Exit(); } Result Error::RequestExit() { @@ -219,4 +216,4 @@ Result Error::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_error.h b/src/core/hle/service/am/frontend/applet_error.h index d822a32bb..678bf33fa 100644 --- a/src/core/hle/service/am/applets/applet_error.h +++ b/src/core/hle/service/am/frontend/applet_error.h @@ -4,13 +4,13 @@ #pragma once #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class ErrorAppletMode : u8 { ShowError = 0, @@ -22,15 +22,14 @@ enum class ErrorAppletMode : u8 { ShowUpdateEula = 8, }; -class Error final : public Applet { +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> 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<ErrorArguments> args; bool complete = false; - Core::System& system; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/frontend/applet_general.cpp index c0032f652..3c091a602 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/frontend/applet_general.cpp @@ -5,27 +5,28 @@ #include "common/hex_util.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/general.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/applet_data_broker.h" +#include "core/hle/service/am/frontend/applet_general.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; -static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { - std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet(); - for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { +static void LogCurrentStorage(std::shared_ptr<Applet> applet, std::string_view prefix) { + std::shared_ptr<IStorage> 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={}", @@ -33,17 +34,17 @@ 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> applet_, LibraryAppletMode applet_mode_, Core::Frontend::ParentalControlsApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Auth::~Auth() = default; void Auth::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); ASSERT(data.size() >= 0xC); @@ -67,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; } @@ -146,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) { std::vector<u8> out(sizeof(Return)); std::memcpy(out.data(), &return_, sizeof(Return)); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out))); + Exit(); } Result Auth::RequestExit() { @@ -155,27 +152,24 @@ Result Auth::RequestExit() { R_SUCCEED(); } -PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, +PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::PhotoViewerApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} PhotoViewer::~PhotoViewer() = default; void PhotoViewer::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); ASSERT(!data.empty()); mode = static_cast<PhotoViewerAppletMode>(data[0]); } -bool PhotoViewer::TransactionComplete() const { - return complete; -} - Result PhotoViewer::GetStatus() const { return ResultSuccess; } @@ -203,8 +197,8 @@ void PhotoViewer::Execute() { } void PhotoViewer::ViewFinished() { - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>{})); + Exit(); } Result PhotoViewer::RequestExit() { @@ -212,27 +206,17 @@ Result PhotoViewer::RequestExit() { R_SUCCEED(); } -StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) - : Applet{system_, applet_mode_}, id{id_}, system{system_} {} +StubApplet::StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_, + LibraryAppletMode applet_mode_) + : FrontendApplet{system_, applet_, applet_mode_}, id{id_} {} StubApplet::~StubApplet() = default; void StubApplet::Initialize() { LOG_WARNING(Service_AM, "called (STUBBED)"); - Applet::Initialize(); + FrontendApplet::Initialize(); - const auto data = broker.PeekDataToAppletForDebug(); - system.GetReporter().SaveUnimplementedAppletReport( - static_cast<u32>(id), static_cast<u32>(common_args.arguments_version), - common_args.library_version, static_cast<u32>(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 { @@ -242,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<IStorage>(system, std::vector<u8>(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + Exit(); } void StubApplet::Execute() { LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "Execute"); + LogCurrentStorage(applet.lock(), "Execute"); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + Exit(); } Result StubApplet::RequestExit() { @@ -265,4 +247,4 @@ Result StubApplet::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_general_backend.h b/src/core/hle/service/am/frontend/applet_general.h index 34ecaebb9..eaa7ae25f 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.h +++ b/src/core/hle/service/am/frontend/applet_general.h @@ -3,13 +3,13 @@ #pragma once -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class AuthAppletType : u32 { ShowParentalAuthentication, @@ -17,14 +17,14 @@ enum class AuthAppletType : u32 { ChangeParentalPasscode, }; -class Auth final : public Applet { +class Auth final : public FrontendApplet { public: - explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Auth(Core::System& system_, std::shared_ptr<Applet> 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; @@ -49,14 +48,14 @@ enum class PhotoViewerAppletMode : u8 { AllApps = 1, }; -class PhotoViewer final : public Applet { +class PhotoViewer final : public FrontendApplet { public: - explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, + explicit PhotoViewer(Core::System& system_, std::shared_ptr<Applet> 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 Applet { +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> 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::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/frontend/applet_mii_edit.cpp index e83e931c5..e3d19fb3d 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/frontend/applet_mii_edit.cpp @@ -6,16 +6,17 @@ #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/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::Applets { +namespace Service::AM::Frontend { -MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::MiiEditApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} +MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_) + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} MiiEdit::~MiiEdit() = default; @@ -24,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<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto applet_input_data = storage->GetData(); @@ -66,10 +67,6 @@ void MiiEdit::Initialize() { manager->Initialize(metadata); } -bool MiiEdit::TransactionComplete() const { - return is_complete; -} - Result MiiEdit::GetStatus() const { return ResultSuccess; } @@ -152,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) { is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, @@ -168,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result MiiEdit::RequestExit() { @@ -177,4 +174,4 @@ Result MiiEdit::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/frontend/applet_mii_edit.h index 7ff34af49..5db792f7d 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.h +++ b/src/core/hle/service/am/frontend/applet_mii_edit.h @@ -4,8 +4,8 @@ #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" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -16,17 +16,17 @@ struct DatabaseSessionMetadata; class MiiManager; } // namespace Service::Mii -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -class MiiEdit final : public Applet { +class MiiEdit final : public FrontendApplet { public: - explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, + explicit MiiEdit(Core::System& system_, std::shared_ptr<Applet> 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{}; @@ -49,4 +48,4 @@ private: Mii::DatabaseSessionMetadata metadata{}; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_mii_edit_types.h b/src/core/hle/service/am/frontend/applet_mii_edit_types.h index f3d764073..23d9d7a69 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit_types.h +++ b/src/core/hle/service/am/frontend/applet_mii_edit_types.h @@ -10,7 +10,7 @@ #include "common/uuid.h" #include "core/hle/service/mii/types/char_info.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class MiiEditAppletVersion : s32 { Version3 = 0x3, // 1.0.0 - 10.1.1 @@ -80,4 +80,4 @@ struct MiiEditAppletOutputForCharInfoEditing { static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80, "MiiEditAppletOutputForCharInfoEditing has incorrect size."); -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/frontend/applet_profile_select.cpp index 89cb323e9..efb4053b8 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/frontend/applet_profile_select.cpp @@ -9,13 +9,15 @@ #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/frontend/applet_profile_select.h" +#include "core/hle/service/am/storage.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, +ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ProfileSelectApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} ProfileSelect::~ProfileSelect() = default; @@ -24,10 +26,10 @@ void ProfileSelect::Initialize() { status = ResultSuccess; final_data.clear(); - Applet::Initialize(); + FrontendApplet::Initialize(); profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; - const auto user_config_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> user_config_storage = PopInData(); ASSERT(user_config_storage != nullptr); const auto& user_config = user_config_storage->GetData(); @@ -50,10 +52,6 @@ void ProfileSelect::Initialize() { } } -bool ProfileSelect::TransactionComplete() const { - return complete; -} - Result ProfileSelect::GetStatus() const { return status; } @@ -64,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() { void ProfileSelect::Execute() { if (complete) { - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); + PushOutData(std::make_shared<IStorage>(system, std::move(final_data))); + Exit(); return; } @@ -111,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { final_data = std::vector<u8>(sizeof(UiReturnArg)); std::memcpy(final_data.data(), &output, final_data.size()); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); - broker.SignalStateChanged(); + + PushOutData(std::make_shared<IStorage>(system, std::move(final_data))); + Exit(); } Result ProfileSelect::RequestExit() { @@ -120,4 +120,4 @@ Result ProfileSelect::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/frontend/applet_profile_select.h index 673eed516..674e7afe1 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/frontend/applet_profile_select.h @@ -8,13 +8,13 @@ #include "common/common_funcs.h" #include "common/uuid.h" #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class ProfileSelectAppletVersion : u32 { Version1 = 0x1, // 1.0.0+ @@ -111,15 +111,15 @@ struct UiReturnArg { }; static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); -class ProfileSelect final : public Applet { +class ProfileSelect final : public FrontendApplet { public: - explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, + explicit ProfileSelect(Core::System& system_, std::shared_ptr<Applet> 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<u8> final_data; - Core::System& system; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp index 4145bb84f..fbf75d379 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp @@ -5,9 +5,10 @@ #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/frontend/applet_software_keyboard.h" +#include "core/hle/service/am/storage.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { namespace { @@ -41,14 +42,15 @@ void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply } // Anonymous namespace -SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, +SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, Core::Frontend::SoftwareKeyboardApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} SoftwareKeyboard::~SoftwareKeyboard() = default; void SoftwareKeyboard::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", applet_mode); @@ -76,10 +78,6 @@ void SoftwareKeyboard::Initialize() { } } -bool SoftwareKeyboard::TransactionComplete() const { - return complete; -} - Result SoftwareKeyboard::GetStatus() const { return status; } @@ -184,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(); @@ -221,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) { @@ -250,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(); @@ -267,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(); @@ -314,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(); @@ -377,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, submitted_text.size() * sizeof(char16_t)); } - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); ExitKeyboard(); } @@ -410,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { current_text.size() * sizeof(char16_t)); } - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(out_data))); } void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { @@ -767,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() { frontend.ExitKeyboard(); - broker.SignalStateChanged(); + Exit(); } Result SoftwareKeyboard::RequestExit() { @@ -967,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyDefault() { @@ -977,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedString() { @@ -999,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursor() { @@ -1019,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedTab() { @@ -1039,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyDecidedEnter() { @@ -1058,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); HideInlineKeyboard(); } @@ -1070,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); HideInlineKeyboard(); } @@ -1095,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorUtf8() { @@ -1116,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyDecidedEnterUtf8() { @@ -1136,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); HideInlineKeyboard(); } @@ -1148,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyReleasedUserWordInfo() { @@ -1158,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { @@ -1168,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedStringV2() { @@ -1194,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorV2() { @@ -1218,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedStringUtf8V2() { @@ -1245,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { @@ -1270,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<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/frontend/applet_software_keyboard.h index 2e919811b..f464b7e15 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.h +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.h @@ -5,8 +5,8 @@ #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" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -17,17 +17,17 @@ struct KeyboardInitializeParameters; struct InlineAppearParameters; } // namespace Core::Frontend -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -class SoftwareKeyboard final : public Applet { +class SoftwareKeyboard final : public FrontendApplet { public: - explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, + explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> 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; @@ -184,4 +183,4 @@ private: Result status{ResultSuccess}; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_software_keyboard_types.h b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h index 1f696900e..a25ff2a6d 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard_types.h +++ b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h @@ -11,7 +11,7 @@ #include "common/swap.h" #include "common/uuid.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; @@ -351,4 +351,4 @@ struct SwkbdDecidedEnterArg { }; static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp index 19057ad7b..6ee4caf34 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp @@ -19,12 +19,13 @@ #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/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::Applets { +namespace Service::AM::Frontend { namespace { @@ -223,14 +224,15 @@ void ExtractSharedFonts(Core::System& system) { } // namespace -WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, +WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_) - : Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {} WebBrowser::~WebBrowser() = default; void WebBrowser::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_AM, "Initializing Web Browser Applet."); @@ -243,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(); @@ -284,10 +286,6 @@ void WebBrowser::Initialize() { } } -bool WebBrowser::TransactionComplete() const { - return complete; -} - Result WebBrowser::GetStatus() const { return status; } @@ -358,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) complete = true; std::vector<u8> out_data(sizeof(WebCommonReturnValue)); std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result WebBrowser::RequestExit() { @@ -504,4 +502,4 @@ void WebBrowser::ExecuteLobby() { LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); WebBrowserExit(WebExitReason::EndButtonPressed); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/frontend/applet_web_browser.h index 36adb2510..ba20b7a4c 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.h +++ b/src/core/hle/service/am/frontend/applet_web_browser.h @@ -9,8 +9,8 @@ #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" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -20,18 +20,17 @@ namespace FileSys { enum class ContentRecordType : u8; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -class WebBrowser final : public Applet { +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> 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::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_web_browser_types.h b/src/core/hle/service/am/frontend/applet_web_browser_types.h index c522c5c1a..2f7c05c24 100644 --- a/src/core/hle/service/am/applets/applet_web_browser_types.h +++ b/src/core/hle/service/am/frontend/applet_web_browser_types.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "common/swap.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class WebAppletVersion : u32_le { Version0 = 0x0, // Only used by WifiWebAuthApplet @@ -174,4 +174,4 @@ static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>; -} // namespace Service::AM::Applets +} // 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..db2b04575 --- /dev/null +++ b/src/core/hle/service/am/frontend/applets.cpp @@ -0,0 +1,240 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <cstring> + +#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_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" +#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 { + +FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_) + : system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {} + +FrontendApplet::~FrontendApplet() = default; + +void FrontendApplet::Initialize() { + std::shared_ptr<IStorage> common = PopInData(); + 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; +} + +std::shared_ptr<IStorage> FrontendApplet::PopInData() { + std::shared_ptr<IStorage> ret; + applet.lock()->caller_applet_broker->GetInData().Pop(&ret); + return ret; +} + +std::shared_ptr<IStorage> FrontendApplet::PopInteractiveInData() { + std::shared_ptr<IStorage> ret; + applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret); + return ret; +} + +void FrontendApplet::PushOutData(std::shared_ptr<IStorage> storage) { + applet.lock()->caller_applet_broker->GetOutData().Push(storage); +} + +void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) { + applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage); +} + +void FrontendApplet::Exit() { + applet.lock()->caller_applet_broker->SignalCompletion(); +} + +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::SetDefaultAppletsIfMissing() { + if (frontend.cabinet == nullptr) { + frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); + } + + if (frontend.controller == nullptr) { + frontend.controller = + std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); + } + + if (frontend.error == nullptr) { + frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); + } + + if (frontend.mii_edit == nullptr) { + frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>(); + } + + if (frontend.parental_controls == nullptr) { + frontend.parental_controls = + std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); + } + + if (frontend.photo_viewer == nullptr) { + frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); + } + + if (frontend.profile_select == nullptr) { + frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); + } + + if (frontend.software_keyboard == nullptr) { + frontend.software_keyboard = + std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); + } + + if (frontend.web_browser == nullptr) { + frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); + } +} + +void FrontendAppletHolder::ClearAll() { + frontend = {}; +} + +std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<Applet> applet, + AppletId id, + LibraryAppletMode mode) const { + switch (id) { + case AppletId::Auth: + return std::make_shared<Auth>(system, applet, mode, *frontend.parental_controls); + case AppletId::Cabinet: + return std::make_shared<Cabinet>(system, applet, mode, *frontend.cabinet); + case AppletId::Controller: + return std::make_shared<Controller>(system, applet, mode, *frontend.controller); + case AppletId::Error: + return std::make_shared<Error>(system, applet, mode, *frontend.error); + case AppletId::ProfileSelect: + return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select); + case AppletId::SoftwareKeyboard: + return std::make_shared<SoftwareKeyboard>(system, applet, mode, + *frontend.software_keyboard); + case AppletId::MiiEdit: + return std::make_shared<MiiEdit>(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<WebBrowser>(system, applet, mode, *frontend.web_browser); + case AppletId::PhotoViewer: + return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer); + default: + UNIMPLEMENTED_MSG( + "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", + static_cast<u8>(id)); + return std::make_shared<StubApplet>(system, applet, 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..1e1fd28b8 --- /dev/null +++ b/src/core/hle/service/am/frontend/applets.h @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <queue> + +#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 FrontendApplet { +public: + explicit FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_); + virtual ~FrontendApplet(); + + virtual void Initialize(); + + virtual Result GetStatus() const = 0; + virtual void ExecuteInteractive() = 0; + virtual void Execute() = 0; + virtual Result RequestExit() = 0; + + LibraryAppletMode GetLibraryAppletMode() const { + return applet_mode; + } + + bool IsInitialized() const { + return initialized; + } + +protected: + std::shared_ptr<IStorage> PopInData(); + std::shared_ptr<IStorage> PopInteractiveInData(); + void PushOutData(std::shared_ptr<IStorage> storage); + void PushInteractiveOutData(std::shared_ptr<IStorage> storage); + void Exit(); + +protected: + Core::System& system; + CommonArguments common_args{}; + std::weak_ptr<Applet> applet{}; + LibraryAppletMode applet_mode{}; + bool initialized{false}; +}; + +struct FrontendAppletSet { + using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>; + using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; + using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; + using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; + using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; + using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; + using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; + using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; + using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; + + 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 SetDefaultAppletsIfMissing(); + void ClearAll(); + + std::shared_ptr<FrontendApplet> GetApplet(std::shared_ptr<Applet> applet, 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/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<IGlobalStateController> { +public: + explicit IGlobalStateController(Core::System& system_); + ~IGlobalStateController() override; +}; + +} // 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..8ed49bac1 --- /dev/null +++ b/src/core/hle/service/am/hid_registration.cpp @@ -0,0 +1,35 @@ +// 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::IHidServer>("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()); + } +} + +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 new file mode 100644 index 000000000..67cd84961 --- /dev/null +++ b/src/core/hle/service/am/hid_registration.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> + +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(); + + void EnableAppletToGetInput(bool enable); + +private: + Process& m_process; + std::shared_ptr<Service::HID::IHidServer> m_hid_server; +}; + +} // 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<IHomeMenuFunctions> { +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..6b20814f8 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -0,0 +1,202 @@ +// 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_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" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr<AppletDataBroker> broker_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)}, + 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); +} + +ILibraryAppletAccessor::~ILibraryAppletAccessor() = default; + +void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetStateChangedEvent().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<u32>(broker->IsCompleted()); +} + +void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->terminate_result); +} + +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"); + + applet->process->Run(); + FrontendExecute(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + applet->message_queue.RequestExit(); + FrontendRequestExit(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetInData().Push(rp.PopIpcInterface<IStorage>().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetOutData().Pop(&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 ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetInteractiveInData().Push(rp.PopIpcInterface<IStorage>().lock()); + FrontendExecuteInteractive(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetInteractiveOutData().Pop(&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 ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetOutData().GetEvent()); +} + +void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent()); +} + +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); +} + +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 new file mode 100644 index 000000000..8be29e003 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.h @@ -0,0 +1,43 @@ +// 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 AppletDataBroker; +struct Applet; + +class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { +public: + explicit ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr<AppletDataBroker> broker_, + std::shared_ptr<Applet> applet_); + ~ILibraryAppletAccessor(); + +protected: + 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); + + void FrontendExecute(); + void FrontendExecuteInteractive(); + void FrontendRequestExit(); + + const std::shared_ptr<AppletDataBroker> broker; + const std::shared_ptr<Applet> 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..47bab7528 --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -0,0 +1,271 @@ +// 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/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" +#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" + +namespace Service::AM { + +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<AppletProgramId>(0); + } +} + +[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet( + Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); + if (program_id == 0) { + // Unknown applet + return {}; + } + + auto process = std::make_unique<Process>(system); + if (!process->Initialize(program_id)) { + // Couldn't initialize the guest process + return {}; + } + + const auto applet = std::make_shared<Applet>(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + // 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<AppletDataBroker>(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = broker; + + system.GetAppletManager().InsertApplet(applet); + + return std::make_shared<ILibraryAppletAccessor>(system, broker, applet); +} + +[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet( + Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); + + auto process = std::make_unique<Process>(system); + auto applet = std::make_shared<Applet>(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<AppletDataBroker>(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = storage; + applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); + + return std::make_shared<ILibraryAppletAccessor>(system, storage, applet); +} + +} // namespace + +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} { + 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<AppletId>(); + const auto applet_mode = rp.PopRaw<LibraryAppletMode>(); + + LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", 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); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + // 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<ILibraryAppletAccessor>(library_applet); +} + +void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 size{rp.Pop<s64>()}; + + 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<u8> data(size); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data))); +} + +void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + struct Parameters { + bool is_writable; + s64 size; + }; + + const auto params{rp.PopRaw<Parameters>()}; + const auto handle{ctx.GetCopyHandle(0)}; + + LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable, + params.size, handle); + + if (params.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<Kernel::KTransferMemory>(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; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>( + system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), + params.is_writable, params.size)); +} + +void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 size{rp.Pop<s64>()}; + 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<Kernel::KTransferMemory>(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; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>( + system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size)); +} + +} // 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..551f287bd --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.h @@ -0,0 +1,26 @@ +// 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 { + +struct Applet; + +class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { +public: + explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_); + ~ILibraryAppletCreator() override; + +private: + void CreateLibraryApplet(HLERequestContext& ctx); + void CreateStorage(HLERequestContext& ctx); + void CreateTransferMemoryStorage(HLERequestContext& ctx); + void CreateHandleStorage(HLERequestContext& ctx); + + const std::shared_ptr<Applet> 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 new file mode 100644 index 000000000..d6108fba3 --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.cpp @@ -0,0 +1,143 @@ +// 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<Applet> applet_, Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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); +} + +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<ICommonStateGetter>(system, applet); +} + +void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger); +} + +void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IWindowController>(system, applet); +} + +void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAudioController>(system); +} + +void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDisplayController>(system, applet); +} + +void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IProcessWindingController>(system, applet); +} + +void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); +} + +void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet); +} + +void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAppletCommonFunctions>(system, applet); +} + +void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IHomeMenuFunctions>(system); +} + +void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IGlobalStateController>(system); +} + +void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDebugFunctions>(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..8f7a25897 --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.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 { + +struct Applet; + +class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { +public: + explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<Applet> applet_, Core::System& system_); + ~ILibraryAppletProxy(); + +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<Applet> 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 new file mode 100644 index 000000000..b560f580b --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -0,0 +1,338 @@ +// 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/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" +#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" +#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" +#include "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/hid_types.h" + +namespace Service::AM { + +namespace { + +AppletIdentityInfo GetCallerIdentity(std::shared_ptr<Applet> applet) { + if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) { + // TODO: is this actually the application ID? + return { + .applet_id = caller_applet->applet_id, + .application_id = caller_applet->program_id, + }; + } else { + return { + .applet_id = AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + } +} + +} // namespace + +ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)}, + broker{applet->caller_applet_broker} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, + {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, + {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"}, + {13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "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, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"}, + {70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "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"}, + {160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; + +void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetInData().Pop(&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::PushOutData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetOutData().Push(rp.PopIpcInterface<IStorage>().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetInteractiveInData().Pop(&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}; + broker->GetInteractiveOutData().Push(rp.PopIpcInterface<IStorage>().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(broker->GetInData().GetEvent()); +} + +void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent()); +} + +void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid); + broker->SignalCompletion(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { + struct LibraryAppletInfo { + AppletId applet_id; + LibraryAppletMode library_applet_mode; + }; + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const LibraryAppletInfo applet_info{ + .applet_id = applet->applet_id, + .library_applet_mode = applet->library_applet_mode, + }; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { + 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); +} + +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<u8>(0); +} + +void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(GetCallerIdentity(applet)); +} + +void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(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::NS>("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}; + s32 user_count{-1}; + + LOG_INFO(Service_AM, "called"); + + if (manager.GetUserCount() > 0) { + is_empty = false; + user_count = static_cast<s32>(manager.GetUserCount()); + ctx.WriteBuffer(manager.GetAllUsers()); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u8>(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<u8>(0); +} + +void ILibraryAppletSelfAccessor::Cmd160(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(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 new file mode 100644 index 000000000..8717a989a --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <deque> +#include <vector> + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class AppletDataBroker; +struct Applet; + +class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { +public: + explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> 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 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> applet; + const std::shared_ptr<AppletDataBroker> broker; +}; + +} // 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<u8>&& 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<u8> 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<u8> LibraryAppletStorage::GetData() { + std::vector<u8> data(this->GetSize()); + this->Read(0, data.data(), data.size()); + return data; +} + +std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) { + return std::make_shared<BufferLibraryAppletStorage>(std::move(data)); +} + +std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + bool is_writable, s64 size) { + return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size); +} + +std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + s64 size) { + return std::make_shared<HandleLibraryAppletStorage>(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<u8> GetData(); +}; + +std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data); +std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + bool is_writable, s64 size); +std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, s64 size); + +} // 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<bool>(); + + 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<u8>(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<u8>(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<ILockAccessor> { +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/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 <set> + +#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<u64> m_managed_display_layers{}; + std::set<u64> 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/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp new file mode 100644 index 000000000..b48b52797 --- /dev/null +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#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" + +namespace Service::AM { + +IProcessWindingController::IProcessWindingController(Core::System& system_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} { + // 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"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(applet->launch_reason); +} + +void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { + 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); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_broker, + 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 new file mode 100644 index 000000000..71ae4c4f5 --- /dev/null +++ b/src/core/hle/service/am/process_winding_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 { + +struct Applet; + +class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { +public: + explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IProcessWindingController() override; + +private: + void GetLaunchReason(HLERequestContext& ctx); + void OpenCallingLibraryApplet(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // 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..0289f5cf1 --- /dev/null +++ b/src/core/hle/service/am/self_controller.cpp @@ -0,0 +1,456 @@ +// 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" +#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_, std::shared_ptr<Applet> applet_, + Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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, &ISelfController::SetScreenShotAppletIdentityInfo, "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); +} + +ISelfController::~ISelfController() = default; + +void ISelfController::Exit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + // TODO + 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) { + + 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); +} + +void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + // Entry and exit of fatal sections must be balanced. + std::scoped_lock lk{applet->lock}; + if (applet->fatal_section_count == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultFatalSectionCountImbalance); + return; + } + + applet->fatal_section_count--; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + applet->library_applet_launchable_event.Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle()); +} + +void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto permission = rp.PopEnum<ScreenshotPermission>(); + LOG_DEBUG(Service_AM, "called, permission={}", permission); + + std::scoped_lock lk{applet->lock}; + applet->screenshot_permission = permission; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const bool notification_enabled = rp.Pop<bool>(); + 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); +} + +void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const bool notification_enabled = rp.Pop<bool>(); + 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) { + IPC::RequestParser rp{ctx}; + + const auto flags = rp.PopRaw<FocusHandlingMode>(); + + 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); +} + +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::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<AppletIdentityInfo>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const bool enabled = rp.Pop<bool>(); + 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) { + IPC::RequestParser rp{ctx}; + + const auto orientation = rp.PopRaw<Capture::AlbumImageOrientation>(); + LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast<s32>(orientation)); + + std::scoped_lock lk{applet->lock}; + applet->album_image_orientation = orientation; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + 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); +} + +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"); + + 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<s64>(buffer_id); + rb.Push<s64>(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<s64>(buffer_id); +} + +Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { + if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) { + return ResultSuccess; + } + + return VI::ResultOperationFailed; +} + +void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + 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, 6}; + rb.Push(ResultSuccess); + rb.Push(layer_id); + rb.Push(recording_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}; + + const auto extension = rp.PopRaw<IdleTimeDetectionExtension>(); + 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); +} + +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.PushRaw<IdleTimeDetectionExtension>(applet->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}; + + std::scoped_lock lk{applet->lock}; + applet->auto_sleep_disabled = rp.Pop<bool>(); + + // 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={}", applet->auto_sleep_disabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +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(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<u64>(applet->suspended_ticks); +} + +void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle()); +} + +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 enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); + + std::scoped_lock lk{applet->lock}; + applet->album_image_taken_notification_enabled = enabled; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto report_option = rp.PopEnum<Capture::AlbumReportOption>(); + + LOG_INFO(Service_AM, "called, report_option={}", report_option); + + const auto screenshot_service = + system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( + "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 enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); + + std::scoped_lock lk{applet->lock}; + applet->record_volume_muted = enabled; + + 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..a63bc2e74 --- /dev/null +++ b/src/core/hle/service/am/self_controller.h @@ -0,0 +1,58 @@ +// 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 { + +struct Applet; + +class ISelfController final : public ServiceFramework<ISelfController> { +public: + explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_, + 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 SetScreenShotAppletIdentityInfo(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); + + Nvnflinger::Nvnflinger& nvnflinger; + const std::shared_ptr<Applet> applet; +}; + +} // 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..4e82afd1c --- /dev/null +++ b/src/core/hle/service/am/storage.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/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 { + +IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> 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<u8>&& 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<IStorageAccessor>(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<ITransferStorageAccessor>(system, impl); +} + +std::vector<u8> 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 new file mode 100644 index 000000000..10d00b141 --- /dev/null +++ b/src/core/hle/service/am/storage.h @@ -0,0 +1,31 @@ +// 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 LibraryAppletStorage; + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_); + explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); + ~IStorage() override; + + std::shared_ptr<LibraryAppletStorage> GetImpl() const { + return impl; + } + + std::vector<u8> GetData() const; + +private: + void Open(HLERequestContext& ctx); + void OpenTransferStorage(HLERequestContext& ctx); + + const std::shared_ptr<LibraryAppletStorage> 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..a1184b065 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.cpp @@ -0,0 +1,90 @@ +// 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_, + std::shared_ptr<LibraryAppletStorage> 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); +} + +IStorageAccessor::~IStorageAccessor() = default; + +void IStorageAccessor::GetSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(ResultSuccess); + rb.Push(impl->GetSize()); +} + +void IStorageAccessor::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 offset{rp.Pop<s64>()}; + const auto data{ctx.ReadBuffer()}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); + + const auto res{impl->Write(offset, data.data(), data.size())}; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void IStorageAccessor::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 offset{rp.Pop<s64>()}; + std::vector<u8> data(ctx.GetWriteBufferSize()); + + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); + + const auto res{impl->Read(offset, data.data(), data.size())}; + + ctx.WriteBuffer(data); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> 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 new file mode 100644 index 000000000..b9aa85a66 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.h @@ -0,0 +1,37 @@ +// 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<IStorageAccessor> { +public: + explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_); + ~IStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Read(HLERequestContext& ctx); + + const std::shared_ptr<LibraryAppletStorage> impl; +}; + +class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> { +public: + explicit ITransferStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl_); + ~ITransferStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void GetHandle(HLERequestContext& ctx); + + const std::shared_ptr<LibraryAppletStorage> impl; +}; + +} // 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..38643408e --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.cpp @@ -0,0 +1,136 @@ +// 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<Applet> applet_, Core::System& system_) + : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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); +} + +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<ICommonStateGetter>(system, applet); +} + +void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger); +} + +void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IWindowController>(system, applet); +} + +void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAudioController>(system); +} + +void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDisplayController>(system, applet); +} + +void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); +} + +void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IHomeMenuFunctions>(system); +} + +void ISystemAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IGlobalStateController>(system); +} + +void ISystemAppletProxy::GetApplicationCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IApplicationCreator>(system); +} + +void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAppletCommonFunctions>(system, applet); +} + +void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDebugFunctions>(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..0390cd1e5 --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.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/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { +public: + explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<Applet> applet_, Core::System& system_); + ~ISystemAppletProxy(); + +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<Applet> applet; +}; + +} // 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..60a9afc9d --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.cpp @@ -0,0 +1,69 @@ +// 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" +#include "core/hle/service/vi/vi_results.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; + 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 new file mode 100644 index 000000000..98c3cf055 --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <set> + +#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; +} + +union Result; + +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; + } + + 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{}; +}; + +} // 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..f00957f83 --- /dev/null +++ b/src/core/hle/service/am/window_controller.cpp @@ -0,0 +1,86 @@ +// 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_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IWindowController"}, applet{std::move(applet_)} { + // 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, &IWindowController::SetAppletWindowVisibility, "SetAppletWindowVisibility"}, + {21, &IWindowController::SetAppletGpuTimeSlice, "SetAppletGpuTimeSlice"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IWindowController::~IWindowController() = default; + +void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(applet->aruid); +} + +void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { + 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<u64>(aruid); +} + +void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + const bool visible = rp.Pop<bool>(); + + 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<s64>(); + + 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 new file mode 100644 index 000000000..a28219abe --- /dev/null +++ b/src/core/hle/service/am/window_controller.h @@ -0,0 +1,27 @@ +// 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 { + +struct Applet; + +class IWindowController final : public ServiceFramework<IWindowController> { +public: + explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IWindowController() override; + +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> applet; +}; + +} // 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/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<ISaveDataInfoReader> { @@ -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<FileSystemType>(); - const auto title_id = rp.PopRaw<u64>(); - 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<InputParameters>(); + 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<IFileSystem>(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<u32>(); + + 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<ContentPath>(); + 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<u64>(); + LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(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<u64>(); + LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(1); +} + +void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto result = rp.PopRaw<Result>(); + LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue()); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(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<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, - {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, + {7991, &NS::PushInterface<IReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"}, {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, {7994, &NS::PushInterface<IFactoryResetInterface>, "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<IDocumentInterface> { public: explicit IDocumentInterface(Core::System& system_); ~IDocumentInterface() override; + +private: + void ResolveApplicationContentPath(HLERequestContext& ctx); + void GetRunningApplicationProgramId(HLERequestContext& ctx); }; class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { @@ -78,6 +82,17 @@ public: ~IFactoryResetInterface() override; }; +class IReadOnlyApplicationRecordInterface final + : public ServiceFramework<IReadOnlyApplicationRecordInterface> { +public: + explicit IReadOnlyApplicationRecordInterface(Core::System& system_); + ~IReadOnlyApplicationRecordInterface() override; + +private: + void HasApplicationRecord(HLERequestContext& ctx); + void IsDataCorruptedResult(HLERequestContext& ctx); +}; + class IReadOnlyApplicationControlDataInterface final : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { public: 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. 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<android::BufferItemConsumer>&& 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<android::BufferItemConsumer> consumer; bool open; + bool visible; }; } // namespace Service::VI 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<u64> stray_layer_ids; bool vsync_event_fetched{false}; }; 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<bool> 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/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 49ec52546..e28df10bd 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -9,6 +9,8 @@ #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" #include "hid_core/frontend/emulated_controller.h" @@ -47,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<Service::AM::AppletOE>("appletOE"); - auto applet_ae = sm.GetService<Service::AM::AppletAE>("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/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 782bcbb61..303d84a1f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,6 +8,7 @@ #include <iostream> #include <memory> #include <thread> +#include "core/hle/service/am/applet_manager.h" #include "core/loader/nca.h" #include "core/tools/renderdoc.h" @@ -39,13 +40,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" @@ -568,7 +570,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk } if (!game_path.isEmpty()) { - BootGame(game_path); + BootGame(game_path, ApplicationAppletParameters()); } } @@ -630,13 +632,14 @@ void GMainWindow::RegisterMetaTypes() { qRegisterMetaType<Core::Frontend::InlineAppearParameters>( "Core::Frontend::InlineAppearParameters"); qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters"); - qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult"); - qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>( - "Service::AM::Applets::SwkbdTextCheckResult"); - qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType"); + qRegisterMetaType<Service::AM::Frontend::SwkbdResult>("Service::AM::Frontend::SwkbdResult"); + qRegisterMetaType<Service::AM::Frontend::SwkbdTextCheckResult>( + "Service::AM::Frontend::SwkbdTextCheckResult"); + qRegisterMetaType<Service::AM::Frontend::SwkbdReplyType>( + "Service::AM::Frontend::SwkbdReplyType"); // Web Browser Applet - qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); + qRegisterMetaType<Service::AM::Frontend::WebExitReason>("Service::AM::Frontend::WebExitReason"); // Register loader types qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus"); @@ -746,7 +749,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); }, @@ -754,7 +757,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); }, @@ -781,7 +784,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!"); @@ -852,7 +855,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; } @@ -940,7 +943,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); } }); @@ -950,7 +953,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()); @@ -983,7 +986,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 } @@ -991,7 +994,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 @@ -1472,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); @@ -1760,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(); @@ -1773,11 +1775,11 @@ 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(); } - system->SetAppletFrontendSet({ + system->SetFrontendAppletSet({ std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr @@ -1792,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<u32>(CalloutFlag::DRDDeprecation)) == 0; @@ -1915,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<u64>(Service::AM::Applets::AppletProgramId::MaxProgramId)) { + if (params.program_id == 0 || + params.program_id > static_cast<u64>(Service::AM::AppletProgramId::MaxProgramId)) { StoreRecentFile(filename); // Put the filename on top of the list } @@ -1935,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) { @@ -1954,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; @@ -1969,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; } @@ -2059,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; @@ -2160,7 +2166,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}); @@ -2239,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, @@ -2280,10 +2289,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 | @@ -3171,7 +3180,7 @@ void GMainWindow::OnMenuLoadFile() { } UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); - BootGame(filename); + BootGame(filename, ApplicationAppletParameters()); } void GMainWindow::OnMenuLoadFolder() { @@ -3185,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.")); @@ -3379,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"), @@ -3417,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()); } } @@ -3485,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<s32>(program_index); + params.launch_type = Service::AM::LaunchType::ApplicationInitiated; + BootGame(last_filename_booted, params); } void GMainWindow::OnExit() { @@ -4153,7 +4165,7 @@ void GMainWindow::OnToggleStatusBar() { } void GMainWindow::OnAlbum() { - constexpr u64 AlbumId = static_cast<u64>(Service::AM::Applets::AppletProgramId::PhotoViewer); + constexpr u64 AlbumId = static_cast<u64>(Service::AM::AppletProgramId::PhotoViewer); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4168,15 +4180,15 @@ 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(); - BootGame(filename, AlbumId); + BootGame(filename, LibraryAppletParameters(AlbumId, Service::AM::AppletId::PhotoViewer)); } void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { - constexpr u64 CabinetId = static_cast<u64>(Service::AM::Applets::AppletProgramId::Cabinet); + constexpr u64 CabinetId = static_cast<u64>(Service::AM::AppletProgramId::Cabinet); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4191,16 +4203,16 @@ 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(); - BootGame(filename, CabinetId); + BootGame(filename, LibraryAppletParameters(CabinetId, Service::AM::AppletId::Cabinet)); } void GMainWindow::OnMiiEdit() { - constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); + constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4215,16 +4227,15 @@ 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(); - BootGame(filename, MiiEditId); + BootGame(filename, LibraryAppletParameters(MiiEditId, Service::AM::AppletId::MiiEdit)); } void GMainWindow::OnOpenControllerMenu() { - constexpr u64 ControllerAppletId = - static_cast<u64>(Service::AM::Applets::AppletProgramId::Controller); + constexpr u64 ControllerAppletId = static_cast<u64>(Service::AM::AppletProgramId::Controller); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4240,11 +4251,12 @@ 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(); - BootGame(filename, ControllerAppletId); + BootGame(filename, + LibraryAppletParameters(ControllerAppletId, Service::AM::AppletId::Controller)); } void GMainWindow::OnCaptureScreenshot() { @@ -4564,7 +4576,7 @@ void GMainWindow::OnCheckFirmwareDecryption() { } bool GMainWindow::CheckFirmwarePresence() { - constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); + constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { @@ -4727,7 +4739,7 @@ bool GMainWindow::DropAction(QDropEvent* event) { } else { // Game if (ConfirmChangeGame()) { - BootGame(filename); + BootGame(filename, ApplicationAppletParameters()); } } return true; @@ -4771,36 +4783,12 @@ void GMainWindow::RequestGameExit() { return; } - auto& sm{system->ServiceManager()}; - auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); - auto applet_ae = sm.GetService<Service::AM::AppletAE>("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<Service::AM::AppletOE>("appletOE"); - auto applet_ae = sm.GetService<Service::AM::AppletAE>("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) { @@ -4942,6 +4930,22 @@ void GMainWindow::changeEvent(QEvent* event) { QWidget::changeEvent(event); } +Service::AM::FrontendAppletParameters GMainWindow::ApplicationAppletParameters() { + return Service::AM::FrontendAppletParameters{ + .applet_id = Service::AM::AppletId::Application, + .applet_type = Service::AM::AppletType::Application, + }; +} + +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 6b72094ff..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,12 +96,17 @@ namespace InputCommon { class InputSubsystem; } -namespace Service::AM::Applets { +namespace Service::AM { +struct FrontendAppletParameters; +enum class AppletId : u32; +} // namespace Service::AM + +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<Common::UUID> 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); @@ -267,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(); @@ -324,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: |