diff options
| author | Narr the Reg <juangerman-13@hotmail.com> | 2024-01-31 10:25:28 -0600 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-31 10:25:28 -0600 | 
| commit | 7cc7d027f74b5bffc0b3f8f3a6c3110999c7cc4c (patch) | |
| tree | 24b2ed412f2683c8460839778ea7761d052bc38f | |
| parent | 12e5293c73ce9965a6f73a8861d8b84f3f4ed615 (diff) | |
| parent | 817d916233adcfb26814fde677e71d9825ce614c (diff) | |
Merge pull request #12760 from liamwhite/mp-am
am: rewrite for multiprocess support
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:  | 
