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 53137b2e20..6ebb46af71 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 1f591ced1b..937b8faf19 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 74e040478f..9943483e81 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 b2fb59b68b..2affc01f6f 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 64627db889..6545101294 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 bfe3fccca5..e49d4e0154 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 ea6b2c285a..570acb1939 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 11bf8d2f69..435ef67934 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 d8862e9cee..90826bd3a1 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::Applets::AppletManager& GetAppletManager();
-    [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
+    [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder();
+    [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder()
+        const;
+
+    [[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
similarity index 97%
rename from src/core/frontend/applets/general_frontend.cpp
rename to src/core/frontend/applets/general.cpp
index b4b213a31c..4c299ee9c7 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
similarity index 100%
rename from src/core/frontend/applets/general_frontend.h
rename to 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 92e2737ea7..880b69ad65 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 7655d215b4..d00da8ac9e 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 8ed96da240..a32a98e4cf 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 6e703ef065..eca8d6d98d 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 178bbdd3f5..b70856a22b 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 f3683cdcc9..34b25be665 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 38f67adcd0..8f90eba34b 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(), &params, 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 905a71b9ff..4a2d797bd5 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 0000000000..a2afc9eec2
--- /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 0000000000..a2b852b122
--- /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 0000000000..5b9056c124
--- /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 0000000000..bce6f9050a
--- /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 e30e6478a9..1b715dea6e 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -1,291 +1,16 @@
 // 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);
-    }
-
-    void GetLibraryAppletCreator(HLERequestContext& ctx) {
-        LOG_DEBUG(Service_AM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(ResultSuccess);
-        rb.PushIpcInterface<ILibraryAppletCreator>(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 GetApplicationCreator(HLERequestContext& ctx) {
-        LOG_DEBUG(Service_AM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(ResultSuccess);
-        rb.PushIpcInterface<IApplicationCreator>(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 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;
-};
-
-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);
-}
-
-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_)} {
+AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
+    : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} {
     // clang-format off
     static const FunctionInfo functions[] = {
         {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
@@ -304,8 +29,45 @@ AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
 
 AppletAE::~AppletAE() = default;
 
-const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
-    return msg_queue;
+void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
+    LOG_DEBUG(Service_AM, "called");
+
+    if (const auto applet = GetAppletFromContext(ctx)) {
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(ResultSuccess);
+        rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system);
+    } else {
+        UNIMPLEMENTED();
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(ResultUnknown);
+    }
+}
+
+void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
+    LOG_DEBUG(Service_AM, "called");
+
+    if (const auto applet = GetAppletFromContext(ctx)) {
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(ResultSuccess);
+        rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system);
+    } else {
+        UNIMPLEMENTED();
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(ResultUnknown);
+    }
+}
+
+void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
+    LOG_DEBUG(Service_AM, "called");
+
+    return OpenLibraryAppletProxy(ctx);
+}
+
+std::shared_ptr<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 538ce2903a..3d7961fa1d 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 0000000000..130614ae54
--- /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 0000000000..b86adf5cba
--- /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 0000000000..4d58c4db50
--- /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 0000000000..12326fd042
--- /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 0000000000..52200d5b25
--- /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 0000000000..4875de309e
--- /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 0000000000..5ed996b70d
--- /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 0000000000..5cb236d477
--- /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 d6c565d854..56bafd1622 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -1,119 +1,16 @@
 // 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");
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(ResultSuccess);
-        rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
-    }
-
-    void GetLibraryAppletCreator(HLERequestContext& ctx) {
-        LOG_DEBUG(Service_AM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(ResultSuccess);
-        rb.PushIpcInterface<ILibraryAppletCreator>(system);
-    }
-
-    void GetApplicationFunctions(HLERequestContext& ctx) {
-        LOG_DEBUG(Service_AM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(ResultSuccess);
-        rb.PushIpcInterface<IApplicationFunctions>(system);
-    }
-
-    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_)} {
+AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
+    : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} {
     static const FunctionInfo functions[] = {
         {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
     };
@@ -122,8 +19,24 @@ AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
 
 AppletOE::~AppletOE() = default;
 
-const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
-    return msg_queue;
+void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
+    LOG_DEBUG(Service_AM, "called");
+
+    if (const auto applet = GetAppletFromContext(ctx)) {
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(ResultSuccess);
+        rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system);
+    } else {
+        UNIMPLEMENTED();
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(ResultUnknown);
+    }
+}
+
+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 39eccc4ab5..f2ba1c9242 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 89d5434afd..0000000000
--- 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 0bf2598b76..0000000000
--- 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 0000000000..79ea045a35
--- /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 0000000000..375a3c4763
--- /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 0000000000..51c5be2d1a
--- /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 0000000000..55eb21d391
--- /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 0000000000..a6fd6d37f9
--- /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 0000000000..eb98b095cb
--- /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 0000000000..ae75db174e
--- /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 0000000000..a47e3bad88
--- /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 0000000000..937ac0bebb
--- /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 0000000000..bf652790cd
--- /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 0000000000..f80b970f2d
--- /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 0000000000..d559687439
--- /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 0000000000..4d6858348a
--- /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(
+        &params.was_written, &params.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(
+        &params.was_written, &params.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(
+        &params.was_written, &params.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(
+        &params.was_written, &params.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 0000000000..75172580c1
--- /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
similarity index 88%
rename from src/core/hle/service/am/applets/applet_cabinet.cpp
rename to src/core/hle/service/am/frontend/applet_cabinet.cpp
index c2ff444a69..0862c81b67 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
similarity index 90%
rename from src/core/hle/service/am/applets/applet_cabinet.h
rename to src/core/hle/service/am/frontend/applet_cabinet.h
index f498796f71..3a211ed372 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
similarity index 93%
rename from src/core/hle/service/am/applets/applet_controller.cpp
rename to src/core/hle/service/am/frontend/applet_controller.cpp
index 0e4d9cc39a..bd3e49fc4d 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
similarity index 93%
rename from src/core/hle/service/am/applets/applet_controller.h
rename to src/core/hle/service/am/frontend/applet_controller.h
index 9f839f3d74..2f219429ca 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
similarity index 92%
rename from src/core/hle/service/am/applets/applet_error.cpp
rename to src/core/hle/service/am/frontend/applet_error.cpp
index 084bc138c0..b97a5f3ea3 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
similarity index 70%
rename from src/core/hle/service/am/applets/applet_error.h
rename to src/core/hle/service/am/frontend/applet_error.h
index d822a32bbe..678bf33fac 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
similarity index 67%
rename from src/core/hle/service/am/applets/applet_general_backend.cpp
rename to src/core/hle/service/am/frontend/applet_general.cpp
index c0032f652b..3c091a602f 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
similarity index 70%
rename from src/core/hle/service/am/applets/applet_general_backend.h
rename to src/core/hle/service/am/frontend/applet_general.h
index 34ecaebb91..eaa7ae25fe 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
similarity index 88%
rename from src/core/hle/service/am/applets/applet_mii_edit.cpp
rename to src/core/hle/service/am/frontend/applet_mii_edit.cpp
index e83e931c5a..e3d19fb3d0 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
similarity index 74%
rename from src/core/hle/service/am/applets/applet_mii_edit.h
rename to src/core/hle/service/am/frontend/applet_mii_edit.h
index 7ff34af494..5db792f7d2 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
similarity index 96%
rename from src/core/hle/service/am/applets/applet_mii_edit_types.h
rename to src/core/hle/service/am/frontend/applet_mii_edit_types.h
index f3d7640732..23d9d7a69b 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
similarity index 82%
rename from src/core/hle/service/am/applets/applet_profile_select.cpp
rename to src/core/hle/service/am/frontend/applet_profile_select.cpp
index 89cb323e9d..efb4053b85 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
similarity index 92%
rename from src/core/hle/service/am/applets/applet_profile_select.h
rename to src/core/hle/service/am/frontend/applet_profile_select.h
index 673eed516e..674e7afe17 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
similarity index 94%
rename from src/core/hle/service/am/applets/applet_software_keyboard.cpp
rename to src/core/hle/service/am/frontend/applet_software_keyboard.cpp
index 4145bb84f0..fbf75d379d 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
similarity index 94%
rename from src/core/hle/service/am/applets/applet_software_keyboard.h
rename to src/core/hle/service/am/frontend/applet_software_keyboard.h
index 2e919811b9..f464b7e156 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
similarity index 99%
rename from src/core/hle/service/am/applets/applet_software_keyboard_types.h
rename to src/core/hle/service/am/frontend/applet_software_keyboard_types.h
index 1f696900e7..a25ff2a6d2 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
similarity index 96%
rename from src/core/hle/service/am/applets/applet_web_browser.cpp
rename to src/core/hle/service/am/frontend/applet_web_browser.cpp
index 19057ad7bd..6ee4caf34c 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
similarity index 80%
rename from src/core/hle/service/am/applets/applet_web_browser.h
rename to src/core/hle/service/am/frontend/applet_web_browser.h
index 36adb25107..ba20b7a4cf 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
similarity index 98%
rename from src/core/hle/service/am/applets/applet_web_browser_types.h
rename to src/core/hle/service/am/frontend/applet_web_browser_types.h
index c522c5c1a5..2f7c05c243 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 0000000000..db2b045754
--- /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 0000000000..1e1fd28b8b
--- /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 0000000000..ed0eb71087
--- /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 0000000000..7125464a15
--- /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 0000000000..8ed49bac12
--- /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 0000000000..67cd849615
--- /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 0000000000..640e9fbb73
--- /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 0000000000..e082d5d73e
--- /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 0000000000..6b20814f89
--- /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 0000000000..8be29e0035
--- /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 0000000000..47bab75284
--- /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 0000000000..551f287bd6
--- /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 0000000000..d6108fba3c
--- /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 0000000000..8f7a258975
--- /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 0000000000..b560f580b4
--- /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 0000000000..8717a989ac
--- /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 0000000000..46e6c0111d
--- /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 0000000000..7f53f3a9cd
--- /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 0000000000..d0bd8d95ee
--- /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 0000000000..626f60e079
--- /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 0000000000..61eb8641ab
--- /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 0000000000..f7fe03f242
--- /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 0000000000..16b685f860
--- /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 0000000000..4b908ade48
--- /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 0000000000..b48b527973
--- /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 0000000000..71ae4c4f53
--- /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 0000000000..0289f5cf10
--- /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 0000000000..a63bc2e74d
--- /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 0000000000..4e82afd1ca
--- /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 0000000000..10d00b1419
--- /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 0000000000..a1184b0652
--- /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 0000000000..b9aa85a666
--- /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 0000000000..38643408e8
--- /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 0000000000..0390cd1e5f
--- /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 0000000000..60a9afc9df
--- /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 0000000000..98c3cf055a
--- /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 0000000000..f00957f830
--- /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 0000000000..a28219abed
--- /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 0000000000..375660d728
--- /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 0000000000..cdbc4635a6
--- /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 2be72b0211..5fe534c734 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");
 
-    IPC::ResponseBuilder rb{ctx, 2, 0, 0};
-    rb.Push(ResultUnknown);
+    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);
+
+    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 22dc55a6dc..8e3224f73c 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 2258ee6093..19c3ff01b3 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 34d2a45dcb..9ee306ef9d 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 86e272b418..e71652cdf1 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 71d6fdb0c3..51133853c5 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 a60e0ae6bb..3694391423 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 725311c533..dab1905cc4 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 04e52a23b1..493bd6e9e5 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 f95e2dc714..b4b031ee75 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 1f3d82c570..73058db9a5 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 79162a4916..66edd6acde 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 ac81ace9e1..2749e6ed31 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 ac23ce0472..7e2fdf09ea 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 34c5fd3be0..cce9b2efb2 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 1234108ae2..e8a0b6931b 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 49ec52546c..e28df10bdb 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 59b317135c..b40af957c7 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 563a3a35b2..79f9c7ec0f 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 782bcbb617..303d84a1f8 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 6b72094ff8..aba61e3882 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 c39ace2eca..3b321dad14 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: