summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt4
-rw-r--r--src/android/app/src/main/jni/applets/software_keyboard.cpp12
-rw-r--r--src/android/app/src/main/jni/applets/software_keyboard.h4
-rw-r--r--src/android/app/src/main/jni/native.cpp45
-rw-r--r--src/android/app/src/main/jni/native.h5
-rw-r--r--src/core/CMakeLists.txt110
-rw-r--r--src/core/core.cpp72
-rw-r--r--src/core/core.h25
-rw-r--r--src/core/frontend/applets/general.cpp (renamed from src/core/frontend/applets/general_frontend.cpp)2
-rw-r--r--src/core/frontend/applets/general.h (renamed from src/core/frontend/applets/general_frontend.h)0
-rw-r--r--src/core/frontend/applets/profile_select.h8
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp12
-rw-r--r--src/core/frontend/applets/software_keyboard.h22
-rw-r--r--src/core/frontend/applets/web_browser.cpp4
-rw-r--r--src/core/frontend/applets/web_browser.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/service/am/am.cpp2685
-rw-r--r--src/core/hle/service/am/am.h454
-rw-r--r--src/core/hle/service/am/am_results.h16
-rw-r--r--src/core/hle/service/am/am_types.h178
-rw-r--r--src/core/hle/service/am/applet.cpp27
-rw-r--r--src/core/hle/service/am/applet.h133
-rw-r--r--src/core/hle/service/am/applet_ae.cpp320
-rw-r--r--src/core/hle/service/am/applet_ae.h10
-rw-r--r--src/core/hle/service/am/applet_common_functions.cpp63
-rw-r--r--src/core/hle/service/am/applet_common_functions.h24
-rw-r--r--src/core/hle/service/am/applet_data_broker.cpp67
-rw-r--r--src/core/hle/service/am/applet_data_broker.h80
-rw-r--r--src/core/hle/service/am/applet_manager.cpp361
-rw-r--r--src/core/hle/service/am/applet_manager.h59
-rw-r--r--src/core/hle/service/am/applet_message_queue.cpp73
-rw-r--r--src/core/hle/service/am/applet_message_queue.h76
-rw-r--r--src/core/hle/service/am/applet_oe.cpp129
-rw-r--r--src/core/hle/service/am/applet_oe.h10
-rw-r--r--src/core/hle/service/am/applets/applets.cpp338
-rw-r--r--src/core/hle/service/am/applets/applets.h289
-rw-r--r--src/core/hle/service/am/application_creator.cpp25
-rw-r--r--src/core/hle/service/am/application_creator.h16
-rw-r--r--src/core/hle/service/am/application_functions.cpp594
-rw-r--r--src/core/hle/service/am/application_functions.h58
-rw-r--r--src/core/hle/service/am/application_proxy.cpp115
-rw-r--r--src/core/hle/service/am/application_proxy.h33
-rw-r--r--src/core/hle/service/am/audio_controller.cpp91
-rw-r--r--src/core/hle/service/am/audio_controller.h36
-rw-r--r--src/core/hle/service/am/common_state_getter.cpp314
-rw-r--r--src/core/hle/service/am/common_state_getter.h77
-rw-r--r--src/core/hle/service/am/debug_functions.cpp44
-rw-r--r--src/core/hle/service/am/debug_functions.h16
-rw-r--r--src/core/hle/service/am/display_controller.cpp135
-rw-r--r--src/core/hle/service/am/display_controller.h30
-rw-r--r--src/core/hle/service/am/frontend/applet_cabinet.cpp (renamed from src/core/hle/service/am/applets/applet_cabinet.cpp)29
-rw-r--r--src/core/hle/service/am/frontend/applet_cabinet.h (renamed from src/core/hle/service/am/applets/applet_cabinet.h)13
-rw-r--r--src/core/hle/service/am/frontend/applet_controller.cpp (renamed from src/core/hle/service/am/applets/applet_controller.cpp)31
-rw-r--r--src/core/hle/service/am/frontend/applet_controller.h (renamed from src/core/hle/service/am/applets/applet_controller.h)13
-rw-r--r--src/core/hle/service/am/frontend/applet_error.cpp (renamed from src/core/hle/service/am/applets/applet_error.cpp)23
-rw-r--r--src/core/hle/service/am/frontend/applet_error.h (renamed from src/core/hle/service/am/applets/applet_error.h)14
-rw-r--r--src/core/hle/service/am/frontend/applet_general.cpp (renamed from src/core/hle/service/am/applets/applet_general_backend.cpp)90
-rw-r--r--src/core/hle/service/am/frontend/applet_general.h (renamed from src/core/hle/service/am/applets/applet_general_backend.h)27
-rw-r--r--src/core/hle/service/am/frontend/applet_mii_edit.cpp (renamed from src/core/hle/service/am/applets/applet_mii_edit.cpp)27
-rw-r--r--src/core/hle/service/am/frontend/applet_mii_edit.h (renamed from src/core/hle/service/am/applets/applet_mii_edit.h)15
-rw-r--r--src/core/hle/service/am/frontend/applet_mii_edit_types.h (renamed from src/core/hle/service/am/applets/applet_mii_edit_types.h)4
-rw-r--r--src/core/hle/service/am/frontend/applet_profile_select.cpp (renamed from src/core/hle/service/am/applets/applet_profile_select.cpp)28
-rw-r--r--src/core/hle/service/am/frontend/applet_profile_select.h (renamed from src/core/hle/service/am/applets/applet_profile_select.h)13
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard.cpp (renamed from src/core/hle/service/am/applets/applet_software_keyboard.cpp)68
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard.h (renamed from src/core/hle/service/am/applets/applet_software_keyboard.h)15
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard_types.h (renamed from src/core/hle/service/am/applets/applet_software_keyboard_types.h)4
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser.cpp (renamed from src/core/hle/service/am/applets/applet_web_browser.cpp)24
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser.h (renamed from src/core/hle/service/am/applets/applet_web_browser.h)17
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser_types.h (renamed from src/core/hle/service/am/applets/applet_web_browser_types.h)4
-rw-r--r--src/core/hle/service/am/frontend/applets.cpp240
-rw-r--r--src/core/hle/service/am/frontend/applets.h146
-rw-r--r--src/core/hle/service/am/global_state_controller.cpp34
-rw-r--r--src/core/hle/service/am/global_state_controller.h16
-rw-r--r--src/core/hle/service/am/hid_registration.cpp35
-rw-r--r--src/core/hle/service/am/hid_registration.h32
-rw-r--r--src/core/hle/service/am/home_menu_functions.cpp57
-rw-r--r--src/core/hle/service/am/home_menu_functions.h25
-rw-r--r--src/core/hle/service/am/library_applet_accessor.cpp202
-rw-r--r--src/core/hle/service/am/library_applet_accessor.h43
-rw-r--r--src/core/hle/service/am/library_applet_creator.cpp271
-rw-r--r--src/core/hle/service/am/library_applet_creator.h26
-rw-r--r--src/core/hle/service/am/library_applet_proxy.cpp143
-rw-r--r--src/core/hle/service/am/library_applet_proxy.h36
-rw-r--r--src/core/hle/service/am/library_applet_self_accessor.cpp338
-rw-r--r--src/core/hle/service/am/library_applet_self_accessor.h44
-rw-r--r--src/core/hle/service/am/library_applet_storage.cpp140
-rw-r--r--src/core/hle/service/am/library_applet_storage.h36
-rw-r--r--src/core/hle/service/am/lock_accessor.cpp71
-rw-r--r--src/core/hle/service/am/lock_accessor.h28
-rw-r--r--src/core/hle/service/am/managed_layer_holder.cpp59
-rw-r--r--src/core/hle/service/am/managed_layer_holder.h32
-rw-r--r--src/core/hle/service/am/process.cpp138
-rw-r--r--src/core/hle/service/am/process.h50
-rw-r--r--src/core/hle/service/am/process_winding_controller.cpp56
-rw-r--r--src/core/hle/service/am/process_winding_controller.h24
-rw-r--r--src/core/hle/service/am/self_controller.cpp456
-rw-r--r--src/core/hle/service/am/self_controller.h58
-rw-r--r--src/core/hle/service/am/storage.cpp59
-rw-r--r--src/core/hle/service/am/storage.h31
-rw-r--r--src/core/hle/service/am/storage_accessor.cpp90
-rw-r--r--src/core/hle/service/am/storage_accessor.h37
-rw-r--r--src/core/hle/service/am/system_applet_proxy.cpp136
-rw-r--r--src/core/hle/service/am/system_applet_proxy.h36
-rw-r--r--src/core/hle/service/am/system_buffer_manager.cpp69
-rw-r--r--src/core/hle/service/am/system_buffer_manager.h51
-rw-r--r--src/core/hle/service/am/window_controller.cpp86
-rw-r--r--src/core/hle/service/am/window_controller.h27
-rw-r--r--src/core/hle/service/event.cpp31
-rw-r--r--src/core/hle/service/event.h31
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp48
-rw-r--r--src/core/hle/service/nifm/nifm.cpp12
-rw-r--r--src/core/hle/service/ns/ns.cpp67
-rw-r--r--src/core/hle/service/ns/ns.h15
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp10
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h3
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp4
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp2
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h9
-rw-r--r--src/core/hle/service/vi/vi.cpp8
-rw-r--r--src/yuzu/applets/qt_profile_select.cpp4
-rw-r--r--src/yuzu/applets/qt_software_keyboard.cpp10
-rw-r--r--src/yuzu/applets/qt_software_keyboard.h17
-rw-r--r--src/yuzu/applets/qt_web_browser.cpp12
-rw-r--r--src/yuzu/applets/qt_web_browser.h10
-rw-r--r--src/yuzu/configuration/configure_input.cpp18
-rw-r--r--src/yuzu/game_list.cpp12
-rw-r--r--src/yuzu/game_list.h3
-rw-r--r--src/yuzu/main.cpp168
-rw-r--r--src/yuzu/main.h38
-rw-r--r--src/yuzu_cmd/yuzu.cpp6
132 files changed, 7084 insertions, 4710 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 53137b2e2..6ebb46af7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -261,7 +261,7 @@ object NativeLibrary {
261 /** 261 /**
262 * Begins emulation. 262 * Begins emulation.
263 */ 263 */
264 external fun run(path: String?, programIndex: Int = 0) 264 external fun run(path: String?, programIndex: Int, frontendInitiated: Boolean)
265 265
266 // Surface Handling 266 // Surface Handling
267 external fun surfaceChanged(surf: Surface?) 267 external fun surfaceChanged(surf: Surface?)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 1f591ced1..937b8faf1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -927,7 +927,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
927 emulationThread.join() 927 emulationThread.join()
928 emulationThread = Thread({ 928 emulationThread = Thread({
929 Log.debug("[EmulationFragment] Starting emulation thread.") 929 Log.debug("[EmulationFragment] Starting emulation thread.")
930 NativeLibrary.run(gamePath, programIndex) 930 NativeLibrary.run(gamePath, programIndex, false)
931 }, "NativeEmulation") 931 }, "NativeEmulation")
932 emulationThread.start() 932 emulationThread.start()
933 } 933 }
@@ -981,7 +981,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
981 State.STOPPED -> { 981 State.STOPPED -> {
982 emulationThread = Thread({ 982 emulationThread = Thread({
983 Log.debug("[EmulationFragment] Starting emulation thread.") 983 Log.debug("[EmulationFragment] Starting emulation thread.")
984 NativeLibrary.run(gamePath, programIndex) 984 NativeLibrary.run(gamePath, programIndex, true)
985 }, "NativeEmulation") 985 }, "NativeEmulation")
986 emulationThread.start() 986 emulationThread.start()
987 } 987 }
diff --git a/src/android/app/src/main/jni/applets/software_keyboard.cpp b/src/android/app/src/main/jni/applets/software_keyboard.cpp
index 74e040478..9943483e8 100644
--- a/src/android/app/src/main/jni/applets/software_keyboard.cpp
+++ b/src/android/app/src/main/jni/applets/software_keyboard.cpp
@@ -82,7 +82,7 @@ AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobj
82 const jstring string = reinterpret_cast<jstring>(env->GetObjectField( 82 const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
83 object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;"))); 83 object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
84 return ResultData{GetJString(env, string), 84 return ResultData{GetJString(env, string),
85 static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField( 85 static_cast<Service::AM::Frontend::SwkbdResult>(env->GetIntField(
86 object, env->GetFieldID(s_keyboard_data_class, "result", "I")))}; 86 object, env->GetFieldID(s_keyboard_data_class, "result", "I")))};
87} 87}
88 88
@@ -149,7 +149,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
149} 149}
150 150
151void AndroidKeyboard::ShowTextCheckDialog( 151void AndroidKeyboard::ShowTextCheckDialog(
152 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 152 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
153 std::u16string text_check_message) const { 153 std::u16string text_check_message) const {
154 LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog."); 154 LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog.");
155} 155}
@@ -204,7 +204,7 @@ void AndroidKeyboard::InlineTextChanged(
204 "\ncursor_position={}", 204 "\ncursor_position={}",
205 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); 205 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
206 206
207 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, 207 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
208 text_parameters.input_text, text_parameters.cursor_position); 208 text_parameters.input_text, text_parameters.cursor_position);
209} 209}
210 210
@@ -219,7 +219,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
219 219
220 m_current_text += submitted_text; 220 m_current_text += submitted_text;
221 221
222 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text, 222 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
223 m_current_text.size()); 223 m_current_text.size());
224} 224}
225 225
@@ -236,12 +236,12 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
236 case KEYCODE_BACK: 236 case KEYCODE_BACK:
237 case KEYCODE_ENTER: 237 case KEYCODE_ENTER:
238 m_is_inline_active = false; 238 m_is_inline_active = false;
239 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text, 239 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, m_current_text,
240 static_cast<s32>(m_current_text.size())); 240 static_cast<s32>(m_current_text.size()));
241 break; 241 break;
242 case KEYCODE_DEL: 242 case KEYCODE_DEL:
243 m_current_text.pop_back(); 243 m_current_text.pop_back();
244 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text, 244 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
245 m_current_text.size()); 245 m_current_text.size());
246 break; 246 break;
247 } 247 }
diff --git a/src/android/app/src/main/jni/applets/software_keyboard.h b/src/android/app/src/main/jni/applets/software_keyboard.h
index b2fb59b68..2affc01f6 100644
--- a/src/android/app/src/main/jni/applets/software_keyboard.h
+++ b/src/android/app/src/main/jni/applets/software_keyboard.h
@@ -24,7 +24,7 @@ public:
24 24
25 void ShowNormalKeyboard() const override; 25 void ShowNormalKeyboard() const override;
26 26
27 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 27 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
28 std::u16string text_check_message) const override; 28 std::u16string text_check_message) const override;
29 29
30 void ShowInlineKeyboard( 30 void ShowInlineKeyboard(
@@ -45,7 +45,7 @@ private:
45 static ResultData CreateFromFrontend(jobject object); 45 static ResultData CreateFromFrontend(jobject object);
46 46
47 std::string text; 47 std::string text;
48 Service::AM::Applets::SwkbdResult result{}; 48 Service::AM::Frontend::SwkbdResult result{};
49 }; 49 };
50 50
51 void SubmitNormalText(const ResultData& result) const; 51 void SubmitNormalText(const ResultData& result) const;
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 64627db88..654510129 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -42,14 +42,15 @@
42#include "core/frontend/applets/cabinet.h" 42#include "core/frontend/applets/cabinet.h"
43#include "core/frontend/applets/controller.h" 43#include "core/frontend/applets/controller.h"
44#include "core/frontend/applets/error.h" 44#include "core/frontend/applets/error.h"
45#include "core/frontend/applets/general_frontend.h" 45#include "core/frontend/applets/general.h"
46#include "core/frontend/applets/mii_edit.h" 46#include "core/frontend/applets/mii_edit.h"
47#include "core/frontend/applets/profile_select.h" 47#include "core/frontend/applets/profile_select.h"
48#include "core/frontend/applets/software_keyboard.h" 48#include "core/frontend/applets/software_keyboard.h"
49#include "core/frontend/applets/web_browser.h" 49#include "core/frontend/applets/web_browser.h"
50#include "core/hle/service/am/applet_ae.h" 50#include "core/hle/service/am/applet_ae.h"
51#include "core/hle/service/am/applet_manager.h"
51#include "core/hle/service/am/applet_oe.h" 52#include "core/hle/service/am/applet_oe.h"
52#include "core/hle/service/am/applets/applets.h" 53#include "core/hle/service/am/frontend/applets.h"
53#include "core/hle/service/filesystem/filesystem.h" 54#include "core/hle/service/filesystem/filesystem.h"
54#include "core/loader/loader.h" 55#include "core/loader/loader.h"
55#include "frontend_common/config.h" 56#include "frontend_common/config.h"
@@ -211,8 +212,15 @@ void EmulationSession::InitializeSystem(bool reload) {
211 m_system.GetFileSystemController().CreateFactories(*m_vfs); 212 m_system.GetFileSystemController().CreateFactories(*m_vfs);
212} 213}
213 214
215void EmulationSession::SetAppletId(int applet_id) {
216 m_applet_id = applet_id;
217 m_system.GetFrontendAppletHolder().SetCurrentAppletId(
218 static_cast<Service::AM::AppletId>(m_applet_id));
219}
220
214Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath, 221Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath,
215 const std::size_t program_index) { 222 const std::size_t program_index,
223 const bool frontend_initiated) {
216 std::scoped_lock lock(m_mutex); 224 std::scoped_lock lock(m_mutex);
217 225
218 // Create the render window. 226 // Create the render window.
@@ -226,7 +234,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
226 m_system.ApplySettings(); 234 m_system.ApplySettings();
227 Settings::LogSettings(); 235 Settings::LogSettings();
228 m_system.HIDCore().ReloadInputDevices(); 236 m_system.HIDCore().ReloadInputDevices();
229 m_system.SetAppletFrontendSet({ 237 m_system.SetFrontendAppletSet({
230 nullptr, // Amiibo Settings 238 nullptr, // Amiibo Settings
231 nullptr, // Controller Selector 239 nullptr, // Controller Selector
232 nullptr, // Error Display 240 nullptr, // Error Display
@@ -242,8 +250,13 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
242 ConfigureFilesystemProvider(filepath); 250 ConfigureFilesystemProvider(filepath);
243 251
244 // Load the ROM. 252 // Load the ROM.
245 m_load_result = 253 Service::AM::FrontendAppletParameters params{
246 m_system.Load(EmulationSession::GetInstance().Window(), filepath, 0, program_index); 254 .applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
255 .launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
256 : Service::AM::LaunchType::ApplicationInitiated,
257 .program_index = static_cast<s32>(program_index),
258 };
259 m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
247 if (m_load_result != Core::SystemResultStatus::Success) { 260 if (m_load_result != Core::SystemResultStatus::Success) {
248 return m_load_result; 261 return m_load_result;
249 } 262 }
@@ -339,6 +352,9 @@ void EmulationSession::RunEmulation() {
339 } 352 }
340 } 353 }
341 } 354 }
355
356 // Reset current applet ID.
357 m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
342} 358}
343 359
344bool EmulationSession::IsHandheldOnly() { 360bool EmulationSession::IsHandheldOnly() {
@@ -434,7 +450,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
434} 450}
435 451
436static Core::SystemResultStatus RunEmulation(const std::string& filepath, 452static Core::SystemResultStatus RunEmulation(const std::string& filepath,
437 const size_t program_index = 0) { 453 const size_t program_index,
454 const bool frontend_initiated) {
438 MicroProfileOnThreadCreate("EmuThread"); 455 MicroProfileOnThreadCreate("EmuThread");
439 SCOPE_EXIT({ MicroProfileShutdown(); }); 456 SCOPE_EXIT({ MicroProfileShutdown(); });
440 457
@@ -447,7 +464,8 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
447 464
448 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); 465 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
449 466
450 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index); 467 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
468 frontend_initiated);
451 if (result != Core::SystemResultStatus::Success) { 469 if (result != Core::SystemResultStatus::Success) {
452 return result; 470 return result;
453 } 471 }
@@ -744,10 +762,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
744} 762}
745 763
746void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path, 764void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
747 jint j_program_index) { 765 jint j_program_index,
766 jboolean j_frontend_initiated) {
748 const std::string path = GetJString(env, j_path); 767 const std::string path = GetJString(env, j_path);
749 768
750 const Core::SystemResultStatus result{RunEmulation(path, j_program_index)}; 769 const Core::SystemResultStatus result{
770 RunEmulation(path, j_program_index, j_frontend_initiated)};
751 if (result != Core::SystemResultStatus::Success) { 771 if (result != Core::SystemResultStatus::Success) {
752 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), 772 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
753 IDCache::GetExitEmulationActivity(), static_cast<int>(result)); 773 IDCache::GetExitEmulationActivity(), static_cast<int>(result));
@@ -809,13 +829,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
809 829
810void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz, 830void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
811 jint jappletId) { 831 jint jappletId) {
812 EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId( 832 EmulationSession::GetInstance().SetAppletId(jappletId);
813 static_cast<Service::AM::Applets::AppletId>(jappletId));
814} 833}
815 834
816void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz, 835void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz,
817 jint jcabinetMode) { 836 jint jcabinetMode) {
818 EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode( 837 EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCabinetMode(
819 static_cast<Service::NFP::CabinetMode>(jcabinetMode)); 838 static_cast<Service::NFP::CabinetMode>(jcabinetMode));
820} 839}
821 840
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h
index bfe3fccca..e49d4e015 100644
--- a/src/android/app/src/main/jni/native.h
+++ b/src/android/app/src/main/jni/native.h
@@ -45,8 +45,10 @@ public:
45 const Core::PerfStatsResults& PerfStats(); 45 const Core::PerfStatsResults& PerfStats();
46 void ConfigureFilesystemProvider(const std::string& filepath); 46 void ConfigureFilesystemProvider(const std::string& filepath);
47 void InitializeSystem(bool reload); 47 void InitializeSystem(bool reload);
48 void SetAppletId(int applet_id);
48 Core::SystemResultStatus InitializeEmulation(const std::string& filepath, 49 Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
49 const std::size_t program_index = 0); 50 const std::size_t program_index,
51 const bool frontend_initiated);
50 52
51 bool IsHandheldOnly(); 53 bool IsHandheldOnly();
52 void SetDeviceType([[maybe_unused]] int index, int type); 54 void SetDeviceType([[maybe_unused]] int index, int type);
@@ -79,6 +81,7 @@ private:
79 std::atomic<bool> m_is_paused = false; 81 std::atomic<bool> m_is_paused = false;
80 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; 82 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
81 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; 83 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
84 int m_applet_id{1};
82 85
83 // GPU driver parameters 86 // GPU driver parameters
84 std::shared_ptr<Common::DynamicLibrary> m_vulkan_library; 87 std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ea6b2c285..570acb193 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -176,8 +176,8 @@ add_library(core STATIC
176 frontend/applets/controller.h 176 frontend/applets/controller.h
177 frontend/applets/error.cpp 177 frontend/applets/error.cpp
178 frontend/applets/error.h 178 frontend/applets/error.h
179 frontend/applets/general_frontend.cpp 179 frontend/applets/general.cpp
180 frontend/applets/general_frontend.h 180 frontend/applets/general.h
181 frontend/applets/mii_edit.cpp 181 frontend/applets/mii_edit.cpp
182 frontend/applets/mii_edit.h 182 frontend/applets/mii_edit.h
183 frontend/applets/profile_select.cpp 183 frontend/applets/profile_select.cpp
@@ -390,39 +390,101 @@ add_library(core STATIC
390 hle/service/acc/errors.h 390 hle/service/acc/errors.h
391 hle/service/acc/profile_manager.cpp 391 hle/service/acc/profile_manager.cpp
392 hle/service/acc/profile_manager.h 392 hle/service/acc/profile_manager.h
393 hle/service/am/frontend/applet_cabinet.cpp
394 hle/service/am/frontend/applet_cabinet.h
395 hle/service/am/frontend/applet_controller.cpp
396 hle/service/am/frontend/applet_controller.h
397 hle/service/am/frontend/applet_error.cpp
398 hle/service/am/frontend/applet_error.h
399 hle/service/am/frontend/applet_general.cpp
400 hle/service/am/frontend/applet_general.h
401 hle/service/am/frontend/applet_mii_edit.cpp
402 hle/service/am/frontend/applet_mii_edit.h
403 hle/service/am/frontend/applet_mii_edit_types.h
404 hle/service/am/frontend/applet_profile_select.cpp
405 hle/service/am/frontend/applet_profile_select.h
406 hle/service/am/frontend/applet_software_keyboard.cpp
407 hle/service/am/frontend/applet_software_keyboard.h
408 hle/service/am/frontend/applet_software_keyboard_types.h
409 hle/service/am/frontend/applet_web_browser.cpp
410 hle/service/am/frontend/applet_web_browser.h
411 hle/service/am/frontend/applet_web_browser_types.h
412 hle/service/am/frontend/applets.cpp
413 hle/service/am/frontend/applets.h
393 hle/service/am/am.cpp 414 hle/service/am/am.cpp
394 hle/service/am/am.h 415 hle/service/am/am.h
416 hle/service/am/am_results.h
417 hle/service/am/am_types.h
418 hle/service/am/applet.cpp
419 hle/service/am/applet.h
395 hle/service/am/applet_ae.cpp 420 hle/service/am/applet_ae.cpp
396 hle/service/am/applet_ae.h 421 hle/service/am/applet_ae.h
422 hle/service/am/applet_manager.cpp
423 hle/service/am/applet_data_broker.cpp
424 hle/service/am/applet_data_broker.h
425 hle/service/am/applet_manager.h
397 hle/service/am/applet_oe.cpp 426 hle/service/am/applet_oe.cpp
398 hle/service/am/applet_oe.h 427 hle/service/am/applet_oe.h
399 hle/service/am/applets/applet_cabinet.cpp 428 hle/service/am/applet_common_functions.cpp
400 hle/service/am/applets/applet_cabinet.h 429 hle/service/am/applet_common_functions.h
401 hle/service/am/applets/applet_controller.cpp 430 hle/service/am/applet_message_queue.cpp
402 hle/service/am/applets/applet_controller.h 431 hle/service/am/applet_message_queue.h
403 hle/service/am/applets/applet_error.cpp 432 hle/service/am/application_creator.cpp
404 hle/service/am/applets/applet_error.h 433 hle/service/am/application_creator.h
405 hle/service/am/applets/applet_general_backend.cpp 434 hle/service/am/application_functions.cpp
406 hle/service/am/applets/applet_general_backend.h 435 hle/service/am/application_functions.h
407 hle/service/am/applets/applet_mii_edit.cpp 436 hle/service/am/application_proxy.cpp
408 hle/service/am/applets/applet_mii_edit.h 437 hle/service/am/application_proxy.h
409 hle/service/am/applets/applet_mii_edit_types.h 438 hle/service/am/audio_controller.cpp
410 hle/service/am/applets/applet_profile_select.cpp 439 hle/service/am/audio_controller.h
411 hle/service/am/applets/applet_profile_select.h 440 hle/service/am/common_state_getter.cpp
412 hle/service/am/applets/applet_software_keyboard.cpp 441 hle/service/am/common_state_getter.h
413 hle/service/am/applets/applet_software_keyboard.h 442 hle/service/am/debug_functions.cpp
414 hle/service/am/applets/applet_software_keyboard_types.h 443 hle/service/am/debug_functions.h
415 hle/service/am/applets/applet_web_browser.cpp 444 hle/service/am/display_controller.cpp
416 hle/service/am/applets/applet_web_browser.h 445 hle/service/am/display_controller.h
417 hle/service/am/applets/applet_web_browser_types.h 446 hle/service/am/global_state_controller.cpp
418 hle/service/am/applets/applets.cpp 447 hle/service/am/global_state_controller.h
419 hle/service/am/applets/applets.h 448 hle/service/am/hid_registration.cpp
449 hle/service/am/hid_registration.h
450 hle/service/am/home_menu_functions.cpp
451 hle/service/am/home_menu_functions.h
420 hle/service/am/idle.cpp 452 hle/service/am/idle.cpp
421 hle/service/am/idle.h 453 hle/service/am/idle.h
454 hle/service/am/library_applet_accessor.cpp
455 hle/service/am/library_applet_accessor.h
456 hle/service/am/library_applet_creator.cpp
457 hle/service/am/library_applet_creator.h
458 hle/service/am/library_applet_proxy.cpp
459 hle/service/am/library_applet_proxy.h
460 hle/service/am/library_applet_self_accessor.cpp
461 hle/service/am/library_applet_self_accessor.h
462 hle/service/am/library_applet_storage.cpp
463 hle/service/am/library_applet_storage.h
464 hle/service/am/lock_accessor.cpp
465 hle/service/am/lock_accessor.h
466 hle/service/am/managed_layer_holder.cpp
467 hle/service/am/managed_layer_holder.h
422 hle/service/am/omm.cpp 468 hle/service/am/omm.cpp
423 hle/service/am/omm.h 469 hle/service/am/omm.h
470 hle/service/am/process_winding_controller.cpp
471 hle/service/am/process_winding_controller.h
472 hle/service/am/process.cpp
473 hle/service/am/process.h
474 hle/service/am/self_controller.cpp
475 hle/service/am/self_controller.h
476 hle/service/am/system_applet_proxy.cpp
477 hle/service/am/system_applet_proxy.h
478 hle/service/am/system_buffer_manager.cpp
479 hle/service/am/system_buffer_manager.h
424 hle/service/am/spsm.cpp 480 hle/service/am/spsm.cpp
425 hle/service/am/spsm.h 481 hle/service/am/spsm.h
482 hle/service/am/storage_accessor.cpp
483 hle/service/am/storage_accessor.h
484 hle/service/am/storage.cpp
485 hle/service/am/storage.h
486 hle/service/am/window_controller.cpp
487 hle/service/am/window_controller.h
426 hle/service/aoc/aoc_u.cpp 488 hle/service/aoc/aoc_u.cpp
427 hle/service/aoc/aoc_u.h 489 hle/service/aoc/aoc_u.h
428 hle/service/apm/apm.cpp 490 hle/service/apm/apm.cpp
@@ -486,6 +548,8 @@ add_library(core STATIC
486 hle/service/es/es.h 548 hle/service/es/es.h
487 hle/service/eupld/eupld.cpp 549 hle/service/eupld/eupld.cpp
488 hle/service/eupld/eupld.h 550 hle/service/eupld/eupld.h
551 hle/service/event.cpp
552 hle/service/event.h
489 hle/service/fatal/fatal.cpp 553 hle/service/fatal/fatal.cpp
490 hle/service/fatal/fatal.h 554 hle/service/fatal/fatal.h
491 hle/service/fatal/fatal_p.cpp 555 hle/service/fatal/fatal_p.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 11bf8d2f6..435ef6793 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -36,7 +36,8 @@
36#include "core/hle/kernel/kernel.h" 36#include "core/hle/kernel/kernel.h"
37#include "core/hle/kernel/physical_core.h" 37#include "core/hle/kernel/physical_core.h"
38#include "core/hle/service/acc/profile_manager.h" 38#include "core/hle/service/acc/profile_manager.h"
39#include "core/hle/service/am/applets/applets.h" 39#include "core/hle/service/am/applet_manager.h"
40#include "core/hle/service/am/frontend/applets.h"
40#include "core/hle/service/apm/apm_controller.h" 41#include "core/hle/service/apm/apm_controller.h"
41#include "core/hle/service/filesystem/filesystem.h" 42#include "core/hle/service/filesystem/filesystem.h"
42#include "core/hle/service/glue/glue_manager.h" 43#include "core/hle/service/glue/glue_manager.h"
@@ -135,8 +136,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
135 136
136struct System::Impl { 137struct System::Impl {
137 explicit Impl(System& system) 138 explicit Impl(System& system)
138 : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, 139 : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
139 cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {} 140 reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
140 141
141 void Initialize(System& system) { 142 void Initialize(System& system) {
142 device_memory = std::make_unique<Core::DeviceMemory>(); 143 device_memory = std::make_unique<Core::DeviceMemory>();
@@ -157,7 +158,7 @@ struct System::Impl {
157 } 158 }
158 159
159 // Create default implementations of applets if one is not provided. 160 // Create default implementations of applets if one is not provided.
160 applet_manager.SetDefaultAppletsIfMissing(); 161 frontend_applets.SetDefaultAppletsIfMissing();
161 162
162 is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); 163 is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
163 164
@@ -330,16 +331,27 @@ struct System::Impl {
330 } 331 }
331 332
332 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, 333 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
333 const std::string& filepath, u64 program_id, 334 const std::string& filepath,
334 std::size_t program_index) { 335 Service::AM::FrontendAppletParameters& params) {
335 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), 336 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
336 program_id, program_index); 337 params.program_id, params.program_index);
337 338
338 if (!app_loader) { 339 if (!app_loader) {
339 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 340 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
340 return SystemResultStatus::ErrorGetLoader; 341 return SystemResultStatus::ErrorGetLoader;
341 } 342 }
342 343
344 if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
345 LOG_ERROR(Core, "Failed to find title id for ROM!");
346 }
347
348 std::string name = "Unknown program";
349 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
350 LOG_ERROR(Core, "Failed to read title for ROM!");
351 }
352
353 LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
354
343 InitializeKernel(system); 355 InitializeKernel(system);
344 356
345 // Create the application process. 357 // Create the application process.
@@ -373,9 +385,14 @@ struct System::Impl {
373 cheat_engine->Initialize(); 385 cheat_engine->Initialize();
374 } 386 }
375 387
388 // Register with applet manager.
389 applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
390 params);
391
376 // All threads are started, begin main process execution, now that we're in the clear. 392 // All threads are started, begin main process execution, now that we're in the clear.
377 main_process->Run(load_parameters->main_thread_priority, 393 main_process->Run(load_parameters->main_thread_priority,
378 load_parameters->main_thread_stack_size); 394 load_parameters->main_thread_stack_size);
395 main_process->Close();
379 396
380 if (Settings::values.gamecard_inserted) { 397 if (Settings::values.gamecard_inserted) {
381 if (Settings::values.gamecard_current_game) { 398 if (Settings::values.gamecard_current_game) {
@@ -386,21 +403,13 @@ struct System::Impl {
386 } 403 }
387 } 404 }
388 405
389 if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { 406 perf_stats = std::make_unique<PerfStats>(params.program_id);
390 LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
391 }
392 perf_stats = std::make_unique<PerfStats>(program_id);
393 // Reset counters and set time origin to current frame 407 // Reset counters and set time origin to current frame
394 GetAndResetPerfStats(); 408 GetAndResetPerfStats();
395 perf_stats->BeginSystemFrame(); 409 perf_stats->BeginSystemFrame();
396 410
397 std::string name = "Unknown Game";
398 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
399 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
400 }
401
402 std::string title_version; 411 std::string title_version;
403 const FileSys::PatchManager pm(program_id, system.GetFileSystemController(), 412 const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(),
404 system.GetContentProvider()); 413 system.GetContentProvider());
405 const auto metadata = pm.GetControlMetadata(); 414 const auto metadata = pm.GetControlMetadata();
406 if (metadata.first != nullptr) { 415 if (metadata.first != nullptr) {
@@ -409,14 +418,15 @@ struct System::Impl {
409 if (auto room_member = room_network.GetRoomMember().lock()) { 418 if (auto room_member = room_network.GetRoomMember().lock()) {
410 Network::GameInfo game_info; 419 Network::GameInfo game_info;
411 game_info.name = name; 420 game_info.name = name;
412 game_info.id = program_id; 421 game_info.id = params.program_id;
413 game_info.version = title_version; 422 game_info.version = title_version;
414 room_member->SendGameInfo(game_info); 423 room_member->SendGameInfo(game_info);
415 } 424 }
416 425
417 // Workarounds: 426 // Workarounds:
418 // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK 427 // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
419 Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL; 428 Settings::values.renderer_amdvlk_depth_bias_workaround =
429 params.program_id == 0x1006A800016E000ULL;
420 430
421 status = SystemResultStatus::Success; 431 status = SystemResultStatus::Success;
422 return status; 432 return status;
@@ -455,6 +465,7 @@ struct System::Impl {
455 } 465 }
456 kernel.CloseServices(); 466 kernel.CloseServices();
457 kernel.ShutdownCores(); 467 kernel.ShutdownCores();
468 applet_manager.Reset();
458 services.reset(); 469 services.reset();
459 service_manager.reset(); 470 service_manager.reset();
460 fs_controller.Reset(); 471 fs_controller.Reset();
@@ -566,8 +577,9 @@ struct System::Impl {
566 577
567 std::unique_ptr<Tools::RenderdocAPI> renderdoc_api; 578 std::unique_ptr<Tools::RenderdocAPI> renderdoc_api;
568 579
569 /// Frontend applets 580 /// Applets
570 Service::AM::Applets::AppletManager applet_manager; 581 Service::AM::AppletManager applet_manager;
582 Service::AM::Frontend::FrontendAppletHolder frontend_applets;
571 583
572 /// APM (Performance) services 584 /// APM (Performance) services
573 Service::APM::Controller apm_controller{core_timing}; 585 Service::APM::Controller apm_controller{core_timing};
@@ -680,8 +692,8 @@ void System::InitializeDebugger() {
680} 692}
681 693
682SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, 694SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
683 u64 program_id, std::size_t program_index) { 695 Service::AM::FrontendAppletParameters& params) {
684 return impl->Load(*this, emu_window, filepath, program_id, program_index); 696 return impl->Load(*this, emu_window, filepath, params);
685} 697}
686 698
687bool System::IsPoweredOn() const { 699bool System::IsPoweredOn() const {
@@ -871,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
871 impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); 883 impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
872} 884}
873 885
874void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) { 886void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
875 impl->applet_manager.SetAppletFrontendSet(std::move(set)); 887 impl->frontend_applets.SetFrontendAppletSet(std::move(set));
876} 888}
877 889
878void System::SetDefaultAppletFrontendSet() { 890Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
879 impl->applet_manager.SetDefaultAppletFrontendSet(); 891 return impl->frontend_applets;
880} 892}
881 893
882Service::AM::Applets::AppletManager& System::GetAppletManager() { 894const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
883 return impl->applet_manager; 895 return impl->frontend_applets;
884} 896}
885 897
886const Service::AM::Applets::AppletManager& System::GetAppletManager() const { 898Service::AM::AppletManager& System::GetAppletManager() {
887 return impl->applet_manager; 899 return impl->applet_manager;
888} 900}
889 901
diff --git a/src/core/core.h b/src/core/core.h
index d8862e9ce..90826bd3a 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -50,10 +50,15 @@ namespace Account {
50class ProfileManager; 50class ProfileManager;
51} // namespace Account 51} // namespace Account
52 52
53namespace AM::Applets { 53namespace AM {
54struct AppletFrontendSet; 54struct FrontendAppletParameters;
55class AppletManager; 55class AppletManager;
56} // namespace AM::Applets 56} // namespace AM
57
58namespace AM::Frontend {
59struct FrontendAppletSet;
60class FrontendAppletHolder;
61} // namespace AM::Frontend
57 62
58namespace APM { 63namespace APM {
59class Controller; 64class Controller;
@@ -203,8 +208,8 @@ public:
203 * @returns SystemResultStatus code, indicating if the operation succeeded. 208 * @returns SystemResultStatus code, indicating if the operation succeeded.
204 */ 209 */
205 [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window, 210 [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window,
206 const std::string& filepath, u64 program_id = 0, 211 const std::string& filepath,
207 std::size_t program_index = 0); 212 Service::AM::FrontendAppletParameters& params);
208 213
209 /** 214 /**
210 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an 215 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -344,11 +349,13 @@ public:
344 const std::array<u8, 0x20>& build_id, u64 main_region_begin, 349 const std::array<u8, 0x20>& build_id, u64 main_region_begin,
345 u64 main_region_size); 350 u64 main_region_size);
346 351
347 void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); 352 void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
348 void SetDefaultAppletFrontendSet(); 353
354 [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder();
355 [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder()
356 const;
349 357
350 [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); 358 [[nodiscard]] Service::AM::AppletManager& GetAppletManager();
351 [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
352 359
353 void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); 360 void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
354 361
diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general.cpp
index b4b213a31..4c299ee9c 100644
--- a/src/core/frontend/applets/general_frontend.cpp
+++ b/src/core/frontend/applets/general.cpp
@@ -2,7 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/frontend/applets/general_frontend.h" 5#include "core/frontend/applets/general.h"
6 6
7namespace Core::Frontend { 7namespace Core::Frontend {
8 8
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general.h
index 319838ac7..319838ac7 100644
--- a/src/core/frontend/applets/general_frontend.h
+++ b/src/core/frontend/applets/general.h
diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h
index 92e2737ea..880b69ad6 100644
--- a/src/core/frontend/applets/profile_select.h
+++ b/src/core/frontend/applets/profile_select.h
@@ -8,15 +8,15 @@
8 8
9#include "common/uuid.h" 9#include "common/uuid.h"
10#include "core/frontend/applets/applet.h" 10#include "core/frontend/applets/applet.h"
11#include "core/hle/service/am/applets/applet_profile_select.h" 11#include "core/hle/service/am/frontend/applet_profile_select.h"
12 12
13namespace Core::Frontend { 13namespace Core::Frontend {
14 14
15struct ProfileSelectParameters { 15struct ProfileSelectParameters {
16 Service::AM::Applets::UiMode mode; 16 Service::AM::Frontend::UiMode mode;
17 std::array<Common::UUID, 8> invalid_uid_list; 17 std::array<Common::UUID, 8> invalid_uid_list;
18 Service::AM::Applets::UiSettingsDisplayOptions display_options; 18 Service::AM::Frontend::UiSettingsDisplayOptions display_options;
19 Service::AM::Applets::UserSelectionPurpose purpose; 19 Service::AM::Frontend::UserSelectionPurpose purpose;
20}; 20};
21 21
22class ProfileSelectApplet : public Applet { 22class ProfileSelectApplet : public Applet {
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
index 7655d215b..d00da8ac9 100644
--- a/src/core/frontend/applets/software_keyboard.cpp
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -69,7 +69,7 @@ void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
69} 69}
70 70
71void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog( 71void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
72 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 72 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
73 std::u16string text_check_message) const { 73 std::u16string text_check_message) const {
74 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog."); 74 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
75} 75}
@@ -118,7 +118,7 @@ void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_
118 "\ncursor_position={}", 118 "\ncursor_position={}",
119 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); 119 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
120 120
121 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, 121 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
122 text_parameters.input_text, text_parameters.cursor_position); 122 text_parameters.input_text, text_parameters.cursor_position);
123} 123}
124 124
@@ -127,22 +127,22 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
127} 127}
128 128
129void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const { 129void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
130 submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true); 130 submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true);
131} 131}
132 132
133void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const { 133void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
134 std::this_thread::sleep_for(std::chrono::milliseconds(500)); 134 std::this_thread::sleep_for(std::chrono::milliseconds(500));
135 135
136 for (std::size_t index = 0; index < text.size(); ++index) { 136 for (std::size_t index = 0; index < text.size(); ++index) {
137 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, 137 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
138 std::u16string(text.data(), text.data() + index + 1), 138 std::u16string(text.data(), text.data() + index + 1),
139 static_cast<s32>(index) + 1); 139 static_cast<s32>(index) + 1);
140 140
141 std::this_thread::sleep_for(std::chrono::milliseconds(250)); 141 std::this_thread::sleep_for(std::chrono::milliseconds(250));
142 } 142 }
143 143
144 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text), 144 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter,
145 static_cast<s32>(text.size())); 145 std::u16string(text), static_cast<s32>(text.size()));
146} 146}
147 147
148} // namespace Core::Frontend 148} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
index 8ed96da24..a32a98e4c 100644
--- a/src/core/frontend/applets/software_keyboard.h
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -8,7 +8,7 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10#include "core/frontend/applets/applet.h" 10#include "core/frontend/applets/applet.h"
11#include "core/hle/service/am/applets/applet_software_keyboard_types.h" 11#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
12 12
13namespace Core::Frontend { 13namespace Core::Frontend {
14 14
@@ -23,10 +23,10 @@ struct KeyboardInitializeParameters {
23 u32 max_text_length; 23 u32 max_text_length;
24 u32 min_text_length; 24 u32 min_text_length;
25 s32 initial_cursor_position; 25 s32 initial_cursor_position;
26 Service::AM::Applets::SwkbdType type; 26 Service::AM::Frontend::SwkbdType type;
27 Service::AM::Applets::SwkbdPasswordMode password_mode; 27 Service::AM::Frontend::SwkbdPasswordMode password_mode;
28 Service::AM::Applets::SwkbdTextDrawType text_draw_type; 28 Service::AM::Frontend::SwkbdTextDrawType text_draw_type;
29 Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; 29 Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
30 bool use_blur_background; 30 bool use_blur_background;
31 bool enable_backspace_button; 31 bool enable_backspace_button;
32 bool enable_return_button; 32 bool enable_return_button;
@@ -40,8 +40,8 @@ struct InlineAppearParameters {
40 f32 key_top_scale_y; 40 f32 key_top_scale_y;
41 f32 key_top_translate_x; 41 f32 key_top_translate_x;
42 f32 key_top_translate_y; 42 f32 key_top_translate_y;
43 Service::AM::Applets::SwkbdType type; 43 Service::AM::Frontend::SwkbdType type;
44 Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; 44 Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
45 bool key_top_as_floating; 45 bool key_top_as_floating;
46 bool enable_backspace_button; 46 bool enable_backspace_button;
47 bool enable_return_button; 47 bool enable_return_button;
@@ -56,9 +56,9 @@ struct InlineTextParameters {
56class SoftwareKeyboardApplet : public Applet { 56class SoftwareKeyboardApplet : public Applet {
57public: 57public:
58 using SubmitInlineCallback = 58 using SubmitInlineCallback =
59 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; 59 std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>;
60 using SubmitNormalCallback = 60 using SubmitNormalCallback =
61 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>; 61 std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>;
62 62
63 virtual ~SoftwareKeyboardApplet(); 63 virtual ~SoftwareKeyboardApplet();
64 64
@@ -69,7 +69,7 @@ public:
69 69
70 virtual void ShowNormalKeyboard() const = 0; 70 virtual void ShowNormalKeyboard() const = 0;
71 71
72 virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 72 virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
73 std::u16string text_check_message) const = 0; 73 std::u16string text_check_message) const = 0;
74 74
75 virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0; 75 virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
@@ -93,7 +93,7 @@ public:
93 93
94 void ShowNormalKeyboard() const override; 94 void ShowNormalKeyboard() const override;
95 95
96 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 96 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
97 std::u16string text_check_message) const override; 97 std::u16string text_check_message) const override;
98 98
99 void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override; 99 void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
index 6e703ef06..eca8d6d98 100644
--- a/src/core/frontend/applets/web_browser.cpp
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -18,7 +18,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url,
18 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}", 18 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
19 local_url); 19 local_url);
20 20
21 callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); 21 callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
22} 22}
23 23
24void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url, 24void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url,
@@ -26,7 +26,7 @@ void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_ur
26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}", 26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
27 external_url); 27 external_url);
28 28
29 callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); 29 callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
30} 30}
31 31
32} // namespace Core::Frontend 32} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
index 178bbdd3f..b70856a22 100644
--- a/src/core/frontend/applets/web_browser.h
+++ b/src/core/frontend/applets/web_browser.h
@@ -6,7 +6,7 @@
6#include <functional> 6#include <functional>
7 7
8#include "core/frontend/applets/applet.h" 8#include "core/frontend/applets/applet.h"
9#include "core/hle/service/am/applets/applet_web_browser_types.h" 9#include "core/hle/service/am/frontend/applet_web_browser_types.h"
10 10
11namespace Core::Frontend { 11namespace Core::Frontend {
12 12
@@ -14,7 +14,7 @@ class WebBrowserApplet : public Applet {
14public: 14public:
15 using ExtractROMFSCallback = std::function<void()>; 15 using ExtractROMFSCallback = std::function<void()>;
16 using OpenWebPageCallback = 16 using OpenWebPageCallback =
17 std::function<void(Service::AM::Applets::WebExitReason, std::string)>; 17 std::function<void(Service::AM::Frontend::WebExitReason, std::string)>;
18 18
19 virtual ~WebBrowserApplet(); 19 virtual ~WebBrowserApplet();
20 20
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f3683cdcc..34b25be66 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -97,8 +97,14 @@ struct KernelCore::Impl {
97 RegisterHostThread(nullptr); 97 RegisterHostThread(nullptr);
98 } 98 }
99 99
100 void TerminateApplicationProcess() { 100 void TerminateAllProcesses() {
101 application_process.load()->Terminate(); 101 std::scoped_lock lk{process_list_lock};
102 for (auto& process : process_list) {
103 process->Terminate();
104 process->Close();
105 process = nullptr;
106 }
107 process_list.clear();
102 } 108 }
103 109
104 void Shutdown() { 110 void Shutdown() {
@@ -107,18 +113,9 @@ struct KernelCore::Impl {
107 113
108 CloseServices(); 114 CloseServices();
109 115
110 auto* old_process = application_process.exchange(nullptr); 116 if (application_process) {
111 if (old_process) { 117 application_process->Close();
112 old_process->Close(); 118 application_process = nullptr;
113 }
114
115 {
116 std::scoped_lock lk{process_list_lock};
117 for (auto* const process : process_list) {
118 process->Terminate();
119 process->Close();
120 }
121 process_list.clear();
122 } 119 }
123 120
124 next_object_id = 0; 121 next_object_id = 0;
@@ -354,6 +351,7 @@ struct KernelCore::Impl {
354 351
355 void MakeApplicationProcess(KProcess* process) { 352 void MakeApplicationProcess(KProcess* process) {
356 application_process = process; 353 application_process = process;
354 application_process->Open();
357 } 355 }
358 356
359 static inline thread_local u8 host_thread_id = UINT8_MAX; 357 static inline thread_local u8 host_thread_id = UINT8_MAX;
@@ -779,7 +777,7 @@ struct KernelCore::Impl {
779 // Lists all processes that exist in the current session. 777 // Lists all processes that exist in the current session.
780 std::mutex process_list_lock; 778 std::mutex process_list_lock;
781 std::vector<KProcess*> process_list; 779 std::vector<KProcess*> process_list;
782 std::atomic<KProcess*> application_process{}; 780 KProcess* application_process{};
783 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; 781 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
784 std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; 782 std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
785 783
@@ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) {
1243} 1241}
1244 1242
1245void KernelCore::ShutdownCores() { 1243void KernelCore::ShutdownCores() {
1246 impl->TerminateApplicationProcess(); 1244 impl->TerminateAllProcesses();
1247 1245
1248 KScopedSchedulerLock lk{*this}; 1246 KScopedSchedulerLock lk{*this};
1249 1247
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 38f67adcd..8f90eba34 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1,2704 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm>
5#include <array>
6#include <cinttypes>
7#include <cstring>
8#include "common/settings.h"
9#include "common/settings_enums.h"
10#include "core/core.h"
11#include "core/core_timing.h"
12#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/savedata_factory.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/kernel/k_transfer_memory.h"
18#include "core/hle/result.h"
19#include "core/hle/service/acc/profile_manager.h"
20#include "core/hle/service/am/am.h" 4#include "core/hle/service/am/am.h"
21#include "core/hle/service/am/applet_ae.h" 5#include "core/hle/service/am/applet_ae.h"
22#include "core/hle/service/am/applet_oe.h" 6#include "core/hle/service/am/applet_oe.h"
23#include "core/hle/service/am/applets/applet_cabinet.h"
24#include "core/hle/service/am/applets/applet_controller.h"
25#include "core/hle/service/am/applets/applet_mii_edit_types.h"
26#include "core/hle/service/am/applets/applet_profile_select.h"
27#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
28#include "core/hle/service/am/applets/applet_web_browser.h"
29#include "core/hle/service/am/applets/applets.h"
30#include "core/hle/service/am/idle.h" 7#include "core/hle/service/am/idle.h"
31#include "core/hle/service/am/omm.h" 8#include "core/hle/service/am/omm.h"
32#include "core/hle/service/am/spsm.h" 9#include "core/hle/service/am/spsm.h"
33#include "core/hle/service/apm/apm_controller.h"
34#include "core/hle/service/apm/apm_interface.h"
35#include "core/hle/service/bcat/backend/backend.h"
36#include "core/hle/service/caps/caps_su.h"
37#include "core/hle/service/caps/caps_types.h"
38#include "core/hle/service/filesystem/filesystem.h"
39#include "core/hle/service/filesystem/save_data_controller.h"
40#include "core/hle/service/ipc_helpers.h"
41#include "core/hle/service/ns/ns.h"
42#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
43#include "core/hle/service/nvnflinger/nvnflinger.h"
44#include "core/hle/service/pm/pm.h"
45#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
46#include "core/hle/service/sm/sm.h"
47#include "core/hle/service/vi/vi.h"
48#include "core/hle/service/vi/vi_results.h"
49#include "core/memory.h"
50#include "hid_core/hid_types.h"
51#include "hid_core/resources/npad/npad.h"
52 11
53namespace Service::AM { 12namespace Service::AM {
54 13
55constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
56constexpr Result ResultNoMessages{ErrorModule::AM, 3};
57constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
58
59enum class LaunchParameterKind : u32 {
60 UserChannel = 1,
61 AccountPreselectedUser = 2,
62};
63
64constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA;
65
66struct LaunchParameterAccountPreselectedUser {
67 u32_le magic;
68 u32_le is_account_selected;
69 Common::UUID current_user;
70 INSERT_PADDING_BYTES(0x70);
71};
72static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
73
74IWindowController::IWindowController(Core::System& system_)
75 : ServiceFramework{system_, "IWindowController"} {
76 // clang-format off
77 static const FunctionInfo functions[] = {
78 {0, nullptr, "CreateWindow"},
79 {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
80 {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
81 {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
82 {11, nullptr, "ReleaseForegroundRights"},
83 {12, nullptr, "RejectToChangeIntoBackground"},
84 {20, nullptr, "SetAppletWindowVisibility"},
85 {21, nullptr, "SetAppletGpuTimeSlice"},
86 };
87 // clang-format on
88
89 RegisterHandlers(functions);
90}
91
92IWindowController::~IWindowController() = default;
93
94void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
95 const u64 process_id = system.ApplicationProcess()->GetProcessId();
96
97 LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
98
99 IPC::ResponseBuilder rb{ctx, 4};
100 rb.Push(ResultSuccess);
101 rb.Push<u64>(process_id);
102}
103
104void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
105 const u64 process_id = 0;
106
107 LOG_WARNING(Service_AM, "(STUBBED) called");
108
109 IPC::ResponseBuilder rb{ctx, 4};
110 rb.Push(ResultSuccess);
111 rb.Push<u64>(process_id);
112}
113
114void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
115 LOG_WARNING(Service_AM, "(STUBBED) called");
116 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(ResultSuccess);
118}
119
120IAudioController::IAudioController(Core::System& system_)
121 : ServiceFramework{system_, "IAudioController"} {
122 // clang-format off
123 static const FunctionInfo functions[] = {
124 {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
125 {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
126 {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
127 {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
128 {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
129 };
130 // clang-format on
131
132 RegisterHandlers(functions);
133}
134
135IAudioController::~IAudioController() = default;
136
137void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
138 IPC::RequestParser rp{ctx};
139 const float main_applet_volume_tmp = rp.Pop<float>();
140 const float library_applet_volume_tmp = rp.Pop<float>();
141
142 LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
143 main_applet_volume_tmp, library_applet_volume_tmp);
144
145 // Ensure the volume values remain within the 0-100% range
146 main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
147 library_applet_volume =
148 std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
149
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(ResultSuccess);
152}
153
154void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
155 LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
156 IPC::ResponseBuilder rb{ctx, 3};
157 rb.Push(ResultSuccess);
158 rb.Push(main_applet_volume);
159}
160
161void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
162 LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
163 IPC::ResponseBuilder rb{ctx, 3};
164 rb.Push(ResultSuccess);
165 rb.Push(library_applet_volume);
166}
167
168void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
169 struct Parameters {
170 float volume;
171 s64 fade_time_ns;
172 };
173 static_assert(sizeof(Parameters) == 16);
174
175 IPC::RequestParser rp{ctx};
176 const auto parameters = rp.PopRaw<Parameters>();
177
178 LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
179 parameters.fade_time_ns);
180
181 main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
182 fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
183
184 IPC::ResponseBuilder rb{ctx, 2};
185 rb.Push(ResultSuccess);
186}
187
188void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
189 IPC::RequestParser rp{ctx};
190 const float transparent_volume_rate_tmp = rp.Pop<float>();
191
192 LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
193
194 // Clamp volume range to 0-100%.
195 transparent_volume_rate =
196 std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
197
198 IPC::ResponseBuilder rb{ctx, 2};
199 rb.Push(ResultSuccess);
200}
201
202IDisplayController::IDisplayController(Core::System& system_)
203 : ServiceFramework{system_, "IDisplayController"} {
204 // clang-format off
205 static const FunctionInfo functions[] = {
206 {0, nullptr, "GetLastForegroundCaptureImage"},
207 {1, nullptr, "UpdateLastForegroundCaptureImage"},
208 {2, nullptr, "GetLastApplicationCaptureImage"},
209 {3, nullptr, "GetCallerAppletCaptureImage"},
210 {4, nullptr, "UpdateCallerAppletCaptureImage"},
211 {5, nullptr, "GetLastForegroundCaptureImageEx"},
212 {6, nullptr, "GetLastApplicationCaptureImageEx"},
213 {7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
214 {8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
215 {9, nullptr, "CopyBetweenCaptureBuffers"},
216 {10, nullptr, "AcquireLastApplicationCaptureBuffer"},
217 {11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
218 {12, nullptr, "AcquireLastForegroundCaptureBuffer"},
219 {13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
220 {14, nullptr, "AcquireCallerAppletCaptureBuffer"},
221 {15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
222 {16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
223 {17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
224 {18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
225 {20, nullptr, "ClearCaptureBuffer"},
226 {21, nullptr, "ClearAppletTransitionBuffer"},
227 {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"},
228 {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
229 {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
230 {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
231 {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
232 {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
233 {28, nullptr, "TakeScreenShotOfOwnLayerEx"},
234 };
235 // clang-format on
236
237 RegisterHandlers(functions);
238}
239
240IDisplayController::~IDisplayController() = default;
241
242void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
243 LOG_WARNING(Service_AM, "(STUBBED) called");
244
245 IPC::ResponseBuilder rb{ctx, 4};
246 rb.Push(ResultSuccess);
247 rb.Push(1u);
248 rb.Push(0);
249}
250
251void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
252 LOG_WARNING(Service_AM, "(STUBBED) called");
253
254 IPC::ResponseBuilder rb{ctx, 2};
255 rb.Push(ResultSuccess);
256}
257
258void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
259 LOG_WARNING(Service_AM, "(STUBBED) called");
260
261 IPC::ResponseBuilder rb{ctx, 4};
262 rb.Push(ResultSuccess);
263 rb.Push(1U);
264 rb.Push(0);
265}
266
267void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
268 LOG_WARNING(Service_AM, "(STUBBED) called");
269
270 IPC::ResponseBuilder rb{ctx, 2};
271 rb.Push(ResultSuccess);
272}
273
274void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
275 LOG_WARNING(Service_AM, "(STUBBED) called");
276
277 IPC::ResponseBuilder rb{ctx, 4};
278 rb.Push(ResultSuccess);
279 rb.Push(1U);
280 rb.Push(0);
281}
282
283void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
284 LOG_WARNING(Service_AM, "(STUBBED) called");
285
286 IPC::ResponseBuilder rb{ctx, 2};
287 rb.Push(ResultSuccess);
288}
289
290IDebugFunctions::IDebugFunctions(Core::System& system_)
291 : ServiceFramework{system_, "IDebugFunctions"} {
292 // clang-format off
293 static const FunctionInfo functions[] = {
294 {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
295 {1, nullptr, "OpenMainApplication"},
296 {10, nullptr, "PerformSystemButtonPressing"},
297 {20, nullptr, "InvalidateTransitionLayer"},
298 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
299 {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
300 {40, nullptr, "GetAppletResourceUsageInfo"},
301 {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
302 {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
303 {100, nullptr, "SetCpuBoostModeForApplet"},
304 {101, nullptr, "CancelCpuBoostModeForApplet"},
305 {110, nullptr, "PushToAppletBoundChannelForDebug"},
306 {111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
307 {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
308 {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
309 {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
310 {130, nullptr, "FriendInvitationSetApplicationParameter"},
311 {131, nullptr, "FriendInvitationClearApplicationParameter"},
312 {132, nullptr, "FriendInvitationPushApplicationParameter"},
313 {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
314 {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
315 {300, nullptr, "TerminateAllRunningApplicationsForDebug"},
316 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
317 };
318 // clang-format on
319
320 RegisterHandlers(functions);
321}
322
323IDebugFunctions::~IDebugFunctions() = default;
324
325ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
326 : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_},
327 service_context{system, "ISelfController"} {
328 // clang-format off
329 static const FunctionInfo functions[] = {
330 {0, &ISelfController::Exit, "Exit"},
331 {1, &ISelfController::LockExit, "LockExit"},
332 {2, &ISelfController::UnlockExit, "UnlockExit"},
333 {3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
334 {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
335 {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
336 {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
337 {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
338 {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
339 {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
340 {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
341 {15, nullptr, "SetScreenShotAppletIdentityInfo"},
342 {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
343 {17, nullptr, "SetControllerFirmwareUpdateSection"},
344 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
345 {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
346 {20, nullptr, "SetDesirableKeyboardLayout"},
347 {21, nullptr, "GetScreenShotProgramId"},
348 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
349 {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
350 {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
351 {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
352 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
353 {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
354 {46, nullptr, "SetRecordingLayerCompositionEnabled"},
355 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
356 {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
357 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
358 {61, nullptr, "SetMediaPlaybackState"},
359 {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
360 {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
361 {64, nullptr, "SetInputDetectionSourceSet"},
362 {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"},
363 {66, nullptr, "GetCurrentIlluminance"},
364 {67, nullptr, "IsIlluminanceAvailable"},
365 {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
366 {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
367 {70, nullptr, "ReportMultimediaError"},
368 {71, nullptr, "GetCurrentIlluminanceEx"},
369 {72, nullptr, "SetInputDetectionPolicy"},
370 {80, nullptr, "SetWirelessPriorityMode"},
371 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
372 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
373 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
374 {110, nullptr, "SetApplicationAlbumUserData"},
375 {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
376 {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"},
377 {1000, nullptr, "GetDebugStorageChannel"},
378 };
379 // clang-format on
380
381 RegisterHandlers(functions);
382
383 launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent");
384
385 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
386 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
387 // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
388 // suspended if the event has previously been created by a call to
389 // GetAccumulatedSuspendedTickChangedEvent.
390
391 accumulated_suspended_tick_changed_event =
392 service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent");
393 accumulated_suspended_tick_changed_event->Signal();
394}
395
396ISelfController::~ISelfController() {
397 service_context.CloseEvent(launchable_event);
398 service_context.CloseEvent(accumulated_suspended_tick_changed_event);
399}
400
401void ISelfController::Exit(HLERequestContext& ctx) {
402 LOG_DEBUG(Service_AM, "called");
403
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(ResultSuccess);
406
407 system.Exit();
408}
409
410void ISelfController::LockExit(HLERequestContext& ctx) {
411 LOG_DEBUG(Service_AM, "called");
412
413 system.SetExitLocked(true);
414
415 IPC::ResponseBuilder rb{ctx, 2};
416 rb.Push(ResultSuccess);
417}
418
419void ISelfController::UnlockExit(HLERequestContext& ctx) {
420 LOG_DEBUG(Service_AM, "called");
421
422 system.SetExitLocked(false);
423
424 IPC::ResponseBuilder rb{ctx, 2};
425 rb.Push(ResultSuccess);
426
427 if (system.GetExitRequested()) {
428 system.Exit();
429 }
430}
431
432void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
433 ++num_fatal_sections_entered;
434 LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered);
435
436 IPC::ResponseBuilder rb{ctx, 2};
437 rb.Push(ResultSuccess);
438}
439
440void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
441 LOG_DEBUG(Service_AM, "called.");
442
443 // Entry and exit of fatal sections must be balanced.
444 if (num_fatal_sections_entered == 0) {
445 IPC::ResponseBuilder rb{ctx, 2};
446 rb.Push(Result{ErrorModule::AM, 512});
447 return;
448 }
449
450 --num_fatal_sections_entered;
451
452 IPC::ResponseBuilder rb{ctx, 2};
453 rb.Push(ResultSuccess);
454}
455
456void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
457 LOG_WARNING(Service_AM, "(STUBBED) called");
458
459 launchable_event->Signal();
460
461 IPC::ResponseBuilder rb{ctx, 2, 1};
462 rb.Push(ResultSuccess);
463 rb.PushCopyObjects(launchable_event->GetReadableEvent());
464}
465
466void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
467 IPC::RequestParser rp{ctx};
468 const auto permission = rp.PopEnum<ScreenshotPermission>();
469 LOG_DEBUG(Service_AM, "called, permission={}", permission);
470
471 screenshot_permission = permission;
472
473 IPC::ResponseBuilder rb{ctx, 2};
474 rb.Push(ResultSuccess);
475}
476
477void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
478 IPC::RequestParser rp{ctx};
479
480 bool flag = rp.Pop<bool>();
481 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
482
483 IPC::ResponseBuilder rb{ctx, 2};
484 rb.Push(ResultSuccess);
485}
486
487void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
488 IPC::RequestParser rp{ctx};
489
490 bool flag = rp.Pop<bool>();
491 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
492
493 IPC::ResponseBuilder rb{ctx, 2};
494 rb.Push(ResultSuccess);
495}
496
497void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
498 // Takes 3 input u8s with each field located immediately after the previous
499 // u8, these are bool flags. No output.
500 IPC::RequestParser rp{ctx};
501
502 struct FocusHandlingModeParams {
503 u8 unknown0;
504 u8 unknown1;
505 u8 unknown2;
506 };
507 const auto flags = rp.PopRaw<FocusHandlingModeParams>();
508
509 LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
510 flags.unknown0, flags.unknown1, flags.unknown2);
511
512 IPC::ResponseBuilder rb{ctx, 2};
513 rb.Push(ResultSuccess);
514}
515
516void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
517 LOG_WARNING(Service_AM, "(STUBBED) called");
518
519 IPC::ResponseBuilder rb{ctx, 2};
520 rb.Push(ResultSuccess);
521}
522
523void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
524 // Takes 3 input u8s with each field located immediately after the previous
525 // u8, these are bool flags. No output.
526 IPC::RequestParser rp{ctx};
527
528 bool enabled = rp.Pop<bool>();
529 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
530
531 IPC::ResponseBuilder rb{ctx, 2};
532 rb.Push(ResultSuccess);
533}
534
535void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
536 LOG_WARNING(Service_AM, "(STUBBED) called");
537
538 IPC::ResponseBuilder rb{ctx, 2};
539 rb.Push(ResultSuccess);
540}
541
542void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
543 LOG_WARNING(Service_AM, "(STUBBED) called");
544
545 // TODO(Subv): Find out how AM determines the display to use, for now just
546 // create the layer in the Default display.
547 const auto display_id = nvnflinger.OpenDisplay("Default");
548 const auto layer_id = nvnflinger.CreateLayer(*display_id);
549
550 IPC::ResponseBuilder rb{ctx, 4};
551 rb.Push(ResultSuccess);
552 rb.Push(*layer_id);
553}
554
555void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
556 LOG_WARNING(Service_AM, "(STUBBED) called");
557
558 IPC::ResponseBuilder rb{ctx, 2};
559 rb.Push(this->EnsureBufferSharingEnabled());
560}
561
562void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
563 LOG_WARNING(Service_AM, "(STUBBED) called");
564
565 IPC::ResponseBuilder rb{ctx, 6};
566 rb.Push(this->EnsureBufferSharingEnabled());
567 rb.Push<s64>(system_shared_buffer_id);
568 rb.Push<s64>(system_shared_layer_id);
569}
570
571void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
572 LOG_WARNING(Service_AM, "(STUBBED) called");
573
574 IPC::ResponseBuilder rb{ctx, 4};
575 rb.Push(this->EnsureBufferSharingEnabled());
576 rb.Push<s64>(system_shared_buffer_id);
577}
578
579Result ISelfController::EnsureBufferSharingEnabled() {
580 if (buffer_sharing_enabled) {
581 return ResultSuccess;
582 }
583
584 if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) {
585 return VI::ResultOperationFailed;
586 }
587
588 const auto display_id = nvnflinger.OpenDisplay("Default");
589 const auto result = nvnflinger.GetSystemBufferManager().Initialize(
590 &system_shared_buffer_id, &system_shared_layer_id, *display_id);
591
592 if (result.IsSuccess()) {
593 buffer_sharing_enabled = true;
594 }
595
596 return result;
597}
598
599void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
600 LOG_WARNING(Service_AM, "(STUBBED) called");
601
602 // TODO(Subv): Find out how AM determines the display to use, for now just
603 // create the layer in the Default display.
604 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
605 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
606 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
607 // side effects.
608 // TODO: Support multiple layers
609 const auto display_id = nvnflinger.OpenDisplay("Default");
610 const auto layer_id = nvnflinger.CreateLayer(*display_id);
611
612 IPC::ResponseBuilder rb{ctx, 4};
613 rb.Push(ResultSuccess);
614 rb.Push(*layer_id);
615}
616
617void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
618 LOG_WARNING(Service_AM, "(STUBBED) called");
619
620 IPC::ResponseBuilder rb{ctx, 2};
621 rb.Push(ResultSuccess);
622}
623
624void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
625 LOG_WARNING(Service_AM, "(STUBBED) called");
626
627 IPC::ResponseBuilder rb{ctx, 2};
628 rb.Push(ResultSuccess);
629}
630
631void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
632 IPC::RequestParser rp{ctx};
633 idle_time_detection_extension = rp.Pop<u32>();
634 LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
635 idle_time_detection_extension);
636
637 IPC::ResponseBuilder rb{ctx, 2};
638 rb.Push(ResultSuccess);
639}
640
641void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
642 LOG_WARNING(Service_AM, "(STUBBED) called");
643
644 IPC::ResponseBuilder rb{ctx, 3};
645 rb.Push(ResultSuccess);
646 rb.Push<u32>(idle_time_detection_extension);
647}
648
649void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
650 LOG_WARNING(Service_AM, "(STUBBED) called");
651
652 IPC::ResponseBuilder rb{ctx, 2};
653 rb.Push(ResultSuccess);
654}
655
656void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
657 IPC::RequestParser rp{ctx};
658 is_auto_sleep_disabled = rp.Pop<bool>();
659
660 // On the system itself, if the previous state of is_auto_sleep_disabled
661 // differed from the current value passed in, it'd signify the internal
662 // window manager to update (and also increment some statistics like update counts)
663 //
664 // It'd also indicate this change to an idle handling context.
665 //
666 // However, given we're emulating this behavior, most of this can be ignored
667 // and it's sufficient to simply set the member variable for querying via
668 // IsAutoSleepDisabled().
669
670 LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled);
671
672 IPC::ResponseBuilder rb{ctx, 2};
673 rb.Push(ResultSuccess);
674}
675
676void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
677 LOG_DEBUG(Service_AM, "called.");
678
679 IPC::ResponseBuilder rb{ctx, 3};
680 rb.Push(ResultSuccess);
681 rb.Push(is_auto_sleep_disabled);
682}
683
684void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
685 LOG_DEBUG(Service_AM, "called.");
686
687 // This command returns the total number of system ticks since ISelfController creation
688 // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
689 // can just always return 0 ticks.
690 IPC::ResponseBuilder rb{ctx, 4};
691 rb.Push(ResultSuccess);
692 rb.Push<u64>(0);
693}
694
695void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
696 LOG_DEBUG(Service_AM, "called.");
697
698 IPC::ResponseBuilder rb{ctx, 2, 1};
699 rb.Push(ResultSuccess);
700 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
701}
702
703void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
704 IPC::RequestParser rp{ctx};
705
706 // This service call sets an internal flag whether a notification is shown when an image is
707 // captured. Currently we do not support capturing images via the capture button, so this can be
708 // stubbed for now.
709 const bool album_image_taken_notification_enabled = rp.Pop<bool>();
710
711 LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}",
712 album_image_taken_notification_enabled);
713
714 IPC::ResponseBuilder rb{ctx, 2};
715 rb.Push(ResultSuccess);
716}
717
718void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
719 IPC::RequestParser rp{ctx};
720
721 const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
722
723 LOG_INFO(Service_AM, "called, report_option={}", report_option);
724
725 const auto screenshot_service =
726 system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
727 "caps:su");
728
729 if (screenshot_service) {
730 screenshot_service->CaptureAndSaveScreenshot(report_option);
731 }
732
733 IPC::ResponseBuilder rb{ctx, 2};
734 rb.Push(ResultSuccess);
735}
736
737void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
738 IPC::RequestParser rp{ctx};
739
740 const auto is_record_volume_muted = rp.Pop<bool>();
741
742 LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted);
743
744 IPC::ResponseBuilder rb{ctx, 2};
745 rb.Push(ResultSuccess);
746}
747
748AppletMessageQueue::AppletMessageQueue(Core::System& system)
749 : service_context{system, "AppletMessageQueue"} {
750 on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
751 on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
752}
753
754AppletMessageQueue::~AppletMessageQueue() {
755 service_context.CloseEvent(on_new_message);
756 service_context.CloseEvent(on_operation_mode_changed);
757}
758
759Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
760 return on_new_message->GetReadableEvent();
761}
762
763Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
764 return on_operation_mode_changed->GetReadableEvent();
765}
766
767void AppletMessageQueue::PushMessage(AppletMessage msg) {
768 messages.push(msg);
769 on_new_message->Signal();
770}
771
772AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
773 if (messages.empty()) {
774 on_new_message->Clear();
775 return AppletMessage::None;
776 }
777 auto msg = messages.front();
778 messages.pop();
779 if (messages.empty()) {
780 on_new_message->Clear();
781 }
782 return msg;
783}
784
785std::size_t AppletMessageQueue::GetMessageCount() const {
786 return messages.size();
787}
788
789void AppletMessageQueue::RequestExit() {
790 PushMessage(AppletMessage::Exit);
791}
792
793void AppletMessageQueue::RequestResume() {
794 PushMessage(AppletMessage::Resume);
795}
796
797void AppletMessageQueue::FocusStateChanged() {
798 PushMessage(AppletMessage::FocusStateChanged);
799}
800
801void AppletMessageQueue::OperationModeChanged() {
802 PushMessage(AppletMessage::OperationModeChanged);
803 PushMessage(AppletMessage::PerformanceModeChanged);
804 on_operation_mode_changed->Signal();
805}
806
807ILockAccessor::ILockAccessor(Core::System& system_)
808 : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
809 // clang-format off
810 static const FunctionInfo functions[] = {
811 {1, &ILockAccessor::TryLock, "TryLock"},
812 {2, &ILockAccessor::Unlock, "Unlock"},
813 {3, &ILockAccessor::GetEvent, "GetEvent"},
814 {4,&ILockAccessor::IsLocked, "IsLocked"},
815 };
816 // clang-format on
817
818 RegisterHandlers(functions);
819
820 lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
821}
822
823ILockAccessor::~ILockAccessor() {
824 service_context.CloseEvent(lock_event);
825};
826
827void ILockAccessor::TryLock(HLERequestContext& ctx) {
828 IPC::RequestParser rp{ctx};
829 const auto return_handle = rp.Pop<bool>();
830
831 LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
832
833 // TODO: When return_handle is true this function should return the lock handle
834
835 is_locked = true;
836
837 IPC::ResponseBuilder rb{ctx, 3};
838 rb.Push(ResultSuccess);
839 rb.Push<u8>(is_locked);
840}
841
842void ILockAccessor::Unlock(HLERequestContext& ctx) {
843 LOG_INFO(Service_AM, "called");
844
845 is_locked = false;
846
847 IPC::ResponseBuilder rb{ctx, 2};
848 rb.Push(ResultSuccess);
849}
850
851void ILockAccessor::GetEvent(HLERequestContext& ctx) {
852 LOG_INFO(Service_AM, "called");
853
854 lock_event->Signal();
855
856 IPC::ResponseBuilder rb{ctx, 2, 1};
857 rb.Push(ResultSuccess);
858 rb.PushCopyObjects(lock_event->GetReadableEvent());
859}
860
861void ILockAccessor::IsLocked(HLERequestContext& ctx) {
862 LOG_INFO(Service_AM, "called");
863
864 IPC::ResponseBuilder rb{ctx, 2};
865 rb.Push(ResultSuccess);
866 rb.Push<u8>(is_locked);
867}
868
869ICommonStateGetter::ICommonStateGetter(Core::System& system_,
870 std::shared_ptr<AppletMessageQueue> msg_queue_)
871 : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
872 service_context{system_, "ICommonStateGetter"} {
873 // clang-format off
874 static const FunctionInfo functions[] = {
875 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
876 {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
877 {2, nullptr, "GetThisAppletKind"},
878 {3, nullptr, "AllowToEnterSleep"},
879 {4, nullptr, "DisallowToEnterSleep"},
880 {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
881 {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
882 {7, nullptr, "GetCradleStatus"},
883 {8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
884 {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
885 {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
886 {11, nullptr, "ReleaseSleepLock"},
887 {12, nullptr, "ReleaseSleepLockTransiently"},
888 {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
889 {14, nullptr, "GetWakeupCount"},
890 {20, nullptr, "PushToGeneralChannel"},
891 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
892 {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
893 {32, nullptr, "GetWriterLockAccessorEx"},
894 {40, nullptr, "GetCradleFwVersion"},
895 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
896 {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
897 {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
898 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
899 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
900 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
901 {59, nullptr, "SetVrPositionForDebug"},
902 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
903 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
904 {62, nullptr, "GetHdcpAuthenticationState"},
905 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
906 {64, nullptr, "SetTvPowerStateMatchingMode"},
907 {65, nullptr, "GetApplicationIdByContentActionName"},
908 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
909 {67, nullptr, "CancelCpuBoostMode"},
910 {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
911 {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
912 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
913 {91, nullptr, "GetCurrentPerformanceConfiguration"},
914 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
915 {110, nullptr, "OpenMyGpuErrorHandler"},
916 {120, nullptr, "GetAppletLaunchedHistory"},
917 {200, nullptr, "GetOperationModeSystemInfo"},
918 {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
919 {400, nullptr, "ActivateMigrationService"},
920 {401, nullptr, "DeactivateMigrationService"},
921 {500, nullptr, "DisableSleepTillShutdown"},
922 {501, nullptr, "SuppressDisablingSleepTemporarily"},
923 {502, nullptr, "IsSleepEnabled"},
924 {503, nullptr, "IsDisablingSleepSuppressed"},
925 {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
926 };
927 // clang-format on
928
929 RegisterHandlers(functions);
930
931 sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent");
932
933 // Configure applets to be in foreground state
934 msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
935 msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
936}
937
938ICommonStateGetter::~ICommonStateGetter() {
939 service_context.CloseEvent(sleep_lock_event);
940};
941
942void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
943 LOG_DEBUG(Service_AM, "called");
944
945 IPC::ResponseBuilder rb{ctx, 3};
946 rb.Push(ResultSuccess);
947 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
948}
949
950void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
951 LOG_DEBUG(Service_AM, "called");
952
953 IPC::ResponseBuilder rb{ctx, 2, 1};
954 rb.Push(ResultSuccess);
955 rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent());
956}
957
958void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
959 LOG_DEBUG(Service_AM, "called");
960
961 const auto message = msg_queue->PopMessage();
962 IPC::ResponseBuilder rb{ctx, 3};
963
964 if (message == AppletMessageQueue::AppletMessage::None) {
965 LOG_ERROR(Service_AM, "Message queue is empty");
966 rb.Push(AM::ResultNoMessages);
967 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
968 return;
969 }
970
971 rb.Push(ResultSuccess);
972 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
973}
974
975void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
976 LOG_DEBUG(Service_AM, "(STUBBED) called");
977
978 IPC::ResponseBuilder rb{ctx, 3};
979 rb.Push(ResultSuccess);
980 rb.Push(static_cast<u8>(FocusState::InFocus));
981}
982
983void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
984 LOG_WARNING(Service_AM, "(STUBBED) called");
985
986 // Sleep lock is acquired immediately.
987 sleep_lock_event->Signal();
988
989 IPC::ResponseBuilder rb{ctx, 2};
990 rb.Push(ResultSuccess);
991}
992
993void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
994 IPC::RequestParser rp{ctx};
995 const auto unknown = rp.Pop<u32>();
996
997 LOG_INFO(Service_AM, "called, unknown={}", unknown);
998
999 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1000
1001 rb.Push(ResultSuccess);
1002 rb.PushIpcInterface<ILockAccessor>(system);
1003}
1004
1005void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
1006 LOG_WARNING(Service_AM, "called");
1007
1008 IPC::ResponseBuilder rb{ctx, 2, 1};
1009 rb.Push(ResultSuccess);
1010 rb.PushCopyObjects(sleep_lock_event->GetReadableEvent());
1011}
1012
1013void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
1014 LOG_DEBUG(Service_AM, "called");
1015
1016 IPC::ResponseBuilder rb{ctx, 3};
1017 rb.Push(ResultSuccess);
1018 rb.Push(vr_mode_state);
1019}
1020
1021void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
1022 IPC::RequestParser rp{ctx};
1023 vr_mode_state = rp.Pop<bool>();
1024
1025 LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off");
1026
1027 IPC::ResponseBuilder rb{ctx, 2};
1028 rb.Push(ResultSuccess);
1029}
1030
1031void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
1032 IPC::RequestParser rp{ctx};
1033 const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
1034
1035 LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
1036 is_lcd_backlight_off_enabled);
1037
1038 IPC::ResponseBuilder rb{ctx, 2};
1039 rb.Push(ResultSuccess);
1040}
1041
1042void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
1043 LOG_WARNING(Service_AM, "(STUBBED) called");
1044
1045 IPC::ResponseBuilder rb{ctx, 2};
1046 rb.Push(ResultSuccess);
1047}
1048
1049void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
1050 LOG_WARNING(Service_AM, "(STUBBED) called");
1051
1052 IPC::ResponseBuilder rb{ctx, 2};
1053 rb.Push(ResultSuccess);
1054}
1055
1056void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
1057 LOG_DEBUG(Service_AM, "called");
1058
1059 IPC::ResponseBuilder rb{ctx, 2, 1};
1060 rb.Push(ResultSuccess);
1061 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
1062}
1063
1064void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
1065 LOG_DEBUG(Service_AM, "called");
1066
1067 IPC::ResponseBuilder rb{ctx, 4};
1068 rb.Push(ResultSuccess);
1069
1070 if (Settings::IsDockedMode()) {
1071 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
1072 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
1073 } else {
1074 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
1075 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
1076 }
1077}
1078
1079void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
1080 LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
1081
1082 const auto& sm = system.ServiceManager();
1083 const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
1084 ASSERT(apm_sys != nullptr);
1085
1086 apm_sys->SetCpuBoostMode(ctx);
1087}
1088
1089void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
1090 LOG_WARNING(Service_AM, "(STUBBED) called");
1091
1092 IPC::ResponseBuilder rb{ctx, 3};
1093 rb.Push(ResultSuccess);
1094 rb.Push(0);
1095}
1096
1097void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
1098 IPC::RequestParser rp{ctx};
1099 const auto system_button{rp.PopEnum<SystemButtonType>()};
1100
1101 LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button);
1102
1103 IPC::ResponseBuilder rb{ctx, 2};
1104 rb.Push(ResultSuccess);
1105}
1106
1107void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) {
1108 LOG_WARNING(Service_AM, "(STUBBED) called");
1109
1110 IPC::ResponseBuilder rb{ctx, 3};
1111 rb.Push(ResultSuccess);
1112 rb.PushEnum(SysPlatformRegion::Global);
1113}
1114
1115void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
1116 HLERequestContext& ctx) {
1117 LOG_WARNING(Service_AM, "(STUBBED) called");
1118
1119 IPC::ResponseBuilder rb{ctx, 2};
1120 rb.Push(ResultSuccess);
1121}
1122
1123IStorageImpl::~IStorageImpl() = default;
1124
1125class StorageDataImpl final : public IStorageImpl {
1126public:
1127 explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {}
1128
1129 std::vector<u8>& GetData() override {
1130 return buffer;
1131 }
1132
1133 const std::vector<u8>& GetData() const override {
1134 return buffer;
1135 }
1136
1137 std::size_t GetSize() const override {
1138 return buffer.size();
1139 }
1140
1141private:
1142 std::vector<u8> buffer;
1143};
1144
1145IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer)
1146 : ServiceFramework{system_, "IStorage"}, impl{std::make_shared<StorageDataImpl>(
1147 std::move(buffer))} {
1148 Register();
1149}
1150
1151void IStorage::Register() {
1152 // clang-format off
1153 static const FunctionInfo functions[] = {
1154 {0, &IStorage::Open, "Open"},
1155 {1, nullptr, "OpenTransferStorage"},
1156 };
1157 // clang-format on
1158
1159 RegisterHandlers(functions);
1160}
1161
1162IStorage::~IStorage() = default;
1163
1164void IStorage::Open(HLERequestContext& ctx) {
1165 LOG_DEBUG(Service_AM, "called");
1166
1167 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1168
1169 rb.Push(ResultSuccess);
1170 rb.PushIpcInterface<IStorageAccessor>(system, *this);
1171}
1172
1173void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
1174 const bool use_docked_mode{Settings::IsDockedMode()};
1175 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
1176
1177 IPC::ResponseBuilder rb{ctx, 3};
1178 rb.Push(ResultSuccess);
1179 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
1180}
1181
1182void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
1183 LOG_DEBUG(Service_AM, "called");
1184
1185 IPC::ResponseBuilder rb{ctx, 3};
1186 rb.Push(ResultSuccess);
1187 rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
1188}
1189
1190class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
1191public:
1192 explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<Applets::Applet> applet_)
1193 : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} {
1194 // clang-format off
1195 static const FunctionInfo functions[] = {
1196 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
1197 {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
1198 {10, &ILibraryAppletAccessor::Start, "Start"},
1199 {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
1200 {25, nullptr, "Terminate"},
1201 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
1202 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
1203 {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},
1204 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
1205 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
1206 {102, nullptr, "PushExtraStorage"},
1207 {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
1208 {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
1209 {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
1210 {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
1211 {110, nullptr, "NeedsToExitProcess"},
1212 {120, nullptr, "GetLibraryAppletInfo"},
1213 {150, nullptr, "RequestForAppletToGetForeground"},
1214 {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"},
1215 };
1216 // clang-format on
1217
1218 RegisterHandlers(functions);
1219 }
1220
1221private:
1222 void GetAppletStateChangedEvent(HLERequestContext& ctx) {
1223 LOG_DEBUG(Service_AM, "called");
1224
1225 IPC::ResponseBuilder rb{ctx, 2, 1};
1226 rb.Push(ResultSuccess);
1227 rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent());
1228 }
1229
1230 void IsCompleted(HLERequestContext& ctx) {
1231 LOG_DEBUG(Service_AM, "called");
1232
1233 IPC::ResponseBuilder rb{ctx, 3};
1234 rb.Push(ResultSuccess);
1235 rb.Push<u32>(applet->TransactionComplete());
1236 }
1237
1238 void GetResult(HLERequestContext& ctx) {
1239 LOG_DEBUG(Service_AM, "called");
1240
1241 IPC::ResponseBuilder rb{ctx, 2};
1242 rb.Push(applet->GetStatus());
1243 }
1244
1245 void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
1246 LOG_WARNING(Service_AM, "(STUBBED) called");
1247
1248 IPC::ResponseBuilder rb{ctx, 2};
1249 rb.Push(ResultSuccess);
1250 }
1251
1252 void Start(HLERequestContext& ctx) {
1253 LOG_DEBUG(Service_AM, "called");
1254
1255 ASSERT(applet != nullptr);
1256
1257 applet->Initialize();
1258 applet->Execute();
1259
1260 IPC::ResponseBuilder rb{ctx, 2};
1261 rb.Push(ResultSuccess);
1262 }
1263
1264 void RequestExit(HLERequestContext& ctx) {
1265 LOG_DEBUG(Service_AM, "called");
1266
1267 ASSERT(applet != nullptr);
1268
1269 IPC::ResponseBuilder rb{ctx, 2};
1270 rb.Push(applet->RequestExit());
1271 }
1272
1273 void PushInData(HLERequestContext& ctx) {
1274 LOG_DEBUG(Service_AM, "called");
1275
1276 IPC::RequestParser rp{ctx};
1277 applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock());
1278
1279 IPC::ResponseBuilder rb{ctx, 2};
1280 rb.Push(ResultSuccess);
1281 }
1282
1283 void PopOutData(HLERequestContext& ctx) {
1284 LOG_DEBUG(Service_AM, "called");
1285
1286 auto storage = applet->GetBroker().PopNormalDataToGame();
1287 if (storage == nullptr) {
1288 LOG_DEBUG(Service_AM,
1289 "storage is a nullptr. There is no data in the current normal channel");
1290 IPC::ResponseBuilder rb{ctx, 2};
1291 rb.Push(AM::ResultNoDataInChannel);
1292 return;
1293 }
1294
1295 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1296 rb.Push(ResultSuccess);
1297 rb.PushIpcInterface<IStorage>(std::move(storage));
1298 }
1299
1300 void PushInteractiveInData(HLERequestContext& ctx) {
1301 LOG_DEBUG(Service_AM, "called");
1302
1303 IPC::RequestParser rp{ctx};
1304 applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock());
1305
1306 ASSERT(applet->IsInitialized());
1307 applet->ExecuteInteractive();
1308 applet->Execute();
1309
1310 IPC::ResponseBuilder rb{ctx, 2};
1311 rb.Push(ResultSuccess);
1312 }
1313
1314 void PopInteractiveOutData(HLERequestContext& ctx) {
1315 LOG_DEBUG(Service_AM, "called");
1316
1317 auto storage = applet->GetBroker().PopInteractiveDataToGame();
1318 if (storage == nullptr) {
1319 LOG_DEBUG(Service_AM,
1320 "storage is a nullptr. There is no data in the current interactive channel");
1321 IPC::ResponseBuilder rb{ctx, 2};
1322 rb.Push(AM::ResultNoDataInChannel);
1323 return;
1324 }
1325
1326 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1327 rb.Push(ResultSuccess);
1328 rb.PushIpcInterface<IStorage>(std::move(storage));
1329 }
1330
1331 void GetPopOutDataEvent(HLERequestContext& ctx) {
1332 LOG_DEBUG(Service_AM, "called");
1333
1334 IPC::ResponseBuilder rb{ctx, 2, 1};
1335 rb.Push(ResultSuccess);
1336 rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
1337 }
1338
1339 void GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
1340 LOG_DEBUG(Service_AM, "called");
1341
1342 IPC::ResponseBuilder rb{ctx, 2, 1};
1343 rb.Push(ResultSuccess);
1344 rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
1345 }
1346
1347 void GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
1348 LOG_WARNING(Service_AM, "(STUBBED) called");
1349
1350 // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
1351 // actually used anywhere
1352 constexpr u64 handle = 0xdeadbeef;
1353
1354 IPC::ResponseBuilder rb{ctx, 4};
1355 rb.Push(ResultSuccess);
1356 rb.Push(handle);
1357 }
1358
1359 std::shared_ptr<Applets::Applet> applet;
1360};
1361
1362IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_)
1363 : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} {
1364 // clang-format off
1365 static const FunctionInfo functions[] = {
1366 {0, &IStorageAccessor::GetSize, "GetSize"},
1367 {10, &IStorageAccessor::Write, "Write"},
1368 {11, &IStorageAccessor::Read, "Read"},
1369 };
1370 // clang-format on
1371
1372 RegisterHandlers(functions);
1373}
1374
1375IStorageAccessor::~IStorageAccessor() = default;
1376
1377void IStorageAccessor::GetSize(HLERequestContext& ctx) {
1378 LOG_DEBUG(Service_AM, "called");
1379
1380 IPC::ResponseBuilder rb{ctx, 4};
1381
1382 rb.Push(ResultSuccess);
1383 rb.Push(static_cast<u64>(backing.GetSize()));
1384}
1385
1386void IStorageAccessor::Write(HLERequestContext& ctx) {
1387 IPC::RequestParser rp{ctx};
1388
1389 const u64 offset{rp.Pop<u64>()};
1390 const auto data{ctx.ReadBuffer()};
1391 const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
1392
1393 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
1394
1395 if (offset > backing.GetSize()) {
1396 LOG_ERROR(Service_AM,
1397 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
1398 backing.GetSize(), size, offset);
1399
1400 IPC::ResponseBuilder rb{ctx, 2};
1401 rb.Push(AM::ResultInvalidOffset);
1402 return;
1403 }
1404
1405 std::memcpy(backing.GetData().data() + offset, data.data(), size);
1406
1407 IPC::ResponseBuilder rb{ctx, 2};
1408 rb.Push(ResultSuccess);
1409}
1410
1411void IStorageAccessor::Read(HLERequestContext& ctx) {
1412 IPC::RequestParser rp{ctx};
1413
1414 const u64 offset{rp.Pop<u64>()};
1415 const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
1416
1417 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
1418
1419 if (offset > backing.GetSize()) {
1420 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
1421 backing.GetSize(), size, offset);
1422
1423 IPC::ResponseBuilder rb{ctx, 2};
1424 rb.Push(AM::ResultInvalidOffset);
1425 return;
1426 }
1427
1428 ctx.WriteBuffer(backing.GetData().data() + offset, size);
1429
1430 IPC::ResponseBuilder rb{ctx, 2};
1431 rb.Push(ResultSuccess);
1432}
1433
1434ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
1435 : ServiceFramework{system_, "ILibraryAppletCreator"} {
1436 static const FunctionInfo functions[] = {
1437 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
1438 {1, nullptr, "TerminateAllLibraryApplets"},
1439 {2, nullptr, "AreAnyLibraryAppletsLeft"},
1440 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
1441 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
1442 {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
1443 };
1444 RegisterHandlers(functions);
1445}
1446
1447ILibraryAppletCreator::~ILibraryAppletCreator() = default;
1448
1449void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
1450 IPC::RequestParser rp{ctx};
1451
1452 const auto applet_id = rp.PopRaw<Applets::AppletId>();
1453 const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
1454
1455 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
1456 applet_mode);
1457
1458 const auto& applet_manager{system.GetAppletManager()};
1459 const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
1460
1461 if (applet == nullptr) {
1462 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
1463
1464 IPC::ResponseBuilder rb{ctx, 2};
1465 rb.Push(ResultUnknown);
1466 return;
1467 }
1468
1469 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1470
1471 rb.Push(ResultSuccess);
1472 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
1473}
1474
1475void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
1476 IPC::RequestParser rp{ctx};
1477
1478 const s64 size{rp.Pop<s64>()};
1479
1480 LOG_DEBUG(Service_AM, "called, size={}", size);
1481
1482 if (size <= 0) {
1483 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1484 IPC::ResponseBuilder rb{ctx, 2};
1485 rb.Push(ResultUnknown);
1486 return;
1487 }
1488
1489 std::vector<u8> buffer(size);
1490
1491 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1492 rb.Push(ResultSuccess);
1493 rb.PushIpcInterface<IStorage>(system, std::move(buffer));
1494}
1495
1496void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
1497 IPC::RequestParser rp{ctx};
1498
1499 struct Parameters {
1500 u8 permissions;
1501 s64 size;
1502 };
1503
1504 const auto parameters{rp.PopRaw<Parameters>()};
1505 const auto handle{ctx.GetCopyHandle(0)};
1506
1507 LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
1508 parameters.size, handle);
1509
1510 if (parameters.size <= 0) {
1511 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1512 IPC::ResponseBuilder rb{ctx, 2};
1513 rb.Push(ResultUnknown);
1514 return;
1515 }
1516
1517 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
1518
1519 if (transfer_mem.IsNull()) {
1520 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1521 IPC::ResponseBuilder rb{ctx, 2};
1522 rb.Push(ResultUnknown);
1523 return;
1524 }
1525
1526 std::vector<u8> memory(transfer_mem->GetSize());
1527 ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
1528
1529 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1530 rb.Push(ResultSuccess);
1531 rb.PushIpcInterface<IStorage>(system, std::move(memory));
1532}
1533
1534void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
1535 IPC::RequestParser rp{ctx};
1536
1537 const s64 size{rp.Pop<s64>()};
1538 const auto handle{ctx.GetCopyHandle(0)};
1539
1540 LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
1541
1542 if (size <= 0) {
1543 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1544 IPC::ResponseBuilder rb{ctx, 2};
1545 rb.Push(ResultUnknown);
1546 return;
1547 }
1548
1549 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
1550
1551 if (transfer_mem.IsNull()) {
1552 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1553 IPC::ResponseBuilder rb{ctx, 2};
1554 rb.Push(ResultUnknown);
1555 return;
1556 }
1557
1558 std::vector<u8> memory(transfer_mem->GetSize());
1559 ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
1560
1561 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1562 rb.Push(ResultSuccess);
1563 rb.PushIpcInterface<IStorage>(system, std::move(memory));
1564}
1565
1566ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
1567 : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} {
1568 // clang-format off
1569 static const FunctionInfo functions[] = {
1570 {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"},
1571 {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"},
1572 {2, nullptr, "PopInteractiveInData"},
1573 {3, nullptr, "PushInteractiveOutData"},
1574 {5, nullptr, "GetPopInDataEvent"},
1575 {6, nullptr, "GetPopInteractiveInDataEvent"},
1576 {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
1577 {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
1578 {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
1579 {13, nullptr, "CanUseApplicationCore"},
1580 {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
1581 {15, nullptr, "GetMainAppletApplicationControlProperty"},
1582 {16, nullptr, "GetMainAppletStorageId"},
1583 {17, nullptr, "GetCallerAppletIdentityInfoStack"},
1584 {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
1585 {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
1586 {20, nullptr, "PopExtraStorage"},
1587 {25, nullptr, "GetPopExtraStorageEvent"},
1588 {30, nullptr, "UnpopInData"},
1589 {31, nullptr, "UnpopExtraStorage"},
1590 {40, nullptr, "GetIndirectLayerProducerHandle"},
1591 {50, nullptr, "ReportVisibleError"},
1592 {51, nullptr, "ReportVisibleErrorWithErrorContext"},
1593 {60, nullptr, "GetMainAppletApplicationDesiredLanguage"},
1594 {70, nullptr, "GetCurrentApplicationId"},
1595 {80, nullptr, "RequestExitToSelf"},
1596 {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
1597 {100, nullptr, "CreateGameMovieTrimmer"},
1598 {101, nullptr, "ReserveResourceForMovieOperation"},
1599 {102, nullptr, "UnreserveResourceForMovieOperation"},
1600 {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
1601 {120, nullptr, "GetLaunchStorageInfoForDebug"},
1602 {130, nullptr, "GetGpuErrorDetectedSystemEvent"},
1603 {140, nullptr, "SetApplicationMemoryReservation"},
1604 {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
1605 };
1606 // clang-format on
1607 RegisterHandlers(functions);
1608
1609 switch (system.GetAppletManager().GetCurrentAppletId()) {
1610 case Applets::AppletId::Cabinet:
1611 PushInShowCabinetData();
1612 break;
1613 case Applets::AppletId::MiiEdit:
1614 PushInShowMiiEditData();
1615 break;
1616 case Applets::AppletId::PhotoViewer:
1617 PushInShowAlbum();
1618 break;
1619 case Applets::AppletId::SoftwareKeyboard:
1620 PushInShowSoftwareKeyboard();
1621 break;
1622 case Applets::AppletId::Controller:
1623 PushInShowController();
1624 break;
1625 default:
1626 break;
1627 }
1628}
1629
1630ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
1631void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
1632 LOG_INFO(Service_AM, "called");
1633
1634 if (queue_data.empty()) {
1635 IPC::ResponseBuilder rb{ctx, 2};
1636 rb.Push(ResultNoDataInChannel);
1637 return;
1638 }
1639
1640 auto data = queue_data.front();
1641 queue_data.pop_front();
1642
1643 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1644 rb.Push(ResultSuccess);
1645 rb.PushIpcInterface<IStorage>(system, std::move(data));
1646}
1647
1648void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) {
1649 LOG_WARNING(Service_AM, "(STUBBED) called");
1650
1651 IPC::ResponseBuilder rb{ctx, 2};
1652 rb.Push(ResultSuccess);
1653}
1654
1655void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
1656 LOG_WARNING(Service_AM, "(STUBBED) called");
1657
1658 system.Exit();
1659
1660 IPC::ResponseBuilder rb{ctx, 2};
1661 rb.Push(ResultSuccess);
1662}
1663
1664void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
1665 struct LibraryAppletInfo {
1666 Applets::AppletId applet_id;
1667 Applets::LibraryAppletMode library_applet_mode;
1668 };
1669
1670 LOG_WARNING(Service_AM, "(STUBBED) called");
1671
1672 const LibraryAppletInfo applet_info{
1673 .applet_id = system.GetAppletManager().GetCurrentAppletId(),
1674 .library_applet_mode = Applets::LibraryAppletMode::AllForeground,
1675 };
1676
1677 IPC::ResponseBuilder rb{ctx, 4};
1678 rb.Push(ResultSuccess);
1679 rb.PushRaw(applet_info);
1680}
1681
1682void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
1683 struct AppletIdentityInfo {
1684 Applets::AppletId applet_id;
1685 INSERT_PADDING_BYTES(0x4);
1686 u64 application_id;
1687 };
1688 static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
1689
1690 LOG_WARNING(Service_AM, "(STUBBED) called");
1691
1692 const AppletIdentityInfo applet_info{
1693 .applet_id = Applets::AppletId::QLaunch,
1694 .application_id = 0x0100000000001000ull,
1695 };
1696
1697 IPC::ResponseBuilder rb{ctx, 6};
1698 rb.Push(ResultSuccess);
1699 rb.PushRaw(applet_info);
1700}
1701
1702void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
1703 struct AppletIdentityInfo {
1704 Applets::AppletId applet_id;
1705 INSERT_PADDING_BYTES(0x4);
1706 u64 application_id;
1707 };
1708 static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
1709 LOG_WARNING(Service_AM, "(STUBBED) called");
1710
1711 const AppletIdentityInfo applet_info{
1712 .applet_id = Applets::AppletId::QLaunch,
1713 .application_id = 0x0100000000001000ull,
1714 };
1715
1716 IPC::ResponseBuilder rb{ctx, 6};
1717 rb.Push(ResultSuccess);
1718 rb.PushRaw(applet_info);
1719}
1720
1721void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) {
1722 LOG_WARNING(Service_AM, "(STUBBED) called");
1723
1724 IPC::ResponseBuilder rb{ctx, 3};
1725 rb.Push(ResultSuccess);
1726 rb.Push<u32>(0);
1727}
1728
1729void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
1730 const Service::Account::ProfileManager manager{};
1731 bool is_empty{true};
1732 s32 user_count{-1};
1733
1734 LOG_INFO(Service_AM, "called");
1735
1736 if (manager.GetUserCount() > 0) {
1737 is_empty = false;
1738 user_count = static_cast<s32>(manager.GetUserCount());
1739 ctx.WriteBuffer(manager.GetAllUsers());
1740 }
1741
1742 IPC::ResponseBuilder rb{ctx, 4};
1743 rb.Push(ResultSuccess);
1744 rb.Push<u8>(is_empty);
1745 rb.Push(user_count);
1746}
1747
1748void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) {
1749 LOG_WARNING(Service_AM, "(STUBBED) called");
1750
1751 IPC::ResponseBuilder rb{ctx, 2};
1752 rb.Push(ResultSuccess);
1753 rb.Push<u8>(0);
1754}
1755
1756void ILibraryAppletSelfAccessor::PushInShowAlbum() {
1757 const Applets::CommonArguments arguments{
1758 .arguments_version = Applets::CommonArgumentVersion::Version3,
1759 .size = Applets::CommonArgumentSize::Version3,
1760 .library_version = 1,
1761 .theme_color = Applets::ThemeColor::BasicBlack,
1762 .play_startup_sound = true,
1763 .system_tick = system.CoreTiming().GetClockTicks(),
1764 };
1765
1766 std::vector<u8> argument_data(sizeof(arguments));
1767 std::vector<u8> settings_data{2};
1768 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1769 queue_data.emplace_back(std::move(argument_data));
1770 queue_data.emplace_back(std::move(settings_data));
1771}
1772
1773void ILibraryAppletSelfAccessor::PushInShowController() {
1774 const Applets::CommonArguments common_args = {
1775 .arguments_version = Applets::CommonArgumentVersion::Version3,
1776 .size = Applets::CommonArgumentSize::Version3,
1777 .library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8),
1778 .theme_color = Applets::ThemeColor::BasicBlack,
1779 .play_startup_sound = true,
1780 .system_tick = system.CoreTiming().GetClockTicks(),
1781 };
1782
1783 Applets::ControllerSupportArgNew user_args = {
1784 .header = {.player_count_min = 1,
1785 .player_count_max = 4,
1786 .enable_take_over_connection = true,
1787 .enable_left_justify = false,
1788 .enable_permit_joy_dual = true,
1789 .enable_single_mode = false,
1790 .enable_identification_color = false},
1791 .identification_colors = {},
1792 .enable_explain_text = false,
1793 .explain_text = {},
1794 };
1795
1796 Applets::ControllerSupportArgPrivate private_args = {
1797 .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate),
1798 .arg_size = sizeof(Applets::ControllerSupportArgNew),
1799 .is_home_menu = true,
1800 .flag_1 = true,
1801 .mode = Applets::ControllerSupportMode::ShowControllerSupport,
1802 .caller = Applets::ControllerSupportCaller::
1803 Application, // switchbrew: Always zero except with
1804 // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
1805 // which sets this to the input param
1806 .style_set = Core::HID::NpadStyleSet::None,
1807 .joy_hold_type = 0,
1808 };
1809 std::vector<u8> common_args_data(sizeof(common_args));
1810 std::vector<u8> private_args_data(sizeof(private_args));
1811 std::vector<u8> user_args_data(sizeof(user_args));
1812
1813 std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
1814 std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
1815 std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
1816
1817 queue_data.emplace_back(std::move(common_args_data));
1818 queue_data.emplace_back(std::move(private_args_data));
1819 queue_data.emplace_back(std::move(user_args_data));
1820}
1821
1822void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
1823 const Applets::CommonArguments arguments{
1824 .arguments_version = Applets::CommonArgumentVersion::Version3,
1825 .size = Applets::CommonArgumentSize::Version3,
1826 .library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1),
1827 .theme_color = Applets::ThemeColor::BasicBlack,
1828 .play_startup_sound = true,
1829 .system_tick = system.CoreTiming().GetClockTicks(),
1830 };
1831
1832 const Applets::StartParamForAmiiboSettings amiibo_settings{
1833 .param_1 = 0,
1834 .applet_mode = system.GetAppletManager().GetCabinetMode(),
1835 .flags = Applets::CabinetFlags::None,
1836 .amiibo_settings_1 = 0,
1837 .device_handle = 0,
1838 .tag_info{},
1839 .register_info{},
1840 .amiibo_settings_3{},
1841 };
1842
1843 std::vector<u8> argument_data(sizeof(arguments));
1844 std::vector<u8> settings_data(sizeof(amiibo_settings));
1845 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1846 std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
1847 queue_data.emplace_back(std::move(argument_data));
1848 queue_data.emplace_back(std::move(settings_data));
1849}
1850
1851void ILibraryAppletSelfAccessor::PushInShowMiiEditData() {
1852 struct MiiEditV3 {
1853 Applets::MiiEditAppletInputCommon common;
1854 Applets::MiiEditAppletInputV3 input;
1855 };
1856 static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
1857
1858 MiiEditV3 mii_arguments{
1859 .common =
1860 {
1861 .version = Applets::MiiEditAppletVersion::Version3,
1862 .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit,
1863 },
1864 .input{},
1865 };
1866
1867 std::vector<u8> argument_data(sizeof(mii_arguments));
1868 std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
1869
1870 queue_data.emplace_back(std::move(argument_data));
1871}
1872
1873void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() {
1874 const Applets::CommonArguments arguments{
1875 .arguments_version = Applets::CommonArgumentVersion::Version3,
1876 .size = Applets::CommonArgumentSize::Version3,
1877 .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301),
1878 .theme_color = Applets::ThemeColor::BasicBlack,
1879 .play_startup_sound = true,
1880 .system_tick = system.CoreTiming().GetClockTicks(),
1881 };
1882
1883 std::vector<char16_t> initial_string(0);
1884
1885 const Applets::SwkbdConfigCommon swkbd_config{
1886 .type = Applets::SwkbdType::Qwerty,
1887 .ok_text{},
1888 .left_optional_symbol_key{},
1889 .right_optional_symbol_key{},
1890 .use_prediction = false,
1891 .key_disable_flags{},
1892 .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start,
1893 .header_text{},
1894 .sub_text{},
1895 .guide_text{},
1896 .max_text_length = 500,
1897 .min_text_length = 0,
1898 .password_mode = Applets::SwkbdPasswordMode::Disabled,
1899 .text_draw_type = Applets::SwkbdTextDrawType::Box,
1900 .enable_return_button = true,
1901 .use_utf8 = false,
1902 .use_blur_background = true,
1903 .initial_string_offset{},
1904 .initial_string_length = static_cast<u32>(initial_string.size()),
1905 .user_dictionary_offset{},
1906 .user_dictionary_entries{},
1907 .use_text_check = false,
1908 };
1909
1910 Applets::SwkbdConfigNew swkbd_config_new{};
1911
1912 std::vector<u8> argument_data(sizeof(arguments));
1913 std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
1914 std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
1915
1916 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1917 std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
1918 std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
1919 sizeof(Applets::SwkbdConfigNew));
1920 std::memcpy(work_buffer.data(), initial_string.data(),
1921 swkbd_config.initial_string_length * sizeof(char16_t));
1922
1923 queue_data.emplace_back(std::move(argument_data));
1924 queue_data.emplace_back(std::move(swkbd_data));
1925 queue_data.emplace_back(std::move(work_buffer));
1926}
1927
1928IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_)
1929 : ServiceFramework{system_, "IAppletCommonFunctions"} {
1930 // clang-format off
1931 static const FunctionInfo functions[] = {
1932 {0, nullptr, "SetTerminateResult"},
1933 {10, nullptr, "ReadThemeStorage"},
1934 {11, nullptr, "WriteThemeStorage"},
1935 {20, nullptr, "PushToAppletBoundChannel"},
1936 {21, nullptr, "TryPopFromAppletBoundChannel"},
1937 {40, nullptr, "GetDisplayLogicalResolution"},
1938 {42, nullptr, "SetDisplayMagnification"},
1939 {50, nullptr, "SetHomeButtonDoubleClickEnabled"},
1940 {51, nullptr, "GetHomeButtonDoubleClickEnabled"},
1941 {52, nullptr, "IsHomeButtonShortPressedBlocked"},
1942 {60, nullptr, "IsVrModeCurtainRequired"},
1943 {61, nullptr, "IsSleepRequiredByHighTemperature"},
1944 {62, nullptr, "IsSleepRequiredByLowBattery"},
1945 {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"},
1946 {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
1947 {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
1948 {90, nullptr, "OpenNamedChannelAsParent"},
1949 {91, nullptr, "OpenNamedChannelAsChild"},
1950 {100, nullptr, "SetApplicationCoreUsageMode"},
1951 };
1952 // clang-format on
1953
1954 RegisterHandlers(functions);
1955}
1956
1957IAppletCommonFunctions::~IAppletCommonFunctions() = default;
1958
1959void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) {
1960 LOG_WARNING(Service_AM, "(STUBBED) called");
1961
1962 IPC::ResponseBuilder rb{ctx, 2};
1963 rb.Push(ResultSuccess);
1964}
1965
1966IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1967 : ServiceFramework{system_, "IApplicationFunctions"}, service_context{system,
1968 "IApplicationFunctions"} {
1969 // clang-format off
1970 static const FunctionInfo functions[] = {
1971 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
1972 {10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
1973 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
1974 {12, nullptr, "CreateApplicationAndRequestToStart"},
1975 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
1976 {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
1977 {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
1978 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
1979 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
1980 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
1981 {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
1982 {24, nullptr, "GetLaunchStorageInfoForDebug"},
1983 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
1984 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
1985 {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
1986 {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
1987 {29, nullptr, "GetCacheStorageMax"},
1988 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
1989 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
1990 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
1991 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
1992 {34, nullptr, "SelectApplicationLicense"},
1993 {35, nullptr, "GetDeviceSaveDataSizeMax"},
1994 {36, nullptr, "GetLimitedApplicationLicense"},
1995 {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
1996 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
1997 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
1998 {60, nullptr, "SetMediaPlaybackStateForApplication"},
1999 {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"},
2000 {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
2001 {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
2002 {68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
2003 {70, nullptr, "RequestToShutdown"},
2004 {71, nullptr, "RequestToReboot"},
2005 {72, nullptr, "RequestToSleep"},
2006 {80, nullptr, "ExitAndRequestToShowThanksMessage"},
2007 {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
2008 {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
2009 {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
2010 {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
2011 {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
2012 {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
2013 {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
2014 {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
2015 {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
2016 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
2017 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
2018 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
2019 {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
2020 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
2021 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
2022 {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"},
2023 {151, nullptr, "TryPopFromNotificationStorageChannel"},
2024 {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
2025 {170, nullptr, "SetHdcpAuthenticationActivated"},
2026 {180, nullptr, "GetLaunchRequiredVersion"},
2027 {181, nullptr, "UpgradeLaunchRequiredVersion"},
2028 {190, nullptr, "SendServerMaintenanceOverlayNotification"},
2029 {200, nullptr, "GetLastApplicationExitReason"},
2030 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
2031 {1000, nullptr, "CreateMovieMaker"},
2032 {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
2033 };
2034 // clang-format on
2035
2036 RegisterHandlers(functions);
2037
2038 gpu_error_detected_event =
2039 service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent");
2040 friend_invitation_storage_channel_event =
2041 service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent");
2042 notification_storage_channel_event =
2043 service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent");
2044 health_warning_disappeared_system_event =
2045 service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent");
2046}
2047
2048IApplicationFunctions::~IApplicationFunctions() {
2049 service_context.CloseEvent(gpu_error_detected_event);
2050 service_context.CloseEvent(friend_invitation_storage_channel_event);
2051 service_context.CloseEvent(notification_storage_channel_event);
2052 service_context.CloseEvent(health_warning_disappeared_system_event);
2053}
2054
2055void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
2056 LOG_WARNING(Service_AM, "(STUBBED) called");
2057
2058 IPC::ResponseBuilder rb{ctx, 2};
2059 rb.Push(ResultSuccess);
2060}
2061
2062void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
2063 LOG_WARNING(Service_AM, "(STUBBED) called");
2064
2065 IPC::ResponseBuilder rb{ctx, 2};
2066 rb.Push(ResultSuccess);
2067}
2068
2069void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
2070 LOG_WARNING(Service_AM, "(STUBBED) called");
2071
2072 IPC::ResponseBuilder rb{ctx, 2};
2073 rb.Push(ResultSuccess);
2074}
2075
2076void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
2077 IPC::RequestParser rp{ctx};
2078 const auto is_visible = rp.Pop<bool>();
2079
2080 LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible);
2081
2082 IPC::ResponseBuilder rb{ctx, 2};
2083 rb.Push(ResultSuccess);
2084}
2085
2086void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
2087 LOG_WARNING(Service_AM, "(STUBBED) called");
2088
2089 IPC::ResponseBuilder rb{ctx, 2};
2090 rb.Push(ResultSuccess);
2091}
2092
2093void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
2094 LOG_WARNING(Service_AM, "(STUBBED) called");
2095
2096 IPC::ResponseBuilder rb{ctx, 2};
2097 rb.Push(ResultSuccess);
2098}
2099
2100void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
2101 LOG_WARNING(Service_AM, "(STUBBED) called");
2102
2103 IPC::ResponseBuilder rb{ctx, 2};
2104 rb.Push(ResultSuccess);
2105}
2106
2107void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
2108 LOG_WARNING(Service_AM, "(STUBBED) called");
2109
2110 IPC::ResponseBuilder rb{ctx, 2};
2111 rb.Push(ResultSuccess);
2112}
2113
2114void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
2115 IPC::RequestParser rp{ctx};
2116 const auto kind = rp.PopEnum<LaunchParameterKind>();
2117
2118 LOG_INFO(Service_AM, "called, kind={:08X}", kind);
2119
2120 if (kind == LaunchParameterKind::UserChannel) {
2121 auto channel = system.GetUserChannel();
2122 if (channel.empty()) {
2123 LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
2124 IPC::ResponseBuilder rb{ctx, 2};
2125 rb.Push(AM::ResultNoDataInChannel);
2126 return;
2127 }
2128
2129 auto data = channel.back();
2130 channel.pop_back();
2131
2132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
2133 rb.Push(ResultSuccess);
2134 rb.PushIpcInterface<IStorage>(system, std::move(data));
2135 } else if (kind == LaunchParameterKind::AccountPreselectedUser &&
2136 !launch_popped_account_preselect) {
2137 // TODO: Verify this is hw-accurate
2138 LaunchParameterAccountPreselectedUser params{};
2139
2140 params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC;
2141 params.is_account_selected = 1;
2142
2143 Account::ProfileManager profile_manager{};
2144 const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
2145 ASSERT(uuid.has_value() && uuid->IsValid());
2146 params.current_user = *uuid;
2147
2148 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
2149 rb.Push(ResultSuccess);
2150
2151 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
2152 std::memcpy(buffer.data(), &params, buffer.size());
2153
2154 rb.PushIpcInterface<IStorage>(system, std::move(buffer));
2155 launch_popped_account_preselect = true;
2156 } else {
2157 LOG_ERROR(Service_AM, "Unknown launch parameter kind.");
2158 IPC::ResponseBuilder rb{ctx, 2};
2159 rb.Push(AM::ResultNoDataInChannel);
2160 }
2161}
2162
2163void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
2164 LOG_WARNING(Service_AM, "(STUBBED) called");
2165
2166 IPC::ResponseBuilder rb{ctx, 2};
2167 rb.Push(ResultSuccess);
2168}
2169
2170void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
2171 IPC::RequestParser rp{ctx};
2172 u128 user_id = rp.PopRaw<u128>();
2173
2174 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
2175
2176 FileSys::SaveDataAttribute attribute{};
2177 attribute.title_id = system.GetApplicationProcessProgramID();
2178 attribute.user_id = user_id;
2179 attribute.type = FileSys::SaveDataType::SaveData;
2180
2181 FileSys::VirtualDir save_data{};
2182 const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
2183 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
2184
2185 IPC::ResponseBuilder rb{ctx, 4};
2186 rb.Push(res);
2187 rb.Push<u64>(0);
2188}
2189
2190void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
2191 // Takes an input u32 Result, no output.
2192 // For example, in some cases official apps use this with error 0x2A2 then
2193 // uses svcBreak.
2194
2195 IPC::RequestParser rp{ctx};
2196 u32 result = rp.Pop<u32>();
2197 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
2198
2199 IPC::ResponseBuilder rb{ctx, 2};
2200 rb.Push(ResultSuccess);
2201}
2202
2203void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
2204 LOG_DEBUG(Service_AM, "called");
2205
2206 std::array<u8, 0x10> version_string{};
2207
2208 const auto res = [this] {
2209 const auto title_id = system.GetApplicationProcessProgramID();
2210
2211 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
2212 system.GetContentProvider()};
2213 auto metadata = pm.GetControlMetadata();
2214 if (metadata.first != nullptr) {
2215 return metadata;
2216 }
2217
2218 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
2219 system.GetFileSystemController(),
2220 system.GetContentProvider()};
2221 return pm_update.GetControlMetadata();
2222 }();
2223
2224 if (res.first != nullptr) {
2225 const auto& version = res.first->GetVersionString();
2226 std::copy(version.begin(), version.end(), version_string.begin());
2227 } else {
2228 static constexpr char default_version[]{"1.0.0"};
2229 std::memcpy(version_string.data(), default_version, sizeof(default_version));
2230 }
2231
2232 IPC::ResponseBuilder rb{ctx, 6};
2233 rb.Push(ResultSuccess);
2234 rb.PushRaw(version_string);
2235}
2236
2237void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
2238 // TODO(bunnei): This should be configurable
2239 LOG_DEBUG(Service_AM, "called");
2240
2241 // Get supported languages from NACP, if possible
2242 // Default to 0 (all languages supported)
2243 u32 supported_languages = 0;
2244
2245 const auto res = [this] {
2246 const auto title_id = system.GetApplicationProcessProgramID();
2247
2248 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
2249 system.GetContentProvider()};
2250 auto metadata = pm.GetControlMetadata();
2251 if (metadata.first != nullptr) {
2252 return metadata;
2253 }
2254
2255 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
2256 system.GetFileSystemController(),
2257 system.GetContentProvider()};
2258 return pm_update.GetControlMetadata();
2259 }();
2260
2261 if (res.first != nullptr) {
2262 supported_languages = res.first->GetSupportedLanguages();
2263 }
2264
2265 // Call IApplicationManagerInterface implementation.
2266 auto& service_manager = system.ServiceManager();
2267 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
2268 auto app_man = ns_am2->GetApplicationManagerInterface();
2269
2270 // Get desired application language
2271 u8 desired_language{};
2272 const auto res_lang =
2273 app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
2274 if (res_lang != ResultSuccess) {
2275 IPC::ResponseBuilder rb{ctx, 2};
2276 rb.Push(res_lang);
2277 return;
2278 }
2279
2280 // Convert to settings language code.
2281 u64 language_code{};
2282 const auto res_code =
2283 app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
2284 if (res_code != ResultSuccess) {
2285 IPC::ResponseBuilder rb{ctx, 2};
2286 rb.Push(res_code);
2287 return;
2288 }
2289
2290 LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
2291
2292 IPC::ResponseBuilder rb{ctx, 4};
2293 rb.Push(ResultSuccess);
2294 rb.Push(language_code);
2295}
2296
2297void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
2298 LOG_WARNING(Service_AM, "(STUBBED) called");
2299
2300 constexpr bool gameplay_recording_supported = false;
2301
2302 IPC::ResponseBuilder rb{ctx, 3};
2303 rb.Push(ResultSuccess);
2304 rb.Push(gameplay_recording_supported);
2305}
2306
2307void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
2308 LOG_WARNING(Service_AM, "(STUBBED) called");
2309
2310 IPC::ResponseBuilder rb{ctx, 2};
2311 rb.Push(ResultSuccess);
2312}
2313
2314void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
2315 LOG_WARNING(Service_AM, "(STUBBED) called");
2316
2317 IPC::ResponseBuilder rb{ctx, 2};
2318 rb.Push(ResultSuccess);
2319}
2320
2321void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
2322 LOG_WARNING(Service_AM, "(STUBBED) called");
2323
2324 IPC::ResponseBuilder rb{ctx, 3};
2325 rb.Push(ResultSuccess);
2326 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
2327}
2328
2329void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
2330 LOG_WARNING(Service_AM, "(STUBBED) called");
2331
2332 IPC::ResponseBuilder rb{ctx, 6};
2333 rb.Push(ResultSuccess);
2334
2335 // Returns a 128-bit UUID
2336 rb.Push<u64>(0);
2337 rb.Push<u64>(0);
2338}
2339
2340void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
2341 struct Parameters {
2342 FileSys::SaveDataType type;
2343 u128 user_id;
2344 u64 new_normal_size;
2345 u64 new_journal_size;
2346 };
2347 static_assert(sizeof(Parameters) == 40);
2348
2349 IPC::RequestParser rp{ctx};
2350 const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
2351
2352 LOG_DEBUG(Service_AM,
2353 "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
2354 "new_journal={:016X}",
2355 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
2356
2357 system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
2358 type, system.GetApplicationProcessProgramID(), user_id,
2359 {new_normal_size, new_journal_size});
2360
2361 IPC::ResponseBuilder rb{ctx, 4};
2362 rb.Push(ResultSuccess);
2363
2364 // The following value is used upon failure to help the system recover.
2365 // Since we always succeed, this should be 0.
2366 rb.Push<u64>(0);
2367}
2368
2369void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
2370 struct Parameters {
2371 FileSys::SaveDataType type;
2372 u128 user_id;
2373 };
2374 static_assert(sizeof(Parameters) == 24);
2375
2376 IPC::RequestParser rp{ctx};
2377 const auto [type, user_id] = rp.PopRaw<Parameters>();
2378
2379 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
2380 user_id[0]);
2381
2382 const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
2383 type, system.GetApplicationProcessProgramID(), user_id);
2384
2385 IPC::ResponseBuilder rb{ctx, 6};
2386 rb.Push(ResultSuccess);
2387 rb.Push(size.normal);
2388 rb.Push(size.journal);
2389}
2390
2391void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
2392 struct InputParameters {
2393 u16 index;
2394 s64 size;
2395 s64 journal_size;
2396 };
2397 static_assert(sizeof(InputParameters) == 24);
2398
2399 struct OutputParameters {
2400 u32 storage_target;
2401 u64 required_size;
2402 };
2403 static_assert(sizeof(OutputParameters) == 16);
2404
2405 IPC::RequestParser rp{ctx};
2406 const auto params = rp.PopRaw<InputParameters>();
2407
2408 LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
2409 params.index, params.size, params.journal_size);
2410
2411 const OutputParameters resp{
2412 .storage_target = 1,
2413 .required_size = 0,
2414 };
2415
2416 IPC::ResponseBuilder rb{ctx, 6};
2417 rb.Push(ResultSuccess);
2418 rb.PushRaw(resp);
2419}
2420
2421void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
2422 LOG_WARNING(Service_AM, "(STUBBED) called");
2423
2424 constexpr u64 size_max_normal = 0xFFFFFFF;
2425 constexpr u64 size_max_journal = 0xFFFFFFF;
2426
2427 IPC::ResponseBuilder rb{ctx, 6};
2428 rb.Push(ResultSuccess);
2429 rb.Push(size_max_normal);
2430 rb.Push(size_max_journal);
2431}
2432
2433void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
2434 LOG_WARNING(Service_AM, "(STUBBED) called");
2435
2436 IPC::ResponseBuilder rb{ctx, 3};
2437 rb.Push(ResultSuccess);
2438 rb.Push<u32>(0);
2439}
2440
2441void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
2442 LOG_WARNING(Service_AM, "(STUBBED) called");
2443
2444 IPC::ResponseBuilder rb{ctx, 3};
2445 rb.Push(ResultSuccess);
2446 rb.Push<u32>(0);
2447}
2448
2449void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
2450 LOG_WARNING(Service_AM, "(STUBBED) called");
2451
2452 IPC::RequestParser rp{ctx};
2453 [[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
2454 [[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
2455 const auto program_index = rp.Pop<u64>();
2456
2457 IPC::ResponseBuilder rb{ctx, 2};
2458 rb.Push(ResultSuccess);
2459
2460 system.ExecuteProgram(program_index);
2461}
2462
2463void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
2464 LOG_DEBUG(Service_AM, "called");
2465
2466 system.GetUserChannel().clear();
2467
2468 IPC::ResponseBuilder rb{ctx, 2};
2469 rb.Push(ResultSuccess);
2470}
2471
2472void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
2473 LOG_DEBUG(Service_AM, "called");
2474
2475 IPC::RequestParser rp{ctx};
2476 const auto storage = rp.PopIpcInterface<IStorage>().lock();
2477 if (storage) {
2478 system.GetUserChannel().push_back(storage->GetData());
2479 }
2480
2481 IPC::ResponseBuilder rb{ctx, 2};
2482 rb.Push(ResultSuccess);
2483}
2484
2485void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
2486 LOG_WARNING(Service_AM, "(STUBBED) called");
2487
2488 IPC::ResponseBuilder rb{ctx, 3};
2489 rb.Push(ResultSuccess);
2490 rb.Push<s32>(previous_program_index);
2491}
2492
2493void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
2494 LOG_WARNING(Service_AM, "(STUBBED) called");
2495
2496 IPC::ResponseBuilder rb{ctx, 2, 1};
2497 rb.Push(ResultSuccess);
2498 rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent());
2499}
2500
2501void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
2502 LOG_DEBUG(Service_AM, "called");
2503
2504 IPC::ResponseBuilder rb{ctx, 2, 1};
2505 rb.Push(ResultSuccess);
2506 rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent());
2507}
2508
2509void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
2510 LOG_DEBUG(Service_AM, "(STUBBED) called");
2511
2512 IPC::ResponseBuilder rb{ctx, 2};
2513 rb.Push(AM::ResultNoDataInChannel);
2514}
2515
2516void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
2517 LOG_DEBUG(Service_AM, "called");
2518
2519 IPC::ResponseBuilder rb{ctx, 2, 1};
2520 rb.Push(ResultSuccess);
2521 rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent());
2522}
2523
2524void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
2525 LOG_DEBUG(Service_AM, "called");
2526
2527 IPC::ResponseBuilder rb{ctx, 2, 1};
2528 rb.Push(ResultSuccess);
2529 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
2530}
2531
2532void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
2533 LOG_WARNING(Service_AM, "(STUBBED) called");
2534
2535 IPC::ResponseBuilder rb{ctx, 2};
2536 rb.Push(ResultSuccess);
2537}
2538
2539void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { 14void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
2540 auto message_queue = std::make_shared<AppletMessageQueue>(system);
2541 auto server_manager = std::make_unique<ServerManager>(system); 15 auto server_manager = std::make_unique<ServerManager>(system);
2542 16
2543 server_manager->RegisterNamedService( 17 server_manager->RegisterNamedService("appletAE",
2544 "appletAE", std::make_shared<AppletAE>(nvnflinger, message_queue, system)); 18 std::make_shared<AppletAE>(nvnflinger, system));
2545 server_manager->RegisterNamedService( 19 server_manager->RegisterNamedService("appletOE",
2546 "appletOE", std::make_shared<AppletOE>(nvnflinger, message_queue, system)); 20 std::make_shared<AppletOE>(nvnflinger, system));
2547 server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system)); 21 server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system));
2548 server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system)); 22 server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system));
2549 server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system)); 23 server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system));
2550 ServerManager::RunServer(std::move(server_manager)); 24 ServerManager::RunServer(std::move(server_manager));
2551} 25}
2552 26
2553IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
2554 : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
2555 "IHomeMenuFunctions"} {
2556 // clang-format off
2557 static const FunctionInfo functions[] = {
2558 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
2559 {11, nullptr, "LockForeground"},
2560 {12, nullptr, "UnlockForeground"},
2561 {20, nullptr, "PopFromGeneralChannel"},
2562 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
2563 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
2564 {31, nullptr, "GetWriterLockAccessorEx"},
2565 {40, nullptr, "IsSleepEnabled"},
2566 {41, nullptr, "IsRebootEnabled"},
2567 {50, nullptr, "LaunchSystemApplet"},
2568 {51, nullptr, "LaunchStarter"},
2569 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
2570 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
2571 {200, nullptr, "LaunchDevMenu"},
2572 {1000, nullptr, "SetLastApplicationExitReason"},
2573 };
2574 // clang-format on
2575
2576 RegisterHandlers(functions);
2577
2578 pop_from_general_channel_event =
2579 service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
2580}
2581
2582IHomeMenuFunctions::~IHomeMenuFunctions() {
2583 service_context.CloseEvent(pop_from_general_channel_event);
2584}
2585
2586void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
2587 LOG_WARNING(Service_AM, "(STUBBED) called");
2588
2589 IPC::ResponseBuilder rb{ctx, 2};
2590 rb.Push(ResultSuccess);
2591}
2592
2593void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
2594 LOG_WARNING(Service_AM, "(STUBBED) called");
2595
2596 IPC::ResponseBuilder rb{ctx, 2, 1};
2597 rb.Push(ResultSuccess);
2598 rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
2599}
2600
2601IGlobalStateController::IGlobalStateController(Core::System& system_)
2602 : ServiceFramework{system_, "IGlobalStateController"} {
2603 // clang-format off
2604 static const FunctionInfo functions[] = {
2605 {0, nullptr, "RequestToEnterSleep"},
2606 {1, nullptr, "EnterSleep"},
2607 {2, nullptr, "StartSleepSequence"},
2608 {3, nullptr, "StartShutdownSequence"},
2609 {4, nullptr, "StartRebootSequence"},
2610 {9, nullptr, "IsAutoPowerDownRequested"},
2611 {10, nullptr, "LoadAndApplyIdlePolicySettings"},
2612 {11, nullptr, "NotifyCecSettingsChanged"},
2613 {12, nullptr, "SetDefaultHomeButtonLongPressTime"},
2614 {13, nullptr, "UpdateDefaultDisplayResolution"},
2615 {14, nullptr, "ShouldSleepOnBoot"},
2616 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
2617 {30, nullptr, "OpenCradleFirmwareUpdater"},
2618 };
2619 // clang-format on
2620
2621 RegisterHandlers(functions);
2622}
2623
2624IGlobalStateController::~IGlobalStateController() = default;
2625
2626IApplicationCreator::IApplicationCreator(Core::System& system_)
2627 : ServiceFramework{system_, "IApplicationCreator"} {
2628 // clang-format off
2629 static const FunctionInfo functions[] = {
2630 {0, nullptr, "CreateApplication"},
2631 {1, nullptr, "PopLaunchRequestedApplication"},
2632 {10, nullptr, "CreateSystemApplication"},
2633 {100, nullptr, "PopFloatingApplicationForDevelopment"},
2634 };
2635 // clang-format on
2636
2637 RegisterHandlers(functions);
2638}
2639
2640IApplicationCreator::~IApplicationCreator() = default;
2641
2642IProcessWindingController::IProcessWindingController(Core::System& system_)
2643 : ServiceFramework{system_, "IProcessWindingController"} {
2644 // clang-format off
2645 static const FunctionInfo functions[] = {
2646 {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"},
2647 {11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"},
2648 {21, nullptr, "PushContext"},
2649 {22, nullptr, "PopContext"},
2650 {23, nullptr, "CancelWindingReservation"},
2651 {30, nullptr, "WindAndDoReserved"},
2652 {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
2653 {41, nullptr, "ReserveToStartAndWait"},
2654 };
2655 // clang-format on
2656
2657 RegisterHandlers(functions);
2658}
2659
2660IProcessWindingController::~IProcessWindingController() = default;
2661
2662void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
2663 LOG_WARNING(Service_AM, "(STUBBED) called");
2664
2665 struct AppletProcessLaunchReason {
2666 u8 flag;
2667 INSERT_PADDING_BYTES(3);
2668 };
2669 static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
2670 "AppletProcessLaunchReason is an invalid size");
2671
2672 AppletProcessLaunchReason reason{
2673 .flag = 0,
2674 };
2675
2676 IPC::ResponseBuilder rb{ctx, 3};
2677 rb.Push(ResultSuccess);
2678 rb.PushRaw(reason);
2679}
2680
2681void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
2682 const auto applet_id = system.GetAppletManager().GetCurrentAppletId();
2683 const auto applet_mode = Applets::LibraryAppletMode::AllForeground;
2684
2685 LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id,
2686 applet_mode);
2687
2688 const auto& applet_manager{system.GetAppletManager()};
2689 const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
2690
2691 if (applet == nullptr) {
2692 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
2693
2694 IPC::ResponseBuilder rb{ctx, 2};
2695 rb.Push(ResultUnknown);
2696 return;
2697 }
2698
2699 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
2700 rb.Push(ResultSuccess);
2701 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
2702}
2703
2704} // namespace Service::AM 27} // namespace Service::AM
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 905a71b9f..4a2d797bd 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -1,20 +1,11 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <chrono> 6namespace Core {
7#include <memory> 7class System;
8#include <queue> 8}
9
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h"
12
13namespace Kernel {
14class KernelCore;
15class KReadableEvent;
16class KTransferMemory;
17} // namespace Kernel
18 9
19namespace Service::Nvnflinger { 10namespace Service::Nvnflinger {
20class Nvnflinger; 11class Nvnflinger;
@@ -22,443 +13,6 @@ class Nvnflinger;
22 13
23namespace Service::AM { 14namespace Service::AM {
24 15
25class AppletMessageQueue {
26public:
27 // This is nn::am::AppletMessage
28 enum class AppletMessage : u32 {
29 None = 0,
30 ChangeIntoForeground = 1,
31 ChangeIntoBackground = 2,
32 Exit = 4,
33 ApplicationExited = 6,
34 FocusStateChanged = 15,
35 Resume = 16,
36 DetectShortPressingHomeButton = 20,
37 DetectLongPressingHomeButton = 21,
38 DetectShortPressingPowerButton = 22,
39 DetectMiddlePressingPowerButton = 23,
40 DetectLongPressingPowerButton = 24,
41 RequestToPrepareSleep = 25,
42 FinishedSleepSequence = 26,
43 SleepRequiredByHighTemperature = 27,
44 SleepRequiredByLowBattery = 28,
45 AutoPowerDown = 29,
46 OperationModeChanged = 30,
47 PerformanceModeChanged = 31,
48 DetectReceivingCecSystemStandby = 32,
49 SdCardRemoved = 33,
50 LaunchApplicationRequested = 50,
51 RequestToDisplay = 51,
52 ShowApplicationLogo = 55,
53 HideApplicationLogo = 56,
54 ForceHideApplicationLogo = 57,
55 FloatingApplicationDetected = 60,
56 DetectShortPressingCaptureButton = 90,
57 AlbumScreenShotTaken = 92,
58 AlbumRecordingSaved = 93,
59 };
60
61 explicit AppletMessageQueue(Core::System& system);
62 ~AppletMessageQueue();
63
64 Kernel::KReadableEvent& GetMessageReceiveEvent();
65 Kernel::KReadableEvent& GetOperationModeChangedEvent();
66 void PushMessage(AppletMessage msg);
67 AppletMessage PopMessage();
68 std::size_t GetMessageCount() const;
69 void RequestExit();
70 void RequestResume();
71 void FocusStateChanged();
72 void OperationModeChanged();
73
74private:
75 KernelHelpers::ServiceContext service_context;
76
77 Kernel::KEvent* on_new_message;
78 Kernel::KEvent* on_operation_mode_changed;
79
80 std::queue<AppletMessage> messages;
81};
82
83class IWindowController final : public ServiceFramework<IWindowController> {
84public:
85 explicit IWindowController(Core::System& system_);
86 ~IWindowController() override;
87
88private:
89 void GetAppletResourceUserId(HLERequestContext& ctx);
90 void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
91 void AcquireForegroundRights(HLERequestContext& ctx);
92};
93
94class IAudioController final : public ServiceFramework<IAudioController> {
95public:
96 explicit IAudioController(Core::System& system_);
97 ~IAudioController() override;
98
99private:
100 void SetExpectedMasterVolume(HLERequestContext& ctx);
101 void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
102 void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
103 void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
104 void SetTransparentAudioRate(HLERequestContext& ctx);
105
106 static constexpr float min_allowed_volume = 0.0f;
107 static constexpr float max_allowed_volume = 1.0f;
108
109 float main_applet_volume{0.25f};
110 float library_applet_volume{max_allowed_volume};
111 float transparent_volume_rate{min_allowed_volume};
112
113 // Volume transition fade time in nanoseconds.
114 // e.g. If the main applet volume was 0% and was changed to 50%
115 // with a fade of 50ns, then over the course of 50ns,
116 // the volume will gradually fade up to 50%
117 std::chrono::nanoseconds fade_time_ns{0};
118};
119
120class IDisplayController final : public ServiceFramework<IDisplayController> {
121public:
122 explicit IDisplayController(Core::System& system_);
123 ~IDisplayController() override;
124
125private:
126 void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
127 void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
128 void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
129 void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
130 void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
131 void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
132};
133
134class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
135public:
136 explicit IDebugFunctions(Core::System& system_);
137 ~IDebugFunctions() override;
138};
139
140class ISelfController final : public ServiceFramework<ISelfController> {
141public:
142 explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_);
143 ~ISelfController() override;
144
145private:
146 void Exit(HLERequestContext& ctx);
147 void LockExit(HLERequestContext& ctx);
148 void UnlockExit(HLERequestContext& ctx);
149 void EnterFatalSection(HLERequestContext& ctx);
150 void LeaveFatalSection(HLERequestContext& ctx);
151 void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
152 void SetScreenShotPermission(HLERequestContext& ctx);
153 void SetOperationModeChangedNotification(HLERequestContext& ctx);
154 void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
155 void SetFocusHandlingMode(HLERequestContext& ctx);
156 void SetRestartMessageEnabled(HLERequestContext& ctx);
157 void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
158 void SetAlbumImageOrientation(HLERequestContext& ctx);
159 void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
160 void GetSystemSharedBufferHandle(HLERequestContext& ctx);
161 void GetSystemSharedLayerHandle(HLERequestContext& ctx);
162 void CreateManagedDisplayLayer(HLERequestContext& ctx);
163 void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
164 void SetHandlesRequestToDisplay(HLERequestContext& ctx);
165 void ApproveToDisplay(HLERequestContext& ctx);
166 void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
167 void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
168 void ReportUserIsActive(HLERequestContext& ctx);
169 void SetAutoSleepDisabled(HLERequestContext& ctx);
170 void IsAutoSleepDisabled(HLERequestContext& ctx);
171 void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
172 void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
173 void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
174 void SaveCurrentScreenshot(HLERequestContext& ctx);
175 void SetRecordVolumeMuted(HLERequestContext& ctx);
176
177 Result EnsureBufferSharingEnabled();
178
179 enum class ScreenshotPermission : u32 {
180 Inherit = 0,
181 Enable = 1,
182 Disable = 2,
183 };
184
185 Nvnflinger::Nvnflinger& nvnflinger;
186
187 KernelHelpers::ServiceContext service_context;
188
189 Kernel::KEvent* launchable_event;
190 Kernel::KEvent* accumulated_suspended_tick_changed_event;
191
192 u32 idle_time_detection_extension = 0;
193 u64 num_fatal_sections_entered = 0;
194 u64 system_shared_buffer_id = 0;
195 u64 system_shared_layer_id = 0;
196 bool is_auto_sleep_disabled = false;
197 bool buffer_sharing_enabled = false;
198 ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
199};
200
201class ILockAccessor final : public ServiceFramework<ILockAccessor> {
202public:
203 explicit ILockAccessor(Core::System& system_);
204 ~ILockAccessor() override;
205
206private:
207 void TryLock(HLERequestContext& ctx);
208 void Unlock(HLERequestContext& ctx);
209 void GetEvent(HLERequestContext& ctx);
210 void IsLocked(HLERequestContext& ctx);
211
212 bool is_locked{};
213
214 Kernel::KEvent* lock_event;
215 KernelHelpers::ServiceContext service_context;
216};
217
218class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
219public:
220 explicit ICommonStateGetter(Core::System& system_,
221 std::shared_ptr<AppletMessageQueue> msg_queue_);
222 ~ICommonStateGetter() override;
223
224private:
225 // This is nn::oe::FocusState
226 enum class FocusState : u8 {
227 InFocus = 1,
228 NotInFocus = 2,
229 Background = 3,
230 };
231
232 // This is nn::oe::OperationMode
233 enum class OperationMode : u8 {
234 Handheld = 0,
235 Docked = 1,
236 };
237
238 // This is nn::am::service::SystemButtonType
239 enum class SystemButtonType {
240 None,
241 HomeButtonShortPressing,
242 HomeButtonLongPressing,
243 PowerButtonShortPressing,
244 PowerButtonLongPressing,
245 ShutdownSystem,
246 CaptureButtonShortPressing,
247 CaptureButtonLongPressing,
248 };
249
250 enum class SysPlatformRegion : s32 {
251 Global = 1,
252 Terra = 2,
253 };
254
255 void GetEventHandle(HLERequestContext& ctx);
256 void ReceiveMessage(HLERequestContext& ctx);
257 void GetCurrentFocusState(HLERequestContext& ctx);
258 void RequestToAcquireSleepLock(HLERequestContext& ctx);
259 void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
260 void GetReaderLockAccessorEx(HLERequestContext& ctx);
261 void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
262 void GetOperationMode(HLERequestContext& ctx);
263 void GetPerformanceMode(HLERequestContext& ctx);
264 void GetBootMode(HLERequestContext& ctx);
265 void IsVrModeEnabled(HLERequestContext& ctx);
266 void SetVrModeEnabled(HLERequestContext& ctx);
267 void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
268 void BeginVrModeEx(HLERequestContext& ctx);
269 void EndVrModeEx(HLERequestContext& ctx);
270 void GetDefaultDisplayResolution(HLERequestContext& ctx);
271 void SetCpuBoostMode(HLERequestContext& ctx);
272 void GetBuiltInDisplayType(HLERequestContext& ctx);
273 void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
274 void GetSettingsPlatformRegion(HLERequestContext& ctx);
275 void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
276
277 std::shared_ptr<AppletMessageQueue> msg_queue;
278 bool vr_mode_state{};
279 Kernel::KEvent* sleep_lock_event;
280 KernelHelpers::ServiceContext service_context;
281};
282
283class IStorageImpl {
284public:
285 virtual ~IStorageImpl();
286 virtual std::vector<u8>& GetData() = 0;
287 virtual const std::vector<u8>& GetData() const = 0;
288 virtual std::size_t GetSize() const = 0;
289};
290
291class IStorage final : public ServiceFramework<IStorage> {
292public:
293 explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
294 ~IStorage() override;
295
296 std::vector<u8>& GetData() {
297 return impl->GetData();
298 }
299
300 const std::vector<u8>& GetData() const {
301 return impl->GetData();
302 }
303
304 std::size_t GetSize() const {
305 return impl->GetSize();
306 }
307
308private:
309 void Register();
310 void Open(HLERequestContext& ctx);
311
312 std::shared_ptr<IStorageImpl> impl;
313};
314
315class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
316public:
317 explicit IStorageAccessor(Core::System& system_, IStorage& backing_);
318 ~IStorageAccessor() override;
319
320private:
321 void GetSize(HLERequestContext& ctx);
322 void Write(HLERequestContext& ctx);
323 void Read(HLERequestContext& ctx);
324
325 IStorage& backing;
326};
327
328class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
329public:
330 explicit ILibraryAppletCreator(Core::System& system_);
331 ~ILibraryAppletCreator() override;
332
333private:
334 void CreateLibraryApplet(HLERequestContext& ctx);
335 void CreateStorage(HLERequestContext& ctx);
336 void CreateTransferMemoryStorage(HLERequestContext& ctx);
337 void CreateHandleStorage(HLERequestContext& ctx);
338};
339
340class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
341public:
342 explicit ILibraryAppletSelfAccessor(Core::System& system_);
343 ~ILibraryAppletSelfAccessor() override;
344
345private:
346 void PopInData(HLERequestContext& ctx);
347 void PushOutData(HLERequestContext& ctx);
348 void GetLibraryAppletInfo(HLERequestContext& ctx);
349 void GetMainAppletIdentityInfo(HLERequestContext& ctx);
350 void ExitProcessAndReturn(HLERequestContext& ctx);
351 void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
352 void GetDesirableKeyboardLayout(HLERequestContext& ctx);
353 void GetMainAppletAvailableUsers(HLERequestContext& ctx);
354 void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
355
356 void PushInShowAlbum();
357 void PushInShowCabinetData();
358 void PushInShowMiiEditData();
359 void PushInShowSoftwareKeyboard();
360 void PushInShowController();
361
362 std::deque<std::vector<u8>> queue_data;
363};
364
365class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
366public:
367 explicit IAppletCommonFunctions(Core::System& system_);
368 ~IAppletCommonFunctions() override;
369
370private:
371 void SetCpuBoostRequestPriority(HLERequestContext& ctx);
372};
373
374class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
375public:
376 explicit IApplicationFunctions(Core::System& system_);
377 ~IApplicationFunctions() override;
378
379private:
380 void PopLaunchParameter(HLERequestContext& ctx);
381 void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
382 void EnsureSaveData(HLERequestContext& ctx);
383 void SetTerminateResult(HLERequestContext& ctx);
384 void GetDisplayVersion(HLERequestContext& ctx);
385 void GetDesiredLanguage(HLERequestContext& ctx);
386 void IsGamePlayRecordingSupported(HLERequestContext& ctx);
387 void InitializeGamePlayRecording(HLERequestContext& ctx);
388 void SetGamePlayRecordingState(HLERequestContext& ctx);
389 void NotifyRunning(HLERequestContext& ctx);
390 void GetPseudoDeviceId(HLERequestContext& ctx);
391 void ExtendSaveData(HLERequestContext& ctx);
392 void GetSaveDataSize(HLERequestContext& ctx);
393 void CreateCacheStorage(HLERequestContext& ctx);
394 void GetSaveDataSizeMax(HLERequestContext& ctx);
395 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
396 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
397 void BeginBlockingHomeButton(HLERequestContext& ctx);
398 void EndBlockingHomeButton(HLERequestContext& ctx);
399 void EnableApplicationCrashReport(HLERequestContext& ctx);
400 void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
401 void SetApplicationCopyrightImage(HLERequestContext& ctx);
402 void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
403 void QueryApplicationPlayStatistics(HLERequestContext& ctx);
404 void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
405 void ExecuteProgram(HLERequestContext& ctx);
406 void ClearUserChannel(HLERequestContext& ctx);
407 void UnpopToUserChannel(HLERequestContext& ctx);
408 void GetPreviousProgramIndex(HLERequestContext& ctx);
409 void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
410 void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
411 void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
412 void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
413 void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
414 void PrepareForJit(HLERequestContext& ctx);
415
416 KernelHelpers::ServiceContext service_context;
417
418 bool launch_popped_account_preselect = false;
419 s32 previous_program_index{-1};
420 Kernel::KEvent* gpu_error_detected_event;
421 Kernel::KEvent* friend_invitation_storage_channel_event;
422 Kernel::KEvent* notification_storage_channel_event;
423 Kernel::KEvent* health_warning_disappeared_system_event;
424};
425
426class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
427public:
428 explicit IHomeMenuFunctions(Core::System& system_);
429 ~IHomeMenuFunctions() override;
430
431private:
432 void RequestToGetForeground(HLERequestContext& ctx);
433 void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
434
435 KernelHelpers::ServiceContext service_context;
436
437 Kernel::KEvent* pop_from_general_channel_event;
438};
439
440class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
441public:
442 explicit IGlobalStateController(Core::System& system_);
443 ~IGlobalStateController() override;
444};
445
446class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
447public:
448 explicit IApplicationCreator(Core::System& system_);
449 ~IApplicationCreator() override;
450};
451
452class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
453public:
454 explicit IProcessWindingController(Core::System& system_);
455 ~IProcessWindingController() override;
456
457private:
458 void GetLaunchReason(HLERequestContext& ctx);
459 void OpenCallingLibraryApplet(HLERequestContext& ctx);
460};
461
462void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); 16void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
463 17
464} // namespace Service::AM 18} // namespace Service::AM
diff --git a/src/core/hle/service/am/am_results.h b/src/core/hle/service/am/am_results.h
new file mode 100644
index 000000000..a2afc9eec
--- /dev/null
+++ b/src/core/hle/service/am/am_results.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::AM {
9
10constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
11constexpr Result ResultNoMessages{ErrorModule::AM, 3};
12constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
13constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
14constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h
new file mode 100644
index 000000000..a2b852b12
--- /dev/null
+++ b/src/core/hle/service/am/am_types.h
@@ -0,0 +1,178 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::AM {
10
11namespace Frontend {
12class FrontendApplet;
13}
14
15enum class AppletType {
16 Application,
17 LibraryApplet,
18 SystemApplet,
19};
20
21enum class GameplayRecordingState : u32 {
22 Disabled,
23 Enabled,
24};
25
26// This is nn::oe::FocusState
27enum class FocusState : u8 {
28 InFocus = 1,
29 NotInFocus = 2,
30 Background = 3,
31};
32
33// This is nn::oe::OperationMode
34enum class OperationMode : u8 {
35 Handheld = 0,
36 Docked = 1,
37};
38
39// This is nn::am::service::SystemButtonType
40enum class SystemButtonType {
41 None,
42 HomeButtonShortPressing,
43 HomeButtonLongPressing,
44 PowerButtonShortPressing,
45 PowerButtonLongPressing,
46 ShutdownSystem,
47 CaptureButtonShortPressing,
48 CaptureButtonLongPressing,
49};
50
51enum class SysPlatformRegion : s32 {
52 Global = 1,
53 Terra = 2,
54};
55
56struct AppletProcessLaunchReason {
57 u8 flag;
58 INSERT_PADDING_BYTES(3);
59};
60static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
61 "AppletProcessLaunchReason is an invalid size");
62
63enum class ScreenshotPermission : u32 {
64 Inherit = 0,
65 Enable = 1,
66 Disable = 2,
67};
68
69struct FocusHandlingMode {
70 bool unknown0;
71 bool unknown1;
72 bool unknown2;
73 bool unknown3;
74};
75
76enum class IdleTimeDetectionExtension : u32 {
77 Disabled = 0,
78 Extended = 1,
79 ExtendedUnsafe = 2,
80};
81
82enum class AppletId : u32 {
83 None = 0x00,
84 Application = 0x01,
85 OverlayDisplay = 0x02,
86 QLaunch = 0x03,
87 Starter = 0x04,
88 Auth = 0x0A,
89 Cabinet = 0x0B,
90 Controller = 0x0C,
91 DataErase = 0x0D,
92 Error = 0x0E,
93 NetConnect = 0x0F,
94 ProfileSelect = 0x10,
95 SoftwareKeyboard = 0x11,
96 MiiEdit = 0x12,
97 Web = 0x13,
98 Shop = 0x14,
99 PhotoViewer = 0x15,
100 Settings = 0x16,
101 OfflineWeb = 0x17,
102 LoginShare = 0x18,
103 WebAuth = 0x19,
104 MyPage = 0x1A,
105};
106
107enum class AppletProgramId : u64 {
108 QLaunch = 0x0100000000001000ull,
109 Auth = 0x0100000000001001ull,
110 Cabinet = 0x0100000000001002ull,
111 Controller = 0x0100000000001003ull,
112 DataErase = 0x0100000000001004ull,
113 Error = 0x0100000000001005ull,
114 NetConnect = 0x0100000000001006ull,
115 ProfileSelect = 0x0100000000001007ull,
116 SoftwareKeyboard = 0x0100000000001008ull,
117 MiiEdit = 0x0100000000001009ull,
118 Web = 0x010000000000100Aull,
119 Shop = 0x010000000000100Bull,
120 OverlayDisplay = 0x010000000000100Cull,
121 PhotoViewer = 0x010000000000100Dull,
122 Settings = 0x010000000000100Eull,
123 OfflineWeb = 0x010000000000100Full,
124 LoginShare = 0x0100000000001010ull,
125 WebAuth = 0x0100000000001011ull,
126 Starter = 0x0100000000001012ull,
127 MyPage = 0x0100000000001013ull,
128 MaxProgramId = 0x0100000000001FFFull,
129};
130
131enum class LibraryAppletMode : u32 {
132 AllForeground = 0,
133 Background = 1,
134 NoUI = 2,
135 BackgroundIndirectDisplay = 3,
136 AllForegroundInitiallyHidden = 4,
137};
138
139enum class CommonArgumentVersion : u32 {
140 Version0,
141 Version1,
142 Version2,
143 Version3,
144};
145
146enum class CommonArgumentSize : u32 {
147 Version3 = 0x20,
148};
149
150enum class ThemeColor : u32 {
151 BasicWhite = 0,
152 BasicBlack = 3,
153};
154
155struct CommonArguments {
156 CommonArgumentVersion arguments_version;
157 CommonArgumentSize size;
158 u32 library_version;
159 ThemeColor theme_color;
160 bool play_startup_sound;
161 u64 system_tick;
162};
163static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
164
165struct AppletIdentityInfo {
166 AppletId applet_id;
167 INSERT_PADDING_BYTES(0x4);
168 u64 application_id;
169};
170static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
171
172using AppletResourceUserId = u64;
173using ProgramId = u64;
174
175struct Applet;
176class AppletDataBroker;
177
178} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet.cpp b/src/core/hle/service/am/applet.cpp
new file mode 100644
index 000000000..5b9056c12
--- /dev/null
+++ b/src/core/hle/service/am/applet.cpp
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/core.h"
7#include "core/hle/service/am/am_results.h"
8#include "core/hle/service/am/applet.h"
9#include "core/hle/service/am/applet_manager.h"
10
11namespace Service::AM {
12
13Applet::Applet(Core::System& system, std::unique_ptr<Process> process_)
14 : context(system, "Applet"), message_queue(system), process(std::move(process_)),
15 hid_registration(system, *process), gpu_error_detected_event(context),
16 friend_invitation_storage_channel_event(context), notification_storage_channel_event(context),
17 health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context),
18 pop_from_general_channel_event(context), library_applet_launchable_event(context),
19 accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) {
20
21 aruid = process->GetProcessId();
22 program_id = process->GetProgramId();
23}
24
25Applet::~Applet() = default;
26
27} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h
new file mode 100644
index 000000000..bce6f9050
--- /dev/null
+++ b/src/core/hle/service/am/applet.h
@@ -0,0 +1,133 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <list>
7#include <mutex>
8
9#include "common/math_util.h"
10#include "core/hle/service/apm/apm_controller.h"
11#include "core/hle/service/caps/caps_types.h"
12#include "core/hle/service/event.h"
13#include "core/hle/service/kernel_helpers.h"
14#include "core/hle/service/service.h"
15
16#include "core/hle/service/am/am_types.h"
17#include "core/hle/service/am/applet_message_queue.h"
18#include "core/hle/service/am/hid_registration.h"
19#include "core/hle/service/am/managed_layer_holder.h"
20#include "core/hle/service/am/process.h"
21#include "core/hle/service/am/storage.h"
22#include "core/hle/service/am/system_buffer_manager.h"
23
24namespace Service::AM {
25
26struct Applet {
27 explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
28 ~Applet();
29
30 // Lock
31 std::mutex lock{};
32
33 // Event creation helper
34 KernelHelpers::ServiceContext context;
35
36 // Applet message queue
37 AppletMessageQueue message_queue;
38
39 // Process
40 std::unique_ptr<Process> process;
41
42 // Creation state
43 AppletId applet_id{};
44 AppletResourceUserId aruid{};
45 AppletProcessLaunchReason launch_reason{};
46 AppletType type{};
47 ProgramId program_id{};
48 LibraryAppletMode library_applet_mode{};
49 s32 previous_program_index{-1};
50 ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable};
51
52 // TODO: some fields above can be AppletIdentityInfo
53 AppletIdentityInfo screen_shot_identity;
54
55 // hid state
56 HidRegistration hid_registration;
57
58 // vi state
59 SystemBufferManager system_buffer_manager{};
60 ManagedLayerHolder managed_layer_holder{};
61
62 // Applet common functions
63 Result terminate_result{};
64 s32 display_logical_width{};
65 s32 display_logical_height{};
66 Common::Rectangle<f32> display_magnification{0, 0, 1, 1};
67 bool home_button_double_click_enabled{};
68 bool home_button_short_pressed_blocked{};
69 bool home_button_long_pressed_blocked{};
70 bool vr_mode_curtain_required{};
71 bool sleep_required_by_high_temperature{};
72 bool sleep_required_by_low_battery{};
73 s32 cpu_boost_request_priority{-1};
74 bool handling_capture_button_short_pressed_message_enabled_for_applet{};
75 bool handling_capture_button_long_pressed_message_enabled_for_applet{};
76 u32 application_core_usage_mode{};
77
78 // Application functions
79 bool gameplay_recording_supported{};
80 GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled};
81 bool jit_service_launched{};
82 bool is_running{};
83 bool application_crash_report_enabled{};
84
85 // Common state
86 FocusState focus_state{};
87 bool sleep_lock_enabled{};
88 bool vr_mode_enabled{};
89 bool lcd_backlight_off_enabled{};
90 APM::CpuBoostMode boost_mode{};
91 bool request_exit_to_library_applet_at_execute_next_program_enabled{};
92
93 // Channels
94 std::deque<std::vector<u8>> user_channel_launch_parameter{};
95 std::deque<std::vector<u8>> preselected_user_launch_parameter{};
96
97 // Caller applet
98 std::weak_ptr<Applet> caller_applet{};
99 std::shared_ptr<AppletDataBroker> caller_applet_broker{};
100
101 // Self state
102 bool exit_locked{};
103 s32 fatal_section_count{};
104 bool operation_mode_changed_notification_enabled{true};
105 bool performance_mode_changed_notification_enabled{true};
106 FocusHandlingMode focus_handling_mode{};
107 bool restart_message_enabled{};
108 bool out_of_focus_suspension_enabled{true};
109 Capture::AlbumImageOrientation album_image_orientation{};
110 bool handles_request_to_display{};
111 ScreenshotPermission screenshot_permission{};
112 IdleTimeDetectionExtension idle_time_detection_extension{};
113 bool auto_sleep_disabled{};
114 u64 suspended_ticks{};
115 bool album_image_taken_notification_enabled{};
116 bool record_volume_muted{};
117
118 // Events
119 Event gpu_error_detected_event;
120 Event friend_invitation_storage_channel_event;
121 Event notification_storage_channel_event;
122 Event health_warning_disappeared_system_event;
123 Event acquired_sleep_lock_event;
124 Event pop_from_general_channel_event;
125 Event library_applet_launchable_event;
126 Event accumulated_suspended_tick_changed_event;
127 Event sleep_lock_event;
128
129 // Frontend state
130 std::shared_ptr<Frontend::FrontendApplet> frontend{};
131};
132
133} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index e30e6478a..1b715dea6 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -1,311 +1,73 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/applet_ae.h" 4#include "core/hle/service/am/applet_ae.h"
5#include "core/hle/service/am/applet_manager.h"
6#include "core/hle/service/am/library_applet_proxy.h"
7#include "core/hle/service/am/system_applet_proxy.h"
8#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nvnflinger/nvnflinger.h"
10 9
11namespace Service::AM { 10namespace Service::AM {
12 11
13class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 12AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
14public: 13 : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} {
15 explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, 14 // clang-format off
16 std::shared_ptr<AppletMessageQueue> msg_queue_, 15 static const FunctionInfo functions[] = {
17 Core::System& system_) 16 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
18 : ServiceFramework{system_, "ILibraryAppletProxy"}, 17 {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
19 nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { 18 {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"},
20 // clang-format off 19 {300, nullptr, "OpenOverlayAppletProxy"},
21 static const FunctionInfo functions[] = { 20 {350, nullptr, "OpenSystemApplicationProxy"},
22 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 21 {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
23 {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, 22 {410, nullptr, "GetSystemAppletControllerForDebug"},
24 {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, 23 {1000, nullptr, "GetDebugFunctions"},
25 {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, 24 };
26 {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, 25 // clang-format on
27 {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
28 {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
29 {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
30 {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
31 {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
32 {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
33 {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
34 };
35 // clang-format on
36
37 RegisterHandlers(functions);
38 }
39
40private:
41 void GetCommonStateGetter(HLERequestContext& ctx) {
42 LOG_DEBUG(Service_AM, "called");
43
44 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
45 rb.Push(ResultSuccess);
46 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
47 }
48
49 void GetSelfController(HLERequestContext& ctx) {
50 LOG_DEBUG(Service_AM, "called");
51
52 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
53 rb.Push(ResultSuccess);
54 rb.PushIpcInterface<ISelfController>(system, nvnflinger);
55 }
56
57 void GetWindowController(HLERequestContext& ctx) {
58 LOG_DEBUG(Service_AM, "called");
59
60 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
61 rb.Push(ResultSuccess);
62 rb.PushIpcInterface<IWindowController>(system);
63 }
64
65 void GetAudioController(HLERequestContext& ctx) {
66 LOG_DEBUG(Service_AM, "called");
67
68 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
69 rb.Push(ResultSuccess);
70 rb.PushIpcInterface<IAudioController>(system);
71 }
72
73 void GetDisplayController(HLERequestContext& ctx) {
74 LOG_DEBUG(Service_AM, "called");
75
76 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
77 rb.Push(ResultSuccess);
78 rb.PushIpcInterface<IDisplayController>(system);
79 }
80
81 void GetProcessWindingController(HLERequestContext& ctx) {
82 LOG_DEBUG(Service_AM, "called");
83
84 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
85 rb.Push(ResultSuccess);
86 rb.PushIpcInterface<IProcessWindingController>(system);
87 }
88
89 void GetLibraryAppletCreator(HLERequestContext& ctx) {
90 LOG_DEBUG(Service_AM, "called");
91
92 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
93 rb.Push(ResultSuccess);
94 rb.PushIpcInterface<ILibraryAppletCreator>(system);
95 }
96
97 void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_AM, "called");
99
100 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
101 rb.Push(ResultSuccess);
102 rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system);
103 }
104
105 void GetAppletCommonFunctions(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_AM, "called");
107
108 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
109 rb.Push(ResultSuccess);
110 rb.PushIpcInterface<IAppletCommonFunctions>(system);
111 }
112
113 void GetHomeMenuFunctions(HLERequestContext& ctx) {
114 LOG_DEBUG(Service_AM, "called");
115
116 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
117 rb.Push(ResultSuccess);
118 rb.PushIpcInterface<IHomeMenuFunctions>(system);
119 }
120
121 void GetGlobalStateController(HLERequestContext& ctx) {
122 LOG_DEBUG(Service_AM, "called");
123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(ResultSuccess);
126 rb.PushIpcInterface<IGlobalStateController>(system);
127 }
128
129 void GetDebugFunctions(HLERequestContext& ctx) {
130 LOG_DEBUG(Service_AM, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<IDebugFunctions>(system);
135 }
136
137 Nvnflinger::Nvnflinger& nvnflinger;
138 std::shared_ptr<AppletMessageQueue> msg_queue;
139};
140
141class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
142public:
143 explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
144 std::shared_ptr<AppletMessageQueue> msg_queue_,
145 Core::System& system_)
146 : ServiceFramework{system_, "ISystemAppletProxy"},
147 nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
148 // clang-format off
149 static const FunctionInfo functions[] = {
150 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
151 {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
152 {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
153 {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
154 {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
155 {10, nullptr, "GetProcessWindingController"},
156 {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
157 {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
158 {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
159 {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
160 {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
161 {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
162 };
163 // clang-format on
164
165 RegisterHandlers(functions);
166 }
167
168private:
169 void GetCommonStateGetter(HLERequestContext& ctx) {
170 LOG_DEBUG(Service_AM, "called");
171
172 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
173 rb.Push(ResultSuccess);
174 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
175 }
176
177 void GetSelfController(HLERequestContext& ctx) {
178 LOG_DEBUG(Service_AM, "called");
179
180 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
181 rb.Push(ResultSuccess);
182 rb.PushIpcInterface<ISelfController>(system, nvnflinger);
183 }
184
185 void GetWindowController(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_AM, "called");
187
188 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
189 rb.Push(ResultSuccess);
190 rb.PushIpcInterface<IWindowController>(system);
191 }
192
193 void GetAudioController(HLERequestContext& ctx) {
194 LOG_DEBUG(Service_AM, "called");
195
196 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
197 rb.Push(ResultSuccess);
198 rb.PushIpcInterface<IAudioController>(system);
199 }
200
201 void GetDisplayController(HLERequestContext& ctx) {
202 LOG_DEBUG(Service_AM, "called");
203
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(ResultSuccess);
206 rb.PushIpcInterface<IDisplayController>(system);
207 }
208 26
209 void GetLibraryAppletCreator(HLERequestContext& ctx) { 27 RegisterHandlers(functions);
210 LOG_DEBUG(Service_AM, "called"); 28}
211 29
212 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 30AppletAE::~AppletAE() = default;
213 rb.Push(ResultSuccess);
214 rb.PushIpcInterface<ILibraryAppletCreator>(system);
215 }
216 31
217 void GetHomeMenuFunctions(HLERequestContext& ctx) { 32void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
218 LOG_DEBUG(Service_AM, "called"); 33 LOG_DEBUG(Service_AM, "called");
219 34
35 if (const auto applet = GetAppletFromContext(ctx)) {
220 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 36 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
221 rb.Push(ResultSuccess); 37 rb.Push(ResultSuccess);
222 rb.PushIpcInterface<IHomeMenuFunctions>(system); 38 rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system);
223 } 39 } else {
224 40 UNIMPLEMENTED();
225 void GetGlobalStateController(HLERequestContext& ctx) {
226 LOG_DEBUG(Service_AM, "called");
227 41
228 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 42 IPC::ResponseBuilder rb{ctx, 2};
229 rb.Push(ResultSuccess); 43 rb.Push(ResultUnknown);
230 rb.PushIpcInterface<IGlobalStateController>(system);
231 }
232
233 void GetApplicationCreator(HLERequestContext& ctx) {
234 LOG_DEBUG(Service_AM, "called");
235
236 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
237 rb.Push(ResultSuccess);
238 rb.PushIpcInterface<IApplicationCreator>(system);
239 } 44 }
45}
240 46
241 void GetAppletCommonFunctions(HLERequestContext& ctx) { 47void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
242 LOG_DEBUG(Service_AM, "called"); 48 LOG_DEBUG(Service_AM, "called");
243 49
50 if (const auto applet = GetAppletFromContext(ctx)) {
244 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 51 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
245 rb.Push(ResultSuccess); 52 rb.Push(ResultSuccess);
246 rb.PushIpcInterface<IAppletCommonFunctions>(system); 53 rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system);
247 } 54 } else {
248 55 UNIMPLEMENTED();
249 void GetDebugFunctions(HLERequestContext& ctx) {
250 LOG_DEBUG(Service_AM, "called");
251 56
252 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 57 IPC::ResponseBuilder rb{ctx, 2};
253 rb.Push(ResultSuccess); 58 rb.Push(ResultUnknown);
254 rb.PushIpcInterface<IDebugFunctions>(system);
255 } 59 }
256
257 Nvnflinger::Nvnflinger& nvnflinger;
258 std::shared_ptr<AppletMessageQueue> msg_queue;
259};
260
261void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
262 LOG_DEBUG(Service_AM, "called");
263
264 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
265 rb.Push(ResultSuccess);
266 rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, msg_queue, system);
267}
268
269void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
270 LOG_DEBUG(Service_AM, "called");
271
272 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
273 rb.Push(ResultSuccess);
274 rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
275} 60}
276 61
277void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { 62void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
278 LOG_DEBUG(Service_AM, "called"); 63 LOG_DEBUG(Service_AM, "called");
279 64
280 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 65 return OpenLibraryAppletProxy(ctx);
281 rb.Push(ResultSuccess);
282 rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
283} 66}
284 67
285AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, 68std::shared_ptr<Applet> AppletAE::GetAppletFromContext(HLERequestContext& ctx) {
286 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_) 69 const auto aruid = ctx.GetPID();
287 : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{ 70 return system.GetAppletManager().GetByAppletResourceUserId(aruid);
288 std::move(msg_queue_)} {
289 // clang-format off
290 static const FunctionInfo functions[] = {
291 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
292 {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
293 {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"},
294 {300, nullptr, "OpenOverlayAppletProxy"},
295 {350, nullptr, "OpenSystemApplicationProxy"},
296 {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
297 {410, nullptr, "GetSystemAppletControllerForDebug"},
298 {1000, nullptr, "GetDebugFunctions"},
299 };
300 // clang-format on
301
302 RegisterHandlers(functions);
303}
304
305AppletAE::~AppletAE() = default;
306
307const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
308 return msg_queue;
309} 71}
310 72
311} // namespace Service::AM 73} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 538ce2903..3d7961fa1 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -18,23 +18,21 @@ class Nvnflinger;
18 18
19namespace AM { 19namespace AM {
20 20
21class AppletMessageQueue; 21struct Applet;
22 22
23class AppletAE final : public ServiceFramework<AppletAE> { 23class AppletAE final : public ServiceFramework<AppletAE> {
24public: 24public:
25 explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, 25 explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
26 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
27 ~AppletAE() override; 26 ~AppletAE() override;
28 27
29 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
30
31private: 28private:
32 void OpenSystemAppletProxy(HLERequestContext& ctx); 29 void OpenSystemAppletProxy(HLERequestContext& ctx);
33 void OpenLibraryAppletProxy(HLERequestContext& ctx); 30 void OpenLibraryAppletProxy(HLERequestContext& ctx);
34 void OpenLibraryAppletProxyOld(HLERequestContext& ctx); 31 void OpenLibraryAppletProxyOld(HLERequestContext& ctx);
35 32
33 std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
34
36 Nvnflinger::Nvnflinger& nvnflinger; 35 Nvnflinger::Nvnflinger& nvnflinger;
37 std::shared_ptr<AppletMessageQueue> msg_queue;
38}; 36};
39 37
40} // namespace AM 38} // namespace AM
diff --git a/src/core/hle/service/am/applet_common_functions.cpp b/src/core/hle/service/am/applet_common_functions.cpp
new file mode 100644
index 000000000..130614ae5
--- /dev/null
+++ b/src/core/hle/service/am/applet_common_functions.cpp
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/applet_common_functions.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::AM {
9
10IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
11 std::shared_ptr<Applet> applet_)
12 : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, nullptr, "SetTerminateResult"},
16 {10, nullptr, "ReadThemeStorage"},
17 {11, nullptr, "WriteThemeStorage"},
18 {20, nullptr, "PushToAppletBoundChannel"},
19 {21, nullptr, "TryPopFromAppletBoundChannel"},
20 {40, nullptr, "GetDisplayLogicalResolution"},
21 {42, nullptr, "SetDisplayMagnification"},
22 {50, nullptr, "SetHomeButtonDoubleClickEnabled"},
23 {51, nullptr, "GetHomeButtonDoubleClickEnabled"},
24 {52, nullptr, "IsHomeButtonShortPressedBlocked"},
25 {60, nullptr, "IsVrModeCurtainRequired"},
26 {61, nullptr, "IsSleepRequiredByHighTemperature"},
27 {62, nullptr, "IsSleepRequiredByLowBattery"},
28 {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"},
29 {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
30 {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
31 {90, nullptr, "OpenNamedChannelAsParent"},
32 {91, nullptr, "OpenNamedChannelAsChild"},
33 {100, nullptr, "SetApplicationCoreUsageMode"},
34 {300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IAppletCommonFunctions::~IAppletCommonFunctions() = default;
42
43void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) {
44 LOG_WARNING(Service_AM, "(STUBBED) called");
45
46 IPC::RequestParser rp{ctx};
47
48 std::scoped_lock lk{applet->lock};
49 applet->cpu_boost_request_priority = rp.Pop<s32>();
50
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(ResultSuccess);
53}
54
55void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) {
56 LOG_WARNING(Service_AM, "(STUBBED) called");
57
58 IPC::ResponseBuilder rb{ctx, 4};
59 rb.Push(ResultSuccess);
60 rb.Push<u64>(system.GetApplicationProcessProgramID() & ~0xFFFULL);
61}
62
63} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_common_functions.h b/src/core/hle/service/am/applet_common_functions.h
new file mode 100644
index 000000000..b86adf5cb
--- /dev/null
+++ b/src/core/hle/service/am/applet_common_functions.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
13public:
14 explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IAppletCommonFunctions() override;
16
17private:
18 void SetCpuBoostRequestPriority(HLERequestContext& ctx);
19 void GetCurrentApplicationId(HLERequestContext& ctx);
20
21 const std::shared_ptr<Applet> applet;
22};
23
24} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp
new file mode 100644
index 000000000..4d58c4db5
--- /dev/null
+++ b/src/core/hle/service/am/applet_data_broker.cpp
@@ -0,0 +1,67 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/core.h"
7#include "core/hle/service/am/am_results.h"
8#include "core/hle/service/am/applet_data_broker.h"
9#include "core/hle/service/am/applet_manager.h"
10
11namespace Service::AM {
12
13AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context)
14 : m_event(context) {}
15AppletStorageChannel::~AppletStorageChannel() = default;
16
17void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
18 std::scoped_lock lk{m_lock};
19
20 m_data.emplace_back(std::move(storage));
21 m_event.Signal();
22}
23
24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
25 std::scoped_lock lk{m_lock};
26
27 SCOPE_EXIT({
28 if (m_data.empty()) {
29 m_event.Clear();
30 }
31 });
32
33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
34
35 *out_storage = std::move(m_data.front());
36 m_data.pop_front();
37
38 R_SUCCEED();
39}
40
41Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
42 return m_event.GetHandle();
43}
44
45AppletDataBroker::AppletDataBroker(Core::System& system_)
46 : system(system_), context(system_, "AppletDataBroker"), in_data(context),
47 interactive_in_data(context), out_data(context), interactive_out_data(context),
48 state_changed_event(context), is_completed(false) {}
49
50AppletDataBroker::~AppletDataBroker() = default;
51
52void AppletDataBroker::SignalCompletion() {
53 {
54 std::scoped_lock lk{lock};
55
56 if (is_completed) {
57 return;
58 }
59
60 is_completed = true;
61 state_changed_event.Signal();
62 }
63
64 system.GetAppletManager().FocusStateChanged();
65}
66
67} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h
new file mode 100644
index 000000000..12326fd04
--- /dev/null
+++ b/src/core/hle/service/am/applet_data_broker.h
@@ -0,0 +1,80 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <deque>
7#include <memory>
8#include <mutex>
9
10#include "core/hle/service/event.h"
11#include "core/hle/service/kernel_helpers.h"
12
13union Result;
14
15namespace Service::AM {
16
17struct Applet;
18class IStorage;
19
20class AppletStorageChannel {
21public:
22 explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx);
23 ~AppletStorageChannel();
24
25 void Push(std::shared_ptr<IStorage> storage);
26 Result Pop(std::shared_ptr<IStorage>* out_storage);
27 Kernel::KReadableEvent* GetEvent();
28
29private:
30 std::mutex m_lock{};
31 std::deque<std::shared_ptr<IStorage>> m_data{};
32 Event m_event;
33};
34
35class AppletDataBroker {
36public:
37 explicit AppletDataBroker(Core::System& system_);
38 ~AppletDataBroker();
39
40 AppletStorageChannel& GetInData() {
41 return in_data;
42 }
43
44 AppletStorageChannel& GetInteractiveInData() {
45 return interactive_in_data;
46 }
47
48 AppletStorageChannel& GetOutData() {
49 return out_data;
50 }
51
52 AppletStorageChannel& GetInteractiveOutData() {
53 return interactive_out_data;
54 }
55
56 Event& GetStateChangedEvent() {
57 return state_changed_event;
58 }
59
60 bool IsCompleted() const {
61 return is_completed;
62 }
63
64 void SignalCompletion();
65
66private:
67 Core::System& system;
68 KernelHelpers::ServiceContext context;
69
70 AppletStorageChannel in_data;
71 AppletStorageChannel interactive_in_data;
72 AppletStorageChannel out_data;
73 AppletStorageChannel interactive_out_data;
74 Event state_changed_event;
75
76 std::mutex lock;
77 bool is_completed;
78};
79
80} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp
new file mode 100644
index 000000000..52200d5b2
--- /dev/null
+++ b/src/core/hle/service/am/applet_manager.cpp
@@ -0,0 +1,361 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "common/uuid.h"
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/hle/service/acc/profile_manager.h"
9#include "core/hle/service/am/applet_data_broker.h"
10#include "core/hle/service/am/applet_manager.h"
11#include "core/hle/service/am/frontend/applet_cabinet.h"
12#include "core/hle/service/am/frontend/applet_controller.h"
13#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
14#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
15#include "hid_core/hid_types.h"
16
17namespace Service::AM {
18
19namespace {
20
21constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA;
22
23struct LaunchParameterAccountPreselectedUser {
24 u32 magic;
25 u32 is_account_selected;
26 Common::UUID current_user;
27 INSERT_PADDING_BYTES(0x70);
28};
29static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
30
31AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system,
32 std::shared_ptr<Applet>& applet) {
33 applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system);
34 return applet->caller_applet_broker->GetInData();
35}
36
37void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) {
38 const CommonArguments arguments{
39 .arguments_version = CommonArgumentVersion::Version3,
40 .size = CommonArgumentSize::Version3,
41 .library_version = 1,
42 .theme_color = ThemeColor::BasicBlack,
43 .play_startup_sound = true,
44 .system_tick = system.CoreTiming().GetClockTicks(),
45 };
46
47 std::vector<u8> argument_data(sizeof(arguments));
48 std::vector<u8> settings_data{2};
49 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
50 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
51 channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
52}
53
54void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
55 const CommonArguments common_args = {
56 .arguments_version = CommonArgumentVersion::Version3,
57 .size = CommonArgumentSize::Version3,
58 .library_version = static_cast<u32>(Frontend::ControllerAppletVersion::Version8),
59 .theme_color = ThemeColor::BasicBlack,
60 .play_startup_sound = true,
61 .system_tick = system.CoreTiming().GetClockTicks(),
62 };
63
64 Frontend::ControllerSupportArgNew user_args = {
65 .header = {.player_count_min = 1,
66 .player_count_max = 4,
67 .enable_take_over_connection = true,
68 .enable_left_justify = false,
69 .enable_permit_joy_dual = true,
70 .enable_single_mode = false,
71 .enable_identification_color = false},
72 .identification_colors = {},
73 .enable_explain_text = false,
74 .explain_text = {},
75 };
76
77 Frontend::ControllerSupportArgPrivate private_args = {
78 .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate),
79 .arg_size = sizeof(Frontend::ControllerSupportArgNew),
80 .is_home_menu = true,
81 .flag_1 = true,
82 .mode = Frontend::ControllerSupportMode::ShowControllerSupport,
83 .caller = Frontend::ControllerSupportCaller::
84 Application, // switchbrew: Always zero except with
85 // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
86 // which sets this to the input param
87 .style_set = Core::HID::NpadStyleSet::None,
88 .joy_hold_type = 0,
89 };
90 std::vector<u8> common_args_data(sizeof(common_args));
91 std::vector<u8> private_args_data(sizeof(private_args));
92 std::vector<u8> user_args_data(sizeof(user_args));
93
94 std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
95 std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
96 std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
97
98 channel.Push(std::make_shared<IStorage>(system, std::move(common_args_data)));
99 channel.Push(std::make_shared<IStorage>(system, std::move(private_args_data)));
100 channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data)));
101}
102
103void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) {
104 const CommonArguments arguments{
105 .arguments_version = CommonArgumentVersion::Version3,
106 .size = CommonArgumentSize::Version3,
107 .library_version = static_cast<u32>(Frontend::CabinetAppletVersion::Version1),
108 .theme_color = ThemeColor::BasicBlack,
109 .play_startup_sound = true,
110 .system_tick = system.CoreTiming().GetClockTicks(),
111 };
112
113 const Frontend::StartParamForAmiiboSettings amiibo_settings{
114 .param_1 = 0,
115 .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(),
116 .flags = Frontend::CabinetFlags::None,
117 .amiibo_settings_1 = 0,
118 .device_handle = 0,
119 .tag_info{},
120 .register_info{},
121 .amiibo_settings_3{},
122 };
123
124 std::vector<u8> argument_data(sizeof(arguments));
125 std::vector<u8> settings_data(sizeof(amiibo_settings));
126 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
127 std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
128 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
129 channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
130}
131
132void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) {
133 struct MiiEditV3 {
134 Frontend::MiiEditAppletInputCommon common;
135 Frontend::MiiEditAppletInputV3 input;
136 };
137 static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
138
139 MiiEditV3 mii_arguments{
140 .common =
141 {
142 .version = Frontend::MiiEditAppletVersion::Version3,
143 .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit,
144 },
145 .input{},
146 };
147
148 std::vector<u8> argument_data(sizeof(mii_arguments));
149 std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
150
151 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
152}
153
154void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) {
155 const CommonArguments arguments{
156 .arguments_version = CommonArgumentVersion::Version3,
157 .size = CommonArgumentSize::Version3,
158 .library_version = static_cast<u32>(Frontend::SwkbdAppletVersion::Version524301),
159 .theme_color = ThemeColor::BasicBlack,
160 .play_startup_sound = true,
161 .system_tick = system.CoreTiming().GetClockTicks(),
162 };
163
164 std::vector<char16_t> initial_string(0);
165
166 const Frontend::SwkbdConfigCommon swkbd_config{
167 .type = Frontend::SwkbdType::Qwerty,
168 .ok_text{},
169 .left_optional_symbol_key{},
170 .right_optional_symbol_key{},
171 .use_prediction = false,
172 .key_disable_flags{},
173 .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start,
174 .header_text{},
175 .sub_text{},
176 .guide_text{},
177 .max_text_length = 500,
178 .min_text_length = 0,
179 .password_mode = Frontend::SwkbdPasswordMode::Disabled,
180 .text_draw_type = Frontend::SwkbdTextDrawType::Box,
181 .enable_return_button = true,
182 .use_utf8 = false,
183 .use_blur_background = true,
184 .initial_string_offset{},
185 .initial_string_length = static_cast<u32>(initial_string.size()),
186 .user_dictionary_offset{},
187 .user_dictionary_entries{},
188 .use_text_check = false,
189 };
190
191 Frontend::SwkbdConfigNew swkbd_config_new{};
192
193 std::vector<u8> argument_data(sizeof(arguments));
194 std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
195 std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
196
197 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
198 std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
199 std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
200 sizeof(Frontend::SwkbdConfigNew));
201 std::memcpy(work_buffer.data(), initial_string.data(),
202 swkbd_config.initial_string_length * sizeof(char16_t));
203
204 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
205 channel.Push(std::make_shared<IStorage>(system, std::move(swkbd_data)));
206 channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer)));
207}
208
209} // namespace
210
211AppletManager::AppletManager(Core::System& system) : m_system(system) {}
212AppletManager::~AppletManager() {
213 this->Reset();
214}
215
216void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) {
217 std::scoped_lock lk{m_lock};
218
219 m_applets.emplace(applet->aruid, std::move(applet));
220}
221
222void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) {
223 std::shared_ptr<Applet> applet;
224 bool should_stop = false;
225 {
226 std::scoped_lock lk{m_lock};
227
228 const auto it = m_applets.find(aruid);
229 if (it == m_applets.end()) {
230 return;
231 }
232
233 applet = it->second;
234 m_applets.erase(it);
235
236 should_stop = m_applets.empty();
237 }
238
239 // Terminate process.
240 applet->process->Terminate();
241
242 // If there were no applets left, stop emulation.
243 if (should_stop) {
244 m_system.Exit();
245 }
246}
247
248void AppletManager::CreateAndInsertByFrontendAppletParameters(
249 AppletResourceUserId aruid, const FrontendAppletParameters& params) {
250 // TODO: this should be run inside AM so that the events will have a parent process
251 // TODO: have am create the guest process
252 auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system));
253
254 applet->aruid = aruid;
255 applet->program_id = params.program_id;
256 applet->applet_id = params.applet_id;
257 applet->type = params.applet_type;
258 applet->previous_program_index = params.previous_program_index;
259
260 // Push UserChannel data from previous application
261 if (params.launch_type == LaunchType::ApplicationInitiated) {
262 applet->user_channel_launch_parameter.swap(m_system.GetUserChannel());
263 }
264
265 // TODO: Read whether we need a preselected user from NACP?
266 // TODO: This can be done quite easily from loader
267 {
268 LaunchParameterAccountPreselectedUser lp{};
269
270 lp.magic = LaunchParameterAccountPreselectedUserMagic;
271 lp.is_account_selected = 1;
272
273 Account::ProfileManager profile_manager{};
274 const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
275 ASSERT(uuid.has_value() && uuid->IsValid());
276 lp.current_user = *uuid;
277
278 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
279 std::memcpy(buffer.data(), &lp, buffer.size());
280
281 applet->preselected_user_launch_parameter.push_back(std::move(buffer));
282 }
283
284 // Starting from frontend, some applets require input data.
285 switch (applet->applet_id) {
286 case AppletId::Cabinet:
287 PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet));
288 break;
289 case AppletId::MiiEdit:
290 PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet));
291 break;
292 case AppletId::PhotoViewer:
293 PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet));
294 break;
295 case AppletId::SoftwareKeyboard:
296 PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet));
297 break;
298 case AppletId::Controller:
299 PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
300 break;
301 default:
302 break;
303 }
304
305 // Applet was started by frontend, so it is foreground.
306 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
307 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
308 applet->focus_state = FocusState::InFocus;
309
310 this->InsertApplet(std::move(applet));
311}
312
313std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const {
314 std::scoped_lock lk{m_lock};
315
316 if (const auto it = m_applets.find(aruid); it != m_applets.end()) {
317 return it->second;
318 }
319
320 return {};
321}
322
323void AppletManager::Reset() {
324 std::scoped_lock lk{m_lock};
325
326 m_applets.clear();
327}
328
329void AppletManager::RequestExit() {
330 std::scoped_lock lk{m_lock};
331
332 for (const auto& [aruid, applet] : m_applets) {
333 applet->message_queue.RequestExit();
334 }
335}
336
337void AppletManager::RequestResume() {
338 std::scoped_lock lk{m_lock};
339
340 for (const auto& [aruid, applet] : m_applets) {
341 applet->message_queue.RequestResume();
342 }
343}
344
345void AppletManager::OperationModeChanged() {
346 std::scoped_lock lk{m_lock};
347
348 for (const auto& [aruid, applet] : m_applets) {
349 applet->message_queue.OperationModeChanged();
350 }
351}
352
353void AppletManager::FocusStateChanged() {
354 std::scoped_lock lk{m_lock};
355
356 for (const auto& [aruid, applet] : m_applets) {
357 applet->message_queue.FocusStateChanged();
358 }
359}
360
361} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_manager.h b/src/core/hle/service/am/applet_manager.h
new file mode 100644
index 000000000..4875de309
--- /dev/null
+++ b/src/core/hle/service/am/applet_manager.h
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <map>
7#include <mutex>
8
9#include "core/hle/service/am/applet.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::AM {
16
17enum class LaunchType {
18 FrontendInitiated,
19 ApplicationInitiated,
20};
21
22struct FrontendAppletParameters {
23 ProgramId program_id{};
24 AppletId applet_id{};
25 AppletType applet_type{};
26 LaunchType launch_type{};
27 s32 program_index{};
28 s32 previous_program_index{-1};
29};
30
31class AppletManager {
32public:
33 explicit AppletManager(Core::System& system);
34 ~AppletManager();
35
36 void InsertApplet(std::shared_ptr<Applet> applet);
37 void TerminateAndRemoveApplet(AppletResourceUserId aruid);
38
39 void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
40 const FrontendAppletParameters& params);
41 std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
42
43 void Reset();
44
45 void RequestExit();
46 void RequestResume();
47 void OperationModeChanged();
48 void FocusStateChanged();
49
50private:
51 Core::System& m_system;
52
53 mutable std::mutex m_lock{};
54 std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
55
56 // AudioController state goes here
57};
58
59} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_message_queue.cpp b/src/core/hle/service/am/applet_message_queue.cpp
new file mode 100644
index 000000000..5ed996b70
--- /dev/null
+++ b/src/core/hle/service/am/applet_message_queue.cpp
@@ -0,0 +1,73 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_message_queue.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9AppletMessageQueue::AppletMessageQueue(Core::System& system)
10 : service_context{system, "AppletMessageQueue"} {
11 on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
12 on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
13}
14
15AppletMessageQueue::~AppletMessageQueue() {
16 service_context.CloseEvent(on_new_message);
17 service_context.CloseEvent(on_operation_mode_changed);
18}
19
20Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
21 return on_new_message->GetReadableEvent();
22}
23
24Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
25 return on_operation_mode_changed->GetReadableEvent();
26}
27
28void AppletMessageQueue::PushMessage(AppletMessage msg) {
29 {
30 std::scoped_lock lk{lock};
31 messages.push(msg);
32 }
33 on_new_message->Signal();
34}
35
36AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
37 std::scoped_lock lk{lock};
38 if (messages.empty()) {
39 on_new_message->Clear();
40 return AppletMessage::None;
41 }
42 auto msg = messages.front();
43 messages.pop();
44 if (messages.empty()) {
45 on_new_message->Clear();
46 }
47 return msg;
48}
49
50std::size_t AppletMessageQueue::GetMessageCount() const {
51 std::scoped_lock lk{lock};
52 return messages.size();
53}
54
55void AppletMessageQueue::RequestExit() {
56 PushMessage(AppletMessage::Exit);
57}
58
59void AppletMessageQueue::RequestResume() {
60 PushMessage(AppletMessage::Resume);
61}
62
63void AppletMessageQueue::FocusStateChanged() {
64 PushMessage(AppletMessage::FocusStateChanged);
65}
66
67void AppletMessageQueue::OperationModeChanged() {
68 PushMessage(AppletMessage::OperationModeChanged);
69 PushMessage(AppletMessage::PerformanceModeChanged);
70 on_operation_mode_changed->Signal();
71}
72
73} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_message_queue.h b/src/core/hle/service/am/applet_message_queue.h
new file mode 100644
index 000000000..5cb236d47
--- /dev/null
+++ b/src/core/hle/service/am/applet_message_queue.h
@@ -0,0 +1,76 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <queue>
7
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Service::AM {
16
17class AppletMessageQueue {
18public:
19 // This is nn::am::AppletMessage
20 enum class AppletMessage : u32 {
21 None = 0,
22 ChangeIntoForeground = 1,
23 ChangeIntoBackground = 2,
24 Exit = 4,
25 ApplicationExited = 6,
26 FocusStateChanged = 15,
27 Resume = 16,
28 DetectShortPressingHomeButton = 20,
29 DetectLongPressingHomeButton = 21,
30 DetectShortPressingPowerButton = 22,
31 DetectMiddlePressingPowerButton = 23,
32 DetectLongPressingPowerButton = 24,
33 RequestToPrepareSleep = 25,
34 FinishedSleepSequence = 26,
35 SleepRequiredByHighTemperature = 27,
36 SleepRequiredByLowBattery = 28,
37 AutoPowerDown = 29,
38 OperationModeChanged = 30,
39 PerformanceModeChanged = 31,
40 DetectReceivingCecSystemStandby = 32,
41 SdCardRemoved = 33,
42 LaunchApplicationRequested = 50,
43 RequestToDisplay = 51,
44 ShowApplicationLogo = 55,
45 HideApplicationLogo = 56,
46 ForceHideApplicationLogo = 57,
47 FloatingApplicationDetected = 60,
48 DetectShortPressingCaptureButton = 90,
49 AlbumScreenShotTaken = 92,
50 AlbumRecordingSaved = 93,
51 };
52
53 explicit AppletMessageQueue(Core::System& system);
54 ~AppletMessageQueue();
55
56 Kernel::KReadableEvent& GetMessageReceiveEvent();
57 Kernel::KReadableEvent& GetOperationModeChangedEvent();
58 void PushMessage(AppletMessage msg);
59 AppletMessage PopMessage();
60 std::size_t GetMessageCount() const;
61 void RequestExit();
62 void RequestResume();
63 void FocusStateChanged();
64 void OperationModeChanged();
65
66private:
67 KernelHelpers::ServiceContext service_context;
68
69 Kernel::KEvent* on_new_message;
70 Kernel::KEvent* on_operation_mode_changed;
71
72 mutable std::mutex lock;
73 std::queue<AppletMessage> messages;
74};
75
76} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index d6c565d85..56bafd162 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -1,129 +1,42 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
5#include "core/hle/service/am/am.h" 4#include "core/hle/service/am/am.h"
5#include "core/hle/service/am/applet_manager.h"
6#include "core/hle/service/am/applet_oe.h" 6#include "core/hle/service/am/applet_oe.h"
7#include "core/hle/service/am/application_proxy.h"
7#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
8#include "core/hle/service/nvnflinger/nvnflinger.h"
9 9
10namespace Service::AM { 10namespace Service::AM {
11 11
12class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 12AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
13public: 13 : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} {
14 explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, 14 static const FunctionInfo functions[] = {
15 std::shared_ptr<AppletMessageQueue> msg_queue_, 15 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
16 Core::System& system_) 16 };
17 : ServiceFramework{system_, "IApplicationProxy"}, 17 RegisterHandlers(functions);
18 nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { 18}
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
22 {1, &IApplicationProxy::GetSelfController, "GetSelfController"},
23 {2, &IApplicationProxy::GetWindowController, "GetWindowController"},
24 {3, &IApplicationProxy::GetAudioController, "GetAudioController"},
25 {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
26 {10, nullptr, "GetProcessWindingController"},
27 {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
28 {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
29 {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
30 };
31 // clang-format on
32
33 RegisterHandlers(functions);
34 }
35
36private:
37 void GetAudioController(HLERequestContext& ctx) {
38 LOG_DEBUG(Service_AM, "called");
39
40 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
41 rb.Push(ResultSuccess);
42 rb.PushIpcInterface<IAudioController>(system);
43 }
44
45 void GetDisplayController(HLERequestContext& ctx) {
46 LOG_DEBUG(Service_AM, "called");
47
48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
49 rb.Push(ResultSuccess);
50 rb.PushIpcInterface<IDisplayController>(system);
51 }
52
53 void GetDebugFunctions(HLERequestContext& ctx) {
54 LOG_DEBUG(Service_AM, "called");
55
56 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
57 rb.Push(ResultSuccess);
58 rb.PushIpcInterface<IDebugFunctions>(system);
59 }
60
61 void GetWindowController(HLERequestContext& ctx) {
62 LOG_DEBUG(Service_AM, "called");
63
64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
65 rb.Push(ResultSuccess);
66 rb.PushIpcInterface<IWindowController>(system);
67 }
68
69 void GetSelfController(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_AM, "called");
71
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(ResultSuccess);
74 rb.PushIpcInterface<ISelfController>(system, nvnflinger);
75 }
76
77 void GetCommonStateGetter(HLERequestContext& ctx) {
78 LOG_DEBUG(Service_AM, "called");
79 19
80 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 20AppletOE::~AppletOE() = default;
81 rb.Push(ResultSuccess);
82 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
83 }
84 21
85 void GetLibraryAppletCreator(HLERequestContext& ctx) { 22void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
86 LOG_DEBUG(Service_AM, "called"); 23 LOG_DEBUG(Service_AM, "called");
87 24
25 if (const auto applet = GetAppletFromContext(ctx)) {
88 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 26 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
89 rb.Push(ResultSuccess); 27 rb.Push(ResultSuccess);
90 rb.PushIpcInterface<ILibraryAppletCreator>(system); 28 rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system);
91 } 29 } else {
92 30 UNIMPLEMENTED();
93 void GetApplicationFunctions(HLERequestContext& ctx) {
94 LOG_DEBUG(Service_AM, "called");
95 31
96 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 32 IPC::ResponseBuilder rb{ctx, 2};
97 rb.Push(ResultSuccess); 33 rb.Push(ResultUnknown);
98 rb.PushIpcInterface<IApplicationFunctions>(system);
99 } 34 }
100
101 Nvnflinger::Nvnflinger& nvnflinger;
102 std::shared_ptr<AppletMessageQueue> msg_queue;
103};
104
105void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_AM, "called");
107
108 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
109 rb.Push(ResultSuccess);
110 rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system);
111}
112
113AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
114 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
115 : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{
116 std::move(msg_queue_)} {
117 static const FunctionInfo functions[] = {
118 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
119 };
120 RegisterHandlers(functions);
121} 35}
122 36
123AppletOE::~AppletOE() = default; 37std::shared_ptr<Applet> AppletOE::GetAppletFromContext(HLERequestContext& ctx) {
124 38 const auto aruid = ctx.GetPID();
125const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const { 39 return system.GetAppletManager().GetByAppletResourceUserId(aruid);
126 return msg_queue;
127} 40}
128 41
129} // namespace Service::AM 42} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 39eccc4ab..f2ba1c924 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -18,21 +18,19 @@ class Nvnflinger;
18 18
19namespace AM { 19namespace AM {
20 20
21class AppletMessageQueue; 21struct Applet;
22 22
23class AppletOE final : public ServiceFramework<AppletOE> { 23class AppletOE final : public ServiceFramework<AppletOE> {
24public: 24public:
25 explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, 25 explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
26 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
27 ~AppletOE() override; 26 ~AppletOE() override;
28 27
29 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
30
31private: 28private:
32 void OpenApplicationProxy(HLERequestContext& ctx); 29 void OpenApplicationProxy(HLERequestContext& ctx);
33 30
31 std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
32
34 Nvnflinger::Nvnflinger& nvnflinger; 33 Nvnflinger::Nvnflinger& nvnflinger;
35 std::shared_ptr<AppletMessageQueue> msg_queue;
36}; 34};
37 35
38} // namespace AM 36} // namespace AM
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
deleted file mode 100644
index 89d5434af..000000000
--- a/src/core/hle/service/am/applets/applets.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstring>
5
6#include "common/assert.h"
7#include "core/core.h"
8#include "core/frontend/applets/cabinet.h"
9#include "core/frontend/applets/controller.h"
10#include "core/frontend/applets/error.h"
11#include "core/frontend/applets/general_frontend.h"
12#include "core/frontend/applets/mii_edit.h"
13#include "core/frontend/applets/profile_select.h"
14#include "core/frontend/applets/software_keyboard.h"
15#include "core/frontend/applets/web_browser.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h"
19#include "core/hle/service/am/applet_oe.h"
20#include "core/hle/service/am/applets/applet_cabinet.h"
21#include "core/hle/service/am/applets/applet_controller.h"
22#include "core/hle/service/am/applets/applet_error.h"
23#include "core/hle/service/am/applets/applet_general_backend.h"
24#include "core/hle/service/am/applets/applet_mii_edit.h"
25#include "core/hle/service/am/applets/applet_profile_select.h"
26#include "core/hle/service/am/applets/applet_software_keyboard.h"
27#include "core/hle/service/am/applets/applet_web_browser.h"
28#include "core/hle/service/am/applets/applets.h"
29#include "core/hle/service/sm/sm.h"
30
31namespace Service::AM::Applets {
32
33AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
34 : system{system_}, applet_mode{applet_mode_}, service_context{system,
35 "ILibraryAppletAccessor"} {
36 state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent");
37 pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent");
38 pop_interactive_out_data_event =
39 service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
40}
41
42AppletDataBroker::~AppletDataBroker() {
43 service_context.CloseEvent(state_changed_event);
44 service_context.CloseEvent(pop_out_data_event);
45 service_context.CloseEvent(pop_interactive_out_data_event);
46}
47
48AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
49 std::vector<std::vector<u8>> out_normal;
50
51 for (const auto& storage : in_channel) {
52 out_normal.push_back(storage->GetData());
53 }
54
55 std::vector<std::vector<u8>> out_interactive;
56
57 for (const auto& storage : in_interactive_channel) {
58 out_interactive.push_back(storage->GetData());
59 }
60
61 return {std::move(out_normal), std::move(out_interactive)};
62}
63
64std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
65 if (out_channel.empty())
66 return nullptr;
67
68 auto out = std::move(out_channel.front());
69 out_channel.pop_front();
70 pop_out_data_event->Clear();
71 return out;
72}
73
74std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
75 if (in_channel.empty())
76 return nullptr;
77
78 auto out = std::move(in_channel.front());
79 in_channel.pop_front();
80 return out;
81}
82
83std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
84 if (out_interactive_channel.empty())
85 return nullptr;
86
87 auto out = std::move(out_interactive_channel.front());
88 out_interactive_channel.pop_front();
89 pop_interactive_out_data_event->Clear();
90 return out;
91}
92
93std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
94 if (in_interactive_channel.empty())
95 return nullptr;
96
97 auto out = std::move(in_interactive_channel.front());
98 in_interactive_channel.pop_front();
99 return out;
100}
101
102void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
103 in_channel.emplace_back(std::move(storage));
104}
105
106void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
107 out_channel.emplace_back(std::move(storage));
108 pop_out_data_event->Signal();
109}
110
111void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
112 in_interactive_channel.emplace_back(std::move(storage));
113}
114
115void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
116 out_interactive_channel.emplace_back(std::move(storage));
117 pop_interactive_out_data_event->Signal();
118}
119
120void AppletDataBroker::SignalStateChanged() {
121 state_changed_event->Signal();
122
123 switch (applet_mode) {
124 case LibraryAppletMode::AllForeground:
125 case LibraryAppletMode::AllForegroundInitiallyHidden: {
126 auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE");
127 auto applet_ae = system.ServiceManager().GetService<AppletAE>("appletAE");
128
129 if (applet_oe) {
130 applet_oe->GetMessageQueue()->FocusStateChanged();
131 break;
132 }
133
134 if (applet_ae) {
135 applet_ae->GetMessageQueue()->FocusStateChanged();
136 break;
137 }
138 break;
139 }
140 default:
141 break;
142 }
143}
144
145Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
146 return pop_out_data_event->GetReadableEvent();
147}
148
149Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
150 return pop_interactive_out_data_event->GetReadableEvent();
151}
152
153Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
154 return state_changed_event->GetReadableEvent();
155}
156
157Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
158 : broker{system_, applet_mode_}, applet_mode{applet_mode_} {}
159
160Applet::~Applet() = default;
161
162void Applet::Initialize() {
163 const auto common = broker.PopNormalDataToApplet();
164 ASSERT(common != nullptr);
165
166 const auto common_data = common->GetData();
167
168 ASSERT(common_data.size() >= sizeof(CommonArguments));
169 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
170
171 initialized = true;
172}
173
174AppletFrontendSet::AppletFrontendSet() = default;
175
176AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
177 ControllerApplet controller_applet, ErrorApplet error_applet,
178 MiiEdit mii_edit_,
179 ParentalControlsApplet parental_controls_applet,
180 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
181 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
182 : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
183 error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
184 parental_controls{std::move(parental_controls_applet)},
185 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
186 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
187
188AppletFrontendSet::~AppletFrontendSet() = default;
189
190AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
191
192AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
193
194AppletManager::AppletManager(Core::System& system_) : system{system_} {}
195
196AppletManager::~AppletManager() = default;
197
198const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
199 return frontend;
200}
201
202NFP::CabinetMode AppletManager::GetCabinetMode() const {
203 return cabinet_mode;
204}
205
206AppletId AppletManager::GetCurrentAppletId() const {
207 return current_applet_id;
208}
209
210void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
211 if (set.cabinet != nullptr) {
212 frontend.cabinet = std::move(set.cabinet);
213 }
214
215 if (set.controller != nullptr) {
216 frontend.controller = std::move(set.controller);
217 }
218
219 if (set.error != nullptr) {
220 frontend.error = std::move(set.error);
221 }
222
223 if (set.mii_edit != nullptr) {
224 frontend.mii_edit = std::move(set.mii_edit);
225 }
226
227 if (set.parental_controls != nullptr) {
228 frontend.parental_controls = std::move(set.parental_controls);
229 }
230
231 if (set.photo_viewer != nullptr) {
232 frontend.photo_viewer = std::move(set.photo_viewer);
233 }
234
235 if (set.profile_select != nullptr) {
236 frontend.profile_select = std::move(set.profile_select);
237 }
238
239 if (set.software_keyboard != nullptr) {
240 frontend.software_keyboard = std::move(set.software_keyboard);
241 }
242
243 if (set.web_browser != nullptr) {
244 frontend.web_browser = std::move(set.web_browser);
245 }
246}
247
248void AppletManager::SetCabinetMode(NFP::CabinetMode mode) {
249 cabinet_mode = mode;
250}
251
252void AppletManager::SetCurrentAppletId(AppletId applet_id) {
253 current_applet_id = applet_id;
254}
255
256void AppletManager::SetDefaultAppletFrontendSet() {
257 ClearAll();
258 SetDefaultAppletsIfMissing();
259}
260
261void AppletManager::SetDefaultAppletsIfMissing() {
262 if (frontend.cabinet == nullptr) {
263 frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
264 }
265
266 if (frontend.controller == nullptr) {
267 frontend.controller =
268 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
269 }
270
271 if (frontend.error == nullptr) {
272 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
273 }
274
275 if (frontend.mii_edit == nullptr) {
276 frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
277 }
278
279 if (frontend.parental_controls == nullptr) {
280 frontend.parental_controls =
281 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
282 }
283
284 if (frontend.photo_viewer == nullptr) {
285 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
286 }
287
288 if (frontend.profile_select == nullptr) {
289 frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
290 }
291
292 if (frontend.software_keyboard == nullptr) {
293 frontend.software_keyboard =
294 std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
295 }
296
297 if (frontend.web_browser == nullptr) {
298 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
299 }
300}
301
302void AppletManager::ClearAll() {
303 frontend = {};
304}
305
306std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
307 switch (id) {
308 case AppletId::Auth:
309 return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
310 case AppletId::Cabinet:
311 return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
312 case AppletId::Controller:
313 return std::make_shared<Controller>(system, mode, *frontend.controller);
314 case AppletId::Error:
315 return std::make_shared<Error>(system, mode, *frontend.error);
316 case AppletId::ProfileSelect:
317 return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
318 case AppletId::SoftwareKeyboard:
319 return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
320 case AppletId::MiiEdit:
321 return std::make_shared<MiiEdit>(system, mode, *frontend.mii_edit);
322 case AppletId::Web:
323 case AppletId::Shop:
324 case AppletId::OfflineWeb:
325 case AppletId::LoginShare:
326 case AppletId::WebAuth:
327 return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
328 case AppletId::PhotoViewer:
329 return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
330 default:
331 UNIMPLEMENTED_MSG(
332 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
333 static_cast<u8>(id));
334 return std::make_shared<StubApplet>(system, id, mode);
335 }
336}
337
338} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
deleted file mode 100644
index 0bf2598b7..000000000
--- a/src/core/hle/service/am/applets/applets.h
+++ /dev/null
@@ -1,289 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <queue>
8
9#include "common/swap.h"
10#include "core/hle/service/kernel_helpers.h"
11
12union Result;
13
14namespace Core {
15class System;
16}
17
18namespace Core::Frontend {
19class CabinetApplet;
20class ControllerApplet;
21class ECommerceApplet;
22class ErrorApplet;
23class MiiEditApplet;
24class ParentalControlsApplet;
25class PhotoViewerApplet;
26class ProfileSelectApplet;
27class SoftwareKeyboardApplet;
28class WebBrowserApplet;
29} // namespace Core::Frontend
30
31namespace Kernel {
32class KernelCore;
33class KEvent;
34class KReadableEvent;
35} // namespace Kernel
36
37namespace Service::NFP {
38enum class CabinetMode : u8;
39} // namespace Service::NFP
40
41namespace Service::AM {
42
43class IStorage;
44
45namespace Applets {
46
47enum class AppletId : u32 {
48 None = 0x00,
49 Application = 0x01,
50 OverlayDisplay = 0x02,
51 QLaunch = 0x03,
52 Starter = 0x04,
53 Auth = 0x0A,
54 Cabinet = 0x0B,
55 Controller = 0x0C,
56 DataErase = 0x0D,
57 Error = 0x0E,
58 NetConnect = 0x0F,
59 ProfileSelect = 0x10,
60 SoftwareKeyboard = 0x11,
61 MiiEdit = 0x12,
62 Web = 0x13,
63 Shop = 0x14,
64 PhotoViewer = 0x15,
65 Settings = 0x16,
66 OfflineWeb = 0x17,
67 LoginShare = 0x18,
68 WebAuth = 0x19,
69 MyPage = 0x1A,
70};
71
72enum class AppletProgramId : u64 {
73 QLaunch = 0x0100000000001000ull,
74 Auth = 0x0100000000001001ull,
75 Cabinet = 0x0100000000001002ull,
76 Controller = 0x0100000000001003ull,
77 DataErase = 0x0100000000001004ull,
78 Error = 0x0100000000001005ull,
79 NetConnect = 0x0100000000001006ull,
80 ProfileSelect = 0x0100000000001007ull,
81 SoftwareKeyboard = 0x0100000000001008ull,
82 MiiEdit = 0x0100000000001009ull,
83 Web = 0x010000000000100Aull,
84 Shop = 0x010000000000100Bull,
85 OverlayDisplay = 0x010000000000100Cull,
86 PhotoViewer = 0x010000000000100Dull,
87 Settings = 0x010000000000100Eull,
88 OfflineWeb = 0x010000000000100Full,
89 LoginShare = 0x0100000000001010ull,
90 WebAuth = 0x0100000000001011ull,
91 Starter = 0x0100000000001012ull,
92 MyPage = 0x0100000000001013ull,
93 MaxProgramId = 0x0100000000001FFFull,
94};
95
96enum class LibraryAppletMode : u32 {
97 AllForeground = 0,
98 Background = 1,
99 NoUI = 2,
100 BackgroundIndirectDisplay = 3,
101 AllForegroundInitiallyHidden = 4,
102};
103
104enum class CommonArgumentVersion : u32 {
105 Version0,
106 Version1,
107 Version2,
108 Version3,
109};
110
111enum class CommonArgumentSize : u32 {
112 Version3 = 0x20,
113};
114
115enum class ThemeColor : u32 {
116 BasicWhite = 0,
117 BasicBlack = 3,
118};
119
120struct CommonArguments {
121 CommonArgumentVersion arguments_version;
122 CommonArgumentSize size;
123 u32 library_version;
124 ThemeColor theme_color;
125 bool play_startup_sound;
126 u64_le system_tick;
127};
128static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
129
130class AppletDataBroker final {
131public:
132 explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
133 ~AppletDataBroker();
134
135 struct RawChannelData {
136 std::vector<std::vector<u8>> normal;
137 std::vector<std::vector<u8>> interactive;
138 };
139
140 // Retrieves but does not pop the data sent to applet.
141 RawChannelData PeekDataToAppletForDebug() const;
142
143 std::shared_ptr<IStorage> PopNormalDataToGame();
144 std::shared_ptr<IStorage> PopNormalDataToApplet();
145
146 std::shared_ptr<IStorage> PopInteractiveDataToGame();
147 std::shared_ptr<IStorage> PopInteractiveDataToApplet();
148
149 void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
150 void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
151
152 void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
153 void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
154
155 void SignalStateChanged();
156
157 Kernel::KReadableEvent& GetNormalDataEvent();
158 Kernel::KReadableEvent& GetInteractiveDataEvent();
159 Kernel::KReadableEvent& GetStateChangedEvent();
160
161private:
162 Core::System& system;
163 LibraryAppletMode applet_mode;
164
165 KernelHelpers::ServiceContext service_context;
166
167 // Queues are named from applet's perspective
168
169 // PopNormalDataToApplet and PushNormalDataFromGame
170 std::deque<std::shared_ptr<IStorage>> in_channel;
171
172 // PopNormalDataToGame and PushNormalDataFromApplet
173 std::deque<std::shared_ptr<IStorage>> out_channel;
174
175 // PopInteractiveDataToApplet and PushInteractiveDataFromGame
176 std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
177
178 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
179 std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
180
181 Kernel::KEvent* state_changed_event;
182
183 // Signaled on PushNormalDataFromApplet
184 Kernel::KEvent* pop_out_data_event;
185
186 // Signaled on PushInteractiveDataFromApplet
187 Kernel::KEvent* pop_interactive_out_data_event;
188};
189
190class Applet {
191public:
192 explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_);
193 virtual ~Applet();
194
195 virtual void Initialize();
196
197 virtual bool TransactionComplete() const = 0;
198 virtual Result GetStatus() const = 0;
199 virtual void ExecuteInteractive() = 0;
200 virtual void Execute() = 0;
201 virtual Result RequestExit() = 0;
202
203 AppletDataBroker& GetBroker() {
204 return broker;
205 }
206
207 const AppletDataBroker& GetBroker() const {
208 return broker;
209 }
210
211 LibraryAppletMode GetLibraryAppletMode() const {
212 return applet_mode;
213 }
214
215 bool IsInitialized() const {
216 return initialized;
217 }
218
219protected:
220 CommonArguments common_args{};
221 AppletDataBroker broker;
222 LibraryAppletMode applet_mode;
223 bool initialized = false;
224};
225
226struct AppletFrontendSet {
227 using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
228 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
229 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
230 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
231 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
232 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
233 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
234 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
235 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
236
237 AppletFrontendSet();
238 AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
239 ErrorApplet error_applet, MiiEdit mii_edit_,
240 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
241 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
242 WebBrowser web_browser_);
243 ~AppletFrontendSet();
244
245 AppletFrontendSet(const AppletFrontendSet&) = delete;
246 AppletFrontendSet& operator=(const AppletFrontendSet&) = delete;
247
248 AppletFrontendSet(AppletFrontendSet&&) noexcept;
249 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
250
251 CabinetApplet cabinet;
252 ControllerApplet controller;
253 ErrorApplet error;
254 MiiEdit mii_edit;
255 ParentalControlsApplet parental_controls;
256 PhotoViewer photo_viewer;
257 ProfileSelect profile_select;
258 SoftwareKeyboard software_keyboard;
259 WebBrowser web_browser;
260};
261
262class AppletManager {
263public:
264 explicit AppletManager(Core::System& system_);
265 ~AppletManager();
266
267 const AppletFrontendSet& GetAppletFrontendSet() const;
268 NFP::CabinetMode GetCabinetMode() const;
269 AppletId GetCurrentAppletId() const;
270
271 void SetAppletFrontendSet(AppletFrontendSet set);
272 void SetCabinetMode(NFP::CabinetMode mode);
273 void SetCurrentAppletId(AppletId applet_id);
274 void SetDefaultAppletFrontendSet();
275 void SetDefaultAppletsIfMissing();
276 void ClearAll();
277
278 std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
279
280private:
281 AppletId current_applet_id{};
282 NFP::CabinetMode cabinet_mode{};
283
284 AppletFrontendSet frontend;
285 Core::System& system;
286};
287
288} // namespace Applets
289} // namespace Service::AM
diff --git a/src/core/hle/service/am/application_creator.cpp b/src/core/hle/service/am/application_creator.cpp
new file mode 100644
index 000000000..79ea045a3
--- /dev/null
+++ b/src/core/hle/service/am/application_creator.cpp
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/application_creator.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IApplicationCreator::IApplicationCreator(Core::System& system_)
10 : ServiceFramework{system_, "IApplicationCreator"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "CreateApplication"},
14 {1, nullptr, "PopLaunchRequestedApplication"},
15 {10, nullptr, "CreateSystemApplication"},
16 {100, nullptr, "PopFloatingApplicationForDevelopment"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21}
22
23IApplicationCreator::~IApplicationCreator() = default;
24
25} // namespace Service::AM
diff --git a/src/core/hle/service/am/application_creator.h b/src/core/hle/service/am/application_creator.h
new file mode 100644
index 000000000..375a3c476
--- /dev/null
+++ b/src/core/hle/service/am/application_creator.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
11public:
12 explicit IApplicationCreator(Core::System& system_);
13 ~IApplicationCreator() override;
14};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/am/application_functions.cpp b/src/core/hle/service/am/application_functions.cpp
new file mode 100644
index 000000000..51c5be2d1
--- /dev/null
+++ b/src/core/hle/service/am/application_functions.cpp
@@ -0,0 +1,594 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "common/uuid.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/registered_cache.h"
9#include "core/file_sys/savedata_factory.h"
10#include "core/hle/service/acc/profile_manager.h"
11#include "core/hle/service/am/am_results.h"
12#include "core/hle/service/am/applet.h"
13#include "core/hle/service/am/application_functions.h"
14#include "core/hle/service/am/storage.h"
15#include "core/hle/service/filesystem/filesystem.h"
16#include "core/hle/service/filesystem/save_data_controller.h"
17#include "core/hle/service/ipc_helpers.h"
18#include "core/hle/service/ns/ns.h"
19#include "core/hle/service/sm/sm.h"
20
21namespace Service::AM {
22
23enum class LaunchParameterKind : u32 {
24 UserChannel = 1,
25 AccountPreselectedUser = 2,
26};
27
28IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_)
29 : ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} {
30 // clang-format off
31 static const FunctionInfo functions[] = {
32 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
33 {10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
34 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
35 {12, nullptr, "CreateApplicationAndRequestToStart"},
36 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
37 {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
38 {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
39 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
40 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
41 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
42 {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
43 {24, nullptr, "GetLaunchStorageInfoForDebug"},
44 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
45 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
46 {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
47 {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
48 {29, nullptr, "GetCacheStorageMax"},
49 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
50 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
51 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
52 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
53 {34, nullptr, "SelectApplicationLicense"},
54 {35, nullptr, "GetDeviceSaveDataSizeMax"},
55 {36, nullptr, "GetLimitedApplicationLicense"},
56 {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
57 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
58 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
59 {60, nullptr, "SetMediaPlaybackStateForApplication"},
60 {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"},
61 {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
62 {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
63 {68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
64 {70, nullptr, "RequestToShutdown"},
65 {71, nullptr, "RequestToReboot"},
66 {72, nullptr, "RequestToSleep"},
67 {80, nullptr, "ExitAndRequestToShowThanksMessage"},
68 {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
69 {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
70 {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
71 {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
72 {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
73 {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
74 {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
75 {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
76 {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
77 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
78 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
79 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
80 {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
81 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
82 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
83 {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"},
84 {151, nullptr, "TryPopFromNotificationStorageChannel"},
85 {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
86 {170, nullptr, "SetHdcpAuthenticationActivated"},
87 {180, nullptr, "GetLaunchRequiredVersion"},
88 {181, nullptr, "UpgradeLaunchRequiredVersion"},
89 {190, nullptr, "SendServerMaintenanceOverlayNotification"},
90 {200, nullptr, "GetLastApplicationExitReason"},
91 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
92 {1000, nullptr, "CreateMovieMaker"},
93 {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
94 };
95 // clang-format on
96
97 RegisterHandlers(functions);
98}
99
100IApplicationFunctions::~IApplicationFunctions() = default;
101
102void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
103 LOG_WARNING(Service_AM, "(STUBBED) called");
104
105 std::scoped_lock lk{applet->lock};
106 applet->application_crash_report_enabled = true;
107
108 IPC::ResponseBuilder rb{ctx, 2};
109 rb.Push(ResultSuccess);
110}
111
112void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
113 LOG_WARNING(Service_AM, "(STUBBED) called");
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(ResultSuccess);
117}
118
119void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
120 LOG_WARNING(Service_AM, "(STUBBED) called");
121
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(ResultSuccess);
124}
125
126void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
127 IPC::RequestParser rp{ctx};
128 const auto is_visible = rp.Pop<bool>();
129
130 LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible);
131
132 IPC::ResponseBuilder rb{ctx, 2};
133 rb.Push(ResultSuccess);
134}
135
136void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
137 LOG_WARNING(Service_AM, "(STUBBED) called");
138
139 std::scoped_lock lk{applet->lock};
140 applet->home_button_long_pressed_blocked = true;
141 applet->home_button_short_pressed_blocked = true;
142
143 IPC::ResponseBuilder rb{ctx, 2};
144 rb.Push(ResultSuccess);
145}
146
147void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
148 LOG_WARNING(Service_AM, "(STUBBED) called");
149
150 std::scoped_lock lk{applet->lock};
151 applet->home_button_long_pressed_blocked = false;
152 applet->home_button_short_pressed_blocked = false;
153
154 IPC::ResponseBuilder rb{ctx, 2};
155 rb.Push(ResultSuccess);
156}
157
158void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
159 LOG_WARNING(Service_AM, "(STUBBED) called");
160
161 std::scoped_lock lk{applet->lock};
162 applet->home_button_long_pressed_blocked = true;
163 applet->home_button_short_pressed_blocked = true;
164 applet->home_button_double_click_enabled = true;
165
166 IPC::ResponseBuilder rb{ctx, 2};
167 rb.Push(ResultSuccess);
168}
169
170void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
171 LOG_WARNING(Service_AM, "(STUBBED) called");
172
173 std::scoped_lock lk{applet->lock};
174 applet->home_button_long_pressed_blocked = false;
175 applet->home_button_short_pressed_blocked = false;
176 applet->home_button_double_click_enabled = false;
177
178 IPC::ResponseBuilder rb{ctx, 2};
179 rb.Push(ResultSuccess);
180}
181
182void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
183 IPC::RequestParser rp{ctx};
184 const auto kind = rp.PopEnum<LaunchParameterKind>();
185
186 LOG_INFO(Service_AM, "called, kind={:08X}", kind);
187
188 std::scoped_lock lk{applet->lock};
189
190 auto& channel = kind == LaunchParameterKind::UserChannel
191 ? applet->user_channel_launch_parameter
192 : applet->preselected_user_launch_parameter;
193
194 if (channel.empty()) {
195 LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind);
196 IPC::ResponseBuilder rb{ctx, 2};
197 rb.Push(AM::ResultNoDataInChannel);
198 return;
199 }
200
201 auto data = channel.back();
202 channel.pop_back();
203
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(ResultSuccess);
206 rb.PushIpcInterface<IStorage>(system, std::move(data));
207}
208
209void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
210 LOG_WARNING(Service_AM, "(STUBBED) called");
211
212 IPC::ResponseBuilder rb{ctx, 2};
213 rb.Push(ResultSuccess);
214}
215
216void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
217 IPC::RequestParser rp{ctx};
218 u128 user_id = rp.PopRaw<u128>();
219
220 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
221
222 FileSys::SaveDataAttribute attribute{};
223 attribute.title_id = applet->program_id;
224 attribute.user_id = user_id;
225 attribute.type = FileSys::SaveDataType::SaveData;
226
227 FileSys::VirtualDir save_data{};
228 const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
229 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
230
231 IPC::ResponseBuilder rb{ctx, 4};
232 rb.Push(res);
233 rb.Push<u64>(0);
234}
235
236void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
237 // Takes an input u32 Result, no output.
238 // For example, in some cases official apps use this with error 0x2A2 then
239 // uses svcBreak.
240
241 IPC::RequestParser rp{ctx};
242 u32 result = rp.Pop<u32>();
243 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
244
245 std::scoped_lock lk{applet->lock};
246 applet->terminate_result = Result(result);
247
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(ResultSuccess);
250}
251
252void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
253 LOG_DEBUG(Service_AM, "called");
254
255 std::array<u8, 0x10> version_string{};
256
257 const auto res = [this] {
258 const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
259 system.GetContentProvider()};
260 auto metadata = pm.GetControlMetadata();
261 if (metadata.first != nullptr) {
262 return metadata;
263 }
264
265 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
266 system.GetFileSystemController(),
267 system.GetContentProvider()};
268 return pm_update.GetControlMetadata();
269 }();
270
271 if (res.first != nullptr) {
272 const auto& version = res.first->GetVersionString();
273 std::copy(version.begin(), version.end(), version_string.begin());
274 } else {
275 static constexpr char default_version[]{"1.0.0"};
276 std::memcpy(version_string.data(), default_version, sizeof(default_version));
277 }
278
279 IPC::ResponseBuilder rb{ctx, 6};
280 rb.Push(ResultSuccess);
281 rb.PushRaw(version_string);
282}
283
284void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
285 // TODO(bunnei): This should be configurable
286 LOG_DEBUG(Service_AM, "called");
287
288 // Get supported languages from NACP, if possible
289 // Default to 0 (all languages supported)
290 u32 supported_languages = 0;
291
292 const auto res = [this] {
293 const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
294 system.GetContentProvider()};
295 auto metadata = pm.GetControlMetadata();
296 if (metadata.first != nullptr) {
297 return metadata;
298 }
299
300 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
301 system.GetFileSystemController(),
302 system.GetContentProvider()};
303 return pm_update.GetControlMetadata();
304 }();
305
306 if (res.first != nullptr) {
307 supported_languages = res.first->GetSupportedLanguages();
308 }
309
310 // Call IApplicationManagerInterface implementation.
311 auto& service_manager = system.ServiceManager();
312 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
313 auto app_man = ns_am2->GetApplicationManagerInterface();
314
315 // Get desired application language
316 u8 desired_language{};
317 const auto res_lang =
318 app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
319 if (res_lang != ResultSuccess) {
320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(res_lang);
322 return;
323 }
324
325 // Convert to settings language code.
326 u64 language_code{};
327 const auto res_code =
328 app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
329 if (res_code != ResultSuccess) {
330 IPC::ResponseBuilder rb{ctx, 2};
331 rb.Push(res_code);
332 return;
333 }
334
335 LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
336
337 IPC::ResponseBuilder rb{ctx, 4};
338 rb.Push(ResultSuccess);
339 rb.Push(language_code);
340}
341
342void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
343 LOG_WARNING(Service_AM, "(STUBBED) called");
344
345 IPC::ResponseBuilder rb{ctx, 3};
346 rb.Push(ResultSuccess);
347 rb.Push(applet->gameplay_recording_supported);
348}
349
350void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
351 LOG_WARNING(Service_AM, "(STUBBED) called");
352
353 IPC::ResponseBuilder rb{ctx, 2};
354 rb.Push(ResultSuccess);
355}
356
357void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
358 LOG_WARNING(Service_AM, "(STUBBED) called");
359
360 IPC::RequestParser rp{ctx};
361
362 std::scoped_lock lk{applet->lock};
363 applet->gameplay_recording_state = rp.PopRaw<GameplayRecordingState>();
364
365 IPC::ResponseBuilder rb{ctx, 2};
366 rb.Push(ResultSuccess);
367}
368
369void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
370 LOG_WARNING(Service_AM, "(STUBBED) called");
371
372 std::scoped_lock lk{applet->lock};
373 applet->is_running = true;
374
375 IPC::ResponseBuilder rb{ctx, 3};
376 rb.Push(ResultSuccess);
377 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
378}
379
380void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
381 LOG_WARNING(Service_AM, "(STUBBED) called");
382
383 IPC::ResponseBuilder rb{ctx, 6};
384 rb.Push(ResultSuccess);
385
386 // Returns a 128-bit UUID
387 rb.Push<u64>(0);
388 rb.Push<u64>(0);
389}
390
391void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
392 struct Parameters {
393 FileSys::SaveDataType type;
394 u128 user_id;
395 u64 new_normal_size;
396 u64 new_journal_size;
397 };
398 static_assert(sizeof(Parameters) == 40);
399
400 IPC::RequestParser rp{ctx};
401 const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
402
403 LOG_DEBUG(Service_AM,
404 "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
405 "new_journal={:016X}",
406 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
407
408 system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
409 type, applet->program_id, user_id, {new_normal_size, new_journal_size});
410
411 IPC::ResponseBuilder rb{ctx, 4};
412 rb.Push(ResultSuccess);
413
414 // The following value is used upon failure to help the system recover.
415 // Since we always succeed, this should be 0.
416 rb.Push<u64>(0);
417}
418
419void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
420 struct Parameters {
421 FileSys::SaveDataType type;
422 u128 user_id;
423 };
424 static_assert(sizeof(Parameters) == 24);
425
426 IPC::RequestParser rp{ctx};
427 const auto [type, user_id] = rp.PopRaw<Parameters>();
428
429 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
430 user_id[0]);
431
432 const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
433 type, applet->program_id, user_id);
434
435 IPC::ResponseBuilder rb{ctx, 6};
436 rb.Push(ResultSuccess);
437 rb.Push(size.normal);
438 rb.Push(size.journal);
439}
440
441void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
442 struct InputParameters {
443 u16 index;
444 s64 size;
445 s64 journal_size;
446 };
447 static_assert(sizeof(InputParameters) == 24);
448
449 struct OutputParameters {
450 u32 storage_target;
451 u64 required_size;
452 };
453 static_assert(sizeof(OutputParameters) == 16);
454
455 IPC::RequestParser rp{ctx};
456 const auto params = rp.PopRaw<InputParameters>();
457
458 LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
459 params.index, params.size, params.journal_size);
460
461 const OutputParameters resp{
462 .storage_target = 1,
463 .required_size = 0,
464 };
465
466 IPC::ResponseBuilder rb{ctx, 6};
467 rb.Push(ResultSuccess);
468 rb.PushRaw(resp);
469}
470
471void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
472 LOG_WARNING(Service_AM, "(STUBBED) called");
473
474 constexpr u64 size_max_normal = 0xFFFFFFF;
475 constexpr u64 size_max_journal = 0xFFFFFFF;
476
477 IPC::ResponseBuilder rb{ctx, 6};
478 rb.Push(ResultSuccess);
479 rb.Push(size_max_normal);
480 rb.Push(size_max_journal);
481}
482
483void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
484 LOG_WARNING(Service_AM, "(STUBBED) called");
485
486 IPC::ResponseBuilder rb{ctx, 3};
487 rb.Push(ResultSuccess);
488 rb.Push<u32>(0);
489}
490
491void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
492 LOG_WARNING(Service_AM, "(STUBBED) called");
493
494 IPC::ResponseBuilder rb{ctx, 3};
495 rb.Push(ResultSuccess);
496 rb.Push<u32>(0);
497}
498
499void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
500 LOG_WARNING(Service_AM, "(STUBBED) called");
501
502 IPC::RequestParser rp{ctx};
503 [[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
504 [[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
505 const auto program_index = rp.Pop<u64>();
506
507 IPC::ResponseBuilder rb{ctx, 2};
508 rb.Push(ResultSuccess);
509
510 // Swap user channel ownership into the system so that it will be preserved
511 system.GetUserChannel().swap(applet->user_channel_launch_parameter);
512 system.ExecuteProgram(program_index);
513}
514
515void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
516 LOG_DEBUG(Service_AM, "called");
517
518 applet->user_channel_launch_parameter.clear();
519
520 IPC::ResponseBuilder rb{ctx, 2};
521 rb.Push(ResultSuccess);
522}
523
524void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
525 LOG_DEBUG(Service_AM, "called");
526
527 IPC::RequestParser rp{ctx};
528 const auto storage = rp.PopIpcInterface<IStorage>().lock();
529 if (storage) {
530 applet->user_channel_launch_parameter.push_back(storage->GetData());
531 }
532
533 IPC::ResponseBuilder rb{ctx, 2};
534 rb.Push(ResultSuccess);
535}
536
537void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
538 LOG_WARNING(Service_AM, "(STUBBED) called");
539
540 IPC::ResponseBuilder rb{ctx, 3};
541 rb.Push(ResultSuccess);
542 rb.Push<s32>(applet->previous_program_index);
543}
544
545void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
546 LOG_WARNING(Service_AM, "(STUBBED) called");
547
548 IPC::ResponseBuilder rb{ctx, 2, 1};
549 rb.Push(ResultSuccess);
550 rb.PushCopyObjects(applet->gpu_error_detected_event.GetHandle());
551}
552
553void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
554 LOG_DEBUG(Service_AM, "called");
555
556 IPC::ResponseBuilder rb{ctx, 2, 1};
557 rb.Push(ResultSuccess);
558 rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle());
559}
560
561void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
562 LOG_DEBUG(Service_AM, "(STUBBED) called");
563
564 IPC::ResponseBuilder rb{ctx, 2};
565 rb.Push(AM::ResultNoDataInChannel);
566}
567
568void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
569 LOG_DEBUG(Service_AM, "called");
570
571 IPC::ResponseBuilder rb{ctx, 2, 1};
572 rb.Push(ResultSuccess);
573 rb.PushCopyObjects(applet->notification_storage_channel_event.GetHandle());
574}
575
576void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
577 LOG_DEBUG(Service_AM, "called");
578
579 IPC::ResponseBuilder rb{ctx, 2, 1};
580 rb.Push(ResultSuccess);
581 rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle());
582}
583
584void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
585 LOG_WARNING(Service_AM, "(STUBBED) called");
586
587 std::scoped_lock lk{applet->lock};
588 applet->jit_service_launched = true;
589
590 IPC::ResponseBuilder rb{ctx, 2};
591 rb.Push(ResultSuccess);
592}
593
594} // namespace Service::AM
diff --git a/src/core/hle/service/am/application_functions.h b/src/core/hle/service/am/application_functions.h
new file mode 100644
index 000000000..55eb21d39
--- /dev/null
+++ b/src/core/hle/service/am/application_functions.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11struct Applet;
12
13class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
14public:
15 explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
16 ~IApplicationFunctions() override;
17
18private:
19 void PopLaunchParameter(HLERequestContext& ctx);
20 void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
21 void EnsureSaveData(HLERequestContext& ctx);
22 void SetTerminateResult(HLERequestContext& ctx);
23 void GetDisplayVersion(HLERequestContext& ctx);
24 void GetDesiredLanguage(HLERequestContext& ctx);
25 void IsGamePlayRecordingSupported(HLERequestContext& ctx);
26 void InitializeGamePlayRecording(HLERequestContext& ctx);
27 void SetGamePlayRecordingState(HLERequestContext& ctx);
28 void NotifyRunning(HLERequestContext& ctx);
29 void GetPseudoDeviceId(HLERequestContext& ctx);
30 void ExtendSaveData(HLERequestContext& ctx);
31 void GetSaveDataSize(HLERequestContext& ctx);
32 void CreateCacheStorage(HLERequestContext& ctx);
33 void GetSaveDataSizeMax(HLERequestContext& ctx);
34 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
35 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
36 void BeginBlockingHomeButton(HLERequestContext& ctx);
37 void EndBlockingHomeButton(HLERequestContext& ctx);
38 void EnableApplicationCrashReport(HLERequestContext& ctx);
39 void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
40 void SetApplicationCopyrightImage(HLERequestContext& ctx);
41 void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
42 void QueryApplicationPlayStatistics(HLERequestContext& ctx);
43 void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
44 void ExecuteProgram(HLERequestContext& ctx);
45 void ClearUserChannel(HLERequestContext& ctx);
46 void UnpopToUserChannel(HLERequestContext& ctx);
47 void GetPreviousProgramIndex(HLERequestContext& ctx);
48 void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
49 void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
50 void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
51 void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
52 void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
53 void PrepareForJit(HLERequestContext& ctx);
54
55 const std::shared_ptr<Applet> applet;
56};
57
58} // namespace Service::AM
diff --git a/src/core/hle/service/am/application_proxy.cpp b/src/core/hle/service/am/application_proxy.cpp
new file mode 100644
index 000000000..a6fd6d37f
--- /dev/null
+++ b/src/core/hle/service/am/application_proxy.cpp
@@ -0,0 +1,115 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_common_functions.h"
5#include "core/hle/service/am/application_functions.h"
6#include "core/hle/service/am/application_proxy.h"
7#include "core/hle/service/am/audio_controller.h"
8#include "core/hle/service/am/common_state_getter.h"
9#include "core/hle/service/am/debug_functions.h"
10#include "core/hle/service/am/display_controller.h"
11#include "core/hle/service/am/library_applet_creator.h"
12#include "core/hle/service/am/library_applet_self_accessor.h"
13#include "core/hle/service/am/process_winding_controller.h"
14#include "core/hle/service/am/self_controller.h"
15#include "core/hle/service/am/window_controller.h"
16#include "core/hle/service/ipc_helpers.h"
17
18namespace Service::AM {
19
20IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
21 std::shared_ptr<Applet> applet_, Core::System& system_)
22 : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
23 applet_)} {
24 // clang-format off
25 static const FunctionInfo functions[] = {
26 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
27 {1, &IApplicationProxy::GetSelfController, "GetSelfController"},
28 {2, &IApplicationProxy::GetWindowController, "GetWindowController"},
29 {3, &IApplicationProxy::GetAudioController, "GetAudioController"},
30 {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
31 {10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"},
32 {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
33 {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
34 {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IApplicationProxy::~IApplicationProxy() = default;
42
43void IApplicationProxy::GetAudioController(HLERequestContext& ctx) {
44 LOG_DEBUG(Service_AM, "called");
45
46 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
47 rb.Push(ResultSuccess);
48 rb.PushIpcInterface<IAudioController>(system);
49}
50
51void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) {
52 LOG_DEBUG(Service_AM, "called");
53
54 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
55 rb.Push(ResultSuccess);
56 rb.PushIpcInterface<IDisplayController>(system, applet);
57}
58
59void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) {
60 LOG_DEBUG(Service_AM, "called");
61
62 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
63 rb.Push(ResultSuccess);
64 rb.PushIpcInterface<IProcessWindingController>(system, applet);
65}
66
67void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) {
68 LOG_DEBUG(Service_AM, "called");
69
70 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
71 rb.Push(ResultSuccess);
72 rb.PushIpcInterface<IDebugFunctions>(system);
73}
74
75void IApplicationProxy::GetWindowController(HLERequestContext& ctx) {
76 LOG_DEBUG(Service_AM, "called");
77
78 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
79 rb.Push(ResultSuccess);
80 rb.PushIpcInterface<IWindowController>(system, applet);
81}
82
83void IApplicationProxy::GetSelfController(HLERequestContext& ctx) {
84 LOG_DEBUG(Service_AM, "called");
85
86 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
87 rb.Push(ResultSuccess);
88 rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
89}
90
91void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) {
92 LOG_DEBUG(Service_AM, "called");
93
94 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
95 rb.Push(ResultSuccess);
96 rb.PushIpcInterface<ICommonStateGetter>(system, applet);
97}
98
99void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
100 LOG_DEBUG(Service_AM, "called");
101
102 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
103 rb.Push(ResultSuccess);
104 rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
105}
106
107void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) {
108 LOG_DEBUG(Service_AM, "called");
109
110 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
111 rb.Push(ResultSuccess);
112 rb.PushIpcInterface<IApplicationFunctions>(system, applet);
113}
114
115} // namespace Service::AM
diff --git a/src/core/hle/service/am/application_proxy.h b/src/core/hle/service/am/application_proxy.h
new file mode 100644
index 000000000..eb98b095c
--- /dev/null
+++ b/src/core/hle/service/am/application_proxy.h
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
13public:
14 explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
15 std::shared_ptr<Applet> msg_queue_, Core::System& system_);
16 ~IApplicationProxy();
17
18private:
19 void GetAudioController(HLERequestContext& ctx);
20 void GetDisplayController(HLERequestContext& ctx);
21 void GetProcessWindingController(HLERequestContext& ctx);
22 void GetDebugFunctions(HLERequestContext& ctx);
23 void GetWindowController(HLERequestContext& ctx);
24 void GetSelfController(HLERequestContext& ctx);
25 void GetCommonStateGetter(HLERequestContext& ctx);
26 void GetLibraryAppletCreator(HLERequestContext& ctx);
27 void GetApplicationFunctions(HLERequestContext& ctx);
28
29 Nvnflinger::Nvnflinger& nvnflinger;
30 std::shared_ptr<Applet> applet;
31};
32
33} // namespace Service::AM
diff --git a/src/core/hle/service/am/audio_controller.cpp b/src/core/hle/service/am/audio_controller.cpp
new file mode 100644
index 000000000..ae75db174
--- /dev/null
+++ b/src/core/hle/service/am/audio_controller.cpp
@@ -0,0 +1,91 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/audio_controller.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IAudioController::IAudioController(Core::System& system_)
10 : ServiceFramework{system_, "IAudioController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
14 {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
15 {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
16 {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
17 {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22}
23
24IAudioController::~IAudioController() = default;
25
26void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
27 IPC::RequestParser rp{ctx};
28 const float main_applet_volume_tmp = rp.Pop<float>();
29 const float library_applet_volume_tmp = rp.Pop<float>();
30
31 LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
32 main_applet_volume_tmp, library_applet_volume_tmp);
33
34 // Ensure the volume values remain within the 0-100% range
35 main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
36 library_applet_volume =
37 std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
38
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(ResultSuccess);
41}
42
43void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
44 LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
45 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(ResultSuccess);
47 rb.Push(main_applet_volume);
48}
49
50void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
51 LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
52 IPC::ResponseBuilder rb{ctx, 3};
53 rb.Push(ResultSuccess);
54 rb.Push(library_applet_volume);
55}
56
57void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
58 struct Parameters {
59 float volume;
60 s64 fade_time_ns;
61 };
62 static_assert(sizeof(Parameters) == 16);
63
64 IPC::RequestParser rp{ctx};
65 const auto parameters = rp.PopRaw<Parameters>();
66
67 LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
68 parameters.fade_time_ns);
69
70 main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
71 fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
72
73 IPC::ResponseBuilder rb{ctx, 2};
74 rb.Push(ResultSuccess);
75}
76
77void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
78 IPC::RequestParser rp{ctx};
79 const float transparent_volume_rate_tmp = rp.Pop<float>();
80
81 LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
82
83 // Clamp volume range to 0-100%.
84 transparent_volume_rate =
85 std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
86
87 IPC::ResponseBuilder rb{ctx, 2};
88 rb.Push(ResultSuccess);
89}
90
91} // namespace Service::AM
diff --git a/src/core/hle/service/am/audio_controller.h b/src/core/hle/service/am/audio_controller.h
new file mode 100644
index 000000000..a47e3bad8
--- /dev/null
+++ b/src/core/hle/service/am/audio_controller.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IAudioController final : public ServiceFramework<IAudioController> {
11public:
12 explicit IAudioController(Core::System& system_);
13 ~IAudioController() override;
14
15private:
16 void SetExpectedMasterVolume(HLERequestContext& ctx);
17 void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
18 void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
19 void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
20 void SetTransparentAudioRate(HLERequestContext& ctx);
21
22 static constexpr float min_allowed_volume = 0.0f;
23 static constexpr float max_allowed_volume = 1.0f;
24
25 float main_applet_volume{0.25f};
26 float library_applet_volume{max_allowed_volume};
27 float transparent_volume_rate{min_allowed_volume};
28
29 // Volume transition fade time in nanoseconds.
30 // e.g. If the main applet volume was 0% and was changed to 50%
31 // with a fade of 50ns, then over the course of 50ns,
32 // the volume will gradually fade up to 50%
33 std::chrono::nanoseconds fade_time_ns{0};
34};
35
36} // namespace Service::AM
diff --git a/src/core/hle/service/am/common_state_getter.cpp b/src/core/hle/service/am/common_state_getter.cpp
new file mode 100644
index 000000000..937ac0beb
--- /dev/null
+++ b/src/core/hle/service/am/common_state_getter.cpp
@@ -0,0 +1,314 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/applet.h"
7#include "core/hle/service/am/common_state_getter.h"
8#include "core/hle/service/am/lock_accessor.h"
9#include "core/hle/service/apm/apm_controller.h"
10#include "core/hle/service/apm/apm_interface.h"
11#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/pm/pm.h"
13#include "core/hle/service/sm/sm.h"
14#include "core/hle/service/vi/vi.h"
15
16namespace Service::AM {
17
18ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_)
19 : ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
23 {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
24 {2, nullptr, "GetThisAppletKind"},
25 {3, nullptr, "AllowToEnterSleep"},
26 {4, nullptr, "DisallowToEnterSleep"},
27 {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
28 {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
29 {7, nullptr, "GetCradleStatus"},
30 {8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
31 {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
32 {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
33 {11, nullptr, "ReleaseSleepLock"},
34 {12, nullptr, "ReleaseSleepLockTransiently"},
35 {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
36 {14, nullptr, "GetWakeupCount"},
37 {20, nullptr, "PushToGeneralChannel"},
38 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
39 {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
40 {32, nullptr, "GetWriterLockAccessorEx"},
41 {40, nullptr, "GetCradleFwVersion"},
42 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
43 {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
44 {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
45 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
46 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
47 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
48 {59, nullptr, "SetVrPositionForDebug"},
49 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
50 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
51 {62, nullptr, "GetHdcpAuthenticationState"},
52 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
53 {64, nullptr, "SetTvPowerStateMatchingMode"},
54 {65, nullptr, "GetApplicationIdByContentActionName"},
55 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
56 {67, nullptr, "CancelCpuBoostMode"},
57 {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
58 {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
59 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
60 {91, nullptr, "GetCurrentPerformanceConfiguration"},
61 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
62 {110, nullptr, "OpenMyGpuErrorHandler"},
63 {120, &ICommonStateGetter::GetAppletLaunchedHistory, "GetAppletLaunchedHistory"},
64 {200, nullptr, "GetOperationModeSystemInfo"},
65 {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
66 {400, nullptr, "ActivateMigrationService"},
67 {401, nullptr, "DeactivateMigrationService"},
68 {500, nullptr, "DisableSleepTillShutdown"},
69 {501, nullptr, "SuppressDisablingSleepTemporarily"},
70 {502, nullptr, "IsSleepEnabled"},
71 {503, nullptr, "IsDisablingSleepSuppressed"},
72 {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
73 };
74 // clang-format on
75
76 RegisterHandlers(functions);
77}
78
79ICommonStateGetter::~ICommonStateGetter() = default;
80
81void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
82 LOG_DEBUG(Service_AM, "called");
83
84 IPC::ResponseBuilder rb{ctx, 3};
85 rb.Push(ResultSuccess);
86 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
87}
88
89void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
90 LOG_DEBUG(Service_AM, "(STUBBED) called");
91
92 IPC::ResponseBuilder rb{ctx, 2, 1};
93 rb.Push(ResultSuccess);
94 rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent());
95}
96
97void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_AM, "called");
99
100 const auto message = applet->message_queue.PopMessage();
101 IPC::ResponseBuilder rb{ctx, 3};
102
103 if (message == AppletMessageQueue::AppletMessage::None) {
104 LOG_ERROR(Service_AM, "Message queue is empty");
105 rb.Push(AM::ResultNoMessages);
106 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
107 return;
108 }
109
110 rb.Push(ResultSuccess);
111 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
112}
113
114void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
115 LOG_DEBUG(Service_AM, "(STUBBED) called");
116
117 std::scoped_lock lk{applet->lock};
118
119 IPC::ResponseBuilder rb{ctx, 3};
120 rb.Push(ResultSuccess);
121 rb.Push(static_cast<u8>(applet->focus_state));
122}
123
124void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
125 const bool use_docked_mode{Settings::IsDockedMode()};
126 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
127
128 IPC::ResponseBuilder rb{ctx, 3};
129 rb.Push(ResultSuccess);
130 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
131}
132
133void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
134 LOG_DEBUG(Service_AM, "called");
135
136 IPC::ResponseBuilder rb{ctx, 3};
137 rb.Push(ResultSuccess);
138 rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
139}
140
141void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
142 LOG_WARNING(Service_AM, "(STUBBED) called");
143
144 // Sleep lock is acquired immediately.
145 applet->sleep_lock_event.Signal();
146
147 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(ResultSuccess);
149}
150
151void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
152 IPC::RequestParser rp{ctx};
153 const auto unknown = rp.Pop<u32>();
154
155 LOG_INFO(Service_AM, "called, unknown={}", unknown);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158
159 rb.Push(ResultSuccess);
160 rb.PushIpcInterface<ILockAccessor>(system);
161}
162
163void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
164 LOG_WARNING(Service_AM, "called");
165
166 IPC::ResponseBuilder rb{ctx, 2, 1};
167 rb.Push(ResultSuccess);
168 rb.PushCopyObjects(applet->sleep_lock_event.GetHandle());
169}
170
171void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_AM, "called");
173
174 std::scoped_lock lk{applet->lock};
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push(applet->vr_mode_enabled);
179}
180
181void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
182 IPC::RequestParser rp{ctx};
183
184 std::scoped_lock lk{applet->lock};
185 applet->vr_mode_enabled = rp.Pop<bool>();
186 LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "on" : "off");
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(ResultSuccess);
190}
191
192void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
193 IPC::RequestParser rp{ctx};
194 const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
195
196 LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
197 is_lcd_backlight_off_enabled);
198
199 IPC::ResponseBuilder rb{ctx, 2};
200 rb.Push(ResultSuccess);
201}
202
203void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
204 LOG_WARNING(Service_AM, "(STUBBED) called");
205
206 std::scoped_lock lk{applet->lock};
207 applet->vr_mode_enabled = true;
208
209 IPC::ResponseBuilder rb{ctx, 2};
210 rb.Push(ResultSuccess);
211}
212
213void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
214 LOG_WARNING(Service_AM, "(STUBBED) called");
215
216 std::scoped_lock lk{applet->lock};
217 applet->vr_mode_enabled = false;
218
219 IPC::ResponseBuilder rb{ctx, 2};
220 rb.Push(ResultSuccess);
221}
222
223void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
224 LOG_DEBUG(Service_AM, "called");
225
226 IPC::ResponseBuilder rb{ctx, 2, 1};
227 rb.Push(ResultSuccess);
228 rb.PushCopyObjects(applet->message_queue.GetOperationModeChangedEvent());
229}
230
231void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
232 LOG_DEBUG(Service_AM, "called");
233
234 IPC::ResponseBuilder rb{ctx, 4};
235 rb.Push(ResultSuccess);
236
237 if (Settings::IsDockedMode()) {
238 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
239 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
240 } else {
241 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
242 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
243 }
244}
245
246void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
247 LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
248
249 const auto& sm = system.ServiceManager();
250 const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
251 ASSERT(apm_sys != nullptr);
252
253 apm_sys->SetCpuBoostMode(ctx);
254}
255
256void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
257 LOG_WARNING(Service_AM, "(STUBBED) called");
258
259 IPC::ResponseBuilder rb{ctx, 3};
260 rb.Push(ResultSuccess);
261 rb.Push(0);
262}
263
264void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
265 IPC::RequestParser rp{ctx};
266 const auto system_button{rp.PopEnum<SystemButtonType>()};
267
268 LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button);
269
270 IPC::ResponseBuilder rb{ctx, 2};
271 rb.Push(ResultSuccess);
272}
273
274void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) {
275 LOG_WARNING(Service_AM, "(STUBBED) called");
276
277 std::shared_ptr<Applet> current_applet = applet;
278 std::vector<AppletId> result;
279
280 const size_t count = ctx.GetWriteBufferNumElements<AppletId>();
281 size_t i;
282
283 for (i = 0; i < count && current_applet != nullptr; i++) {
284 result.push_back(current_applet->applet_id);
285 current_applet = current_applet->caller_applet.lock();
286 }
287
288 ctx.WriteBuffer(result);
289
290 IPC::ResponseBuilder rb{ctx, 3};
291 rb.Push(ResultSuccess);
292 rb.Push(static_cast<u32>(i));
293}
294
295void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) {
296 LOG_WARNING(Service_AM, "(STUBBED) called");
297
298 IPC::ResponseBuilder rb{ctx, 3};
299 rb.Push(ResultSuccess);
300 rb.PushEnum(SysPlatformRegion::Global);
301}
302
303void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
304 HLERequestContext& ctx) {
305 LOG_WARNING(Service_AM, "(STUBBED) called");
306
307 std::scoped_lock lk{applet->lock};
308 applet->request_exit_to_library_applet_at_execute_next_program_enabled = true;
309
310 IPC::ResponseBuilder rb{ctx, 2};
311 rb.Push(ResultSuccess);
312}
313
314} // namespace Service::AM
diff --git a/src/core/hle/service/am/common_state_getter.h b/src/core/hle/service/am/common_state_getter.h
new file mode 100644
index 000000000..bf652790c
--- /dev/null
+++ b/src/core/hle/service/am/common_state_getter.h
@@ -0,0 +1,77 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9#include "core/hle/service/am/applet_message_queue.h"
10
11namespace Service::AM {
12
13struct Applet;
14
15class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
16public:
17 explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_);
18 ~ICommonStateGetter() override;
19
20private:
21 // This is nn::oe::FocusState
22 enum class FocusState : u8 {
23 InFocus = 1,
24 NotInFocus = 2,
25 Background = 3,
26 };
27
28 // This is nn::oe::OperationMode
29 enum class OperationMode : u8 {
30 Handheld = 0,
31 Docked = 1,
32 };
33
34 // This is nn::am::service::SystemButtonType
35 enum class SystemButtonType {
36 None,
37 HomeButtonShortPressing,
38 HomeButtonLongPressing,
39 PowerButtonShortPressing,
40 PowerButtonLongPressing,
41 ShutdownSystem,
42 CaptureButtonShortPressing,
43 CaptureButtonLongPressing,
44 };
45
46 enum class SysPlatformRegion : s32 {
47 Global = 1,
48 Terra = 2,
49 };
50
51 void GetEventHandle(HLERequestContext& ctx);
52 void ReceiveMessage(HLERequestContext& ctx);
53 void GetCurrentFocusState(HLERequestContext& ctx);
54 void RequestToAcquireSleepLock(HLERequestContext& ctx);
55 void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
56 void GetReaderLockAccessorEx(HLERequestContext& ctx);
57 void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
58 void GetOperationMode(HLERequestContext& ctx);
59 void GetPerformanceMode(HLERequestContext& ctx);
60 void GetBootMode(HLERequestContext& ctx);
61 void IsVrModeEnabled(HLERequestContext& ctx);
62 void SetVrModeEnabled(HLERequestContext& ctx);
63 void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
64 void BeginVrModeEx(HLERequestContext& ctx);
65 void EndVrModeEx(HLERequestContext& ctx);
66 void GetDefaultDisplayResolution(HLERequestContext& ctx);
67 void SetCpuBoostMode(HLERequestContext& ctx);
68 void GetBuiltInDisplayType(HLERequestContext& ctx);
69 void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
70 void GetAppletLaunchedHistory(HLERequestContext& ctx);
71 void GetSettingsPlatformRegion(HLERequestContext& ctx);
72 void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
73
74 const std::shared_ptr<Applet> applet;
75};
76
77} // namespace Service::AM
diff --git a/src/core/hle/service/am/debug_functions.cpp b/src/core/hle/service/am/debug_functions.cpp
new file mode 100644
index 000000000..f80b970f2
--- /dev/null
+++ b/src/core/hle/service/am/debug_functions.cpp
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/debug_functions.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IDebugFunctions::IDebugFunctions(Core::System& system_)
10 : ServiceFramework{system_, "IDebugFunctions"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
14 {1, nullptr, "OpenMainApplication"},
15 {10, nullptr, "PerformSystemButtonPressing"},
16 {20, nullptr, "InvalidateTransitionLayer"},
17 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
18 {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
19 {40, nullptr, "GetAppletResourceUsageInfo"},
20 {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
21 {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
22 {100, nullptr, "SetCpuBoostModeForApplet"},
23 {101, nullptr, "CancelCpuBoostModeForApplet"},
24 {110, nullptr, "PushToAppletBoundChannelForDebug"},
25 {111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
26 {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
27 {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
28 {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
29 {130, nullptr, "FriendInvitationSetApplicationParameter"},
30 {131, nullptr, "FriendInvitationClearApplicationParameter"},
31 {132, nullptr, "FriendInvitationPushApplicationParameter"},
32 {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
33 {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
34 {300, nullptr, "TerminateAllRunningApplicationsForDebug"},
35 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40}
41
42IDebugFunctions::~IDebugFunctions() = default;
43
44} // namespace Service::AM
diff --git a/src/core/hle/service/am/debug_functions.h b/src/core/hle/service/am/debug_functions.h
new file mode 100644
index 000000000..d55968743
--- /dev/null
+++ b/src/core/hle/service/am/debug_functions.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
11public:
12 explicit IDebugFunctions(Core::System& system_);
13 ~IDebugFunctions() override;
14};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/am/display_controller.cpp b/src/core/hle/service/am/display_controller.cpp
new file mode 100644
index 000000000..4d6858348
--- /dev/null
+++ b/src/core/hle/service/am/display_controller.cpp
@@ -0,0 +1,135 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/display_controller.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::AM {
9
10namespace {
11struct OutputParameters {
12 bool was_written;
13 s32 fbshare_layer_index;
14};
15
16static_assert(sizeof(OutputParameters) == 8, "OutputParameters has wrong size");
17} // namespace
18
19IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
20 : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, nullptr, "GetLastForegroundCaptureImage"},
24 {1, nullptr, "UpdateLastForegroundCaptureImage"},
25 {2, nullptr, "GetLastApplicationCaptureImage"},
26 {3, nullptr, "GetCallerAppletCaptureImage"},
27 {4, nullptr, "UpdateCallerAppletCaptureImage"},
28 {5, nullptr, "GetLastForegroundCaptureImageEx"},
29 {6, nullptr, "GetLastApplicationCaptureImageEx"},
30 {7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
31 {8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
32 {9, nullptr, "CopyBetweenCaptureBuffers"},
33 {10, nullptr, "AcquireLastApplicationCaptureBuffer"},
34 {11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
35 {12, nullptr, "AcquireLastForegroundCaptureBuffer"},
36 {13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
37 {14, nullptr, "AcquireCallerAppletCaptureBuffer"},
38 {15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
39 {16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
40 {17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
41 {18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
42 {20, nullptr, "ClearCaptureBuffer"},
43 {21, nullptr, "ClearAppletTransitionBuffer"},
44 {22, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"},
45 {23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "ReleaseLastApplicationCaptureSharedBuffer"},
46 {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
47 {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
48 {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
49 {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
50 {28, nullptr, "TakeScreenShotOfOwnLayerEx"},
51 };
52 // clang-format on
53
54 RegisterHandlers(functions);
55}
56
57IDisplayController::~IDisplayController() = default;
58
59void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
60 LOG_WARNING(Service_AM, "(STUBBED) called");
61
62 OutputParameters params{};
63 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
64 &params.was_written, &params.fbshare_layer_index);
65
66 IPC::ResponseBuilder rb{ctx, 4};
67 rb.Push(res);
68 rb.PushRaw(params);
69}
70
71void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
72 LOG_WARNING(Service_AM, "(STUBBED) called");
73
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(ResultSuccess);
76}
77
78void IDisplayController::AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
79 LOG_WARNING(Service_AM, "(STUBBED) called");
80
81 OutputParameters params{};
82 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
83 &params.was_written, &params.fbshare_layer_index);
84
85 IPC::ResponseBuilder rb{ctx, 4};
86 rb.Push(res);
87 rb.PushRaw(params);
88}
89
90void IDisplayController::ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
91 LOG_WARNING(Service_AM, "(STUBBED) called");
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(ResultSuccess);
95}
96
97void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
98 LOG_WARNING(Service_AM, "(STUBBED) called");
99
100 OutputParameters params{};
101 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
102 &params.was_written, &params.fbshare_layer_index);
103
104 IPC::ResponseBuilder rb{ctx, 4};
105 rb.Push(res);
106 rb.PushRaw(params);
107}
108
109void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
110 LOG_WARNING(Service_AM, "(STUBBED) called");
111
112 IPC::ResponseBuilder rb{ctx, 2};
113 rb.Push(ResultSuccess);
114}
115
116void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
117 LOG_WARNING(Service_AM, "(STUBBED) called");
118
119 OutputParameters params{};
120 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
121 &params.was_written, &params.fbshare_layer_index);
122
123 IPC::ResponseBuilder rb{ctx, 4};
124 rb.Push(res);
125 rb.PushRaw(params);
126}
127
128void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
129 LOG_WARNING(Service_AM, "(STUBBED) called");
130
131 IPC::ResponseBuilder rb{ctx, 2};
132 rb.Push(ResultSuccess);
133}
134
135} // namespace Service::AM
diff --git a/src/core/hle/service/am/display_controller.h b/src/core/hle/service/am/display_controller.h
new file mode 100644
index 000000000..75172580c
--- /dev/null
+++ b/src/core/hle/service/am/display_controller.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IDisplayController final : public ServiceFramework<IDisplayController> {
13public:
14 explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IDisplayController() override;
16
17private:
18 void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
19 void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
20 void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
21 void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
22 void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
23 void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
24 void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
25 void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
26
27 const std::shared_ptr<Applet> applet;
28};
29
30} // namespace Service::AM
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/frontend/applet_cabinet.cpp
index c2ff444a6..0862c81b6 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/frontend/applet_cabinet.cpp
@@ -8,16 +8,17 @@
8#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
9#include "core/hle/kernel/k_readable_event.h" 9#include "core/hle/kernel/k_readable_event.h"
10#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/applet_cabinet.h" 11#include "core/hle/service/am/frontend/applet_cabinet.h"
12#include "core/hle/service/am/storage.h"
12#include "core/hle/service/mii/mii_manager.h" 13#include "core/hle/service/mii/mii_manager.h"
13#include "core/hle/service/nfc/common/device.h" 14#include "core/hle/service/nfc/common/device.h"
14#include "hid_core/hid_core.h" 15#include "hid_core/hid_core.h"
15 16
16namespace Service::AM::Applets { 17namespace Service::AM::Frontend {
17 18
18Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, 19Cabinet::Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
19 const Core::Frontend::CabinetApplet& frontend_) 20 LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_)
20 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ 21 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{
21 system_, 22 system_,
22 "CabinetApplet"} { 23 "CabinetApplet"} {
23 24
@@ -30,7 +31,7 @@ Cabinet::~Cabinet() {
30}; 31};
31 32
32void Cabinet::Initialize() { 33void Cabinet::Initialize() {
33 Applet::Initialize(); 34 FrontendApplet::Initialize();
34 35
35 LOG_INFO(Service_HID, "Initializing Cabinet Applet."); 36 LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
36 37
@@ -41,7 +42,7 @@ void Cabinet::Initialize() {
41 common_args.play_startup_sound, common_args.size, common_args.system_tick, 42 common_args.play_startup_sound, common_args.size, common_args.system_tick,
42 common_args.theme_color); 43 common_args.theme_color);
43 44
44 const auto storage = broker.PopNormalDataToApplet(); 45 std::shared_ptr<IStorage> storage = PopInData();
45 ASSERT(storage != nullptr); 46 ASSERT(storage != nullptr);
46 47
47 const auto applet_input_data = storage->GetData(); 48 const auto applet_input_data = storage->GetData();
@@ -51,10 +52,6 @@ void Cabinet::Initialize() {
51 sizeof(StartParamForAmiiboSettings)); 52 sizeof(StartParamForAmiiboSettings));
52} 53}
53 54
54bool Cabinet::TransactionComplete() const {
55 return is_complete;
56}
57
58Result Cabinet::GetStatus() const { 55Result Cabinet::GetStatus() const {
59 return ResultSuccess; 56 return ResultSuccess;
60} 57}
@@ -160,8 +157,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
160 157
161 is_complete = true; 158 is_complete = true;
162 159
163 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 160 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
164 broker.SignalStateChanged(); 161 Exit();
165} 162}
166 163
167void Cabinet::Cancel() { 164void Cabinet::Cancel() {
@@ -175,8 +172,8 @@ void Cabinet::Cancel() {
175 172
176 is_complete = true; 173 is_complete = true;
177 174
178 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 175 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
179 broker.SignalStateChanged(); 176 Exit();
180} 177}
181 178
182Result Cabinet::RequestExit() { 179Result Cabinet::RequestExit() {
@@ -184,4 +181,4 @@ Result Cabinet::RequestExit() {
184 R_SUCCEED(); 181 R_SUCCEED();
185} 182}
186 183
187} // namespace Service::AM::Applets 184} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/frontend/applet_cabinet.h
index f498796f7..3a211ed37 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.h
+++ b/src/core/hle/service/am/frontend/applet_cabinet.h
@@ -6,7 +6,7 @@
6#include <array> 6#include <array>
7 7
8#include "core/hle/result.h" 8#include "core/hle/result.h"
9#include "core/hle/service/am/applets/applets.h" 9#include "core/hle/service/am/frontend/applets.h"
10#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/nfp/nfp_types.h" 11#include "core/hle/service/nfp/nfp_types.h"
12 12
@@ -23,7 +23,7 @@ namespace Service::NFC {
23class NfcDevice; 23class NfcDevice;
24} 24}
25 25
26namespace Service::AM::Applets { 26namespace Service::AM::Frontend {
27 27
28enum class CabinetAppletVersion : u32 { 28enum class CabinetAppletVersion : u32 {
29 Version1 = 0x1, 29 Version1 = 0x1,
@@ -84,15 +84,15 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
84 "ReturnValueForAmiiboSettings is an invalid size"); 84 "ReturnValueForAmiiboSettings is an invalid size");
85#pragma pack(pop) 85#pragma pack(pop)
86 86
87class Cabinet final : public Applet { 87class Cabinet final : public FrontendApplet {
88public: 88public:
89 explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, 89 explicit Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
90 LibraryAppletMode applet_mode_,
90 const Core::Frontend::CabinetApplet& frontend_); 91 const Core::Frontend::CabinetApplet& frontend_);
91 ~Cabinet() override; 92 ~Cabinet() override;
92 93
93 void Initialize() override; 94 void Initialize() override;
94 95
95 bool TransactionComplete() const override;
96 Result GetStatus() const override; 96 Result GetStatus() const override;
97 void ExecuteInteractive() override; 97 void ExecuteInteractive() override;
98 void Execute() override; 98 void Execute() override;
@@ -102,7 +102,6 @@ public:
102 102
103private: 103private:
104 const Core::Frontend::CabinetApplet& frontend; 104 const Core::Frontend::CabinetApplet& frontend;
105 Core::System& system;
106 105
107 bool is_complete{false}; 106 bool is_complete{false};
108 std::shared_ptr<Service::NFC::NfcDevice> nfp_device; 107 std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
@@ -111,4 +110,4 @@ private:
111 StartParamForAmiiboSettings applet_input_common{}; 110 StartParamForAmiiboSettings applet_input_common{};
112}; 111};
113 112
114} // namespace Service::AM::Applets 113} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/frontend/applet_controller.cpp
index 0e4d9cc39..bd3e49fc4 100644
--- a/src/core/hle/service/am/applets/applet_controller.cpp
+++ b/src/core/hle/service/am/frontend/applet_controller.cpp
@@ -11,13 +11,14 @@
11#include "core/frontend/applets/controller.h" 11#include "core/frontend/applets/controller.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13#include "core/hle/service/am/am.h" 13#include "core/hle/service/am/am.h"
14#include "core/hle/service/am/applets/applet_controller.h" 14#include "core/hle/service/am/frontend/applet_controller.h"
15#include "core/hle/service/am/storage.h"
15#include "hid_core/frontend/emulated_controller.h" 16#include "hid_core/frontend/emulated_controller.h"
16#include "hid_core/hid_core.h" 17#include "hid_core/hid_core.h"
17#include "hid_core/hid_types.h" 18#include "hid_core/hid_types.h"
18#include "hid_core/resources/npad/npad.h" 19#include "hid_core/resources/npad/npad.h"
19 20
20namespace Service::AM::Applets { 21namespace Service::AM::Frontend {
21 22
22[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101}; 23[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101};
23[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID, 24[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID,
@@ -46,14 +47,15 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
46 }; 47 };
47} 48}
48 49
49Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, 50Controller::Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
51 LibraryAppletMode applet_mode_,
50 const Core::Frontend::ControllerApplet& frontend_) 52 const Core::Frontend::ControllerApplet& frontend_)
51 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 53 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
52 54
53Controller::~Controller() = default; 55Controller::~Controller() = default;
54 56
55void Controller::Initialize() { 57void Controller::Initialize() {
56 Applet::Initialize(); 58 FrontendApplet::Initialize();
57 59
58 LOG_INFO(Service_HID, "Initializing Controller Applet."); 60 LOG_INFO(Service_HID, "Initializing Controller Applet.");
59 61
@@ -66,7 +68,7 @@ void Controller::Initialize() {
66 68
67 controller_applet_version = ControllerAppletVersion{common_args.library_version}; 69 controller_applet_version = ControllerAppletVersion{common_args.library_version};
68 70
69 const auto private_arg_storage = broker.PopNormalDataToApplet(); 71 const std::shared_ptr<IStorage> private_arg_storage = PopInData();
70 ASSERT(private_arg_storage != nullptr); 72 ASSERT(private_arg_storage != nullptr);
71 73
72 const auto& private_arg = private_arg_storage->GetData(); 74 const auto& private_arg = private_arg_storage->GetData();
@@ -116,7 +118,7 @@ void Controller::Initialize() {
116 switch (controller_private_arg.mode) { 118 switch (controller_private_arg.mode) {
117 case ControllerSupportMode::ShowControllerSupport: 119 case ControllerSupportMode::ShowControllerSupport:
118 case ControllerSupportMode::ShowControllerStrapGuide: { 120 case ControllerSupportMode::ShowControllerStrapGuide: {
119 const auto user_arg_storage = broker.PopNormalDataToApplet(); 121 const std::shared_ptr<IStorage> user_arg_storage = PopInData();
120 ASSERT(user_arg_storage != nullptr); 122 ASSERT(user_arg_storage != nullptr);
121 123
122 const auto& user_arg = user_arg_storage->GetData(); 124 const auto& user_arg = user_arg_storage->GetData();
@@ -142,7 +144,7 @@ void Controller::Initialize() {
142 break; 144 break;
143 } 145 }
144 case ControllerSupportMode::ShowControllerFirmwareUpdate: { 146 case ControllerSupportMode::ShowControllerFirmwareUpdate: {
145 const auto update_arg_storage = broker.PopNormalDataToApplet(); 147 const std::shared_ptr<IStorage> update_arg_storage = PopInData();
146 ASSERT(update_arg_storage != nullptr); 148 ASSERT(update_arg_storage != nullptr);
147 149
148 const auto& update_arg = update_arg_storage->GetData(); 150 const auto& update_arg = update_arg_storage->GetData();
@@ -152,7 +154,7 @@ void Controller::Initialize() {
152 break; 154 break;
153 } 155 }
154 case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { 156 case ControllerSupportMode::ShowControllerKeyRemappingForSystem: {
155 const auto remapping_arg_storage = broker.PopNormalDataToApplet(); 157 const std::shared_ptr<IStorage> remapping_arg_storage = PopInData();
156 ASSERT(remapping_arg_storage != nullptr); 158 ASSERT(remapping_arg_storage != nullptr);
157 159
158 const auto& remapping_arg = remapping_arg_storage->GetData(); 160 const auto& remapping_arg = remapping_arg_storage->GetData();
@@ -168,10 +170,6 @@ void Controller::Initialize() {
168 } 170 }
169} 171}
170 172
171bool Controller::TransactionComplete() const {
172 return complete;
173}
174
175Result Controller::GetStatus() const { 173Result Controller::GetStatus() const {
176 return status; 174 return status;
177} 175}
@@ -260,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) {
260 complete = true; 258 complete = true;
261 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); 259 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
262 std::memcpy(out_data.data(), &result_info, out_data.size()); 260 std::memcpy(out_data.data(), &result_info, out_data.size());
263 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 261
264 broker.SignalStateChanged(); 262 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
263 Exit();
265} 264}
266 265
267Result Controller::RequestExit() { 266Result Controller::RequestExit() {
@@ -269,4 +268,4 @@ Result Controller::RequestExit() {
269 R_SUCCEED(); 268 R_SUCCEED();
270} 269}
271 270
272} // namespace Service::AM::Applets 271} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/frontend/applet_controller.h
index 9f839f3d7..2f219429c 100644
--- a/src/core/hle/service/am/applets/applet_controller.h
+++ b/src/core/hle/service/am/frontend/applet_controller.h
@@ -9,7 +9,7 @@
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "core/hle/service/am/applets/applets.h" 12#include "core/hle/service/am/frontend/applets.h"
13 13
14namespace Core { 14namespace Core {
15class System; 15class System;
@@ -19,7 +19,7 @@ namespace Core::HID {
19enum class NpadStyleSet : u32; 19enum class NpadStyleSet : u32;
20} 20}
21 21
22namespace Service::AM::Applets { 22namespace Service::AM::Frontend {
23 23
24using IdentificationColor = std::array<u8, 4>; 24using IdentificationColor = std::array<u8, 4>;
25using ExplainText = std::array<char, 0x81>; 25using ExplainText = std::array<char, 0x81>;
@@ -122,15 +122,15 @@ struct ControllerSupportResultInfo {
122static_assert(sizeof(ControllerSupportResultInfo) == 0xC, 122static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
123 "ControllerSupportResultInfo has incorrect size."); 123 "ControllerSupportResultInfo has incorrect size.");
124 124
125class Controller final : public Applet { 125class Controller final : public FrontendApplet {
126public: 126public:
127 explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, 127 explicit Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
128 LibraryAppletMode applet_mode_,
128 const Core::Frontend::ControllerApplet& frontend_); 129 const Core::Frontend::ControllerApplet& frontend_);
129 ~Controller() override; 130 ~Controller() override;
130 131
131 void Initialize() override; 132 void Initialize() override;
132 133
133 bool TransactionComplete() const override;
134 Result GetStatus() const override; 134 Result GetStatus() const override;
135 void ExecuteInteractive() override; 135 void ExecuteInteractive() override;
136 void Execute() override; 136 void Execute() override;
@@ -140,7 +140,6 @@ public:
140 140
141private: 141private:
142 const Core::Frontend::ControllerApplet& frontend; 142 const Core::Frontend::ControllerApplet& frontend;
143 Core::System& system;
144 143
145 ControllerAppletVersion controller_applet_version; 144 ControllerAppletVersion controller_applet_version;
146 ControllerSupportArgPrivate controller_private_arg; 145 ControllerSupportArgPrivate controller_private_arg;
@@ -154,4 +153,4 @@ private:
154 std::vector<u8> out_data; 153 std::vector<u8> out_data;
155}; 154};
156 155
157} // namespace Service::AM::Applets 156} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/frontend/applet_error.cpp
index 084bc138c..b97a5f3ea 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/frontend/applet_error.cpp
@@ -9,10 +9,11 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/frontend/applets/error.h" 10#include "core/frontend/applets/error.h"
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_error.h" 12#include "core/hle/service/am/frontend/applet_error.h"
13#include "core/hle/service/am/storage.h"
13#include "core/reporter.h" 14#include "core/reporter.h"
14 15
15namespace Service::AM::Applets { 16namespace Service::AM::Frontend {
16 17
17struct ErrorCode { 18struct ErrorCode {
18 u32 error_category{}; 19 u32 error_category{};
@@ -103,18 +104,18 @@ Result Decode64BitError(u64 error) {
103 104
104} // Anonymous namespace 105} // Anonymous namespace
105 106
106Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, 107Error::Error(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
107 const Core::Frontend::ErrorApplet& frontend_) 108 const Core::Frontend::ErrorApplet& frontend_)
108 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 109 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
109 110
110Error::~Error() = default; 111Error::~Error() = default;
111 112
112void Error::Initialize() { 113void Error::Initialize() {
113 Applet::Initialize(); 114 FrontendApplet::Initialize();
114 args = std::make_unique<ErrorArguments>(); 115 args = std::make_unique<ErrorArguments>();
115 complete = false; 116 complete = false;
116 117
117 const auto storage = broker.PopNormalDataToApplet(); 118 const std::shared_ptr<IStorage> storage = PopInData();
118 ASSERT(storage != nullptr); 119 ASSERT(storage != nullptr);
119 const auto data = storage->GetData(); 120 const auto data = storage->GetData();
120 121
@@ -152,10 +153,6 @@ void Error::Initialize() {
152 } 153 }
153} 154}
154 155
155bool Error::TransactionComplete() const {
156 return complete;
157}
158
159Result Error::GetStatus() const { 156Result Error::GetStatus() const {
160 return ResultSuccess; 157 return ResultSuccess;
161} 158}
@@ -210,8 +207,8 @@ void Error::Execute() {
210 207
211void Error::DisplayCompleted() { 208void Error::DisplayCompleted() {
212 complete = true; 209 complete = true;
213 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); 210 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
214 broker.SignalStateChanged(); 211 Exit();
215} 212}
216 213
217Result Error::RequestExit() { 214Result Error::RequestExit() {
@@ -219,4 +216,4 @@ Result Error::RequestExit() {
219 R_SUCCEED(); 216 R_SUCCEED();
220} 217}
221 218
222} // namespace Service::AM::Applets 219} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_error.h b/src/core/hle/service/am/frontend/applet_error.h
index d822a32bb..678bf33fa 100644
--- a/src/core/hle/service/am/applets/applet_error.h
+++ b/src/core/hle/service/am/frontend/applet_error.h
@@ -4,13 +4,13 @@
4#pragma once 4#pragma once
5 5
6#include "core/hle/result.h" 6#include "core/hle/result.h"
7#include "core/hle/service/am/applets/applets.h" 7#include "core/hle/service/am/frontend/applets.h"
8 8
9namespace Core { 9namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::AM::Applets { 13namespace Service::AM::Frontend {
14 14
15enum class ErrorAppletMode : u8 { 15enum class ErrorAppletMode : u8 {
16 ShowError = 0, 16 ShowError = 0,
@@ -22,15 +22,14 @@ enum class ErrorAppletMode : u8 {
22 ShowUpdateEula = 8, 22 ShowUpdateEula = 8,
23}; 23};
24 24
25class Error final : public Applet { 25class Error final : public FrontendApplet {
26public: 26public:
27 explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, 27 explicit Error(Core::System& system_, std::shared_ptr<Applet> applet_,
28 const Core::Frontend::ErrorApplet& frontend_); 28 LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_);
29 ~Error() override; 29 ~Error() override;
30 30
31 void Initialize() override; 31 void Initialize() override;
32 32
33 bool TransactionComplete() const override;
34 Result GetStatus() const override; 33 Result GetStatus() const override;
35 void ExecuteInteractive() override; 34 void ExecuteInteractive() override;
36 void Execute() override; 35 void Execute() override;
@@ -47,7 +46,6 @@ private:
47 std::unique_ptr<ErrorArguments> args; 46 std::unique_ptr<ErrorArguments> args;
48 47
49 bool complete = false; 48 bool complete = false;
50 Core::System& system;
51}; 49};
52 50
53} // namespace Service::AM::Applets 51} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/frontend/applet_general.cpp
index c0032f652..3c091a602 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.cpp
+++ b/src/core/hle/service/am/frontend/applet_general.cpp
@@ -5,27 +5,28 @@
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/frontend/applets/general_frontend.h" 8#include "core/frontend/applets/general.h"
9#include "core/hle/result.h" 9#include "core/hle/result.h"
10#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/applet_general_backend.h" 11#include "core/hle/service/am/applet_data_broker.h"
12#include "core/hle/service/am/frontend/applet_general.h"
13#include "core/hle/service/am/storage.h"
12#include "core/reporter.h" 14#include "core/reporter.h"
13 15
14namespace Service::AM::Applets { 16namespace Service::AM::Frontend {
15 17
16constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; 18constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
17 19
18static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { 20static void LogCurrentStorage(std::shared_ptr<Applet> applet, std::string_view prefix) {
19 std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet(); 21 std::shared_ptr<IStorage> storage;
20 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { 22 while (R_SUCCEEDED(applet->caller_applet_broker->GetInData().Pop(&storage))) {
21 const auto data = storage->GetData(); 23 const auto data = storage->GetData();
22 LOG_INFO(Service_AM, 24 LOG_INFO(Service_AM,
23 "called (STUBBED), during {} received normal data with size={:08X}, data={}", 25 "called (STUBBED), during {} received normal data with size={:08X}, data={}",
24 prefix, data.size(), Common::HexToString(data)); 26 prefix, data.size(), Common::HexToString(data));
25 } 27 }
26 28
27 storage = broker.PopInteractiveDataToApplet(); 29 while (R_SUCCEEDED(applet->caller_applet_broker->GetInteractiveInData().Pop(&storage))) {
28 for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
29 const auto data = storage->GetData(); 30 const auto data = storage->GetData();
30 LOG_INFO(Service_AM, 31 LOG_INFO(Service_AM,
31 "called (STUBBED), during {} received interactive data with size={:08X}, data={}", 32 "called (STUBBED), during {} received interactive data with size={:08X}, data={}",
@@ -33,17 +34,17 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
33 } 34 }
34} 35}
35 36
36Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, 37Auth::Auth(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
37 Core::Frontend::ParentalControlsApplet& frontend_) 38 Core::Frontend::ParentalControlsApplet& frontend_)
38 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 39 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
39 40
40Auth::~Auth() = default; 41Auth::~Auth() = default;
41 42
42void Auth::Initialize() { 43void Auth::Initialize() {
43 Applet::Initialize(); 44 FrontendApplet::Initialize();
44 complete = false; 45 complete = false;
45 46
46 const auto storage = broker.PopNormalDataToApplet(); 47 const std::shared_ptr<IStorage> storage = PopInData();
47 ASSERT(storage != nullptr); 48 ASSERT(storage != nullptr);
48 const auto data = storage->GetData(); 49 const auto data = storage->GetData();
49 ASSERT(data.size() >= 0xC); 50 ASSERT(data.size() >= 0xC);
@@ -67,10 +68,6 @@ void Auth::Initialize() {
67 arg2 = arg.arg2; 68 arg2 = arg.arg2;
68} 69}
69 70
70bool Auth::TransactionComplete() const {
71 return complete;
72}
73
74Result Auth::GetStatus() const { 71Result Auth::GetStatus() const {
75 return successful ? ResultSuccess : ERROR_INVALID_PIN; 72 return successful ? ResultSuccess : ERROR_INVALID_PIN;
76} 73}
@@ -146,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) {
146 std::vector<u8> out(sizeof(Return)); 143 std::vector<u8> out(sizeof(Return));
147 std::memcpy(out.data(), &return_, sizeof(Return)); 144 std::memcpy(out.data(), &return_, sizeof(Return));
148 145
149 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out))); 146 PushOutData(std::make_shared<IStorage>(system, std::move(out)));
150 broker.SignalStateChanged(); 147 Exit();
151} 148}
152 149
153Result Auth::RequestExit() { 150Result Auth::RequestExit() {
@@ -155,27 +152,24 @@ Result Auth::RequestExit() {
155 R_SUCCEED(); 152 R_SUCCEED();
156} 153}
157 154
158PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, 155PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
156 LibraryAppletMode applet_mode_,
159 const Core::Frontend::PhotoViewerApplet& frontend_) 157 const Core::Frontend::PhotoViewerApplet& frontend_)
160 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 158 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
161 159
162PhotoViewer::~PhotoViewer() = default; 160PhotoViewer::~PhotoViewer() = default;
163 161
164void PhotoViewer::Initialize() { 162void PhotoViewer::Initialize() {
165 Applet::Initialize(); 163 FrontendApplet::Initialize();
166 complete = false; 164 complete = false;
167 165
168 const auto storage = broker.PopNormalDataToApplet(); 166 const std::shared_ptr<IStorage> storage = PopInData();
169 ASSERT(storage != nullptr); 167 ASSERT(storage != nullptr);
170 const auto data = storage->GetData(); 168 const auto data = storage->GetData();
171 ASSERT(!data.empty()); 169 ASSERT(!data.empty());
172 mode = static_cast<PhotoViewerAppletMode>(data[0]); 170 mode = static_cast<PhotoViewerAppletMode>(data[0]);
173} 171}
174 172
175bool PhotoViewer::TransactionComplete() const {
176 return complete;
177}
178
179Result PhotoViewer::GetStatus() const { 173Result PhotoViewer::GetStatus() const {
180 return ResultSuccess; 174 return ResultSuccess;
181} 175}
@@ -203,8 +197,8 @@ void PhotoViewer::Execute() {
203} 197}
204 198
205void PhotoViewer::ViewFinished() { 199void PhotoViewer::ViewFinished() {
206 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); 200 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>{}));
207 broker.SignalStateChanged(); 201 Exit();
208} 202}
209 203
210Result PhotoViewer::RequestExit() { 204Result PhotoViewer::RequestExit() {
@@ -212,27 +206,17 @@ Result PhotoViewer::RequestExit() {
212 R_SUCCEED(); 206 R_SUCCEED();
213} 207}
214 208
215StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) 209StubApplet::StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
216 : Applet{system_, applet_mode_}, id{id_}, system{system_} {} 210 LibraryAppletMode applet_mode_)
211 : FrontendApplet{system_, applet_, applet_mode_}, id{id_} {}
217 212
218StubApplet::~StubApplet() = default; 213StubApplet::~StubApplet() = default;
219 214
220void StubApplet::Initialize() { 215void StubApplet::Initialize() {
221 LOG_WARNING(Service_AM, "called (STUBBED)"); 216 LOG_WARNING(Service_AM, "called (STUBBED)");
222 Applet::Initialize(); 217 FrontendApplet::Initialize();
223 218
224 const auto data = broker.PeekDataToAppletForDebug(); 219 LogCurrentStorage(applet.lock(), "Initialize");
225 system.GetReporter().SaveUnimplementedAppletReport(
226 static_cast<u32>(id), static_cast<u32>(common_args.arguments_version),
227 common_args.library_version, static_cast<u32>(common_args.theme_color),
228 common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive);
229
230 LogCurrentStorage(broker, "Initialize");
231}
232
233bool StubApplet::TransactionComplete() const {
234 LOG_WARNING(Service_AM, "called (STUBBED)");
235 return true;
236} 220}
237 221
238Result StubApplet::GetStatus() const { 222Result StubApplet::GetStatus() const {
@@ -242,22 +226,20 @@ Result StubApplet::GetStatus() const {
242 226
243void StubApplet::ExecuteInteractive() { 227void StubApplet::ExecuteInteractive() {
244 LOG_WARNING(Service_AM, "called (STUBBED)"); 228 LOG_WARNING(Service_AM, "called (STUBBED)");
245 LogCurrentStorage(broker, "ExecuteInteractive"); 229 LogCurrentStorage(applet.lock(), "ExecuteInteractive");
246 230
247 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 231 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
248 broker.PushInteractiveDataFromApplet( 232 PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
249 std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 233 Exit();
250 broker.SignalStateChanged();
251} 234}
252 235
253void StubApplet::Execute() { 236void StubApplet::Execute() {
254 LOG_WARNING(Service_AM, "called (STUBBED)"); 237 LOG_WARNING(Service_AM, "called (STUBBED)");
255 LogCurrentStorage(broker, "Execute"); 238 LogCurrentStorage(applet.lock(), "Execute");
256 239
257 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 240 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
258 broker.PushInteractiveDataFromApplet( 241 PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
259 std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 242 Exit();
260 broker.SignalStateChanged();
261} 243}
262 244
263Result StubApplet::RequestExit() { 245Result StubApplet::RequestExit() {
@@ -265,4 +247,4 @@ Result StubApplet::RequestExit() {
265 R_SUCCEED(); 247 R_SUCCEED();
266} 248}
267 249
268} // namespace Service::AM::Applets 250} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_general_backend.h b/src/core/hle/service/am/frontend/applet_general.h
index 34ecaebb9..eaa7ae25f 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.h
+++ b/src/core/hle/service/am/frontend/applet_general.h
@@ -3,13 +3,13 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/am/applets/applets.h" 6#include "core/hle/service/am/frontend/applets.h"
7 7
8namespace Core { 8namespace Core {
9class System; 9class System;
10} 10}
11 11
12namespace Service::AM::Applets { 12namespace Service::AM::Frontend {
13 13
14enum class AuthAppletType : u32 { 14enum class AuthAppletType : u32 {
15 ShowParentalAuthentication, 15 ShowParentalAuthentication,
@@ -17,14 +17,14 @@ enum class AuthAppletType : u32 {
17 ChangeParentalPasscode, 17 ChangeParentalPasscode,
18}; 18};
19 19
20class Auth final : public Applet { 20class Auth final : public FrontendApplet {
21public: 21public:
22 explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, 22 explicit Auth(Core::System& system_, std::shared_ptr<Applet> applet_,
23 LibraryAppletMode applet_mode_,
23 Core::Frontend::ParentalControlsApplet& frontend_); 24 Core::Frontend::ParentalControlsApplet& frontend_);
24 ~Auth() override; 25 ~Auth() override;
25 26
26 void Initialize() override; 27 void Initialize() override;
27 bool TransactionComplete() const override;
28 Result GetStatus() const override; 28 Result GetStatus() const override;
29 void ExecuteInteractive() override; 29 void ExecuteInteractive() override;
30 void Execute() override; 30 void Execute() override;
@@ -34,7 +34,6 @@ public:
34 34
35private: 35private:
36 Core::Frontend::ParentalControlsApplet& frontend; 36 Core::Frontend::ParentalControlsApplet& frontend;
37 Core::System& system;
38 bool complete = false; 37 bool complete = false;
39 bool successful = false; 38 bool successful = false;
40 39
@@ -49,14 +48,14 @@ enum class PhotoViewerAppletMode : u8 {
49 AllApps = 1, 48 AllApps = 1,
50}; 49};
51 50
52class PhotoViewer final : public Applet { 51class PhotoViewer final : public FrontendApplet {
53public: 52public:
54 explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, 53 explicit PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
54 LibraryAppletMode applet_mode_,
55 const Core::Frontend::PhotoViewerApplet& frontend_); 55 const Core::Frontend::PhotoViewerApplet& frontend_);
56 ~PhotoViewer() override; 56 ~PhotoViewer() override;
57 57
58 void Initialize() override; 58 void Initialize() override;
59 bool TransactionComplete() const override;
60 Result GetStatus() const override; 59 Result GetStatus() const override;
61 void ExecuteInteractive() override; 60 void ExecuteInteractive() override;
62 void Execute() override; 61 void Execute() override;
@@ -68,17 +67,16 @@ private:
68 const Core::Frontend::PhotoViewerApplet& frontend; 67 const Core::Frontend::PhotoViewerApplet& frontend;
69 bool complete = false; 68 bool complete = false;
70 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; 69 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
71 Core::System& system;
72}; 70};
73 71
74class StubApplet final : public Applet { 72class StubApplet final : public FrontendApplet {
75public: 73public:
76 explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); 74 explicit StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
75 LibraryAppletMode applet_mode_);
77 ~StubApplet() override; 76 ~StubApplet() override;
78 77
79 void Initialize() override; 78 void Initialize() override;
80 79
81 bool TransactionComplete() const override;
82 Result GetStatus() const override; 80 Result GetStatus() const override;
83 void ExecuteInteractive() override; 81 void ExecuteInteractive() override;
84 void Execute() override; 82 void Execute() override;
@@ -86,7 +84,6 @@ public:
86 84
87private: 85private:
88 AppletId id; 86 AppletId id;
89 Core::System& system;
90}; 87};
91 88
92} // namespace Service::AM::Applets 89} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/frontend/applet_mii_edit.cpp
index e83e931c5..e3d19fb3d 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.cpp
+++ b/src/core/hle/service/am/frontend/applet_mii_edit.cpp
@@ -6,16 +6,17 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/frontend/applets/mii_edit.h" 7#include "core/frontend/applets/mii_edit.h"
8#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applets/applet_mii_edit.h" 9#include "core/hle/service/am/frontend/applet_mii_edit.h"
10#include "core/hle/service/am/storage.h"
10#include "core/hle/service/mii/mii.h" 11#include "core/hle/service/mii/mii.h"
11#include "core/hle/service/mii/mii_manager.h" 12#include "core/hle/service/mii/mii_manager.h"
12#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
13 14
14namespace Service::AM::Applets { 15namespace Service::AM::Frontend {
15 16
16MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, 17MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
17 const Core::Frontend::MiiEditApplet& frontend_) 18 LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_)
18 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 19 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
19 20
20MiiEdit::~MiiEdit() = default; 21MiiEdit::~MiiEdit() = default;
21 22
@@ -24,7 +25,7 @@ void MiiEdit::Initialize() {
24 // Instead, it is initialized by an AppletInput storage with size 0x100 bytes. 25 // Instead, it is initialized by an AppletInput storage with size 0x100 bytes.
25 // Do NOT call Applet::Initialize() here. 26 // Do NOT call Applet::Initialize() here.
26 27
27 const auto storage = broker.PopNormalDataToApplet(); 28 const std::shared_ptr<IStorage> storage = PopInData();
28 ASSERT(storage != nullptr); 29 ASSERT(storage != nullptr);
29 30
30 const auto applet_input_data = storage->GetData(); 31 const auto applet_input_data = storage->GetData();
@@ -66,10 +67,6 @@ void MiiEdit::Initialize() {
66 manager->Initialize(metadata); 67 manager->Initialize(metadata);
67} 68}
68 69
69bool MiiEdit::TransactionComplete() const {
70 return is_complete;
71}
72
73Result MiiEdit::GetStatus() const { 70Result MiiEdit::GetStatus() const {
74 return ResultSuccess; 71 return ResultSuccess;
75} 72}
@@ -152,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) {
152 149
153 is_complete = true; 150 is_complete = true;
154 151
155 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 152 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
156 broker.SignalStateChanged(); 153 Exit();
157} 154}
158 155
159void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, 156void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
@@ -168,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
168 165
169 is_complete = true; 166 is_complete = true;
170 167
171 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 168 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
172 broker.SignalStateChanged(); 169 Exit();
173} 170}
174 171
175Result MiiEdit::RequestExit() { 172Result MiiEdit::RequestExit() {
@@ -177,4 +174,4 @@ Result MiiEdit::RequestExit() {
177 R_SUCCEED(); 174 R_SUCCEED();
178} 175}
179 176
180} // namespace Service::AM::Applets 177} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/frontend/applet_mii_edit.h
index 7ff34af49..5db792f7d 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.h
+++ b/src/core/hle/service/am/frontend/applet_mii_edit.h
@@ -4,8 +4,8 @@
4#pragma once 4#pragma once
5 5
6#include "core/hle/result.h" 6#include "core/hle/result.h"
7#include "core/hle/service/am/applets/applet_mii_edit_types.h" 7#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
8#include "core/hle/service/am/applets/applets.h" 8#include "core/hle/service/am/frontend/applets.h"
9 9
10namespace Core { 10namespace Core {
11class System; 11class System;
@@ -16,17 +16,17 @@ struct DatabaseSessionMetadata;
16class MiiManager; 16class MiiManager;
17} // namespace Service::Mii 17} // namespace Service::Mii
18 18
19namespace Service::AM::Applets { 19namespace Service::AM::Frontend {
20 20
21class MiiEdit final : public Applet { 21class MiiEdit final : public FrontendApplet {
22public: 22public:
23 explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, 23 explicit MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
24 LibraryAppletMode applet_mode_,
24 const Core::Frontend::MiiEditApplet& frontend_); 25 const Core::Frontend::MiiEditApplet& frontend_);
25 ~MiiEdit() override; 26 ~MiiEdit() override;
26 27
27 void Initialize() override; 28 void Initialize() override;
28 29
29 bool TransactionComplete() const override;
30 Result GetStatus() const override; 30 Result GetStatus() const override;
31 void ExecuteInteractive() override; 31 void ExecuteInteractive() override;
32 void Execute() override; 32 void Execute() override;
@@ -38,7 +38,6 @@ public:
38 38
39private: 39private:
40 const Core::Frontend::MiiEditApplet& frontend; 40 const Core::Frontend::MiiEditApplet& frontend;
41 Core::System& system;
42 41
43 MiiEditAppletInputCommon applet_input_common{}; 42 MiiEditAppletInputCommon applet_input_common{};
44 MiiEditAppletInputV3 applet_input_v3{}; 43 MiiEditAppletInputV3 applet_input_v3{};
@@ -49,4 +48,4 @@ private:
49 Mii::DatabaseSessionMetadata metadata{}; 48 Mii::DatabaseSessionMetadata metadata{};
50}; 49};
51 50
52} // namespace Service::AM::Applets 51} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_mii_edit_types.h b/src/core/hle/service/am/frontend/applet_mii_edit_types.h
index f3d764073..23d9d7a69 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit_types.h
+++ b/src/core/hle/service/am/frontend/applet_mii_edit_types.h
@@ -10,7 +10,7 @@
10#include "common/uuid.h" 10#include "common/uuid.h"
11#include "core/hle/service/mii/types/char_info.h" 11#include "core/hle/service/mii/types/char_info.h"
12 12
13namespace Service::AM::Applets { 13namespace Service::AM::Frontend {
14 14
15enum class MiiEditAppletVersion : s32 { 15enum class MiiEditAppletVersion : s32 {
16 Version3 = 0x3, // 1.0.0 - 10.1.1 16 Version3 = 0x3, // 1.0.0 - 10.1.1
@@ -80,4 +80,4 @@ struct MiiEditAppletOutputForCharInfoEditing {
80static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80, 80static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80,
81 "MiiEditAppletOutputForCharInfoEditing has incorrect size."); 81 "MiiEditAppletOutputForCharInfoEditing has incorrect size.");
82 82
83} // namespace Service::AM::Applets 83} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/frontend/applet_profile_select.cpp
index 89cb323e9..efb4053b8 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.cpp
+++ b/src/core/hle/service/am/frontend/applet_profile_select.cpp
@@ -9,13 +9,15 @@
9#include "core/frontend/applets/profile_select.h" 9#include "core/frontend/applets/profile_select.h"
10#include "core/hle/service/acc/errors.h" 10#include "core/hle/service/acc/errors.h"
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_profile_select.h" 12#include "core/hle/service/am/frontend/applet_profile_select.h"
13#include "core/hle/service/am/storage.h"
13 14
14namespace Service::AM::Applets { 15namespace Service::AM::Frontend {
15 16
16ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, 17ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
18 LibraryAppletMode applet_mode_,
17 const Core::Frontend::ProfileSelectApplet& frontend_) 19 const Core::Frontend::ProfileSelectApplet& frontend_)
18 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 20 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
19 21
20ProfileSelect::~ProfileSelect() = default; 22ProfileSelect::~ProfileSelect() = default;
21 23
@@ -24,10 +26,10 @@ void ProfileSelect::Initialize() {
24 status = ResultSuccess; 26 status = ResultSuccess;
25 final_data.clear(); 27 final_data.clear();
26 28
27 Applet::Initialize(); 29 FrontendApplet::Initialize();
28 profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; 30 profile_select_version = ProfileSelectAppletVersion{common_args.library_version};
29 31
30 const auto user_config_storage = broker.PopNormalDataToApplet(); 32 const std::shared_ptr<IStorage> user_config_storage = PopInData();
31 ASSERT(user_config_storage != nullptr); 33 ASSERT(user_config_storage != nullptr);
32 const auto& user_config = user_config_storage->GetData(); 34 const auto& user_config = user_config_storage->GetData();
33 35
@@ -50,10 +52,6 @@ void ProfileSelect::Initialize() {
50 } 52 }
51} 53}
52 54
53bool ProfileSelect::TransactionComplete() const {
54 return complete;
55}
56
57Result ProfileSelect::GetStatus() const { 55Result ProfileSelect::GetStatus() const {
58 return status; 56 return status;
59} 57}
@@ -64,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() {
64 62
65void ProfileSelect::Execute() { 63void ProfileSelect::Execute() {
66 if (complete) { 64 if (complete) {
67 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); 65 PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
66 Exit();
68 return; 67 return;
69 } 68 }
70 69
@@ -111,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
111 110
112 final_data = std::vector<u8>(sizeof(UiReturnArg)); 111 final_data = std::vector<u8>(sizeof(UiReturnArg));
113 std::memcpy(final_data.data(), &output, final_data.size()); 112 std::memcpy(final_data.data(), &output, final_data.size());
114 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); 113
115 broker.SignalStateChanged(); 114 PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
115 Exit();
116} 116}
117 117
118Result ProfileSelect::RequestExit() { 118Result ProfileSelect::RequestExit() {
@@ -120,4 +120,4 @@ Result ProfileSelect::RequestExit() {
120 R_SUCCEED(); 120 R_SUCCEED();
121} 121}
122 122
123} // namespace Service::AM::Applets 123} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/frontend/applet_profile_select.h
index 673eed516..674e7afe1 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.h
+++ b/src/core/hle/service/am/frontend/applet_profile_select.h
@@ -8,13 +8,13 @@
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/uuid.h" 9#include "common/uuid.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11#include "core/hle/service/am/applets/applets.h" 11#include "core/hle/service/am/frontend/applets.h"
12 12
13namespace Core { 13namespace Core {
14class System; 14class System;
15} 15}
16 16
17namespace Service::AM::Applets { 17namespace Service::AM::Frontend {
18 18
19enum class ProfileSelectAppletVersion : u32 { 19enum class ProfileSelectAppletVersion : u32 {
20 Version1 = 0x1, // 1.0.0+ 20 Version1 = 0x1, // 1.0.0+
@@ -111,15 +111,15 @@ struct UiReturnArg {
111}; 111};
112static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); 112static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size.");
113 113
114class ProfileSelect final : public Applet { 114class ProfileSelect final : public FrontendApplet {
115public: 115public:
116 explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, 116 explicit ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
117 LibraryAppletMode applet_mode_,
117 const Core::Frontend::ProfileSelectApplet& frontend_); 118 const Core::Frontend::ProfileSelectApplet& frontend_);
118 ~ProfileSelect() override; 119 ~ProfileSelect() override;
119 120
120 void Initialize() override; 121 void Initialize() override;
121 122
122 bool TransactionComplete() const override;
123 Result GetStatus() const override; 123 Result GetStatus() const override;
124 void ExecuteInteractive() override; 124 void ExecuteInteractive() override;
125 void Execute() override; 125 void Execute() override;
@@ -137,7 +137,6 @@ private:
137 bool complete = false; 137 bool complete = false;
138 Result status = ResultSuccess; 138 Result status = ResultSuccess;
139 std::vector<u8> final_data; 139 std::vector<u8> final_data;
140 Core::System& system;
141}; 140};
142 141
143} // namespace Service::AM::Applets 142} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp
index 4145bb84f..fbf75d379 100644
--- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp
+++ b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp
@@ -5,9 +5,10 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/frontend/applets/software_keyboard.h" 6#include "core/frontend/applets/software_keyboard.h"
7#include "core/hle/service/am/am.h" 7#include "core/hle/service/am/am.h"
8#include "core/hle/service/am/applets/applet_software_keyboard.h" 8#include "core/hle/service/am/frontend/applet_software_keyboard.h"
9#include "core/hle/service/am/storage.h"
9 10
10namespace Service::AM::Applets { 11namespace Service::AM::Frontend {
11 12
12namespace { 13namespace {
13 14
@@ -41,14 +42,15 @@ void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply
41 42
42} // Anonymous namespace 43} // Anonymous namespace
43 44
44SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, 45SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
46 LibraryAppletMode applet_mode_,
45 Core::Frontend::SoftwareKeyboardApplet& frontend_) 47 Core::Frontend::SoftwareKeyboardApplet& frontend_)
46 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 48 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
47 49
48SoftwareKeyboard::~SoftwareKeyboard() = default; 50SoftwareKeyboard::~SoftwareKeyboard() = default;
49 51
50void SoftwareKeyboard::Initialize() { 52void SoftwareKeyboard::Initialize() {
51 Applet::Initialize(); 53 FrontendApplet::Initialize();
52 54
53 LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", 55 LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
54 applet_mode); 56 applet_mode);
@@ -76,10 +78,6 @@ void SoftwareKeyboard::Initialize() {
76 } 78 }
77} 79}
78 80
79bool SoftwareKeyboard::TransactionComplete() const {
80 return complete;
81}
82
83Result SoftwareKeyboard::GetStatus() const { 81Result SoftwareKeyboard::GetStatus() const {
84 return status; 82 return status;
85} 83}
@@ -184,7 +182,7 @@ void SoftwareKeyboard::InitializeForeground() {
184 182
185 is_background = false; 183 is_background = false;
186 184
187 const auto swkbd_config_storage = broker.PopNormalDataToApplet(); 185 const auto swkbd_config_storage = PopInData();
188 ASSERT(swkbd_config_storage != nullptr); 186 ASSERT(swkbd_config_storage != nullptr);
189 187
190 const auto& swkbd_config_data = swkbd_config_storage->GetData(); 188 const auto& swkbd_config_data = swkbd_config_storage->GetData();
@@ -221,7 +219,7 @@ void SoftwareKeyboard::InitializeForeground() {
221 break; 219 break;
222 } 220 }
223 221
224 const auto work_buffer_storage = broker.PopNormalDataToApplet(); 222 const auto work_buffer_storage = PopInData();
225 ASSERT(work_buffer_storage != nullptr); 223 ASSERT(work_buffer_storage != nullptr);
226 224
227 if (swkbd_config_common.initial_string_length == 0) { 225 if (swkbd_config_common.initial_string_length == 0) {
@@ -250,7 +248,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
250 248
251 is_background = true; 249 is_background = true;
252 250
253 const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); 251 const auto swkbd_inline_initialize_arg_storage = PopInData();
254 ASSERT(swkbd_inline_initialize_arg_storage != nullptr); 252 ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
255 253
256 const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); 254 const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
@@ -267,7 +265,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
267} 265}
268 266
269void SoftwareKeyboard::ProcessTextCheck() { 267void SoftwareKeyboard::ProcessTextCheck() {
270 const auto text_check_storage = broker.PopInteractiveDataToApplet(); 268 const auto text_check_storage = PopInteractiveInData();
271 ASSERT(text_check_storage != nullptr); 269 ASSERT(text_check_storage != nullptr);
272 270
273 const auto& text_check_data = text_check_storage->GetData(); 271 const auto& text_check_data = text_check_storage->GetData();
@@ -314,7 +312,7 @@ void SoftwareKeyboard::ProcessTextCheck() {
314} 312}
315 313
316void SoftwareKeyboard::ProcessInlineKeyboardRequest() { 314void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
317 const auto request_data_storage = broker.PopInteractiveDataToApplet(); 315 const auto request_data_storage = PopInteractiveInData();
318 ASSERT(request_data_storage != nullptr); 316 ASSERT(request_data_storage != nullptr);
319 317
320 const auto& request_data = request_data_storage->GetData(); 318 const auto& request_data = request_data_storage->GetData();
@@ -377,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
377 submitted_text.size() * sizeof(char16_t)); 375 submitted_text.size() * sizeof(char16_t));
378 } 376 }
379 377
380 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 378 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
381 379
382 ExitKeyboard(); 380 ExitKeyboard();
383} 381}
@@ -410,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
410 current_text.size() * sizeof(char16_t)); 408 current_text.size() * sizeof(char16_t));
411 } 409 }
412 410
413 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 411 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(out_data)));
414} 412}
415 413
416void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { 414void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
@@ -767,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() {
767 765
768 frontend.ExitKeyboard(); 766 frontend.ExitKeyboard();
769 767
770 broker.SignalStateChanged(); 768 Exit();
771} 769}
772 770
773Result SoftwareKeyboard::RequestExit() { 771Result SoftwareKeyboard::RequestExit() {
@@ -967,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() {
967 965
968 SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); 966 SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
969 967
970 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 968 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
971} 969}
972 970
973void SoftwareKeyboard::ReplyDefault() { 971void SoftwareKeyboard::ReplyDefault() {
@@ -977,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() {
977 975
978 SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); 976 SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
979 977
980 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 978 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
981} 979}
982 980
983void SoftwareKeyboard::ReplyChangedString() { 981void SoftwareKeyboard::ReplyChangedString() {
@@ -999,7 +997,7 @@ void SoftwareKeyboard::ReplyChangedString() {
999 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, 997 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
1000 sizeof(SwkbdChangedStringArg)); 998 sizeof(SwkbdChangedStringArg));
1001 999
1002 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1000 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1003} 1001}
1004 1002
1005void SoftwareKeyboard::ReplyMovedCursor() { 1003void SoftwareKeyboard::ReplyMovedCursor() {
@@ -1019,7 +1017,7 @@ void SoftwareKeyboard::ReplyMovedCursor() {
1019 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, 1017 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
1020 sizeof(SwkbdMovedCursorArg)); 1018 sizeof(SwkbdMovedCursorArg));
1021 1019
1022 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1020 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1023} 1021}
1024 1022
1025void SoftwareKeyboard::ReplyMovedTab() { 1023void SoftwareKeyboard::ReplyMovedTab() {
@@ -1039,7 +1037,7 @@ void SoftwareKeyboard::ReplyMovedTab() {
1039 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, 1037 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
1040 sizeof(SwkbdMovedTabArg)); 1038 sizeof(SwkbdMovedTabArg));
1041 1039
1042 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1040 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1043} 1041}
1044 1042
1045void SoftwareKeyboard::ReplyDecidedEnter() { 1043void SoftwareKeyboard::ReplyDecidedEnter() {
@@ -1058,7 +1056,7 @@ void SoftwareKeyboard::ReplyDecidedEnter() {
1058 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, 1056 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
1059 sizeof(SwkbdDecidedEnterArg)); 1057 sizeof(SwkbdDecidedEnterArg));
1060 1058
1061 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1059 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1062 1060
1063 HideInlineKeyboard(); 1061 HideInlineKeyboard();
1064} 1062}
@@ -1070,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() {
1070 1068
1071 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); 1069 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
1072 1070
1073 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1071 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1074 1072
1075 HideInlineKeyboard(); 1073 HideInlineKeyboard();
1076} 1074}
@@ -1095,7 +1093,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8() {
1095 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, 1093 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
1096 sizeof(SwkbdChangedStringArg)); 1094 sizeof(SwkbdChangedStringArg));
1097 1095
1098 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1096 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1099} 1097}
1100 1098
1101void SoftwareKeyboard::ReplyMovedCursorUtf8() { 1099void SoftwareKeyboard::ReplyMovedCursorUtf8() {
@@ -1116,7 +1114,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8() {
1116 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, 1114 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
1117 sizeof(SwkbdMovedCursorArg)); 1115 sizeof(SwkbdMovedCursorArg));
1118 1116
1119 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1117 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1120} 1118}
1121 1119
1122void SoftwareKeyboard::ReplyDecidedEnterUtf8() { 1120void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
@@ -1136,7 +1134,7 @@ void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
1136 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, 1134 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
1137 sizeof(SwkbdDecidedEnterArg)); 1135 sizeof(SwkbdDecidedEnterArg));
1138 1136
1139 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1137 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1140 1138
1141 HideInlineKeyboard(); 1139 HideInlineKeyboard();
1142} 1140}
@@ -1148,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
1148 1146
1149 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); 1147 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
1150 1148
1151 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1149 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1152} 1150}
1153 1151
1154void SoftwareKeyboard::ReplyReleasedUserWordInfo() { 1152void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
@@ -1158,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
1158 1156
1159 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); 1157 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
1160 1158
1161 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1159 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1162} 1160}
1163 1161
1164void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { 1162void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
@@ -1168,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
1168 1166
1169 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); 1167 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
1170 1168
1171 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1169 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1172} 1170}
1173 1171
1174void SoftwareKeyboard::ReplyChangedStringV2() { 1172void SoftwareKeyboard::ReplyChangedStringV2() {
@@ -1194,7 +1192,7 @@ void SoftwareKeyboard::ReplyChangedStringV2() {
1194 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), 1192 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
1195 &flag, 1); 1193 &flag, 1);
1196 1194
1197 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1195 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1198} 1196}
1199 1197
1200void SoftwareKeyboard::ReplyMovedCursorV2() { 1198void SoftwareKeyboard::ReplyMovedCursorV2() {
@@ -1218,7 +1216,7 @@ void SoftwareKeyboard::ReplyMovedCursorV2() {
1218 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), 1216 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
1219 &flag, 1); 1217 &flag, 1);
1220 1218
1221 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1219 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1222} 1220}
1223 1221
1224void SoftwareKeyboard::ReplyChangedStringUtf8V2() { 1222void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
@@ -1245,7 +1243,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
1245 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), 1243 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
1246 &flag, 1); 1244 &flag, 1);
1247 1245
1248 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1246 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1249} 1247}
1250 1248
1251void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { 1249void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
@@ -1270,7 +1268,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
1270 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), 1268 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
1271 &flag, 1); 1269 &flag, 1);
1272 1270
1273 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1271 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1274} 1272}
1275 1273
1276} // namespace Service::AM::Applets 1274} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/frontend/applet_software_keyboard.h
index 2e919811b..f464b7e15 100644
--- a/src/core/hle/service/am/applets/applet_software_keyboard.h
+++ b/src/core/hle/service/am/frontend/applet_software_keyboard.h
@@ -5,8 +5,8 @@
5 5
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/hle/result.h" 7#include "core/hle/result.h"
8#include "core/hle/service/am/applets/applet_software_keyboard_types.h" 8#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
9#include "core/hle/service/am/applets/applets.h" 9#include "core/hle/service/am/frontend/applets.h"
10 10
11namespace Core { 11namespace Core {
12class System; 12class System;
@@ -17,17 +17,17 @@ struct KeyboardInitializeParameters;
17struct InlineAppearParameters; 17struct InlineAppearParameters;
18} // namespace Core::Frontend 18} // namespace Core::Frontend
19 19
20namespace Service::AM::Applets { 20namespace Service::AM::Frontend {
21 21
22class SoftwareKeyboard final : public Applet { 22class SoftwareKeyboard final : public FrontendApplet {
23public: 23public:
24 explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, 24 explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
25 LibraryAppletMode applet_mode_,
25 Core::Frontend::SoftwareKeyboardApplet& frontend_); 26 Core::Frontend::SoftwareKeyboardApplet& frontend_);
26 ~SoftwareKeyboard() override; 27 ~SoftwareKeyboard() override;
27 28
28 void Initialize() override; 29 void Initialize() override;
29 30
30 bool TransactionComplete() const override;
31 Result GetStatus() const override; 31 Result GetStatus() const override;
32 void ExecuteInteractive() override; 32 void ExecuteInteractive() override;
33 void Execute() override; 33 void Execute() override;
@@ -156,7 +156,6 @@ private:
156 void ReplyMovedCursorUtf8V2(); 156 void ReplyMovedCursorUtf8V2();
157 157
158 Core::Frontend::SoftwareKeyboardApplet& frontend; 158 Core::Frontend::SoftwareKeyboardApplet& frontend;
159 Core::System& system;
160 159
161 SwkbdAppletVersion swkbd_applet_version; 160 SwkbdAppletVersion swkbd_applet_version;
162 161
@@ -184,4 +183,4 @@ private:
184 Result status{ResultSuccess}; 183 Result status{ResultSuccess};
185}; 184};
186 185
187} // namespace Service::AM::Applets 186} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard_types.h b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h
index 1f696900e..a25ff2a6d 100644
--- a/src/core/hle/service/am/applets/applet_software_keyboard_types.h
+++ b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h
@@ -11,7 +11,7 @@
11#include "common/swap.h" 11#include "common/swap.h"
12#include "common/uuid.h" 12#include "common/uuid.h"
13 13
14namespace Service::AM::Applets { 14namespace Service::AM::Frontend {
15 15
16constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; 16constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
17constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; 17constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
@@ -351,4 +351,4 @@ struct SwkbdDecidedEnterArg {
351}; 351};
352static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); 352static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
353 353
354} // namespace Service::AM::Applets 354} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp
index 19057ad7b..6ee4caf34 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.cpp
+++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp
@@ -19,12 +19,13 @@
19#include "core/frontend/applets/web_browser.h" 19#include "core/frontend/applets/web_browser.h"
20#include "core/hle/result.h" 20#include "core/hle/result.h"
21#include "core/hle/service/am/am.h" 21#include "core/hle/service/am/am.h"
22#include "core/hle/service/am/applets/applet_web_browser.h" 22#include "core/hle/service/am/frontend/applet_web_browser.h"
23#include "core/hle/service/am/storage.h"
23#include "core/hle/service/filesystem/filesystem.h" 24#include "core/hle/service/filesystem/filesystem.h"
24#include "core/hle/service/ns/iplatform_service_manager.h" 25#include "core/hle/service/ns/iplatform_service_manager.h"
25#include "core/loader/loader.h" 26#include "core/loader/loader.h"
26 27
27namespace Service::AM::Applets { 28namespace Service::AM::Frontend {
28 29
29namespace { 30namespace {
30 31
@@ -223,14 +224,15 @@ void ExtractSharedFonts(Core::System& system) {
223 224
224} // namespace 225} // namespace
225 226
226WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, 227WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
228 LibraryAppletMode applet_mode_,
227 const Core::Frontend::WebBrowserApplet& frontend_) 229 const Core::Frontend::WebBrowserApplet& frontend_)
228 : Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {} 230 : FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {}
229 231
230WebBrowser::~WebBrowser() = default; 232WebBrowser::~WebBrowser() = default;
231 233
232void WebBrowser::Initialize() { 234void WebBrowser::Initialize() {
233 Applet::Initialize(); 235 FrontendApplet::Initialize();
234 236
235 LOG_INFO(Service_AM, "Initializing Web Browser Applet."); 237 LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
236 238
@@ -243,7 +245,7 @@ void WebBrowser::Initialize() {
243 245
244 web_applet_version = WebAppletVersion{common_args.library_version}; 246 web_applet_version = WebAppletVersion{common_args.library_version};
245 247
246 const auto web_arg_storage = broker.PopNormalDataToApplet(); 248 const auto web_arg_storage = PopInData();
247 ASSERT(web_arg_storage != nullptr); 249 ASSERT(web_arg_storage != nullptr);
248 250
249 const auto& web_arg = web_arg_storage->GetData(); 251 const auto& web_arg = web_arg_storage->GetData();
@@ -284,10 +286,6 @@ void WebBrowser::Initialize() {
284 } 286 }
285} 287}
286 288
287bool WebBrowser::TransactionComplete() const {
288 return complete;
289}
290
291Result WebBrowser::GetStatus() const { 289Result WebBrowser::GetStatus() const {
292 return status; 290 return status;
293} 291}
@@ -358,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url)
358 complete = true; 356 complete = true;
359 std::vector<u8> out_data(sizeof(WebCommonReturnValue)); 357 std::vector<u8> out_data(sizeof(WebCommonReturnValue));
360 std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); 358 std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
361 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 359 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
362 broker.SignalStateChanged(); 360 Exit();
363} 361}
364 362
365Result WebBrowser::RequestExit() { 363Result WebBrowser::RequestExit() {
@@ -504,4 +502,4 @@ void WebBrowser::ExecuteLobby() {
504 LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); 502 LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
505 WebBrowserExit(WebExitReason::EndButtonPressed); 503 WebBrowserExit(WebExitReason::EndButtonPressed);
506} 504}
507} // namespace Service::AM::Applets 505} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/frontend/applet_web_browser.h
index 36adb2510..ba20b7a4c 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.h
+++ b/src/core/hle/service/am/frontend/applet_web_browser.h
@@ -9,8 +9,8 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs/vfs_types.h" 10#include "core/file_sys/vfs/vfs_types.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "core/hle/service/am/applets/applet_web_browser_types.h" 12#include "core/hle/service/am/frontend/applet_web_browser_types.h"
13#include "core/hle/service/am/applets/applets.h" 13#include "core/hle/service/am/frontend/applets.h"
14 14
15namespace Core { 15namespace Core {
16class System; 16class System;
@@ -20,18 +20,17 @@ namespace FileSys {
20enum class ContentRecordType : u8; 20enum class ContentRecordType : u8;
21} 21}
22 22
23namespace Service::AM::Applets { 23namespace Service::AM::Frontend {
24 24
25class WebBrowser final : public Applet { 25class WebBrowser final : public FrontendApplet {
26public: 26public:
27 WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, 27 WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
28 const Core::Frontend::WebBrowserApplet& frontend_); 28 LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_);
29 29
30 ~WebBrowser() override; 30 ~WebBrowser() override;
31 31
32 void Initialize() override; 32 void Initialize() override;
33 33
34 bool TransactionComplete() const override;
35 Result GetStatus() const override; 34 Result GetStatus() const override;
36 void ExecuteInteractive() override; 35 void ExecuteInteractive() override;
37 void Execute() override; 36 void Execute() override;
@@ -80,8 +79,6 @@ private:
80 FileSys::VirtualFile offline_romfs; 79 FileSys::VirtualFile offline_romfs;
81 80
82 std::string external_url; 81 std::string external_url;
83
84 Core::System& system;
85}; 82};
86 83
87} // namespace Service::AM::Applets 84} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/applets/applet_web_browser_types.h b/src/core/hle/service/am/frontend/applet_web_browser_types.h
index c522c5c1a..2f7c05c24 100644
--- a/src/core/hle/service/am/applets/applet_web_browser_types.h
+++ b/src/core/hle/service/am/frontend/applet_web_browser_types.h
@@ -11,7 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13 13
14namespace Service::AM::Applets { 14namespace Service::AM::Frontend {
15 15
16enum class WebAppletVersion : u32_le { 16enum class WebAppletVersion : u32_le {
17 Version0 = 0x0, // Only used by WifiWebAuthApplet 17 Version0 = 0x0, // Only used by WifiWebAuthApplet
@@ -174,4 +174,4 @@ static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has
174 174
175using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>; 175using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
176 176
177} // namespace Service::AM::Applets 177} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp
new file mode 100644
index 000000000..db2b04575
--- /dev/null
+++ b/src/core/hle/service/am/frontend/applets.cpp
@@ -0,0 +1,240 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstring>
5
6#include "common/assert.h"
7#include "core/core.h"
8#include "core/frontend/applets/cabinet.h"
9#include "core/frontend/applets/controller.h"
10#include "core/frontend/applets/error.h"
11#include "core/frontend/applets/general.h"
12#include "core/frontend/applets/mii_edit.h"
13#include "core/frontend/applets/profile_select.h"
14#include "core/frontend/applets/software_keyboard.h"
15#include "core/frontend/applets/web_browser.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h"
19#include "core/hle/service/am/applet_data_broker.h"
20#include "core/hle/service/am/applet_manager.h"
21#include "core/hle/service/am/applet_message_queue.h"
22#include "core/hle/service/am/applet_oe.h"
23#include "core/hle/service/am/frontend/applet_cabinet.h"
24#include "core/hle/service/am/frontend/applet_controller.h"
25#include "core/hle/service/am/frontend/applet_error.h"
26#include "core/hle/service/am/frontend/applet_general.h"
27#include "core/hle/service/am/frontend/applet_mii_edit.h"
28#include "core/hle/service/am/frontend/applet_profile_select.h"
29#include "core/hle/service/am/frontend/applet_software_keyboard.h"
30#include "core/hle/service/am/frontend/applet_web_browser.h"
31#include "core/hle/service/am/frontend/applets.h"
32#include "core/hle/service/am/storage.h"
33#include "core/hle/service/sm/sm.h"
34
35namespace Service::AM::Frontend {
36
37FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
38 LibraryAppletMode applet_mode_)
39 : system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {}
40
41FrontendApplet::~FrontendApplet() = default;
42
43void FrontendApplet::Initialize() {
44 std::shared_ptr<IStorage> common = PopInData();
45 ASSERT(common != nullptr);
46 const auto common_data = common->GetData();
47
48 ASSERT(common_data.size() >= sizeof(CommonArguments));
49 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
50
51 initialized = true;
52}
53
54std::shared_ptr<IStorage> FrontendApplet::PopInData() {
55 std::shared_ptr<IStorage> ret;
56 applet.lock()->caller_applet_broker->GetInData().Pop(&ret);
57 return ret;
58}
59
60std::shared_ptr<IStorage> FrontendApplet::PopInteractiveInData() {
61 std::shared_ptr<IStorage> ret;
62 applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret);
63 return ret;
64}
65
66void FrontendApplet::PushOutData(std::shared_ptr<IStorage> storage) {
67 applet.lock()->caller_applet_broker->GetOutData().Push(storage);
68}
69
70void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
71 applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage);
72}
73
74void FrontendApplet::Exit() {
75 applet.lock()->caller_applet_broker->SignalCompletion();
76}
77
78FrontendAppletSet::FrontendAppletSet() = default;
79
80FrontendAppletSet::FrontendAppletSet(CabinetApplet cabinet_applet,
81 ControllerApplet controller_applet, ErrorApplet error_applet,
82 MiiEdit mii_edit_,
83 ParentalControlsApplet parental_controls_applet,
84 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
85 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
86 : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
87 error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
88 parental_controls{std::move(parental_controls_applet)},
89 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
90 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
91
92FrontendAppletSet::~FrontendAppletSet() = default;
93
94FrontendAppletSet::FrontendAppletSet(FrontendAppletSet&&) noexcept = default;
95
96FrontendAppletSet& FrontendAppletSet::operator=(FrontendAppletSet&&) noexcept = default;
97
98FrontendAppletHolder::FrontendAppletHolder(Core::System& system_) : system{system_} {}
99
100FrontendAppletHolder::~FrontendAppletHolder() = default;
101
102const FrontendAppletSet& FrontendAppletHolder::GetFrontendAppletSet() const {
103 return frontend;
104}
105
106NFP::CabinetMode FrontendAppletHolder::GetCabinetMode() const {
107 return cabinet_mode;
108}
109
110AppletId FrontendAppletHolder::GetCurrentAppletId() const {
111 return current_applet_id;
112}
113
114void FrontendAppletHolder::SetFrontendAppletSet(FrontendAppletSet set) {
115 if (set.cabinet != nullptr) {
116 frontend.cabinet = std::move(set.cabinet);
117 }
118
119 if (set.controller != nullptr) {
120 frontend.controller = std::move(set.controller);
121 }
122
123 if (set.error != nullptr) {
124 frontend.error = std::move(set.error);
125 }
126
127 if (set.mii_edit != nullptr) {
128 frontend.mii_edit = std::move(set.mii_edit);
129 }
130
131 if (set.parental_controls != nullptr) {
132 frontend.parental_controls = std::move(set.parental_controls);
133 }
134
135 if (set.photo_viewer != nullptr) {
136 frontend.photo_viewer = std::move(set.photo_viewer);
137 }
138
139 if (set.profile_select != nullptr) {
140 frontend.profile_select = std::move(set.profile_select);
141 }
142
143 if (set.software_keyboard != nullptr) {
144 frontend.software_keyboard = std::move(set.software_keyboard);
145 }
146
147 if (set.web_browser != nullptr) {
148 frontend.web_browser = std::move(set.web_browser);
149 }
150}
151
152void FrontendAppletHolder::SetCabinetMode(NFP::CabinetMode mode) {
153 cabinet_mode = mode;
154}
155
156void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) {
157 current_applet_id = applet_id;
158}
159
160void FrontendAppletHolder::SetDefaultAppletsIfMissing() {
161 if (frontend.cabinet == nullptr) {
162 frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
163 }
164
165 if (frontend.controller == nullptr) {
166 frontend.controller =
167 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
168 }
169
170 if (frontend.error == nullptr) {
171 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
172 }
173
174 if (frontend.mii_edit == nullptr) {
175 frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
176 }
177
178 if (frontend.parental_controls == nullptr) {
179 frontend.parental_controls =
180 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
181 }
182
183 if (frontend.photo_viewer == nullptr) {
184 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
185 }
186
187 if (frontend.profile_select == nullptr) {
188 frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
189 }
190
191 if (frontend.software_keyboard == nullptr) {
192 frontend.software_keyboard =
193 std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
194 }
195
196 if (frontend.web_browser == nullptr) {
197 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
198 }
199}
200
201void FrontendAppletHolder::ClearAll() {
202 frontend = {};
203}
204
205std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<Applet> applet,
206 AppletId id,
207 LibraryAppletMode mode) const {
208 switch (id) {
209 case AppletId::Auth:
210 return std::make_shared<Auth>(system, applet, mode, *frontend.parental_controls);
211 case AppletId::Cabinet:
212 return std::make_shared<Cabinet>(system, applet, mode, *frontend.cabinet);
213 case AppletId::Controller:
214 return std::make_shared<Controller>(system, applet, mode, *frontend.controller);
215 case AppletId::Error:
216 return std::make_shared<Error>(system, applet, mode, *frontend.error);
217 case AppletId::ProfileSelect:
218 return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select);
219 case AppletId::SoftwareKeyboard:
220 return std::make_shared<SoftwareKeyboard>(system, applet, mode,
221 *frontend.software_keyboard);
222 case AppletId::MiiEdit:
223 return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit);
224 case AppletId::Web:
225 case AppletId::Shop:
226 case AppletId::OfflineWeb:
227 case AppletId::LoginShare:
228 case AppletId::WebAuth:
229 return std::make_shared<WebBrowser>(system, applet, mode, *frontend.web_browser);
230 case AppletId::PhotoViewer:
231 return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
232 default:
233 UNIMPLEMENTED_MSG(
234 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
235 static_cast<u8>(id));
236 return std::make_shared<StubApplet>(system, applet, id, mode);
237 }
238}
239
240} // namespace Service::AM::Frontend
diff --git a/src/core/hle/service/am/frontend/applets.h b/src/core/hle/service/am/frontend/applets.h
new file mode 100644
index 000000000..1e1fd28b8
--- /dev/null
+++ b/src/core/hle/service/am/frontend/applets.h
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <queue>
8
9#include "common/swap.h"
10#include "core/hle/service/am/applet.h"
11
12union Result;
13
14namespace Core {
15class System;
16}
17
18namespace Core::Frontend {
19class CabinetApplet;
20class ControllerApplet;
21class ECommerceApplet;
22class ErrorApplet;
23class MiiEditApplet;
24class ParentalControlsApplet;
25class PhotoViewerApplet;
26class ProfileSelectApplet;
27class SoftwareKeyboardApplet;
28class WebBrowserApplet;
29} // namespace Core::Frontend
30
31namespace Kernel {
32class KernelCore;
33class KEvent;
34class KReadableEvent;
35} // namespace Kernel
36
37namespace Service::NFP {
38enum class CabinetMode : u8;
39} // namespace Service::NFP
40
41namespace Service::AM {
42
43class IStorage;
44
45namespace Frontend {
46
47class FrontendApplet {
48public:
49 explicit FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
50 LibraryAppletMode applet_mode_);
51 virtual ~FrontendApplet();
52
53 virtual void Initialize();
54
55 virtual Result GetStatus() const = 0;
56 virtual void ExecuteInteractive() = 0;
57 virtual void Execute() = 0;
58 virtual Result RequestExit() = 0;
59
60 LibraryAppletMode GetLibraryAppletMode() const {
61 return applet_mode;
62 }
63
64 bool IsInitialized() const {
65 return initialized;
66 }
67
68protected:
69 std::shared_ptr<IStorage> PopInData();
70 std::shared_ptr<IStorage> PopInteractiveInData();
71 void PushOutData(std::shared_ptr<IStorage> storage);
72 void PushInteractiveOutData(std::shared_ptr<IStorage> storage);
73 void Exit();
74
75protected:
76 Core::System& system;
77 CommonArguments common_args{};
78 std::weak_ptr<Applet> applet{};
79 LibraryAppletMode applet_mode{};
80 bool initialized{false};
81};
82
83struct FrontendAppletSet {
84 using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
85 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
86 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
87 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
88 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
89 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
90 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
91 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
92 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
93
94 FrontendAppletSet();
95 FrontendAppletSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
96 ErrorApplet error_applet, MiiEdit mii_edit_,
97 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
98 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
99 WebBrowser web_browser_);
100 ~FrontendAppletSet();
101
102 FrontendAppletSet(const FrontendAppletSet&) = delete;
103 FrontendAppletSet& operator=(const FrontendAppletSet&) = delete;
104
105 FrontendAppletSet(FrontendAppletSet&&) noexcept;
106 FrontendAppletSet& operator=(FrontendAppletSet&&) noexcept;
107
108 CabinetApplet cabinet;
109 ControllerApplet controller;
110 ErrorApplet error;
111 MiiEdit mii_edit;
112 ParentalControlsApplet parental_controls;
113 PhotoViewer photo_viewer;
114 ProfileSelect profile_select;
115 SoftwareKeyboard software_keyboard;
116 WebBrowser web_browser;
117};
118
119class FrontendAppletHolder {
120public:
121 explicit FrontendAppletHolder(Core::System& system_);
122 ~FrontendAppletHolder();
123
124 const FrontendAppletSet& GetFrontendAppletSet() const;
125 NFP::CabinetMode GetCabinetMode() const;
126 AppletId GetCurrentAppletId() const;
127
128 void SetFrontendAppletSet(FrontendAppletSet set);
129 void SetCabinetMode(NFP::CabinetMode mode);
130 void SetCurrentAppletId(AppletId applet_id);
131 void SetDefaultAppletsIfMissing();
132 void ClearAll();
133
134 std::shared_ptr<FrontendApplet> GetApplet(std::shared_ptr<Applet> applet, AppletId id,
135 LibraryAppletMode mode) const;
136
137private:
138 AppletId current_applet_id{};
139 NFP::CabinetMode cabinet_mode{};
140
141 FrontendAppletSet frontend;
142 Core::System& system;
143};
144
145} // namespace Frontend
146} // namespace Service::AM
diff --git a/src/core/hle/service/am/global_state_controller.cpp b/src/core/hle/service/am/global_state_controller.cpp
new file mode 100644
index 000000000..ed0eb7108
--- /dev/null
+++ b/src/core/hle/service/am/global_state_controller.cpp
@@ -0,0 +1,34 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/global_state_controller.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IGlobalStateController::IGlobalStateController(Core::System& system_)
10 : ServiceFramework{system_, "IGlobalStateController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "RequestToEnterSleep"},
14 {1, nullptr, "EnterSleep"},
15 {2, nullptr, "StartSleepSequence"},
16 {3, nullptr, "StartShutdownSequence"},
17 {4, nullptr, "StartRebootSequence"},
18 {9, nullptr, "IsAutoPowerDownRequested"},
19 {10, nullptr, "LoadAndApplyIdlePolicySettings"},
20 {11, nullptr, "NotifyCecSettingsChanged"},
21 {12, nullptr, "SetDefaultHomeButtonLongPressTime"},
22 {13, nullptr, "UpdateDefaultDisplayResolution"},
23 {14, nullptr, "ShouldSleepOnBoot"},
24 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
25 {30, nullptr, "OpenCradleFirmwareUpdater"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IGlobalStateController::~IGlobalStateController() = default;
33
34} // namespace Service::AM
diff --git a/src/core/hle/service/am/global_state_controller.h b/src/core/hle/service/am/global_state_controller.h
new file mode 100644
index 000000000..7125464a1
--- /dev/null
+++ b/src/core/hle/service/am/global_state_controller.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
11public:
12 explicit IGlobalStateController(Core::System& system_);
13 ~IGlobalStateController() override;
14};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/am/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp
new file mode 100644
index 000000000..8ed49bac1
--- /dev/null
+++ b/src/core/hle/service/am/hid_registration.cpp
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/am/hid_registration.h"
6#include "core/hle/service/am/process.h"
7#include "core/hle/service/hid/hid_server.h"
8#include "core/hle/service/sm/sm.h"
9#include "hid_core/resource_manager.h"
10
11namespace Service::AM {
12
13HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
14 m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid");
15
16 if (m_process.IsInitialized()) {
17 m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
18 true);
19 }
20}
21
22HidRegistration::~HidRegistration() {
23 if (m_process.IsInitialized()) {
24 m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
25 m_process.GetProcessId());
26 }
27}
28
29void HidRegistration::EnableAppletToGetInput(bool enable) {
30 if (m_process.IsInitialized()) {
31 m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
32 }
33}
34
35} // namespace Service::AM
diff --git a/src/core/hle/service/am/hid_registration.h b/src/core/hle/service/am/hid_registration.h
new file mode 100644
index 000000000..67cd84961
--- /dev/null
+++ b/src/core/hle/service/am/hid_registration.h
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8namespace Core {
9class System;
10}
11
12namespace Service::HID {
13class IHidServer;
14}
15
16namespace Service::AM {
17
18class Process;
19
20class HidRegistration {
21public:
22 explicit HidRegistration(Core::System& system, Process& process);
23 ~HidRegistration();
24
25 void EnableAppletToGetInput(bool enable);
26
27private:
28 Process& m_process;
29 std::shared_ptr<Service::HID::IHidServer> m_hid_server;
30};
31
32} // namespace Service::AM
diff --git a/src/core/hle/service/am/home_menu_functions.cpp b/src/core/hle/service/am/home_menu_functions.cpp
new file mode 100644
index 000000000..640e9fbb7
--- /dev/null
+++ b/src/core/hle/service/am/home_menu_functions.cpp
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/home_menu_functions.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
10 : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
11 "IHomeMenuFunctions"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
15 {11, nullptr, "LockForeground"},
16 {12, nullptr, "UnlockForeground"},
17 {20, nullptr, "PopFromGeneralChannel"},
18 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
19 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
20 {31, nullptr, "GetWriterLockAccessorEx"},
21 {40, nullptr, "IsSleepEnabled"},
22 {41, nullptr, "IsRebootEnabled"},
23 {50, nullptr, "LaunchSystemApplet"},
24 {51, nullptr, "LaunchStarter"},
25 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
26 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
27 {200, nullptr, "LaunchDevMenu"},
28 {1000, nullptr, "SetLastApplicationExitReason"},
29 };
30 // clang-format on
31
32 RegisterHandlers(functions);
33
34 pop_from_general_channel_event =
35 service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
36}
37
38IHomeMenuFunctions::~IHomeMenuFunctions() {
39 service_context.CloseEvent(pop_from_general_channel_event);
40}
41
42void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
43 LOG_WARNING(Service_AM, "(STUBBED) called");
44
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(ResultSuccess);
47}
48
49void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
50 LOG_WARNING(Service_AM, "(STUBBED) called");
51
52 IPC::ResponseBuilder rb{ctx, 2, 1};
53 rb.Push(ResultSuccess);
54 rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
55}
56
57} // namespace Service::AM
diff --git a/src/core/hle/service/am/home_menu_functions.h b/src/core/hle/service/am/home_menu_functions.h
new file mode 100644
index 000000000..e082d5d73
--- /dev/null
+++ b/src/core/hle/service/am/home_menu_functions.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
12public:
13 explicit IHomeMenuFunctions(Core::System& system_);
14 ~IHomeMenuFunctions() override;
15
16private:
17 void RequestToGetForeground(HLERequestContext& ctx);
18 void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
19
20 KernelHelpers::ServiceContext service_context;
21
22 Kernel::KEvent* pop_from_general_channel_event;
23};
24
25} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_accessor.cpp b/src/core/hle/service/am/library_applet_accessor.cpp
new file mode 100644
index 000000000..6b20814f8
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_accessor.cpp
@@ -0,0 +1,202 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/applet_data_broker.h"
7#include "core/hle/service/am/frontend/applets.h"
8#include "core/hle/service/am/library_applet_accessor.h"
9#include "core/hle/service/am/storage.h"
10#include "core/hle/service/ipc_helpers.h"
11
12namespace Service::AM {
13
14ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
15 std::shared_ptr<AppletDataBroker> broker_,
16 std::shared_ptr<Applet> applet_)
17 : ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)},
18 applet{std::move(applet_)} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
22 {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
23 {10, &ILibraryAppletAccessor::Start, "Start"},
24 {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
25 {25, nullptr, "Terminate"},
26 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
27 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
28 {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},
29 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
30 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
31 {102, nullptr, "PushExtraStorage"},
32 {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
33 {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
34 {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
35 {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
36 {110, nullptr, "NeedsToExitProcess"},
37 {120, nullptr, "GetLibraryAppletInfo"},
38 {150, nullptr, "RequestForAppletToGetForeground"},
39 {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44}
45
46ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
47
48void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) {
49 LOG_DEBUG(Service_AM, "called");
50
51 IPC::ResponseBuilder rb{ctx, 2, 1};
52 rb.Push(ResultSuccess);
53 rb.PushCopyObjects(broker->GetStateChangedEvent().GetHandle());
54}
55
56void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) {
57 LOG_DEBUG(Service_AM, "called");
58
59 std::scoped_lock lk{applet->lock};
60
61 IPC::ResponseBuilder rb{ctx, 3};
62 rb.Push(ResultSuccess);
63 rb.Push<u32>(broker->IsCompleted());
64}
65
66void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) {
67 LOG_DEBUG(Service_AM, "called");
68
69 IPC::ResponseBuilder rb{ctx, 2};
70 rb.Push(applet->terminate_result);
71}
72
73void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
74 LOG_WARNING(Service_AM, "(STUBBED) called");
75
76 IPC::ResponseBuilder rb{ctx, 2};
77 rb.Push(ResultSuccess);
78}
79
80void ILibraryAppletAccessor::Start(HLERequestContext& ctx) {
81 LOG_DEBUG(Service_AM, "called");
82
83 applet->process->Run();
84 FrontendExecute();
85
86 IPC::ResponseBuilder rb{ctx, 2};
87 rb.Push(ResultSuccess);
88}
89
90void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) {
91 LOG_DEBUG(Service_AM, "called");
92
93 ASSERT(applet != nullptr);
94 applet->message_queue.RequestExit();
95 FrontendRequestExit();
96
97 IPC::ResponseBuilder rb{ctx, 2};
98 rb.Push(ResultSuccess);
99}
100
101void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) {
102 LOG_DEBUG(Service_AM, "called");
103
104 IPC::RequestParser rp{ctx};
105 broker->GetInData().Push(rp.PopIpcInterface<IStorage>().lock());
106
107 IPC::ResponseBuilder rb{ctx, 2};
108 rb.Push(ResultSuccess);
109}
110
111void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) {
112 LOG_DEBUG(Service_AM, "called");
113
114 std::shared_ptr<IStorage> data;
115 const auto res = broker->GetOutData().Pop(&data);
116
117 if (res.IsSuccess()) {
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
119 rb.Push(res);
120 rb.PushIpcInterface(std::move(data));
121 } else {
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(res);
124 }
125}
126
127void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) {
128 LOG_DEBUG(Service_AM, "called");
129
130 IPC::RequestParser rp{ctx};
131 broker->GetInteractiveInData().Push(rp.PopIpcInterface<IStorage>().lock());
132 FrontendExecuteInteractive();
133
134 IPC::ResponseBuilder rb{ctx, 2};
135 rb.Push(ResultSuccess);
136}
137
138void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) {
139 LOG_DEBUG(Service_AM, "called");
140
141 std::shared_ptr<IStorage> data;
142 const auto res = broker->GetInteractiveOutData().Pop(&data);
143
144 if (res.IsSuccess()) {
145 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
146 rb.Push(res);
147 rb.PushIpcInterface(std::move(data));
148 } else {
149 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(res);
151 }
152}
153
154void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) {
155 LOG_DEBUG(Service_AM, "called");
156
157 IPC::ResponseBuilder rb{ctx, 2, 1};
158 rb.Push(ResultSuccess);
159 rb.PushCopyObjects(broker->GetOutData().GetEvent());
160}
161
162void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
163 LOG_DEBUG(Service_AM, "called");
164
165 IPC::ResponseBuilder rb{ctx, 2, 1};
166 rb.Push(ResultSuccess);
167 rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent());
168}
169
170void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
171 LOG_WARNING(Service_AM, "(STUBBED) called");
172
173 // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
174 // actually used anywhere
175 constexpr u64 handle = 0xdeadbeef;
176
177 IPC::ResponseBuilder rb{ctx, 4};
178 rb.Push(ResultSuccess);
179 rb.Push(handle);
180}
181
182void ILibraryAppletAccessor::FrontendExecute() {
183 if (applet->frontend) {
184 applet->frontend->Initialize();
185 applet->frontend->Execute();
186 }
187}
188
189void ILibraryAppletAccessor::FrontendExecuteInteractive() {
190 if (applet->frontend) {
191 applet->frontend->ExecuteInteractive();
192 applet->frontend->Execute();
193 }
194}
195
196void ILibraryAppletAccessor::FrontendRequestExit() {
197 if (applet->frontend) {
198 applet->frontend->RequestExit();
199 }
200}
201
202} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_accessor.h b/src/core/hle/service/am/library_applet_accessor.h
new file mode 100644
index 000000000..8be29e003
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_accessor.h
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class AppletDataBroker;
11struct Applet;
12
13class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
14public:
15 explicit ILibraryAppletAccessor(Core::System& system_,
16 std::shared_ptr<AppletDataBroker> broker_,
17 std::shared_ptr<Applet> applet_);
18 ~ILibraryAppletAccessor();
19
20protected:
21 void GetAppletStateChangedEvent(HLERequestContext& ctx);
22 void IsCompleted(HLERequestContext& ctx);
23 void GetResult(HLERequestContext& ctx);
24 void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx);
25 void Start(HLERequestContext& ctx);
26 void RequestExit(HLERequestContext& ctx);
27 void PushInData(HLERequestContext& ctx);
28 void PopOutData(HLERequestContext& ctx);
29 void PushInteractiveInData(HLERequestContext& ctx);
30 void PopInteractiveOutData(HLERequestContext& ctx);
31 void GetPopOutDataEvent(HLERequestContext& ctx);
32 void GetPopInteractiveOutDataEvent(HLERequestContext& ctx);
33 void GetIndirectLayerConsumerHandle(HLERequestContext& ctx);
34
35 void FrontendExecute();
36 void FrontendExecuteInteractive();
37 void FrontendRequestExit();
38
39 const std::shared_ptr<AppletDataBroker> broker;
40 const std::shared_ptr<Applet> applet;
41};
42
43} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp
new file mode 100644
index 000000000..47bab7528
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_creator.cpp
@@ -0,0 +1,271 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_transfer_memory.h"
5#include "core/hle/service/am/applet_data_broker.h"
6#include "core/hle/service/am/applet_manager.h"
7#include "core/hle/service/am/frontend/applets.h"
8#include "core/hle/service/am/library_applet_accessor.h"
9#include "core/hle/service/am/library_applet_creator.h"
10#include "core/hle/service/am/library_applet_storage.h"
11#include "core/hle/service/am/storage.h"
12#include "core/hle/service/ipc_helpers.h"
13#include "core/hle/service/sm/sm.h"
14
15namespace Service::AM {
16
17namespace {
18
19AppletProgramId AppletIdToProgramId(AppletId applet_id) {
20 switch (applet_id) {
21 case AppletId::OverlayDisplay:
22 return AppletProgramId::OverlayDisplay;
23 case AppletId::QLaunch:
24 return AppletProgramId::QLaunch;
25 case AppletId::Starter:
26 return AppletProgramId::Starter;
27 case AppletId::Auth:
28 return AppletProgramId::Auth;
29 case AppletId::Cabinet:
30 return AppletProgramId::Cabinet;
31 case AppletId::Controller:
32 return AppletProgramId::Controller;
33 case AppletId::DataErase:
34 return AppletProgramId::DataErase;
35 case AppletId::Error:
36 return AppletProgramId::Error;
37 case AppletId::NetConnect:
38 return AppletProgramId::NetConnect;
39 case AppletId::ProfileSelect:
40 return AppletProgramId::ProfileSelect;
41 case AppletId::SoftwareKeyboard:
42 return AppletProgramId::SoftwareKeyboard;
43 case AppletId::MiiEdit:
44 return AppletProgramId::MiiEdit;
45 case AppletId::Web:
46 return AppletProgramId::Web;
47 case AppletId::Shop:
48 return AppletProgramId::Shop;
49 case AppletId::PhotoViewer:
50 return AppletProgramId::PhotoViewer;
51 case AppletId::Settings:
52 return AppletProgramId::Settings;
53 case AppletId::OfflineWeb:
54 return AppletProgramId::OfflineWeb;
55 case AppletId::LoginShare:
56 return AppletProgramId::LoginShare;
57 case AppletId::WebAuth:
58 return AppletProgramId::WebAuth;
59 case AppletId::MyPage:
60 return AppletProgramId::MyPage;
61 default:
62 return static_cast<AppletProgramId>(0);
63 }
64}
65
66[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
67 Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
68 LibraryAppletMode mode) {
69 const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
70 if (program_id == 0) {
71 // Unknown applet
72 return {};
73 }
74
75 auto process = std::make_unique<Process>(system);
76 if (!process->Initialize(program_id)) {
77 // Couldn't initialize the guest process
78 return {};
79 }
80
81 const auto applet = std::make_shared<Applet>(system, std::move(process));
82 applet->program_id = program_id;
83 applet->applet_id = applet_id;
84 applet->type = AppletType::LibraryApplet;
85 applet->library_applet_mode = mode;
86
87 // Set focus state
88 switch (mode) {
89 case LibraryAppletMode::AllForeground:
90 case LibraryAppletMode::NoUI:
91 applet->focus_state = FocusState::InFocus;
92 applet->hid_registration.EnableAppletToGetInput(true);
93 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
94 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
95 break;
96 case LibraryAppletMode::AllForegroundInitiallyHidden:
97 applet->system_buffer_manager.SetWindowVisibility(false);
98 applet->focus_state = FocusState::NotInFocus;
99 applet->hid_registration.EnableAppletToGetInput(false);
100 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
101 break;
102 case LibraryAppletMode::Background:
103 case LibraryAppletMode::BackgroundIndirectDisplay:
104 default:
105 applet->focus_state = FocusState::Background;
106 applet->hid_registration.EnableAppletToGetInput(true);
107 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
108 break;
109 }
110
111 auto broker = std::make_shared<AppletDataBroker>(system);
112 applet->caller_applet = caller_applet;
113 applet->caller_applet_broker = broker;
114
115 system.GetAppletManager().InsertApplet(applet);
116
117 return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
118}
119
120[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
121 Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
122 LibraryAppletMode mode) {
123 const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
124
125 auto process = std::make_unique<Process>(system);
126 auto applet = std::make_shared<Applet>(system, std::move(process));
127 applet->program_id = program_id;
128 applet->applet_id = applet_id;
129 applet->type = AppletType::LibraryApplet;
130 applet->library_applet_mode = mode;
131
132 auto storage = std::make_shared<AppletDataBroker>(system);
133 applet->caller_applet = caller_applet;
134 applet->caller_applet_broker = storage;
135 applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
136
137 return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
138}
139
140} // namespace
141
142ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_)
143 : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} {
144 static const FunctionInfo functions[] = {
145 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
146 {1, nullptr, "TerminateAllLibraryApplets"},
147 {2, nullptr, "AreAnyLibraryAppletsLeft"},
148 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
149 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
150 {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
151 };
152 RegisterHandlers(functions);
153}
154
155ILibraryAppletCreator::~ILibraryAppletCreator() = default;
156
157void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
158 IPC::RequestParser rp{ctx};
159
160 const auto applet_id = rp.PopRaw<AppletId>();
161 const auto applet_mode = rp.PopRaw<LibraryAppletMode>();
162
163 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
164 applet_mode);
165
166 auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
167 if (!library_applet) {
168 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
169
170 IPC::ResponseBuilder rb{ctx, 2};
171 rb.Push(ResultUnknown);
172 return;
173 }
174
175 // Applet is created, can now be launched.
176 applet->library_applet_launchable_event.Signal();
177
178 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
179 rb.Push(ResultSuccess);
180 rb.PushIpcInterface<ILibraryAppletAccessor>(library_applet);
181}
182
183void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
184 IPC::RequestParser rp{ctx};
185
186 const s64 size{rp.Pop<s64>()};
187
188 LOG_DEBUG(Service_AM, "called, size={}", size);
189
190 if (size <= 0) {
191 LOG_ERROR(Service_AM, "size is less than or equal to 0");
192 IPC::ResponseBuilder rb{ctx, 2};
193 rb.Push(ResultUnknown);
194 return;
195 }
196
197 std::vector<u8> data(size);
198
199 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
200 rb.Push(ResultSuccess);
201 rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data)));
202}
203
204void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
205 IPC::RequestParser rp{ctx};
206
207 struct Parameters {
208 bool is_writable;
209 s64 size;
210 };
211
212 const auto params{rp.PopRaw<Parameters>()};
213 const auto handle{ctx.GetCopyHandle(0)};
214
215 LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable,
216 params.size, handle);
217
218 if (params.size <= 0) {
219 LOG_ERROR(Service_AM, "size is less than or equal to 0");
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(ResultUnknown);
222 return;
223 }
224
225 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
226
227 if (transfer_mem.IsNull()) {
228 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
229 IPC::ResponseBuilder rb{ctx, 2};
230 rb.Push(ResultUnknown);
231 return;
232 }
233
234 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
235 rb.Push(ResultSuccess);
236 rb.PushIpcInterface<IStorage>(
237 system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(),
238 params.is_writable, params.size));
239}
240
241void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
242 IPC::RequestParser rp{ctx};
243
244 const s64 size{rp.Pop<s64>()};
245 const auto handle{ctx.GetCopyHandle(0)};
246
247 LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
248
249 if (size <= 0) {
250 LOG_ERROR(Service_AM, "size is less than or equal to 0");
251 IPC::ResponseBuilder rb{ctx, 2};
252 rb.Push(ResultUnknown);
253 return;
254 }
255
256 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
257
258 if (transfer_mem.IsNull()) {
259 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
260 IPC::ResponseBuilder rb{ctx, 2};
261 rb.Push(ResultUnknown);
262 return;
263 }
264
265 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
266 rb.Push(ResultSuccess);
267 rb.PushIpcInterface<IStorage>(
268 system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size));
269}
270
271} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_creator.h b/src/core/hle/service/am/library_applet_creator.h
new file mode 100644
index 000000000..551f287bd
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_creator.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
13public:
14 explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~ILibraryAppletCreator() override;
16
17private:
18 void CreateLibraryApplet(HLERequestContext& ctx);
19 void CreateStorage(HLERequestContext& ctx);
20 void CreateTransferMemoryStorage(HLERequestContext& ctx);
21 void CreateHandleStorage(HLERequestContext& ctx);
22
23 const std::shared_ptr<Applet> applet;
24};
25
26} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_proxy.cpp b/src/core/hle/service/am/library_applet_proxy.cpp
new file mode 100644
index 000000000..d6108fba3
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_proxy.cpp
@@ -0,0 +1,143 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_common_functions.h"
5#include "core/hle/service/am/audio_controller.h"
6#include "core/hle/service/am/common_state_getter.h"
7#include "core/hle/service/am/debug_functions.h"
8#include "core/hle/service/am/display_controller.h"
9#include "core/hle/service/am/global_state_controller.h"
10#include "core/hle/service/am/home_menu_functions.h"
11#include "core/hle/service/am/library_applet_creator.h"
12#include "core/hle/service/am/library_applet_proxy.h"
13#include "core/hle/service/am/library_applet_self_accessor.h"
14#include "core/hle/service/am/process_winding_controller.h"
15#include "core/hle/service/am/self_controller.h"
16#include "core/hle/service/am/window_controller.h"
17#include "core/hle/service/ipc_helpers.h"
18
19namespace Service::AM {
20
21ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
22 std::shared_ptr<Applet> applet_, Core::System& system_)
23 : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
24 applet_)} {
25 // clang-format off
26 static const FunctionInfo functions[] = {
27 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
28 {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
29 {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
30 {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
31 {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
32 {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
33 {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
34 {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
35 {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
36 {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
37 {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
38 {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43}
44
45ILibraryAppletProxy::~ILibraryAppletProxy() = default;
46
47void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) {
48 LOG_DEBUG(Service_AM, "called");
49
50 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
51 rb.Push(ResultSuccess);
52 rb.PushIpcInterface<ICommonStateGetter>(system, applet);
53}
54
55void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) {
56 LOG_DEBUG(Service_AM, "called");
57
58 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
59 rb.Push(ResultSuccess);
60 rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
61}
62
63void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) {
64 LOG_DEBUG(Service_AM, "called");
65
66 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
67 rb.Push(ResultSuccess);
68 rb.PushIpcInterface<IWindowController>(system, applet);
69}
70
71void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) {
72 LOG_DEBUG(Service_AM, "called");
73
74 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
75 rb.Push(ResultSuccess);
76 rb.PushIpcInterface<IAudioController>(system);
77}
78
79void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_AM, "called");
81
82 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
83 rb.Push(ResultSuccess);
84 rb.PushIpcInterface<IDisplayController>(system, applet);
85}
86
87void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) {
88 LOG_DEBUG(Service_AM, "called");
89
90 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
91 rb.Push(ResultSuccess);
92 rb.PushIpcInterface<IProcessWindingController>(system, applet);
93}
94
95void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
96 LOG_DEBUG(Service_AM, "called");
97
98 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
99 rb.Push(ResultSuccess);
100 rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
101}
102
103void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
104 LOG_DEBUG(Service_AM, "called");
105
106 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
107 rb.Push(ResultSuccess);
108 rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet);
109}
110
111void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) {
112 LOG_DEBUG(Service_AM, "called");
113
114 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
115 rb.Push(ResultSuccess);
116 rb.PushIpcInterface<IAppletCommonFunctions>(system, applet);
117}
118
119void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_AM, "called");
121
122 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
123 rb.Push(ResultSuccess);
124 rb.PushIpcInterface<IHomeMenuFunctions>(system);
125}
126
127void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) {
128 LOG_DEBUG(Service_AM, "called");
129
130 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
131 rb.Push(ResultSuccess);
132 rb.PushIpcInterface<IGlobalStateController>(system);
133}
134
135void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) {
136 LOG_DEBUG(Service_AM, "called");
137
138 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
139 rb.Push(ResultSuccess);
140 rb.PushIpcInterface<IDebugFunctions>(system);
141}
142
143} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_proxy.h b/src/core/hle/service/am/library_applet_proxy.h
new file mode 100644
index 000000000..8f7a25897
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_proxy.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
13public:
14 explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
15 std::shared_ptr<Applet> applet_, Core::System& system_);
16 ~ILibraryAppletProxy();
17
18private:
19 void GetCommonStateGetter(HLERequestContext& ctx);
20 void GetSelfController(HLERequestContext& ctx);
21 void GetWindowController(HLERequestContext& ctx);
22 void GetAudioController(HLERequestContext& ctx);
23 void GetDisplayController(HLERequestContext& ctx);
24 void GetProcessWindingController(HLERequestContext& ctx);
25 void GetLibraryAppletCreator(HLERequestContext& ctx);
26 void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx);
27 void GetAppletCommonFunctions(HLERequestContext& ctx);
28 void GetHomeMenuFunctions(HLERequestContext& ctx);
29 void GetGlobalStateController(HLERequestContext& ctx);
30 void GetDebugFunctions(HLERequestContext& ctx);
31
32 Nvnflinger::Nvnflinger& nvnflinger;
33 std::shared_ptr<Applet> applet;
34};
35
36} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp
new file mode 100644
index 000000000..b560f580b
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_self_accessor.cpp
@@ -0,0 +1,338 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5#include "core/core_timing.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/registered_cache.h"
9#include "core/hle/service/acc/profile_manager.h"
10#include "core/hle/service/am/am_results.h"
11#include "core/hle/service/am/applet_data_broker.h"
12#include "core/hle/service/am/applet_manager.h"
13#include "core/hle/service/am/frontend/applet_cabinet.h"
14#include "core/hle/service/am/frontend/applet_controller.h"
15#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
16#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
17#include "core/hle/service/am/frontend/applets.h"
18#include "core/hle/service/am/library_applet_self_accessor.h"
19#include "core/hle/service/am/storage.h"
20#include "core/hle/service/ipc_helpers.h"
21#include "core/hle/service/ns/ns.h"
22#include "core/hle/service/sm/sm.h"
23#include "hid_core/hid_types.h"
24
25namespace Service::AM {
26
27namespace {
28
29AppletIdentityInfo GetCallerIdentity(std::shared_ptr<Applet> applet) {
30 if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) {
31 // TODO: is this actually the application ID?
32 return {
33 .applet_id = caller_applet->applet_id,
34 .application_id = caller_applet->program_id,
35 };
36 } else {
37 return {
38 .applet_id = AppletId::QLaunch,
39 .application_id = 0x0100000000001000ull,
40 };
41 }
42}
43
44} // namespace
45
46ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
47 std::shared_ptr<Applet> applet_)
48 : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)},
49 broker{applet->caller_applet_broker} {
50 // clang-format off
51 static const FunctionInfo functions[] = {
52 {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"},
53 {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"},
54 {2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"},
55 {3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"},
56 {5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"},
57 {6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"},
58 {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
59 {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
60 {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
61 {13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "CanUseApplicationCore"},
62 {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
63 {15, nullptr, "GetMainAppletApplicationControlProperty"},
64 {16, nullptr, "GetMainAppletStorageId"},
65 {17, nullptr, "GetCallerAppletIdentityInfoStack"},
66 {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
67 {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
68 {20, nullptr, "PopExtraStorage"},
69 {25, nullptr, "GetPopExtraStorageEvent"},
70 {30, nullptr, "UnpopInData"},
71 {31, nullptr, "UnpopExtraStorage"},
72 {40, nullptr, "GetIndirectLayerProducerHandle"},
73 {50, nullptr, "ReportVisibleError"},
74 {51, nullptr, "ReportVisibleErrorWithErrorContext"},
75 {60, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"},
76 {70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "GetCurrentApplicationId"},
77 {80, nullptr, "RequestExitToSelf"},
78 {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
79 {100, nullptr, "CreateGameMovieTrimmer"},
80 {101, nullptr, "ReserveResourceForMovieOperation"},
81 {102, nullptr, "UnreserveResourceForMovieOperation"},
82 {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
83 {120, nullptr, "GetLaunchStorageInfoForDebug"},
84 {130, nullptr, "GetGpuErrorDetectedSystemEvent"},
85 {140, nullptr, "SetApplicationMemoryReservation"},
86 {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
87 {160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"},
88 };
89 // clang-format on
90 RegisterHandlers(functions);
91}
92
93ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
94
95void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
96 LOG_INFO(Service_AM, "called");
97
98 std::shared_ptr<IStorage> data;
99 const auto res = broker->GetInData().Pop(&data);
100
101 if (res.IsSuccess()) {
102 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
103 rb.Push(res);
104 rb.PushIpcInterface(std::move(data));
105 } else {
106 IPC::ResponseBuilder rb{ctx, 2};
107 rb.Push(res);
108 }
109}
110
111void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) {
112 LOG_INFO(Service_AM, "called");
113
114 IPC::RequestParser rp{ctx};
115 broker->GetOutData().Push(rp.PopIpcInterface<IStorage>().lock());
116
117 IPC::ResponseBuilder rb{ctx, 2};
118 rb.Push(ResultSuccess);
119}
120
121void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) {
122 LOG_INFO(Service_AM, "called");
123
124 std::shared_ptr<IStorage> data;
125 const auto res = broker->GetInteractiveInData().Pop(&data);
126
127 if (res.IsSuccess()) {
128 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
129 rb.Push(res);
130 rb.PushIpcInterface(std::move(data));
131 } else {
132 IPC::ResponseBuilder rb{ctx, 2};
133 rb.Push(res);
134 }
135}
136
137void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) {
138 LOG_INFO(Service_AM, "called");
139
140 IPC::RequestParser rp{ctx};
141 broker->GetInteractiveOutData().Push(rp.PopIpcInterface<IStorage>().lock());
142
143 IPC::ResponseBuilder rb{ctx, 2};
144 rb.Push(ResultSuccess);
145}
146
147void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) {
148 LOG_INFO(Service_AM, "called");
149
150 IPC::ResponseBuilder rb{ctx, 2, 1};
151 rb.Push(ResultSuccess);
152 rb.PushCopyObjects(broker->GetInData().GetEvent());
153}
154
155void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) {
156 LOG_INFO(Service_AM, "called");
157
158 IPC::ResponseBuilder rb{ctx, 2, 1};
159 rb.Push(ResultSuccess);
160 rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent());
161}
162
163void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
164 LOG_INFO(Service_AM, "called");
165
166 system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid);
167 broker->SignalCompletion();
168
169 IPC::ResponseBuilder rb{ctx, 2};
170 rb.Push(ResultSuccess);
171}
172
173void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
174 struct LibraryAppletInfo {
175 AppletId applet_id;
176 LibraryAppletMode library_applet_mode;
177 };
178
179 LOG_WARNING(Service_AM, "(STUBBED) called");
180
181 const LibraryAppletInfo applet_info{
182 .applet_id = applet->applet_id,
183 .library_applet_mode = applet->library_applet_mode,
184 };
185
186 IPC::ResponseBuilder rb{ctx, 4};
187 rb.Push(ResultSuccess);
188 rb.PushRaw(applet_info);
189}
190
191void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
192 LOG_WARNING(Service_AM, "(STUBBED) called");
193
194 const AppletIdentityInfo applet_info{
195 .applet_id = AppletId::QLaunch,
196 .application_id = 0x0100000000001000ull,
197 };
198
199 IPC::ResponseBuilder rb{ctx, 6};
200 rb.Push(ResultSuccess);
201 rb.PushRaw(applet_info);
202}
203
204void ILibraryAppletSelfAccessor::CanUseApplicationCore(HLERequestContext& ctx) {
205 LOG_WARNING(Service_AM, "(STUBBED) called");
206
207 // TODO: This appears to read the NPDM from state and check the core mask of the applet.
208 IPC::ResponseBuilder rb{ctx, 3};
209 rb.Push(ResultSuccess);
210 rb.Push<u8>(0);
211}
212
213void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
214 LOG_WARNING(Service_AM, "(STUBBED) called");
215
216 IPC::ResponseBuilder rb{ctx, 6};
217 rb.Push(ResultSuccess);
218 rb.PushRaw(GetCallerIdentity(applet));
219}
220
221void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) {
222 LOG_WARNING(Service_AM, "(STUBBED) called");
223
224 IPC::ResponseBuilder rb{ctx, 3};
225 rb.Push(ResultSuccess);
226 rb.Push<u32>(0);
227}
228
229void ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx) {
230 // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
231 auto identity = GetCallerIdentity(applet);
232
233 // TODO(bunnei): This should be configurable
234 LOG_DEBUG(Service_AM, "called");
235
236 // Get supported languages from NACP, if possible
237 // Default to 0 (all languages supported)
238 u32 supported_languages = 0;
239
240 const auto res = [this, identity] {
241 const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
242 system.GetContentProvider()};
243 auto metadata = pm.GetControlMetadata();
244 if (metadata.first != nullptr) {
245 return metadata;
246 }
247
248 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
249 system.GetFileSystemController(),
250 system.GetContentProvider()};
251 return pm_update.GetControlMetadata();
252 }();
253
254 if (res.first != nullptr) {
255 supported_languages = res.first->GetSupportedLanguages();
256 }
257
258 // Call IApplicationManagerInterface implementation.
259 auto& service_manager = system.ServiceManager();
260 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
261 auto app_man = ns_am2->GetApplicationManagerInterface();
262
263 // Get desired application language
264 u8 desired_language{};
265 const auto res_lang =
266 app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
267 if (res_lang != ResultSuccess) {
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(res_lang);
270 return;
271 }
272
273 // Convert to settings language code.
274 u64 language_code{};
275 const auto res_code =
276 app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
277 if (res_code != ResultSuccess) {
278 IPC::ResponseBuilder rb{ctx, 2};
279 rb.Push(res_code);
280 return;
281 }
282
283 LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
284
285 IPC::ResponseBuilder rb{ctx, 4};
286 rb.Push(ResultSuccess);
287 rb.Push(language_code);
288}
289
290void ILibraryAppletSelfAccessor::GetCurrentApplicationId(HLERequestContext& ctx) {
291 LOG_WARNING(Service_AM, "(STUBBED) called");
292
293 u64 application_id = 0;
294 if (auto caller_applet = applet->caller_applet.lock(); caller_applet) {
295 application_id = caller_applet->program_id;
296 }
297
298 IPC::ResponseBuilder rb{ctx, 4};
299 rb.Push(ResultSuccess);
300 rb.Push(application_id);
301}
302
303void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
304 const Service::Account::ProfileManager manager{};
305 bool is_empty{true};
306 s32 user_count{-1};
307
308 LOG_INFO(Service_AM, "called");
309
310 if (manager.GetUserCount() > 0) {
311 is_empty = false;
312 user_count = static_cast<s32>(manager.GetUserCount());
313 ctx.WriteBuffer(manager.GetAllUsers());
314 }
315
316 IPC::ResponseBuilder rb{ctx, 4};
317 rb.Push(ResultSuccess);
318 rb.Push<u8>(is_empty);
319 rb.Push(user_count);
320}
321
322void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) {
323 LOG_WARNING(Service_AM, "(STUBBED) called");
324
325 IPC::ResponseBuilder rb{ctx, 3};
326 rb.Push(ResultSuccess);
327 rb.Push<u8>(0);
328}
329
330void ILibraryAppletSelfAccessor::Cmd160(HLERequestContext& ctx) {
331 LOG_WARNING(Service_AM, "(STUBBED) called");
332
333 IPC::ResponseBuilder rb{ctx, 4};
334 rb.Push(ResultSuccess);
335 rb.Push<u64>(0);
336}
337
338} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_self_accessor.h b/src/core/hle/service/am/library_applet_self_accessor.h
new file mode 100644
index 000000000..8717a989a
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_self_accessor.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <deque>
7#include <vector>
8
9#include "core/hle/service/service.h"
10
11namespace Service::AM {
12
13class AppletDataBroker;
14struct Applet;
15
16class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
17public:
18 explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet_);
19 ~ILibraryAppletSelfAccessor() override;
20
21private:
22 void PopInData(HLERequestContext& ctx);
23 void PushOutData(HLERequestContext& ctx);
24 void PopInteractiveInData(HLERequestContext& ctx);
25 void PushInteractiveOutData(HLERequestContext& ctx);
26 void GetPopInDataEvent(HLERequestContext& ctx);
27 void GetPopInteractiveInDataEvent(HLERequestContext& ctx);
28 void GetLibraryAppletInfo(HLERequestContext& ctx);
29 void GetMainAppletIdentityInfo(HLERequestContext& ctx);
30 void CanUseApplicationCore(HLERequestContext& ctx);
31 void ExitProcessAndReturn(HLERequestContext& ctx);
32 void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
33 void GetDesirableKeyboardLayout(HLERequestContext& ctx);
34 void GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx);
35 void GetCurrentApplicationId(HLERequestContext& ctx);
36 void GetMainAppletAvailableUsers(HLERequestContext& ctx);
37 void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
38 void Cmd160(HLERequestContext& ctx);
39
40 const std::shared_ptr<Applet> applet;
41 const std::shared_ptr<AppletDataBroker> broker;
42};
43
44} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_storage.cpp b/src/core/hle/service/am/library_applet_storage.cpp
new file mode 100644
index 000000000..46e6c0111
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_storage.cpp
@@ -0,0 +1,140 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_transfer_memory.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/library_applet_storage.h"
7#include "core/memory.h"
8
9namespace Service::AM {
10
11namespace {
12
13Result ValidateOffset(s64 offset, size_t size, size_t data_size) {
14 R_UNLESS(offset >= 0, AM::ResultInvalidOffset);
15
16 const size_t begin = offset;
17 const size_t end = begin + size;
18
19 R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset);
20 R_SUCCEED();
21}
22
23class BufferLibraryAppletStorage final : public LibraryAppletStorage {
24public:
25 explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {}
26 ~BufferLibraryAppletStorage() = default;
27
28 Result Read(s64 offset, void* buffer, size_t size) override {
29 R_TRY(ValidateOffset(offset, size, m_data.size()));
30
31 std::memcpy(buffer, m_data.data() + offset, size);
32
33 R_SUCCEED();
34 }
35
36 Result Write(s64 offset, const void* buffer, size_t size) override {
37 R_TRY(ValidateOffset(offset, size, m_data.size()));
38
39 std::memcpy(m_data.data() + offset, buffer, size);
40
41 R_SUCCEED();
42 }
43
44 s64 GetSize() override {
45 return m_data.size();
46 }
47
48 Kernel::KTransferMemory* GetHandle() override {
49 return nullptr;
50 }
51
52private:
53 std::vector<u8> m_data;
54};
55
56class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage {
57public:
58 explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory,
59 Kernel::KTransferMemory* trmem, bool is_writable,
60 s64 size)
61 : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) {
62 m_trmem->Open();
63 }
64
65 ~TransferMemoryLibraryAppletStorage() {
66 m_trmem->Close();
67 m_trmem = nullptr;
68 }
69
70 Result Read(s64 offset, void* buffer, size_t size) override {
71 R_TRY(ValidateOffset(offset, size, m_size));
72
73 m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size);
74
75 R_SUCCEED();
76 }
77
78 Result Write(s64 offset, const void* buffer, size_t size) override {
79 R_UNLESS(m_is_writable, ResultUnknown);
80 R_TRY(ValidateOffset(offset, size, m_size));
81
82 m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size);
83
84 R_SUCCEED();
85 }
86
87 s64 GetSize() override {
88 return m_size;
89 }
90
91 Kernel::KTransferMemory* GetHandle() override {
92 return nullptr;
93 }
94
95protected:
96 Core::Memory::Memory& m_memory;
97 Kernel::KTransferMemory* m_trmem;
98 bool m_is_writable;
99 s64 m_size;
100};
101
102class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage {
103public:
104 explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory,
105 Kernel::KTransferMemory* trmem, s64 size)
106 : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {}
107 ~HandleLibraryAppletStorage() = default;
108
109 Kernel::KTransferMemory* GetHandle() override {
110 return m_trmem;
111 }
112};
113
114} // namespace
115
116LibraryAppletStorage::~LibraryAppletStorage() = default;
117
118std::vector<u8> LibraryAppletStorage::GetData() {
119 std::vector<u8> data(this->GetSize());
120 this->Read(0, data.data(), data.size());
121 return data;
122}
123
124std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) {
125 return std::make_shared<BufferLibraryAppletStorage>(std::move(data));
126}
127
128std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
129 Kernel::KTransferMemory* trmem,
130 bool is_writable, s64 size) {
131 return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size);
132}
133
134std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
135 Kernel::KTransferMemory* trmem,
136 s64 size) {
137 return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size);
138}
139
140} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_storage.h b/src/core/hle/service/am/library_applet_storage.h
new file mode 100644
index 000000000..7f53f3a9c
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_storage.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core::Memory {
9class Memory;
10}
11
12namespace Kernel {
13class KTransferMemory;
14}
15
16namespace Service::AM {
17
18class LibraryAppletStorage {
19public:
20 virtual ~LibraryAppletStorage();
21 virtual Result Read(s64 offset, void* buffer, size_t size) = 0;
22 virtual Result Write(s64 offset, const void* buffer, size_t size) = 0;
23 virtual s64 GetSize() = 0;
24 virtual Kernel::KTransferMemory* GetHandle() = 0;
25
26 std::vector<u8> GetData();
27};
28
29std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data);
30std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
31 Kernel::KTransferMemory* trmem,
32 bool is_writable, s64 size);
33std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
34 Kernel::KTransferMemory* trmem, s64 size);
35
36} // namespace Service::AM
diff --git a/src/core/hle/service/am/lock_accessor.cpp b/src/core/hle/service/am/lock_accessor.cpp
new file mode 100644
index 000000000..d0bd8d95e
--- /dev/null
+++ b/src/core/hle/service/am/lock_accessor.cpp
@@ -0,0 +1,71 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/lock_accessor.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9ILockAccessor::ILockAccessor(Core::System& system_)
10 : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {1, &ILockAccessor::TryLock, "TryLock"},
14 {2, &ILockAccessor::Unlock, "Unlock"},
15 {3, &ILockAccessor::GetEvent, "GetEvent"},
16 {4,&ILockAccessor::IsLocked, "IsLocked"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21
22 lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
23}
24
25ILockAccessor::~ILockAccessor() {
26 service_context.CloseEvent(lock_event);
27};
28
29void ILockAccessor::TryLock(HLERequestContext& ctx) {
30 IPC::RequestParser rp{ctx};
31 const auto return_handle = rp.Pop<bool>();
32
33 LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
34
35 // TODO: When return_handle is true this function should return the lock handle
36
37 is_locked = true;
38
39 IPC::ResponseBuilder rb{ctx, 3};
40 rb.Push(ResultSuccess);
41 rb.Push<u8>(is_locked);
42}
43
44void ILockAccessor::Unlock(HLERequestContext& ctx) {
45 LOG_INFO(Service_AM, "called");
46
47 is_locked = false;
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(ResultSuccess);
51}
52
53void ILockAccessor::GetEvent(HLERequestContext& ctx) {
54 LOG_INFO(Service_AM, "called");
55
56 lock_event->Signal();
57
58 IPC::ResponseBuilder rb{ctx, 2, 1};
59 rb.Push(ResultSuccess);
60 rb.PushCopyObjects(lock_event->GetReadableEvent());
61}
62
63void ILockAccessor::IsLocked(HLERequestContext& ctx) {
64 LOG_INFO(Service_AM, "called");
65
66 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(ResultSuccess);
68 rb.Push<u8>(is_locked);
69}
70
71} // namespace Service::AM
diff --git a/src/core/hle/service/am/lock_accessor.h b/src/core/hle/service/am/lock_accessor.h
new file mode 100644
index 000000000..626f60e07
--- /dev/null
+++ b/src/core/hle/service/am/lock_accessor.h
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11class ILockAccessor final : public ServiceFramework<ILockAccessor> {
12public:
13 explicit ILockAccessor(Core::System& system_);
14 ~ILockAccessor() override;
15
16private:
17 void TryLock(HLERequestContext& ctx);
18 void Unlock(HLERequestContext& ctx);
19 void GetEvent(HLERequestContext& ctx);
20 void IsLocked(HLERequestContext& ctx);
21
22 bool is_locked{};
23
24 Kernel::KEvent* lock_event;
25 KernelHelpers::ServiceContext service_context;
26};
27
28} // namespace Service::AM
diff --git a/src/core/hle/service/am/managed_layer_holder.cpp b/src/core/hle/service/am/managed_layer_holder.cpp
new file mode 100644
index 000000000..61eb8641a
--- /dev/null
+++ b/src/core/hle/service/am/managed_layer_holder.cpp
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/managed_layer_holder.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h"
6
7namespace Service::AM {
8
9ManagedLayerHolder::ManagedLayerHolder() = default;
10ManagedLayerHolder::~ManagedLayerHolder() {
11 if (!m_nvnflinger) {
12 return;
13 }
14
15 for (const auto& layer : m_managed_display_layers) {
16 m_nvnflinger->DestroyLayer(layer);
17 }
18
19 for (const auto& layer : m_managed_display_recording_layers) {
20 m_nvnflinger->DestroyLayer(layer);
21 }
22
23 m_nvnflinger = nullptr;
24}
25
26void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
27 m_nvnflinger = nvnflinger;
28}
29
30void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
31 // TODO(Subv): Find out how AM determines the display to use, for now just
32 // create the layer in the Default display.
33 const auto display_id = m_nvnflinger->OpenDisplay("Default");
34 const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
35
36 m_managed_display_layers.emplace(*layer_id);
37
38 *out_layer = *layer_id;
39}
40
41void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
42 u64* out_recording_layer) {
43 // TODO(Subv): Find out how AM determines the display to use, for now just
44 // create the layer in the Default display.
45 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
46 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
47 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
48 // side effects.
49 // TODO: Support multiple layers
50 const auto display_id = m_nvnflinger->OpenDisplay("Default");
51 const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
52
53 m_managed_display_layers.emplace(*layer_id);
54
55 *out_layer = *layer_id;
56 *out_recording_layer = 0;
57}
58
59} // namespace Service::AM
diff --git a/src/core/hle/service/am/managed_layer_holder.h b/src/core/hle/service/am/managed_layer_holder.h
new file mode 100644
index 000000000..f7fe03f24
--- /dev/null
+++ b/src/core/hle/service/am/managed_layer_holder.h
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace Service::Nvnflinger {
12class Nvnflinger;
13}
14
15namespace Service::AM {
16
17class ManagedLayerHolder {
18public:
19 ManagedLayerHolder();
20 ~ManagedLayerHolder();
21
22 void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
23 void CreateManagedDisplayLayer(u64* out_layer);
24 void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
25
26private:
27 Nvnflinger::Nvnflinger* m_nvnflinger{};
28 std::set<u64> m_managed_display_layers{};
29 std::set<u64> m_managed_display_recording_layers{};
30};
31
32} // namespace Service::AM
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp
new file mode 100644
index 000000000..16b685f86
--- /dev/null
+++ b/src/core/hle/service/am/process.cpp
@@ -0,0 +1,138 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/file_sys/nca_metadata.h"
7#include "core/file_sys/registered_cache.h"
8#include "core/hle/kernel/k_process.h"
9#include "core/hle/service/am/process.h"
10#include "core/hle/service/filesystem/filesystem.h"
11#include "core/loader/loader.h"
12
13namespace Service::AM {
14
15Process::Process(Core::System& system)
16 : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
17 m_program_id(), m_process_started() {}
18
19Process::~Process() {
20 this->Finalize();
21}
22
23bool Process::Initialize(u64 program_id) {
24 // First, ensure we are not holding another process.
25 this->Finalize();
26
27 // Get the filesystem controller.
28 auto& fsc = m_system.GetFileSystemController();
29
30 // Attempt to load program NCA.
31 const FileSys::RegisteredCache* bis_system{};
32 FileSys::VirtualFile nca{};
33
34 // Get the program NCA from built-in storage.
35 bis_system = fsc.GetSystemNANDContents();
36 if (bis_system) {
37 nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
38 }
39
40 // Ensure we retrieved a program NCA.
41 if (!nca) {
42 return false;
43 }
44
45 // Get the appropriate loader to parse this NCA.
46 auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
47
48 // Ensure we have a loader which can parse the NCA.
49 if (!app_loader) {
50 return false;
51 }
52
53 // Create the process.
54 auto* const process = Kernel::KProcess::Create(m_system.Kernel());
55 Kernel::KProcess::Register(m_system.Kernel(), process);
56
57 // On exit, ensure we free the additional reference to the process.
58 SCOPE_EXIT({ process->Close(); });
59
60 // Insert process modules into memory.
61 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
62
63 // Ensure loading was successful.
64 if (load_result != Loader::ResultStatus::Success) {
65 return false;
66 }
67
68 // TODO: remove this, kernel already tracks this
69 m_system.Kernel().AppendNewProcess(process);
70
71 // Note the load parameters from NPDM.
72 m_main_thread_priority = load_parameters->main_thread_priority;
73 m_main_thread_stack_size = load_parameters->main_thread_stack_size;
74
75 // This process has not started yet.
76 m_process_started = false;
77
78 // Take ownership of the process object.
79 m_process = process;
80 m_process->Open();
81
82 // We succeeded.
83 return true;
84}
85
86void Process::Finalize() {
87 // Terminate, if we are currently holding a process.
88 this->Terminate();
89
90 // Close the process.
91 if (m_process) {
92 m_process->Close();
93
94 // TODO: remove this, kernel already tracks this
95 m_system.Kernel().RemoveProcess(m_process);
96 }
97
98 // Clean up.
99 m_process = nullptr;
100 m_main_thread_priority = 0;
101 m_main_thread_stack_size = 0;
102 m_program_id = 0;
103 m_process_started = false;
104}
105
106bool Process::Run() {
107 // If we already started the process, don't start again.
108 if (m_process_started) {
109 return false;
110 }
111
112 // Start.
113 if (m_process) {
114 m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
115 }
116
117 // Mark as started.
118 m_process_started = true;
119
120 // We succeeded.
121 return true;
122}
123
124void Process::Terminate() {
125 if (m_process) {
126 m_process->Terminate();
127 }
128}
129
130u64 Process::GetProcessId() const {
131 if (m_process) {
132 return m_process->GetProcessId();
133 }
134
135 return 0;
136}
137
138} // namespace Service::AM
diff --git a/src/core/hle/service/am/process.h b/src/core/hle/service/am/process.h
new file mode 100644
index 000000000..4b908ade4
--- /dev/null
+++ b/src/core/hle/service/am/process.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Kernel {
10class KProcess;
11}
12
13namespace Core {
14class System;
15}
16
17namespace Service::AM {
18
19class Process {
20public:
21 explicit Process(Core::System& system);
22 ~Process();
23
24 bool Initialize(u64 program_id);
25 void Finalize();
26
27 bool Run();
28 void Terminate();
29
30 bool IsInitialized() const {
31 return m_process != nullptr;
32 }
33 u64 GetProcessId() const;
34 u64 GetProgramId() const {
35 return m_program_id;
36 }
37 Kernel::KProcess* GetProcess() const {
38 return m_process;
39 }
40
41private:
42 Core::System& m_system;
43 Kernel::KProcess* m_process{};
44 s32 m_main_thread_priority{};
45 u64 m_main_thread_stack_size{};
46 u64 m_program_id{};
47 bool m_process_started{};
48};
49
50} // namespace Service::AM
diff --git a/src/core/hle/service/am/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp
new file mode 100644
index 000000000..b48b52797
--- /dev/null
+++ b/src/core/hle/service/am/process_winding_controller.cpp
@@ -0,0 +1,56 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/frontend/applets.h"
5#include "core/hle/service/am/library_applet_accessor.h"
6#include "core/hle/service/am/process_winding_controller.h"
7#include "core/hle/service/ipc_helpers.h"
8
9namespace Service::AM {
10
11IProcessWindingController::IProcessWindingController(Core::System& system_,
12 std::shared_ptr<Applet> applet_)
13 : ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"},
17 {11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"},
18 {21, nullptr, "PushContext"},
19 {22, nullptr, "PopContext"},
20 {23, nullptr, "CancelWindingReservation"},
21 {30, nullptr, "WindAndDoReserved"},
22 {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
23 {41, nullptr, "ReserveToStartAndWait"},
24 };
25 // clang-format on
26
27 RegisterHandlers(functions);
28}
29
30IProcessWindingController::~IProcessWindingController() = default;
31
32void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
33 LOG_WARNING(Service_AM, "(STUBBED) called");
34
35 IPC::ResponseBuilder rb{ctx, 3};
36 rb.Push(ResultSuccess);
37 rb.PushRaw(applet->launch_reason);
38}
39
40void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
41 const auto caller_applet = applet->caller_applet.lock();
42 if (caller_applet == nullptr) {
43 LOG_ERROR(Service_AM, "No calling applet available");
44
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(ResultUnknown);
47 return;
48 }
49
50 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
51 rb.Push(ResultSuccess);
52 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_broker,
53 caller_applet);
54}
55
56} // namespace Service::AM
diff --git a/src/core/hle/service/am/process_winding_controller.h b/src/core/hle/service/am/process_winding_controller.h
new file mode 100644
index 000000000..71ae4c4f5
--- /dev/null
+++ b/src/core/hle/service/am/process_winding_controller.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
13public:
14 explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IProcessWindingController() override;
16
17private:
18 void GetLaunchReason(HLERequestContext& ctx);
19 void OpenCallingLibraryApplet(HLERequestContext& ctx);
20
21 const std::shared_ptr<Applet> applet;
22};
23
24} // namespace Service::AM
diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp
new file mode 100644
index 000000000..0289f5cf1
--- /dev/null
+++ b/src/core/hle/service/am/self_controller.cpp
@@ -0,0 +1,456 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/am_results.h"
5#include "core/hle/service/am/frontend/applets.h"
6#include "core/hle/service/am/self_controller.h"
7#include "core/hle/service/caps/caps_su.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
10#include "core/hle/service/nvnflinger/nvnflinger.h"
11#include "core/hle/service/sm/sm.h"
12#include "core/hle/service/vi/vi_results.h"
13
14namespace Service::AM {
15
16ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
17 Nvnflinger::Nvnflinger& nvnflinger_)
18 : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move(
19 applet_)} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, &ISelfController::Exit, "Exit"},
23 {1, &ISelfController::LockExit, "LockExit"},
24 {2, &ISelfController::UnlockExit, "UnlockExit"},
25 {3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
26 {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
27 {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
28 {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
29 {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
30 {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
31 {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
32 {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
33 {15, &ISelfController::SetScreenShotAppletIdentityInfo, "SetScreenShotAppletIdentityInfo"},
34 {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
35 {17, nullptr, "SetControllerFirmwareUpdateSection"},
36 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
37 {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
38 {20, nullptr, "SetDesirableKeyboardLayout"},
39 {21, nullptr, "GetScreenShotProgramId"},
40 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
41 {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
42 {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
43 {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
44 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
45 {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
46 {46, nullptr, "SetRecordingLayerCompositionEnabled"},
47 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
48 {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
49 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
50 {61, nullptr, "SetMediaPlaybackState"},
51 {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
52 {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
53 {64, nullptr, "SetInputDetectionSourceSet"},
54 {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"},
55 {66, nullptr, "GetCurrentIlluminance"},
56 {67, nullptr, "IsIlluminanceAvailable"},
57 {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
58 {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
59 {70, nullptr, "ReportMultimediaError"},
60 {71, nullptr, "GetCurrentIlluminanceEx"},
61 {72, nullptr, "SetInputDetectionPolicy"},
62 {80, nullptr, "SetWirelessPriorityMode"},
63 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
64 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
65 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
66 {110, nullptr, "SetApplicationAlbumUserData"},
67 {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
68 {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"},
69 {1000, nullptr, "GetDebugStorageChannel"},
70 };
71 // clang-format on
72
73 RegisterHandlers(functions);
74}
75
76ISelfController::~ISelfController() = default;
77
78void ISelfController::Exit(HLERequestContext& ctx) {
79 LOG_DEBUG(Service_AM, "called");
80
81 IPC::ResponseBuilder rb{ctx, 2};
82 rb.Push(ResultSuccess);
83
84 // TODO
85 system.Exit();
86}
87
88void ISelfController::LockExit(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_AM, "called");
90
91 system.SetExitLocked(true);
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(ResultSuccess);
95}
96
97void ISelfController::UnlockExit(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_AM, "called");
99
100 system.SetExitLocked(false);
101
102 IPC::ResponseBuilder rb{ctx, 2};
103 rb.Push(ResultSuccess);
104
105 if (system.GetExitRequested()) {
106 system.Exit();
107 }
108}
109
110void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
111
112 std::scoped_lock lk{applet->lock};
113 applet->fatal_section_count++;
114 LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", applet->fatal_section_count);
115
116 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(ResultSuccess);
118}
119
120void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
121 LOG_DEBUG(Service_AM, "called.");
122
123 // Entry and exit of fatal sections must be balanced.
124 std::scoped_lock lk{applet->lock};
125 if (applet->fatal_section_count == 0) {
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(AM::ResultFatalSectionCountImbalance);
128 return;
129 }
130
131 applet->fatal_section_count--;
132
133 IPC::ResponseBuilder rb{ctx, 2};
134 rb.Push(ResultSuccess);
135}
136
137void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
138 LOG_WARNING(Service_AM, "(STUBBED) called");
139
140 applet->library_applet_launchable_event.Signal();
141
142 IPC::ResponseBuilder rb{ctx, 2, 1};
143 rb.Push(ResultSuccess);
144 rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle());
145}
146
147void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
148 IPC::RequestParser rp{ctx};
149 const auto permission = rp.PopEnum<ScreenshotPermission>();
150 LOG_DEBUG(Service_AM, "called, permission={}", permission);
151
152 std::scoped_lock lk{applet->lock};
153 applet->screenshot_permission = permission;
154
155 IPC::ResponseBuilder rb{ctx, 2};
156 rb.Push(ResultSuccess);
157}
158
159void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
160 IPC::RequestParser rp{ctx};
161
162 const bool notification_enabled = rp.Pop<bool>();
163 LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
164
165 std::scoped_lock lk{applet->lock};
166 applet->operation_mode_changed_notification_enabled = notification_enabled;
167
168 IPC::ResponseBuilder rb{ctx, 2};
169 rb.Push(ResultSuccess);
170}
171
172void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
173 IPC::RequestParser rp{ctx};
174
175 const bool notification_enabled = rp.Pop<bool>();
176 LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
177
178 std::scoped_lock lk{applet->lock};
179 applet->performance_mode_changed_notification_enabled = notification_enabled;
180
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(ResultSuccess);
183}
184
185void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
186 IPC::RequestParser rp{ctx};
187
188 const auto flags = rp.PopRaw<FocusHandlingMode>();
189
190 LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
191 flags.unknown0, flags.unknown1, flags.unknown2);
192
193 std::scoped_lock lk{applet->lock};
194 applet->focus_handling_mode = flags;
195
196 IPC::ResponseBuilder rb{ctx, 2};
197 rb.Push(ResultSuccess);
198}
199
200void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
201 LOG_WARNING(Service_AM, "(STUBBED) called");
202
203 std::scoped_lock lk{applet->lock};
204 applet->restart_message_enabled = true;
205
206 IPC::ResponseBuilder rb{ctx, 2};
207 rb.Push(ResultSuccess);
208}
209
210void ISelfController::SetScreenShotAppletIdentityInfo(HLERequestContext& ctx) {
211 LOG_WARNING(Service_AM, "(STUBBED) called");
212
213 IPC::RequestParser rp{ctx};
214 std::scoped_lock lk{applet->lock};
215 applet->screen_shot_identity = rp.PopRaw<AppletIdentityInfo>();
216
217 IPC::ResponseBuilder rb{ctx, 2};
218 rb.Push(ResultSuccess);
219}
220
221void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
222 IPC::RequestParser rp{ctx};
223
224 const bool enabled = rp.Pop<bool>();
225 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
226
227 std::scoped_lock lk{applet->lock};
228 ASSERT(applet->type == AppletType::Application);
229 applet->out_of_focus_suspension_enabled = enabled;
230
231 IPC::ResponseBuilder rb{ctx, 2};
232 rb.Push(ResultSuccess);
233}
234
235void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
236 IPC::RequestParser rp{ctx};
237
238 const auto orientation = rp.PopRaw<Capture::AlbumImageOrientation>();
239 LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast<s32>(orientation));
240
241 std::scoped_lock lk{applet->lock};
242 applet->album_image_orientation = orientation;
243
244 IPC::ResponseBuilder rb{ctx, 2};
245 rb.Push(ResultSuccess);
246}
247
248void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
249 LOG_WARNING(Service_AM, "(STUBBED) called");
250
251 u64 layer_id{};
252 applet->managed_layer_holder.Initialize(&nvnflinger);
253 applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_id);
254
255 IPC::ResponseBuilder rb{ctx, 4};
256 rb.Push(ResultSuccess);
257 rb.Push(layer_id);
258}
259
260void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
261 LOG_WARNING(Service_AM, "(STUBBED) called");
262
263 IPC::ResponseBuilder rb{ctx, 2};
264 rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
265}
266
267void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
268 LOG_WARNING(Service_AM, "(STUBBED) called");
269
270 u64 buffer_id, layer_id;
271 applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
272
273 IPC::ResponseBuilder rb{ctx, 6};
274 rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
275 rb.Push<s64>(buffer_id);
276 rb.Push<s64>(layer_id);
277}
278
279void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
280 LOG_WARNING(Service_AM, "(STUBBED) called");
281
282 u64 buffer_id, layer_id;
283 applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
284
285 IPC::ResponseBuilder rb{ctx, 4};
286 rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
287 rb.Push<s64>(buffer_id);
288}
289
290Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
291 if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
292 return ResultSuccess;
293 }
294
295 return VI::ResultOperationFailed;
296}
297
298void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
299 LOG_WARNING(Service_AM, "(STUBBED) called");
300
301 u64 layer_id{};
302 u64 recording_layer_id{};
303 applet->managed_layer_holder.Initialize(&nvnflinger);
304 applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id);
305
306 IPC::ResponseBuilder rb{ctx, 6};
307 rb.Push(ResultSuccess);
308 rb.Push(layer_id);
309 rb.Push(recording_layer_id);
310}
311
312void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
313 LOG_WARNING(Service_AM, "(STUBBED) called");
314
315 IPC::ResponseBuilder rb{ctx, 2};
316 rb.Push(ResultSuccess);
317}
318
319void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
320 LOG_WARNING(Service_AM, "(STUBBED) called");
321
322 IPC::ResponseBuilder rb{ctx, 2};
323 rb.Push(ResultSuccess);
324}
325
326void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
327 IPC::RequestParser rp{ctx};
328
329 const auto extension = rp.PopRaw<IdleTimeDetectionExtension>();
330 LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", extension);
331
332 std::scoped_lock lk{applet->lock};
333 applet->idle_time_detection_extension = extension;
334
335 IPC::ResponseBuilder rb{ctx, 2};
336 rb.Push(ResultSuccess);
337}
338
339void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
340 LOG_WARNING(Service_AM, "(STUBBED) called");
341
342 std::scoped_lock lk{applet->lock};
343
344 IPC::ResponseBuilder rb{ctx, 3};
345 rb.Push(ResultSuccess);
346 rb.PushRaw<IdleTimeDetectionExtension>(applet->idle_time_detection_extension);
347}
348
349void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
350 LOG_WARNING(Service_AM, "(STUBBED) called");
351
352 IPC::ResponseBuilder rb{ctx, 2};
353 rb.Push(ResultSuccess);
354}
355
356void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
357 IPC::RequestParser rp{ctx};
358
359 std::scoped_lock lk{applet->lock};
360 applet->auto_sleep_disabled = rp.Pop<bool>();
361
362 // On the system itself, if the previous state of is_auto_sleep_disabled
363 // differed from the current value passed in, it'd signify the internal
364 // window manager to update (and also increment some statistics like update counts)
365 //
366 // It'd also indicate this change to an idle handling context.
367 //
368 // However, given we're emulating this behavior, most of this can be ignored
369 // and it's sufficient to simply set the member variable for querying via
370 // IsAutoSleepDisabled().
371
372 LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", applet->auto_sleep_disabled);
373
374 IPC::ResponseBuilder rb{ctx, 2};
375 rb.Push(ResultSuccess);
376}
377
378void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
379 LOG_DEBUG(Service_AM, "called.");
380
381 std::scoped_lock lk{applet->lock};
382
383 IPC::ResponseBuilder rb{ctx, 3};
384 rb.Push(ResultSuccess);
385 rb.Push(applet->auto_sleep_disabled);
386}
387
388void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
389 LOG_DEBUG(Service_AM, "called.");
390
391 std::scoped_lock lk{applet->lock};
392 // This command returns the total number of system ticks since ISelfController creation
393 // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
394 // can just always return 0 ticks.
395 IPC::ResponseBuilder rb{ctx, 4};
396 rb.Push(ResultSuccess);
397 rb.Push<u64>(applet->suspended_ticks);
398}
399
400void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
401 LOG_DEBUG(Service_AM, "called.");
402
403 IPC::ResponseBuilder rb{ctx, 2, 1};
404 rb.Push(ResultSuccess);
405 rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle());
406}
407
408void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
409 IPC::RequestParser rp{ctx};
410
411 // This service call sets an internal flag whether a notification is shown when an image is
412 // captured. Currently we do not support capturing images via the capture button, so this can be
413 // stubbed for now.
414 const bool enabled = rp.Pop<bool>();
415 LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
416
417 std::scoped_lock lk{applet->lock};
418 applet->album_image_taken_notification_enabled = enabled;
419
420 IPC::ResponseBuilder rb{ctx, 2};
421 rb.Push(ResultSuccess);
422}
423
424void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
425 IPC::RequestParser rp{ctx};
426
427 const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
428
429 LOG_INFO(Service_AM, "called, report_option={}", report_option);
430
431 const auto screenshot_service =
432 system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
433 "caps:su");
434
435 if (screenshot_service) {
436 screenshot_service->CaptureAndSaveScreenshot(report_option);
437 }
438
439 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(ResultSuccess);
441}
442
443void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
444 IPC::RequestParser rp{ctx};
445
446 const auto enabled = rp.Pop<bool>();
447 LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
448
449 std::scoped_lock lk{applet->lock};
450 applet->record_volume_muted = enabled;
451
452 IPC::ResponseBuilder rb{ctx, 2};
453 rb.Push(ResultSuccess);
454}
455
456} // namespace Service::AM
diff --git a/src/core/hle/service/am/self_controller.h b/src/core/hle/service/am/self_controller.h
new file mode 100644
index 000000000..a63bc2e74
--- /dev/null
+++ b/src/core/hle/service/am/self_controller.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11struct Applet;
12
13class ISelfController final : public ServiceFramework<ISelfController> {
14public:
15 explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
16 Nvnflinger::Nvnflinger& nvnflinger_);
17 ~ISelfController() override;
18
19private:
20 void Exit(HLERequestContext& ctx);
21 void LockExit(HLERequestContext& ctx);
22 void UnlockExit(HLERequestContext& ctx);
23 void EnterFatalSection(HLERequestContext& ctx);
24 void LeaveFatalSection(HLERequestContext& ctx);
25 void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
26 void SetScreenShotPermission(HLERequestContext& ctx);
27 void SetOperationModeChangedNotification(HLERequestContext& ctx);
28 void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
29 void SetFocusHandlingMode(HLERequestContext& ctx);
30 void SetRestartMessageEnabled(HLERequestContext& ctx);
31 void SetScreenShotAppletIdentityInfo(HLERequestContext& ctx);
32 void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
33 void SetAlbumImageOrientation(HLERequestContext& ctx);
34 void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
35 void GetSystemSharedBufferHandle(HLERequestContext& ctx);
36 void GetSystemSharedLayerHandle(HLERequestContext& ctx);
37 void CreateManagedDisplayLayer(HLERequestContext& ctx);
38 void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
39 void SetHandlesRequestToDisplay(HLERequestContext& ctx);
40 void ApproveToDisplay(HLERequestContext& ctx);
41 void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
42 void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
43 void ReportUserIsActive(HLERequestContext& ctx);
44 void SetAutoSleepDisabled(HLERequestContext& ctx);
45 void IsAutoSleepDisabled(HLERequestContext& ctx);
46 void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
47 void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
48 void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
49 void SaveCurrentScreenshot(HLERequestContext& ctx);
50 void SetRecordVolumeMuted(HLERequestContext& ctx);
51
52 Result EnsureBufferSharingEnabled(Kernel::KProcess* process);
53
54 Nvnflinger::Nvnflinger& nvnflinger;
55 const std::shared_ptr<Applet> applet;
56};
57
58} // namespace Service::AM
diff --git a/src/core/hle/service/am/storage.cpp b/src/core/hle/service/am/storage.cpp
new file mode 100644
index 000000000..4e82afd1c
--- /dev/null
+++ b/src/core/hle/service/am/storage.cpp
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/am_results.h"
5#include "core/hle/service/am/library_applet_storage.h"
6#include "core/hle/service/am/storage.h"
7#include "core/hle/service/am/storage_accessor.h"
8#include "core/hle/service/ipc_helpers.h"
9
10namespace Service::AM {
11
12IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_)
13 : ServiceFramework{system_, "IStorage"}, impl{std::move(impl_)} {
14 static const FunctionInfo functions[] = {
15 {0, &IStorage::Open, "Open"},
16 {1, &IStorage::OpenTransferStorage, "OpenTransferStorage"},
17 };
18
19 RegisterHandlers(functions);
20}
21
22IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
23 : IStorage(system_, CreateStorage(std::move(data))) {}
24
25IStorage::~IStorage() = default;
26
27void IStorage::Open(HLERequestContext& ctx) {
28 LOG_DEBUG(Service_AM, "called");
29
30 if (impl->GetHandle() != nullptr) {
31 IPC::ResponseBuilder rb{ctx, 2};
32 rb.Push(AM::ResultInvalidStorageType);
33 return;
34 }
35
36 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
37 rb.Push(ResultSuccess);
38 rb.PushIpcInterface<IStorageAccessor>(system, impl);
39}
40
41void IStorage::OpenTransferStorage(HLERequestContext& ctx) {
42 LOG_DEBUG(Service_AM, "called");
43
44 if (impl->GetHandle() == nullptr) {
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(AM::ResultInvalidStorageType);
47 return;
48 }
49
50 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
51 rb.Push(ResultSuccess);
52 rb.PushIpcInterface<ITransferStorageAccessor>(system, impl);
53}
54
55std::vector<u8> IStorage::GetData() const {
56 return impl->GetData();
57}
58
59} // namespace Service::AM
diff --git a/src/core/hle/service/am/storage.h b/src/core/hle/service/am/storage.h
new file mode 100644
index 000000000..10d00b141
--- /dev/null
+++ b/src/core/hle/service/am/storage.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class LibraryAppletStorage;
11
12class IStorage final : public ServiceFramework<IStorage> {
13public:
14 explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_);
15 explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
16 ~IStorage() override;
17
18 std::shared_ptr<LibraryAppletStorage> GetImpl() const {
19 return impl;
20 }
21
22 std::vector<u8> GetData() const;
23
24private:
25 void Open(HLERequestContext& ctx);
26 void OpenTransferStorage(HLERequestContext& ctx);
27
28 const std::shared_ptr<LibraryAppletStorage> impl;
29};
30
31} // namespace Service::AM
diff --git a/src/core/hle/service/am/storage_accessor.cpp b/src/core/hle/service/am/storage_accessor.cpp
new file mode 100644
index 000000000..a1184b065
--- /dev/null
+++ b/src/core/hle/service/am/storage_accessor.cpp
@@ -0,0 +1,90 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_transfer_memory.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/library_applet_storage.h"
7#include "core/hle/service/am/storage_accessor.h"
8#include "core/hle/service/ipc_helpers.h"
9
10namespace Service::AM {
11
12IStorageAccessor::IStorageAccessor(Core::System& system_,
13 std::shared_ptr<LibraryAppletStorage> impl_)
14 : ServiceFramework{system_, "IStorageAccessor"}, impl{std::move(impl_)} {
15 static const FunctionInfo functions[] = {
16 {0, &IStorageAccessor::GetSize, "GetSize"},
17 {10, &IStorageAccessor::Write, "Write"},
18 {11, &IStorageAccessor::Read, "Read"},
19 };
20
21 RegisterHandlers(functions);
22}
23
24IStorageAccessor::~IStorageAccessor() = default;
25
26void IStorageAccessor::GetSize(HLERequestContext& ctx) {
27 LOG_DEBUG(Service_AM, "called");
28
29 IPC::ResponseBuilder rb{ctx, 4};
30
31 rb.Push(ResultSuccess);
32 rb.Push(impl->GetSize());
33}
34
35void IStorageAccessor::Write(HLERequestContext& ctx) {
36 IPC::RequestParser rp{ctx};
37
38 const s64 offset{rp.Pop<s64>()};
39 const auto data{ctx.ReadBuffer()};
40 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
41
42 const auto res{impl->Write(offset, data.data(), data.size())};
43
44 IPC::ResponseBuilder rb{ctx, 2};
45 rb.Push(res);
46}
47
48void IStorageAccessor::Read(HLERequestContext& ctx) {
49 IPC::RequestParser rp{ctx};
50
51 const s64 offset{rp.Pop<s64>()};
52 std::vector<u8> data(ctx.GetWriteBufferSize());
53
54 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
55
56 const auto res{impl->Read(offset, data.data(), data.size())};
57
58 ctx.WriteBuffer(data);
59
60 IPC::ResponseBuilder rb{ctx, 2};
61 rb.Push(res);
62}
63
64ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_,
65 std::shared_ptr<LibraryAppletStorage> impl_)
66 : ServiceFramework{system_, "ITransferStorageAccessor"}, impl{std::move(impl_)} {
67 static const FunctionInfo functions[] = {
68 {0, &ITransferStorageAccessor::GetSize, "GetSize"},
69 {1, &ITransferStorageAccessor::GetHandle, "GetHandle"},
70 };
71
72 RegisterHandlers(functions);
73}
74
75ITransferStorageAccessor::~ITransferStorageAccessor() = default;
76
77void ITransferStorageAccessor::GetSize(HLERequestContext& ctx) {
78 IPC::ResponseBuilder rb{ctx, 4};
79 rb.Push(ResultSuccess);
80 rb.Push(impl->GetSize());
81}
82
83void ITransferStorageAccessor::GetHandle(HLERequestContext& ctx) {
84 IPC::ResponseBuilder rb{ctx, 4, 1};
85 rb.Push(ResultSuccess);
86 rb.Push(impl->GetSize());
87 rb.PushCopyObjects(impl->GetHandle());
88}
89
90} // namespace Service::AM
diff --git a/src/core/hle/service/am/storage_accessor.h b/src/core/hle/service/am/storage_accessor.h
new file mode 100644
index 000000000..b9aa85a66
--- /dev/null
+++ b/src/core/hle/service/am/storage_accessor.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/am/storage.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
12public:
13 explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_);
14 ~IStorageAccessor() override;
15
16private:
17 void GetSize(HLERequestContext& ctx);
18 void Write(HLERequestContext& ctx);
19 void Read(HLERequestContext& ctx);
20
21 const std::shared_ptr<LibraryAppletStorage> impl;
22};
23
24class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> {
25public:
26 explicit ITransferStorageAccessor(Core::System& system_,
27 std::shared_ptr<LibraryAppletStorage> impl_);
28 ~ITransferStorageAccessor() override;
29
30private:
31 void GetSize(HLERequestContext& ctx);
32 void GetHandle(HLERequestContext& ctx);
33
34 const std::shared_ptr<LibraryAppletStorage> impl;
35};
36
37} // namespace Service::AM
diff --git a/src/core/hle/service/am/system_applet_proxy.cpp b/src/core/hle/service/am/system_applet_proxy.cpp
new file mode 100644
index 000000000..38643408e
--- /dev/null
+++ b/src/core/hle/service/am/system_applet_proxy.cpp
@@ -0,0 +1,136 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_common_functions.h"
5#include "core/hle/service/am/application_creator.h"
6#include "core/hle/service/am/audio_controller.h"
7#include "core/hle/service/am/common_state_getter.h"
8#include "core/hle/service/am/debug_functions.h"
9#include "core/hle/service/am/display_controller.h"
10#include "core/hle/service/am/global_state_controller.h"
11#include "core/hle/service/am/home_menu_functions.h"
12#include "core/hle/service/am/library_applet_creator.h"
13#include "core/hle/service/am/library_applet_self_accessor.h"
14#include "core/hle/service/am/process_winding_controller.h"
15#include "core/hle/service/am/self_controller.h"
16#include "core/hle/service/am/system_applet_proxy.h"
17#include "core/hle/service/am/window_controller.h"
18#include "core/hle/service/ipc_helpers.h"
19
20namespace Service::AM {
21
22ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
23 std::shared_ptr<Applet> applet_, Core::System& system_)
24 : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
25 applet_)} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
29 {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
30 {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
31 {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
32 {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
33 {10, nullptr, "GetProcessWindingController"},
34 {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
35 {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
36 {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
37 {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
38 {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
39 {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44}
45
46ISystemAppletProxy::~ISystemAppletProxy() = default;
47
48void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) {
49 LOG_DEBUG(Service_AM, "called");
50
51 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
52 rb.Push(ResultSuccess);
53 rb.PushIpcInterface<ICommonStateGetter>(system, applet);
54}
55
56void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) {
57 LOG_DEBUG(Service_AM, "called");
58
59 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
60 rb.Push(ResultSuccess);
61 rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
62}
63
64void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) {
65 LOG_DEBUG(Service_AM, "called");
66
67 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
68 rb.Push(ResultSuccess);
69 rb.PushIpcInterface<IWindowController>(system, applet);
70}
71
72void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) {
73 LOG_DEBUG(Service_AM, "called");
74
75 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
76 rb.Push(ResultSuccess);
77 rb.PushIpcInterface<IAudioController>(system);
78}
79
80void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) {
81 LOG_DEBUG(Service_AM, "called");
82
83 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
84 rb.Push(ResultSuccess);
85 rb.PushIpcInterface<IDisplayController>(system, applet);
86}
87
88void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_AM, "called");
90
91 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
92 rb.Push(ResultSuccess);
93 rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
94}
95
96void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) {
97 LOG_DEBUG(Service_AM, "called");
98
99 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
100 rb.Push(ResultSuccess);
101 rb.PushIpcInterface<IHomeMenuFunctions>(system);
102}
103
104void ISystemAppletProxy::GetGlobalStateController(HLERequestContext& ctx) {
105 LOG_DEBUG(Service_AM, "called");
106
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(ResultSuccess);
109 rb.PushIpcInterface<IGlobalStateController>(system);
110}
111
112void ISystemAppletProxy::GetApplicationCreator(HLERequestContext& ctx) {
113 LOG_DEBUG(Service_AM, "called");
114
115 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
116 rb.Push(ResultSuccess);
117 rb.PushIpcInterface<IApplicationCreator>(system);
118}
119
120void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) {
121 LOG_DEBUG(Service_AM, "called");
122
123 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
124 rb.Push(ResultSuccess);
125 rb.PushIpcInterface<IAppletCommonFunctions>(system, applet);
126}
127
128void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) {
129 LOG_DEBUG(Service_AM, "called");
130
131 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
132 rb.Push(ResultSuccess);
133 rb.PushIpcInterface<IDebugFunctions>(system);
134}
135
136} // namespace Service::AM
diff --git a/src/core/hle/service/am/system_applet_proxy.h b/src/core/hle/service/am/system_applet_proxy.h
new file mode 100644
index 000000000..0390cd1e5
--- /dev/null
+++ b/src/core/hle/service/am/system_applet_proxy.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/am/applet_message_queue.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11struct Applet;
12
13class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
14public:
15 explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
16 std::shared_ptr<Applet> applet_, Core::System& system_);
17 ~ISystemAppletProxy();
18
19private:
20 void GetCommonStateGetter(HLERequestContext& ctx);
21 void GetSelfController(HLERequestContext& ctx);
22 void GetWindowController(HLERequestContext& ctx);
23 void GetAudioController(HLERequestContext& ctx);
24 void GetDisplayController(HLERequestContext& ctx);
25 void GetLibraryAppletCreator(HLERequestContext& ctx);
26 void GetHomeMenuFunctions(HLERequestContext& ctx);
27 void GetGlobalStateController(HLERequestContext& ctx);
28 void GetApplicationCreator(HLERequestContext& ctx);
29 void GetAppletCommonFunctions(HLERequestContext& ctx);
30 void GetDebugFunctions(HLERequestContext& ctx);
31
32 Nvnflinger::Nvnflinger& nvnflinger;
33 std::shared_ptr<Applet> applet;
34};
35
36} // namespace Service::AM
diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp
new file mode 100644
index 000000000..60a9afc9d
--- /dev/null
+++ b/src/core/hle/service/am/system_buffer_manager.cpp
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/system_buffer_manager.h"
5#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
6#include "core/hle/service/nvnflinger/nvnflinger.h"
7#include "core/hle/service/vi/vi_results.h"
8
9namespace Service::AM {
10
11SystemBufferManager::SystemBufferManager() = default;
12
13SystemBufferManager::~SystemBufferManager() {
14 if (!m_nvnflinger) {
15 return;
16 }
17
18 // Clean up shared layers.
19 if (m_buffer_sharing_enabled) {
20 }
21}
22
23bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
24 AppletId applet_id) {
25 if (m_nvnflinger) {
26 return m_buffer_sharing_enabled;
27 }
28
29 m_process = process;
30 m_nvnflinger = nvnflinger;
31 m_buffer_sharing_enabled = false;
32 m_system_shared_buffer_id = 0;
33 m_system_shared_layer_id = 0;
34
35 if (applet_id <= AppletId::Application) {
36 return false;
37 }
38
39 const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
40 const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
41 &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
42
43 if (res.IsSuccess()) {
44 m_buffer_sharing_enabled = true;
45 m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
46 }
47
48 return m_buffer_sharing_enabled;
49}
50
51void SystemBufferManager::SetWindowVisibility(bool visible) {
52 if (m_visible == visible) {
53 return;
54 }
55
56 m_visible = visible;
57
58 if (m_nvnflinger) {
59 m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
60 }
61}
62
63Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
64 s32* out_fbshare_layer_index) {
65 // TODO
66 R_SUCCEED();
67}
68
69} // namespace Service::AM
diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h
new file mode 100644
index 000000000..98c3cf055
--- /dev/null
+++ b/src/core/hle/service/am/system_buffer_manager.h
@@ -0,0 +1,51 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11#include "core/hle/service/am/am_types.h"
12
13namespace Kernel {
14class KProcess;
15}
16
17namespace Service::Nvnflinger {
18class Nvnflinger;
19}
20
21union Result;
22
23namespace Service::AM {
24
25class SystemBufferManager {
26public:
27 SystemBufferManager();
28 ~SystemBufferManager();
29
30 bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id);
31
32 void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
33 u64* out_system_shared_layer_id) {
34 *out_system_shared_buffer_id = m_system_shared_buffer_id;
35 *out_system_shared_layer_id = m_system_shared_layer_id;
36 }
37
38 void SetWindowVisibility(bool visible);
39
40 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
41
42private:
43 Kernel::KProcess* m_process{};
44 Nvnflinger::Nvnflinger* m_nvnflinger{};
45 bool m_buffer_sharing_enabled{};
46 bool m_visible{true};
47 u64 m_system_shared_buffer_id{};
48 u64 m_system_shared_layer_id{};
49};
50
51} // namespace Service::AM
diff --git a/src/core/hle/service/am/window_controller.cpp b/src/core/hle/service/am/window_controller.cpp
new file mode 100644
index 000000000..f00957f83
--- /dev/null
+++ b/src/core/hle/service/am/window_controller.cpp
@@ -0,0 +1,86 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/window_controller.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::AM {
9
10IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_)
11 : ServiceFramework{system_, "IWindowController"}, applet{std::move(applet_)} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, nullptr, "CreateWindow"},
15 {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
16 {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
17 {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
18 {11, nullptr, "ReleaseForegroundRights"},
19 {12, nullptr, "RejectToChangeIntoBackground"},
20 {20, &IWindowController::SetAppletWindowVisibility, "SetAppletWindowVisibility"},
21 {21, &IWindowController::SetAppletGpuTimeSlice, "SetAppletGpuTimeSlice"},
22 };
23 // clang-format on
24
25 RegisterHandlers(functions);
26}
27
28IWindowController::~IWindowController() = default;
29
30void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
31 IPC::ResponseBuilder rb{ctx, 4};
32 rb.Push(ResultSuccess);
33 rb.Push<u64>(applet->aruid);
34}
35
36void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
37 u64 aruid = 0;
38 if (auto caller = applet->caller_applet.lock(); caller) {
39 aruid = caller->aruid;
40 }
41
42 LOG_WARNING(Service_AM, "(STUBBED) called");
43
44 IPC::ResponseBuilder rb{ctx, 4};
45 rb.Push(ResultSuccess);
46 rb.Push<u64>(aruid);
47}
48
49void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
50 LOG_WARNING(Service_AM, "(STUBBED) called");
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(ResultSuccess);
53}
54
55void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) {
56 LOG_INFO(Service_AM, "called");
57
58 IPC::RequestParser rp{ctx};
59 const bool visible = rp.Pop<bool>();
60
61 applet->system_buffer_manager.SetWindowVisibility(visible);
62 applet->hid_registration.EnableAppletToGetInput(visible);
63
64 if (visible) {
65 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
66 applet->focus_state = FocusState::InFocus;
67 } else {
68 applet->focus_state = FocusState::NotInFocus;
69 }
70 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
71
72 IPC::ResponseBuilder rb{ctx, 2};
73 rb.Push(ResultSuccess);
74}
75
76void IWindowController::SetAppletGpuTimeSlice(HLERequestContext& ctx) {
77 IPC::RequestParser rp{ctx};
78 const auto time_slice = rp.Pop<s64>();
79
80 LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice);
81
82 IPC::ResponseBuilder rb{ctx, 2};
83 rb.Push(ResultSuccess);
84}
85
86} // namespace Service::AM
diff --git a/src/core/hle/service/am/window_controller.h b/src/core/hle/service/am/window_controller.h
new file mode 100644
index 000000000..a28219abe
--- /dev/null
+++ b/src/core/hle/service/am/window_controller.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IWindowController final : public ServiceFramework<IWindowController> {
13public:
14 explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IWindowController() override;
16
17private:
18 void GetAppletResourceUserId(HLERequestContext& ctx);
19 void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
20 void AcquireForegroundRights(HLERequestContext& ctx);
21 void SetAppletWindowVisibility(HLERequestContext& ctx);
22 void SetAppletGpuTimeSlice(HLERequestContext& ctx);
23
24 const std::shared_ptr<Applet> applet;
25};
26
27} // namespace Service::AM
diff --git a/src/core/hle/service/event.cpp b/src/core/hle/service/event.cpp
new file mode 100644
index 000000000..375660d72
--- /dev/null
+++ b/src/core/hle/service/event.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_event.h"
5#include "core/hle/service/event.h"
6#include "core/hle/service/kernel_helpers.h"
7
8namespace Service {
9
10Event::Event(KernelHelpers::ServiceContext& ctx) {
11 m_event = ctx.CreateEvent("Event");
12}
13
14Event::~Event() {
15 m_event->GetReadableEvent().Close();
16 m_event->Close();
17}
18
19void Event::Signal() {
20 m_event->Signal();
21}
22
23void Event::Clear() {
24 m_event->Clear();
25}
26
27Kernel::KReadableEvent* Event::GetHandle() {
28 return &m_event->GetReadableEvent();
29}
30
31} // namespace Service
diff --git a/src/core/hle/service/event.h b/src/core/hle/service/event.h
new file mode 100644
index 000000000..cdbc4635a
--- /dev/null
+++ b/src/core/hle/service/event.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace Kernel {
7class KEvent;
8class KReadableEvent;
9} // namespace Kernel
10
11namespace Service {
12
13namespace KernelHelpers {
14class ServiceContext;
15}
16
17class Event {
18public:
19 explicit Event(KernelHelpers::ServiceContext& ctx);
20 ~Event();
21
22 void Signal();
23 void Clear();
24
25 Kernel::KReadableEvent* GetHandle();
26
27private:
28 Kernel::KEvent* m_event;
29};
30
31} // namespace Service
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 2be72b021..5fe534c73 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -15,11 +15,13 @@
15#include "common/settings.h" 15#include "common/settings.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/file_sys/content_archive.h"
18#include "core/file_sys/errors.h" 19#include "core/file_sys/errors.h"
19#include "core/file_sys/fs_directory.h" 20#include "core/file_sys/fs_directory.h"
20#include "core/file_sys/fs_filesystem.h" 21#include "core/file_sys/fs_filesystem.h"
21#include "core/file_sys/nca_metadata.h" 22#include "core/file_sys/nca_metadata.h"
22#include "core/file_sys/patch_manager.h" 23#include "core/file_sys/patch_manager.h"
24#include "core/file_sys/romfs.h"
23#include "core/file_sys/romfs_factory.h" 25#include "core/file_sys/romfs_factory.h"
24#include "core/file_sys/savedata_factory.h" 26#include "core/file_sys/savedata_factory.h"
25#include "core/file_sys/system_archive/system_archive.h" 27#include "core/file_sys/system_archive/system_archive.h"
@@ -33,18 +35,20 @@
33#include "core/hle/service/filesystem/save_data_controller.h" 35#include "core/hle/service/filesystem/save_data_controller.h"
34#include "core/hle/service/hle_ipc.h" 36#include "core/hle/service/hle_ipc.h"
35#include "core/hle/service/ipc_helpers.h" 37#include "core/hle/service/ipc_helpers.h"
38#include "core/loader/loader.h"
36#include "core/reporter.h" 39#include "core/reporter.h"
37 40
38namespace Service::FileSystem { 41namespace Service::FileSystem {
39enum class FileSystemType : u8 { 42enum class FileSystemProxyType : u8 {
40 Invalid0 = 0, 43 Code = 0,
41 Invalid1 = 1, 44 Rom = 1,
42 Logo = 2, 45 Logo = 2,
43 ContentControl = 3, 46 Control = 3,
44 ContentManual = 4, 47 Manual = 4,
45 ContentMeta = 5, 48 Meta = 5,
46 ContentData = 6, 49 Data = 6,
47 ApplicationPackage = 7, 50 Package = 7,
51 RegisteredUpdate = 8,
48}; 52};
49 53
50class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { 54class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
@@ -357,12 +361,30 @@ void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
357void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { 361void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
358 IPC::RequestParser rp{ctx}; 362 IPC::RequestParser rp{ctx};
359 363
360 const auto type = rp.PopRaw<FileSystemType>(); 364 struct InputParameters {
361 const auto title_id = rp.PopRaw<u64>(); 365 FileSystemProxyType type;
362 LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); 366 u64 program_id;
367 };
368 static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
369
370 const auto params = rp.PopRaw<InputParameters>();
371 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
372 params.program_id);
373
374 // FIXME: many issues with this
375 ASSERT(params.type == FileSystemProxyType::Manual);
376 const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
377 params.program_id, FileSys::ContentRecordType::HtmlDocument);
363 378
364 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 379 ASSERT(manual_romfs != nullptr);
365 rb.Push(ResultUnknown); 380
381 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
382 ASSERT(extracted_romfs != nullptr);
383
384 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
385 rb.Push(ResultSuccess);
386 rb.PushIpcInterface<IFileSystem>(system, extracted_romfs,
387 SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
366} 388}
367 389
368void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { 390void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 22dc55a6d..8e3224f73 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -185,7 +185,7 @@ public:
185 {3, &IRequest::Cancel, "Cancel"}, 185 {3, &IRequest::Cancel, "Cancel"},
186 {4, &IRequest::Submit, "Submit"}, 186 {4, &IRequest::Submit, "Submit"},
187 {5, nullptr, "SetRequirement"}, 187 {5, nullptr, "SetRequirement"},
188 {6, nullptr, "SetRequirementPreset"}, 188 {6, &IRequest::SetRequirementPreset, "SetRequirementPreset"},
189 {8, nullptr, "SetPriority"}, 189 {8, nullptr, "SetPriority"},
190 {9, nullptr, "SetNetworkProfileId"}, 190 {9, nullptr, "SetNetworkProfileId"},
191 {10, nullptr, "SetRejectable"}, 191 {10, nullptr, "SetRejectable"},
@@ -237,6 +237,16 @@ private:
237 rb.PushEnum(state); 237 rb.PushEnum(state);
238 } 238 }
239 239
240 void SetRequirementPreset(HLERequestContext& ctx) {
241 IPC::RequestParser rp{ctx};
242 const auto param_1 = rp.Pop<u32>();
243
244 LOG_WARNING(Service_NIFM, "(STUBBED) called, param_1={}", param_1);
245
246 IPC::ResponseBuilder rb{ctx, 2};
247 rb.Push(ResultSuccess);
248 }
249
240 void GetResult(HLERequestContext& ctx) { 250 void GetResult(HLERequestContext& ctx) {
241 LOG_DEBUG(Service_NIFM, "(STUBBED) called"); 251 LOG_DEBUG(Service_NIFM, "(STUBBED) called");
242 252
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 2258ee609..19c3ff01b 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -3,6 +3,7 @@
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "common/settings.h" 5#include "common/settings.h"
6#include "core/arm/debug.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/file_sys/control_metadata.h" 8#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h" 9#include "core/file_sys/patch_manager.h"
@@ -544,8 +545,8 @@ IDocumentInterface::IDocumentInterface(Core::System& system_)
544 // clang-format off 545 // clang-format off
545 static const FunctionInfo functions[] = { 546 static const FunctionInfo functions[] = {
546 {21, nullptr, "GetApplicationContentPath"}, 547 {21, nullptr, "GetApplicationContentPath"},
547 {23, nullptr, "ResolveApplicationContentPath"}, 548 {23, &IDocumentInterface::ResolveApplicationContentPath, "ResolveApplicationContentPath"},
548 {93, nullptr, "GetRunningApplicationProgramId"}, 549 {92, &IDocumentInterface::GetRunningApplicationProgramId, "GetRunningApplicationProgramId"},
549 }; 550 };
550 // clang-format on 551 // clang-format on
551 552
@@ -554,6 +555,32 @@ IDocumentInterface::IDocumentInterface(Core::System& system_)
554 555
555IDocumentInterface::~IDocumentInterface() = default; 556IDocumentInterface::~IDocumentInterface() = default;
556 557
558void IDocumentInterface::ResolveApplicationContentPath(HLERequestContext& ctx) {
559 struct ContentPath {
560 u8 file_system_proxy_type;
561 u64 program_id;
562 };
563 static_assert(sizeof(ContentPath) == 0x10, "ContentPath has wrong size");
564
565 IPC::RequestParser rp{ctx};
566 auto content_path = rp.PopRaw<ContentPath>();
567 LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}",
568 content_path.file_system_proxy_type, content_path.program_id);
569
570 IPC::ResponseBuilder rb{ctx, 2};
571 rb.Push(ResultSuccess);
572}
573
574void IDocumentInterface::GetRunningApplicationProgramId(HLERequestContext& ctx) {
575 IPC::RequestParser rp{ctx};
576 const auto caller_program_id = rp.PopRaw<u64>();
577 LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id);
578
579 IPC::ResponseBuilder rb{ctx, 4};
580 rb.Push(ResultSuccess);
581 rb.Push<u64>(system.GetApplicationProcessProgramID());
582}
583
557IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) 584IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_)
558 : ServiceFramework{system_, "IDownloadTaskInterface"} { 585 : ServiceFramework{system_, "IDownloadTaskInterface"} {
559 // clang-format off 586 // clang-format off
@@ -613,6 +640,40 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
613 640
614IFactoryResetInterface::~IFactoryResetInterface() = default; 641IFactoryResetInterface::~IFactoryResetInterface() = default;
615 642
643IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_)
644 : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} {
645 static const FunctionInfo functions[] = {
646 {0, &IReadOnlyApplicationRecordInterface::HasApplicationRecord, "HasApplicationRecord"},
647 {1, nullptr, "NotifyApplicationFailure"},
648 {2, &IReadOnlyApplicationRecordInterface::IsDataCorruptedResult, "IsDataCorruptedResult"},
649 };
650 // clang-format on
651
652 RegisterHandlers(functions);
653}
654
655IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default;
656
657void IReadOnlyApplicationRecordInterface::HasApplicationRecord(HLERequestContext& ctx) {
658 IPC::RequestParser rp{ctx};
659 const u64 program_id = rp.PopRaw<u64>();
660 LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id);
661
662 IPC::ResponseBuilder rb{ctx, 3};
663 rb.Push(ResultSuccess);
664 rb.Push<u8>(1);
665}
666
667void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) {
668 IPC::RequestParser rp{ctx};
669 const auto result = rp.PopRaw<Result>();
670 LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue());
671
672 IPC::ResponseBuilder rb{ctx, 3};
673 rb.Push(ResultSuccess);
674 rb.Push<u8>(0);
675}
676
616IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( 677IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
617 Core::System& system_) 678 Core::System& system_)
618 : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { 679 : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
@@ -663,7 +724,7 @@ NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name
663 static const FunctionInfo functions[] = { 724 static const FunctionInfo functions[] = {
664 {7988, nullptr, "GetDynamicRightsInterface"}, 725 {7988, nullptr, "GetDynamicRightsInterface"},
665 {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, 726 {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"},
666 {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, 727 {7991, &NS::PushInterface<IReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"},
667 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, 728 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
668 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, 729 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
669 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, 730 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 34d2a45dc..9ee306ef9 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -58,6 +58,10 @@ class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
58public: 58public:
59 explicit IDocumentInterface(Core::System& system_); 59 explicit IDocumentInterface(Core::System& system_);
60 ~IDocumentInterface() override; 60 ~IDocumentInterface() override;
61
62private:
63 void ResolveApplicationContentPath(HLERequestContext& ctx);
64 void GetRunningApplicationProgramId(HLERequestContext& ctx);
61}; 65};
62 66
63class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { 67class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
@@ -78,6 +82,17 @@ public:
78 ~IFactoryResetInterface() override; 82 ~IFactoryResetInterface() override;
79}; 83};
80 84
85class IReadOnlyApplicationRecordInterface final
86 : public ServiceFramework<IReadOnlyApplicationRecordInterface> {
87public:
88 explicit IReadOnlyApplicationRecordInterface(Core::System& system_);
89 ~IReadOnlyApplicationRecordInterface() override;
90
91private:
92 void HasApplicationRecord(HLERequestContext& ctx);
93 void IsDataCorruptedResult(HLERequestContext& ctx);
94};
95
81class IReadOnlyApplicationControlDataInterface final 96class IReadOnlyApplicationControlDataInterface final
82 : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { 97 : public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
83public: 98public:
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index 86e272b41..e71652cdf 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -128,7 +128,7 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
128 128
129 // Ensure we maintain a clean state on failure. 129 // Ensure we maintain a clean state on failure.
130 ON_RESULT_FAILURE { 130 ON_RESULT_FAILURE {
131 ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); 131 R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd));
132 }; 132 };
133 133
134 // Assign the allocated memory to the handle. 134 // Assign the allocated memory to the handle.
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 71d6fdb0c..51133853c 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -198,6 +198,16 @@ bool Nvnflinger::CloseLayer(u64 layer_id) {
198 return false; 198 return false;
199} 199}
200 200
201void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) {
202 const auto lock_guard = Lock();
203
204 for (auto& display : displays) {
205 if (auto* layer = display.FindLayer(layer_id); layer) {
206 layer->SetVisibility(visible);
207 }
208 }
209}
210
201void Nvnflinger::DestroyLayer(u64 layer_id) { 211void Nvnflinger::DestroyLayer(u64 layer_id) {
202 const auto lock_guard = Lock(); 212 const auto lock_guard = Lock();
203 213
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index a60e0ae6b..369439142 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -79,6 +79,9 @@ public:
79 /// Closes a layer on all displays for the given layer ID. 79 /// Closes a layer on all displays for the given layer ID.
80 bool CloseLayer(u64 layer_id); 80 bool CloseLayer(u64 layer_id);
81 81
82 /// Makes a layer visible on all displays for the given layer ID.
83 void SetLayerVisibility(u64 layer_id, bool visible);
84
82 /// Destroys the given layer ID. 85 /// Destroys the given layer ID.
83 void DestroyLayer(u64 layer_id); 86 void DestroyLayer(u64 layer_id);
84 87
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index 725311c53..dab1905cc 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -53,7 +53,7 @@ Display::~Display() {
53Layer& Display::GetLayer(std::size_t index) { 53Layer& Display::GetLayer(std::size_t index) {
54 size_t i = 0; 54 size_t i = 0;
55 for (auto& layer : layers) { 55 for (auto& layer : layers) {
56 if (!layer->IsOpen()) { 56 if (!layer->IsOpen() || !layer->IsVisible()) {
57 continue; 57 continue;
58 } 58 }
59 59
@@ -68,7 +68,7 @@ Layer& Display::GetLayer(std::size_t index) {
68} 68}
69 69
70size_t Display::GetNumLayers() const { 70size_t Display::GetNumLayers() const {
71 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); 71 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); });
72} 72}
73 73
74Kernel::KReadableEvent* Display::GetVSyncEvent() { 74Kernel::KReadableEvent* Display::GetVSyncEvent() {
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 04e52a23b..493bd6e9e 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -9,7 +9,7 @@ Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
9 android::BufferQueueProducer& binder_, 9 android::BufferQueueProducer& binder_,
10 std::shared_ptr<android::BufferItemConsumer>&& consumer_) 10 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
11 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, 11 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
12 consumer{std::move(consumer_)}, open{false} {} 12 consumer{std::move(consumer_)}, open{false}, visible{true} {}
13 13
14Layer::~Layer() = default; 14Layer::~Layer() = default;
15 15
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index f95e2dc71..b4b031ee7 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -72,6 +72,14 @@ public:
72 return core; 72 return core;
73 } 73 }
74 74
75 bool IsVisible() const {
76 return visible;
77 }
78
79 void SetVisibility(bool v) {
80 visible = v;
81 }
82
75 bool IsOpen() const { 83 bool IsOpen() const {
76 return open; 84 return open;
77 } 85 }
@@ -91,6 +99,7 @@ private:
91 android::BufferQueueProducer& binder; 99 android::BufferQueueProducer& binder;
92 std::shared_ptr<android::BufferItemConsumer> consumer; 100 std::shared_ptr<android::BufferItemConsumer> consumer;
93 bool open; 101 bool open;
102 bool visible;
94}; 103};
95 104
96} // namespace Service::VI 105} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 1f3d82c57..73058db9a 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -535,6 +535,12 @@ public:
535 RegisterHandlers(functions); 535 RegisterHandlers(functions);
536 } 536 }
537 537
538 ~IApplicationDisplayService() {
539 for (const auto layer_id : stray_layer_ids) {
540 nvnflinger.DestroyLayer(layer_id);
541 }
542 }
543
538private: 544private:
539 enum class ConvertedScaleMode : u64 { 545 enum class ConvertedScaleMode : u64 {
540 Freeze = 0, 546 Freeze = 0,
@@ -770,6 +776,7 @@ private:
770 return; 776 return;
771 } 777 }
772 778
779 stray_layer_ids.push_back(*layer_id);
773 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); 780 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id);
774 if (!buffer_queue_id) { 781 if (!buffer_queue_id) {
775 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); 782 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
@@ -916,6 +923,7 @@ private:
916 923
917 Nvnflinger::Nvnflinger& nvnflinger; 924 Nvnflinger::Nvnflinger& nvnflinger;
918 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; 925 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
926 std::vector<u64> stray_layer_ids;
919 bool vsync_event_fetched{false}; 927 bool vsync_event_fetched{false};
920}; 928};
921 929
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp
index 79162a491..66edd6acd 100644
--- a/src/yuzu/applets/qt_profile_select.cpp
+++ b/src/yuzu/applets/qt_profile_select.cpp
@@ -162,7 +162,7 @@ void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) {
162 162
163void QtProfileSelectionDialog::SetWindowTitle( 163void QtProfileSelectionDialog::SetWindowTitle(
164 const Core::Frontend::ProfileSelectParameters& parameters) { 164 const Core::Frontend::ProfileSelectParameters& parameters) {
165 using Service::AM::Applets::UiMode; 165 using Service::AM::Frontend::UiMode;
166 switch (parameters.mode) { 166 switch (parameters.mode) {
167 case UiMode::UserCreator: 167 case UiMode::UserCreator:
168 case UiMode::UserCreatorForStarter: 168 case UiMode::UserCreatorForStarter:
@@ -193,7 +193,7 @@ void QtProfileSelectionDialog::SetWindowTitle(
193 193
194void QtProfileSelectionDialog::SetDialogPurpose( 194void QtProfileSelectionDialog::SetDialogPurpose(
195 const Core::Frontend::ProfileSelectParameters& parameters) { 195 const Core::Frontend::ProfileSelectParameters& parameters) {
196 using Service::AM::Applets::UserSelectionPurpose; 196 using Service::AM::Frontend::UserSelectionPurpose;
197 197
198 switch (parameters.purpose) { 198 switch (parameters.purpose) {
199 case UserSelectionPurpose::GameCardRegistration: 199 case UserSelectionPurpose::GameCardRegistration:
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp
index ac81ace9e..2749e6ed3 100644
--- a/src/yuzu/applets/qt_software_keyboard.cpp
+++ b/src/yuzu/applets/qt_software_keyboard.cpp
@@ -20,7 +20,7 @@
20 20
21namespace { 21namespace {
22 22
23using namespace Service::AM::Applets; 23using namespace Service::AM::Frontend;
24 24
25constexpr float BASE_HEADER_FONT_SIZE = 23.0f; 25constexpr float BASE_HEADER_FONT_SIZE = 23.0f;
26constexpr float BASE_SUB_FONT_SIZE = 17.0f; 26constexpr float BASE_SUB_FONT_SIZE = 17.0f;
@@ -389,7 +389,7 @@ void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) {
389} 389}
390 390
391void QtSoftwareKeyboardDialog::ShowTextCheckDialog( 391void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
392 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 392 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
393 std::u16string text_check_message) { 393 std::u16string text_check_message) {
394 switch (text_check_result) { 394 switch (text_check_result) {
395 case SwkbdTextCheckResult::Success: 395 case SwkbdTextCheckResult::Success:
@@ -1612,7 +1612,7 @@ void QtSoftwareKeyboard::ShowNormalKeyboard() const {
1612} 1612}
1613 1613
1614void QtSoftwareKeyboard::ShowTextCheckDialog( 1614void QtSoftwareKeyboard::ShowTextCheckDialog(
1615 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 1615 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
1616 std::u16string text_check_message) const { 1616 std::u16string text_check_message) const {
1617 emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message)); 1617 emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message));
1618} 1618}
@@ -1662,12 +1662,12 @@ void QtSoftwareKeyboard::ExitKeyboard() const {
1662 emit MainWindowExitKeyboard(); 1662 emit MainWindowExitKeyboard();
1663} 1663}
1664 1664
1665void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result, 1665void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Frontend::SwkbdResult result,
1666 std::u16string submitted_text, bool confirmed) const { 1666 std::u16string submitted_text, bool confirmed) const {
1667 submit_normal_callback(result, submitted_text, confirmed); 1667 submit_normal_callback(result, submitted_text, confirmed);
1668} 1668}
1669 1669
1670void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 1670void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
1671 std::u16string submitted_text, 1671 std::u16string submitted_text,
1672 s32 cursor_position) const { 1672 s32 cursor_position) const {
1673 submit_inline_callback(reply_type, submitted_text, cursor_position); 1673 submit_inline_callback(reply_type, submitted_text, cursor_position);
diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h
index ac23ce047..7e2fdf09e 100644
--- a/src/yuzu/applets/qt_software_keyboard.h
+++ b/src/yuzu/applets/qt_software_keyboard.h
@@ -39,7 +39,7 @@ public:
39 39
40 void ShowNormalKeyboard(QPoint pos, QSize size); 40 void ShowNormalKeyboard(QPoint pos, QSize size);
41 41
42 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 42 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
43 std::u16string text_check_message); 43 std::u16string text_check_message);
44 44
45 void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, 45 void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
@@ -52,10 +52,10 @@ public:
52 void ExitKeyboard(); 52 void ExitKeyboard();
53 53
54signals: 54signals:
55 void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, 55 void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text,
56 bool confirmed = false) const; 56 bool confirmed = false) const;
57 57
58 void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 58 void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
59 std::u16string submitted_text, s32 cursor_position) const; 59 std::u16string submitted_text, s32 cursor_position) const;
60 60
61public slots: 61public slots:
@@ -244,7 +244,7 @@ public:
244 244
245 void ShowNormalKeyboard() const override; 245 void ShowNormalKeyboard() const override;
246 246
247 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 247 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
248 std::u16string text_check_message) const override; 248 std::u16string text_check_message) const override;
249 249
250 void ShowInlineKeyboard( 250 void ShowInlineKeyboard(
@@ -262,8 +262,9 @@ signals:
262 262
263 void MainWindowShowNormalKeyboard() const; 263 void MainWindowShowNormalKeyboard() const;
264 264
265 void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 265 void MainWindowShowTextCheckDialog(
266 std::u16string text_check_message) const; 266 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
267 std::u16string text_check_message) const;
267 268
268 void MainWindowShowInlineKeyboard( 269 void MainWindowShowInlineKeyboard(
269 Core::Frontend::InlineAppearParameters appear_parameters) const; 270 Core::Frontend::InlineAppearParameters appear_parameters) const;
@@ -275,10 +276,10 @@ signals:
275 void MainWindowExitKeyboard() const; 276 void MainWindowExitKeyboard() const;
276 277
277private: 278private:
278 void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, 279 void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text,
279 bool confirmed) const; 280 bool confirmed) const;
280 281
281 void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 282 void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
282 std::u16string submitted_text, s32 cursor_position) const; 283 std::u16string submitted_text, s32 cursor_position) const;
283 284
284 mutable SubmitNormalCallback submit_normal_callback; 285 mutable SubmitNormalCallback submit_normal_callback;
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index 34c5fd3be..cce9b2efb 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -96,7 +96,7 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
96 [this] { 96 [this] {
97 if (page()->url() == url_interceptor->GetRequestedURL()) { 97 if (page()->url() == url_interceptor->GetRequestedURL()) {
98 SetFinished(true); 98 SetFinished(true);
99 SetExitReason(Service::AM::Applets::WebExitReason::WindowClosed); 99 SetExitReason(Service::AM::Frontend::WebExitReason::WindowClosed);
100 } 100 }
101 }, 101 },
102 Qt::QueuedConnection); 102 Qt::QueuedConnection);
@@ -115,7 +115,7 @@ void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url,
115 FocusFirstLinkElement(); 115 FocusFirstLinkElement();
116 SetUserAgent(UserAgent::WebApplet); 116 SetUserAgent(UserAgent::WebApplet);
117 SetFinished(false); 117 SetFinished(false);
118 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); 118 SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed);
119 SetLastURL("http://localhost/"); 119 SetLastURL("http://localhost/");
120 StartInputThread(); 120 StartInputThread();
121 121
@@ -130,7 +130,7 @@ void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url,
130 FocusFirstLinkElement(); 130 FocusFirstLinkElement();
131 SetUserAgent(UserAgent::WebApplet); 131 SetUserAgent(UserAgent::WebApplet);
132 SetFinished(false); 132 SetFinished(false);
133 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); 133 SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed);
134 SetLastURL("http://localhost/"); 134 SetLastURL("http://localhost/");
135 StartInputThread(); 135 StartInputThread();
136 136
@@ -170,11 +170,11 @@ void QtNXWebEngineView::SetFinished(bool finished_) {
170 finished = finished_; 170 finished = finished_;
171} 171}
172 172
173Service::AM::Applets::WebExitReason QtNXWebEngineView::GetExitReason() const { 173Service::AM::Frontend::WebExitReason QtNXWebEngineView::GetExitReason() const {
174 return exit_reason; 174 return exit_reason;
175} 175}
176 176
177void QtNXWebEngineView::SetExitReason(Service::AM::Applets::WebExitReason exit_reason_) { 177void QtNXWebEngineView::SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_) {
178 exit_reason = exit_reason_; 178 exit_reason = exit_reason_;
179} 179}
180 180
@@ -441,7 +441,7 @@ void QtWebBrowser::MainWindowExtractOfflineRomFS() {
441 extract_romfs_callback(); 441 extract_romfs_callback();
442} 442}
443 443
444void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, 444void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason,
445 std::string last_url) { 445 std::string last_url) {
446 if (callback) { 446 if (callback) {
447 callback(exit_reason, last_url); 447 callback(exit_reason, last_url);
diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h
index 1234108ae..e8a0b6931 100644
--- a/src/yuzu/applets/qt_web_browser.h
+++ b/src/yuzu/applets/qt_web_browser.h
@@ -85,8 +85,8 @@ public:
85 [[nodiscard]] bool IsFinished() const; 85 [[nodiscard]] bool IsFinished() const;
86 void SetFinished(bool finished_); 86 void SetFinished(bool finished_);
87 87
88 [[nodiscard]] Service::AM::Applets::WebExitReason GetExitReason() const; 88 [[nodiscard]] Service::AM::Frontend::WebExitReason GetExitReason() const;
89 void SetExitReason(Service::AM::Applets::WebExitReason exit_reason_); 89 void SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_);
90 90
91 [[nodiscard]] const std::string& GetLastURL() const; 91 [[nodiscard]] const std::string& GetLastURL() const;
92 void SetLastURL(std::string last_url_); 92 void SetLastURL(std::string last_url_);
@@ -176,8 +176,8 @@ private:
176 176
177 std::atomic<bool> finished{}; 177 std::atomic<bool> finished{};
178 178
179 Service::AM::Applets::WebExitReason exit_reason{ 179 Service::AM::Frontend::WebExitReason exit_reason{
180 Service::AM::Applets::WebExitReason::EndButtonPressed}; 180 Service::AM::Frontend::WebExitReason::EndButtonPressed};
181 181
182 std::string last_url{"http://localhost/"}; 182 std::string last_url{"http://localhost/"};
183 183
@@ -212,7 +212,7 @@ signals:
212private: 212private:
213 void MainWindowExtractOfflineRomFS(); 213 void MainWindowExtractOfflineRomFS();
214 214
215 void MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, 215 void MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason,
216 std::string last_url); 216 std::string last_url);
217 217
218 mutable ExtractROMFSCallback extract_romfs_callback; 218 mutable ExtractROMFSCallback extract_romfs_callback;
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 49ec52546..e28df10bd 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -9,6 +9,8 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applet_ae.h" 11#include "core/hle/service/am/applet_ae.h"
12#include "core/hle/service/am/applet_manager.h"
13#include "core/hle/service/am/applet_message_queue.h"
12#include "core/hle/service/am/applet_oe.h" 14#include "core/hle/service/am/applet_oe.h"
13#include "core/hle/service/sm/sm.h" 15#include "core/hle/service/sm/sm.h"
14#include "hid_core/frontend/emulated_controller.h" 16#include "hid_core/frontend/emulated_controller.h"
@@ -47,22 +49,8 @@ void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system)
47 if (!system.IsPoweredOn()) { 49 if (!system.IsPoweredOn()) {
48 return; 50 return;
49 } 51 }
50 Service::SM::ServiceManager& sm = system.ServiceManager();
51 52
52 // Message queue is shared between these services, we just need to signal an operation 53 system.GetAppletManager().OperationModeChanged();
53 // change to one and it will handle both automatically
54 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
55 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
56 bool has_signalled = false;
57
58 if (applet_oe != nullptr) {
59 applet_oe->GetMessageQueue()->OperationModeChanged();
60 has_signalled = true;
61 }
62
63 if (applet_ae != nullptr && !has_signalled) {
64 applet_ae->GetMessageQueue()->OperationModeChanged();
65 }
66} 54}
67 55
68ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) 56ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent)
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 59b317135..b40af957c 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -596,14 +596,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
596 connect(open_save_location, &QAction::triggered, [this, program_id, path]() { 596 connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
597 emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); 597 emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
598 }); 598 });
599 connect(start_game, &QAction::triggered, [this, path]() { 599 connect(start_game, &QAction::triggered,
600 emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal, 600 [this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Normal); });
601 AmLaunchType::UserInitiated); 601 connect(start_game_global, &QAction::triggered,
602 }); 602 [this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Global); });
603 connect(start_game_global, &QAction::triggered, [this, path]() {
604 emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global,
605 AmLaunchType::UserInitiated);
606 });
607 connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { 603 connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
608 emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); 604 emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
609 }); 605 });
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 563a3a35b..79f9c7ec0 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -106,8 +106,7 @@ public:
106 static const QStringList supported_file_extensions; 106 static const QStringList supported_file_extensions;
107 107
108signals: 108signals:
109 void BootGame(const QString& game_path, u64 program_id, std::size_t program_index, 109 void BootGame(const QString& game_path, StartGameType type);
110 StartGameType type, AmLaunchType launch_type);
111 void GameChosen(const QString& game_path, const u64 title_id = 0); 110 void GameChosen(const QString& game_path, const u64 title_id = 0);
112 void OpenFolderRequested(u64 program_id, GameListOpenTarget target, 111 void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
113 const std::string& game_path); 112 const std::string& game_path);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 782bcbb61..303d84a1f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -8,6 +8,7 @@
8#include <iostream> 8#include <iostream>
9#include <memory> 9#include <memory>
10#include <thread> 10#include <thread>
11#include "core/hle/service/am/applet_manager.h"
11#include "core/loader/nca.h" 12#include "core/loader/nca.h"
12#include "core/tools/renderdoc.h" 13#include "core/tools/renderdoc.h"
13 14
@@ -39,13 +40,14 @@
39#include "core/file_sys/vfs/vfs_real.h" 40#include "core/file_sys/vfs/vfs_real.h"
40#include "core/frontend/applets/cabinet.h" 41#include "core/frontend/applets/cabinet.h"
41#include "core/frontend/applets/controller.h" 42#include "core/frontend/applets/controller.h"
42#include "core/frontend/applets/general_frontend.h" 43#include "core/frontend/applets/general.h"
43#include "core/frontend/applets/mii_edit.h" 44#include "core/frontend/applets/mii_edit.h"
44#include "core/frontend/applets/software_keyboard.h" 45#include "core/frontend/applets/software_keyboard.h"
45#include "core/hle/service/acc/profile_manager.h" 46#include "core/hle/service/acc/profile_manager.h"
46#include "core/hle/service/am/applet_ae.h" 47#include "core/hle/service/am/applet_ae.h"
48#include "core/hle/service/am/applet_message_queue.h"
47#include "core/hle/service/am/applet_oe.h" 49#include "core/hle/service/am/applet_oe.h"
48#include "core/hle/service/am/applets/applets.h" 50#include "core/hle/service/am/frontend/applets.h"
49#include "core/hle/service/set/system_settings_server.h" 51#include "core/hle/service/set/system_settings_server.h"
50#include "frontend_common/content_manager.h" 52#include "frontend_common/content_manager.h"
51#include "hid_core/frontend/emulated_controller.h" 53#include "hid_core/frontend/emulated_controller.h"
@@ -568,7 +570,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
568 } 570 }
569 571
570 if (!game_path.isEmpty()) { 572 if (!game_path.isEmpty()) {
571 BootGame(game_path); 573 BootGame(game_path, ApplicationAppletParameters());
572 } 574 }
573} 575}
574 576
@@ -630,13 +632,14 @@ void GMainWindow::RegisterMetaTypes() {
630 qRegisterMetaType<Core::Frontend::InlineAppearParameters>( 632 qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
631 "Core::Frontend::InlineAppearParameters"); 633 "Core::Frontend::InlineAppearParameters");
632 qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters"); 634 qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
633 qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult"); 635 qRegisterMetaType<Service::AM::Frontend::SwkbdResult>("Service::AM::Frontend::SwkbdResult");
634 qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>( 636 qRegisterMetaType<Service::AM::Frontend::SwkbdTextCheckResult>(
635 "Service::AM::Applets::SwkbdTextCheckResult"); 637 "Service::AM::Frontend::SwkbdTextCheckResult");
636 qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType"); 638 qRegisterMetaType<Service::AM::Frontend::SwkbdReplyType>(
639 "Service::AM::Frontend::SwkbdReplyType");
637 640
638 // Web Browser Applet 641 // Web Browser Applet
639 qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); 642 qRegisterMetaType<Service::AM::Frontend::WebExitReason>("Service::AM::Frontend::WebExitReason");
640 643
641 // Register loader types 644 // Register loader types
642 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus"); 645 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
@@ -746,7 +749,7 @@ void GMainWindow::SoftwareKeyboardInitialize(
746 if (is_inline) { 749 if (is_inline) {
747 connect( 750 connect(
748 software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this, 751 software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this,
749 [this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text, 752 [this](Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text,
750 s32 cursor_position) { 753 s32 cursor_position) {
751 emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position); 754 emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position);
752 }, 755 },
@@ -754,7 +757,7 @@ void GMainWindow::SoftwareKeyboardInitialize(
754 } else { 757 } else {
755 connect( 758 connect(
756 software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this, 759 software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
757 [this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, 760 [this](Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text,
758 bool confirmed) { 761 bool confirmed) {
759 emit SoftwareKeyboardSubmitNormalText(result, submitted_text, confirmed); 762 emit SoftwareKeyboardSubmitNormalText(result, submitted_text, confirmed);
760 }, 763 },
@@ -781,7 +784,7 @@ void GMainWindow::SoftwareKeyboardShowNormal() {
781} 784}
782 785
783void GMainWindow::SoftwareKeyboardShowTextCheck( 786void GMainWindow::SoftwareKeyboardShowTextCheck(
784 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 787 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
785 std::u16string text_check_message) { 788 std::u16string text_check_message) {
786 if (!software_keyboard) { 789 if (!software_keyboard) {
787 LOG_ERROR(Frontend, "The software keyboard is not initialized!"); 790 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
@@ -852,7 +855,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
852 855
853 // Raw input breaks with the web applet, Disable web applets if enabled 856 // Raw input breaks with the web applet, Disable web applets if enabled
854 if (UISettings::values.disable_web_applet || Settings::values.enable_raw_input) { 857 if (UISettings::values.disable_web_applet || Settings::values.enable_raw_input) {
855 emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, 858 emit WebBrowserClosed(Service::AM::Frontend::WebExitReason::WindowClosed,
856 "http://localhost/"); 859 "http://localhost/");
857 return; 860 return;
858 } 861 }
@@ -940,7 +943,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
940 if (variant.toBool()) { 943 if (variant.toBool()) {
941 web_applet->SetFinished(true); 944 web_applet->SetFinished(true);
942 web_applet->SetExitReason( 945 web_applet->SetExitReason(
943 Service::AM::Applets::WebExitReason::EndButtonPressed); 946 Service::AM::Frontend::WebExitReason::EndButtonPressed);
944 } 947 }
945 }); 948 });
946 949
@@ -950,7 +953,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
950 if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) { 953 if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) {
951 if (!web_applet->IsFinished()) { 954 if (!web_applet->IsFinished()) {
952 web_applet->SetFinished(true); 955 web_applet->SetFinished(true);
953 web_applet->SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); 956 web_applet->SetExitReason(Service::AM::Frontend::WebExitReason::CallbackURL);
954 } 957 }
955 958
956 web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString()); 959 web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString());
@@ -983,7 +986,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
983#else 986#else
984 987
985 // Utilize the same fallback as the default web browser applet. 988 // Utilize the same fallback as the default web browser applet.
986 emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); 989 emit WebBrowserClosed(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
987 990
988#endif 991#endif
989} 992}
@@ -991,7 +994,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
991void GMainWindow::WebBrowserRequestExit() { 994void GMainWindow::WebBrowserRequestExit() {
992#ifdef YUZU_USE_QT_WEB_ENGINE 995#ifdef YUZU_USE_QT_WEB_ENGINE
993 if (web_applet) { 996 if (web_applet) {
994 web_applet->SetExitReason(Service::AM::Applets::WebExitReason::ExitRequested); 997 web_applet->SetExitReason(Service::AM::Frontend::WebExitReason::ExitRequested);
995 web_applet->SetFinished(true); 998 web_applet->SetFinished(true);
996 } 999 }
997#endif 1000#endif
@@ -1472,7 +1475,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1472} 1475}
1473 1476
1474void GMainWindow::ConnectWidgetEvents() { 1477void GMainWindow::ConnectWidgetEvents() {
1475 connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame); 1478 connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGameFromList);
1476 connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); 1479 connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
1477 connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); 1480 connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
1478 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); 1481 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
@@ -1760,8 +1763,7 @@ void GMainWindow::AllowOSSleep() {
1760#endif 1763#endif
1761} 1764}
1762 1765
1763bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index, 1766bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params) {
1764 AmLaunchType launch_type) {
1765 // Shutdown previous session if the emu thread is still active... 1767 // Shutdown previous session if the emu thread is still active...
1766 if (emu_thread != nullptr) { 1768 if (emu_thread != nullptr) {
1767 ShutdownGame(); 1769 ShutdownGame();
@@ -1773,11 +1775,11 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1773 1775
1774 system->SetFilesystem(vfs); 1776 system->SetFilesystem(vfs);
1775 1777
1776 if (launch_type == AmLaunchType::UserInitiated) { 1778 if (params.launch_type == Service::AM::LaunchType::FrontendInitiated) {
1777 system->GetUserChannel().clear(); 1779 system->GetUserChannel().clear();
1778 } 1780 }
1779 1781
1780 system->SetAppletFrontendSet({ 1782 system->SetFrontendAppletSet({
1781 std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings 1783 std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
1782 (UISettings::values.controller_applet_disabled.GetValue() == true) 1784 (UISettings::values.controller_applet_disabled.GetValue() == true)
1783 ? nullptr 1785 ? nullptr
@@ -1792,7 +1794,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1792 }); 1794 });
1793 1795
1794 const Core::SystemResultStatus result{ 1796 const Core::SystemResultStatus result{
1795 system->Load(*render_window, filename.toStdString(), program_id, program_index)}; 1797 system->Load(*render_window, filename.toStdString(), params)};
1796 1798
1797 const auto drd_callout = (UISettings::values.callout_flags.GetValue() & 1799 const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
1798 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; 1800 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
@@ -1915,12 +1917,12 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
1915 } 1917 }
1916} 1918}
1917 1919
1918void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, 1920void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletParameters params,
1919 StartGameType type, AmLaunchType launch_type) { 1921 StartGameType type) {
1920 LOG_INFO(Frontend, "yuzu starting..."); 1922 LOG_INFO(Frontend, "yuzu starting...");
1921 1923
1922 if (program_id == 0 || 1924 if (params.program_id == 0 ||
1923 program_id > static_cast<u64>(Service::AM::Applets::AppletProgramId::MaxProgramId)) { 1925 params.program_id > static_cast<u64>(Service::AM::AppletProgramId::MaxProgramId)) {
1924 StoreRecentFile(filename); // Put the filename on top of the list 1926 StoreRecentFile(filename); // Put the filename on top of the list
1925 } 1927 }
1926 1928
@@ -1935,7 +1937,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1935 1937
1936 ConfigureFilesystemProvider(filename.toStdString()); 1938 ConfigureFilesystemProvider(filename.toStdString());
1937 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); 1939 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
1938 const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index); 1940 const auto loader = Loader::GetLoader(*system, v_file, params.program_id, params.program_index);
1939 1941
1940 if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && 1942 if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
1941 type == StartGameType::Normal) { 1943 type == StartGameType::Normal) {
@@ -1954,10 +1956,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1954 1956
1955 if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) { 1957 if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) {
1956 const Core::Frontend::ProfileSelectParameters parameters{ 1958 const Core::Frontend::ProfileSelectParameters parameters{
1957 .mode = Service::AM::Applets::UiMode::UserSelector, 1959 .mode = Service::AM::Frontend::UiMode::UserSelector,
1958 .invalid_uid_list = {}, 1960 .invalid_uid_list = {},
1959 .display_options = {}, 1961 .display_options = {},
1960 .purpose = Service::AM::Applets::UserSelectionPurpose::General, 1962 .purpose = Service::AM::Frontend::UserSelectionPurpose::General,
1961 }; 1963 };
1962 if (SelectAndSetCurrentUser(parameters) == false) { 1964 if (SelectAndSetCurrentUser(parameters) == false) {
1963 return; 1965 return;
@@ -1969,7 +1971,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1969 // behavior of asking. 1971 // behavior of asking.
1970 user_flag_cmd_line = false; 1972 user_flag_cmd_line = false;
1971 1973
1972 if (!LoadROM(filename, program_id, program_index, launch_type)) { 1974 if (!LoadROM(filename, params)) {
1973 return; 1975 return;
1974 } 1976 }
1975 1977
@@ -2059,6 +2061,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
2059 OnStartGame(); 2061 OnStartGame();
2060} 2062}
2061 2063
2064void GMainWindow::BootGameFromList(const QString& filename, StartGameType with_config) {
2065 BootGame(filename, ApplicationAppletParameters(), with_config);
2066}
2067
2062bool GMainWindow::OnShutdownBegin() { 2068bool GMainWindow::OnShutdownBegin() {
2063 if (!emulation_running) { 2069 if (!emulation_running) {
2064 return false; 2070 return false;
@@ -2160,7 +2166,7 @@ void GMainWindow::OnEmulationStopped() {
2160 OnTasStateChanged(); 2166 OnTasStateChanged();
2161 render_window->FinalizeCamera(); 2167 render_window->FinalizeCamera();
2162 2168
2163 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::None); 2169 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None);
2164 2170
2165 // Enable all controllers 2171 // Enable all controllers
2166 system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); 2172 system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
@@ -2239,7 +2245,10 @@ void GMainWindow::UpdateRecentFiles() {
2239} 2245}
2240 2246
2241void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { 2247void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) {
2242 BootGame(game_path, program_id); 2248 auto params = ApplicationAppletParameters();
2249 params.program_id = program_id;
2250
2251 BootGame(game_path, params);
2243} 2252}
2244 2253
2245void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, 2254void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target,
@@ -2280,10 +2289,10 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2280 // User save data 2289 // User save data
2281 const auto select_profile = [this] { 2290 const auto select_profile = [this] {
2282 const Core::Frontend::ProfileSelectParameters parameters{ 2291 const Core::Frontend::ProfileSelectParameters parameters{
2283 .mode = Service::AM::Applets::UiMode::UserSelector, 2292 .mode = Service::AM::Frontend::UiMode::UserSelector,
2284 .invalid_uid_list = {}, 2293 .invalid_uid_list = {},
2285 .display_options = {}, 2294 .display_options = {},
2286 .purpose = Service::AM::Applets::UserSelectionPurpose::General, 2295 .purpose = Service::AM::Frontend::UserSelectionPurpose::General,
2287 }; 2296 };
2288 QtProfileSelectionDialog dialog(*system, this, parameters); 2297 QtProfileSelectionDialog dialog(*system, this, parameters);
2289 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 2298 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
@@ -3171,7 +3180,7 @@ void GMainWindow::OnMenuLoadFile() {
3171 } 3180 }
3172 3181
3173 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 3182 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
3174 BootGame(filename); 3183 BootGame(filename, ApplicationAppletParameters());
3175} 3184}
3176 3185
3177void GMainWindow::OnMenuLoadFolder() { 3186void GMainWindow::OnMenuLoadFolder() {
@@ -3185,7 +3194,7 @@ void GMainWindow::OnMenuLoadFolder() {
3185 const QDir dir{dir_path}; 3194 const QDir dir{dir_path};
3186 const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files); 3195 const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files);
3187 if (matching_main.size() == 1) { 3196 if (matching_main.size() == 1) {
3188 BootGame(dir.path() + QDir::separator() + matching_main[0]); 3197 BootGame(dir.path() + QDir::separator() + matching_main[0], ApplicationAppletParameters());
3189 } else { 3198 } else {
3190 QMessageBox::warning(this, tr("Invalid Directory Selected"), 3199 QMessageBox::warning(this, tr("Invalid Directory Selected"),
3191 tr("The directory you have selected does not contain a 'main' file.")); 3200 tr("The directory you have selected does not contain a 'main' file."));
@@ -3379,7 +3388,7 @@ void GMainWindow::OnMenuRecentFile() {
3379 3388
3380 const QString filename = action->data().toString(); 3389 const QString filename = action->data().toString();
3381 if (QFileInfo::exists(filename)) { 3390 if (QFileInfo::exists(filename)) {
3382 BootGame(filename); 3391 BootGame(filename, ApplicationAppletParameters());
3383 } else { 3392 } else {
3384 // Display an error message and remove the file from the list. 3393 // Display an error message and remove the file from the list.
3385 QMessageBox::information(this, tr("File not found"), 3394 QMessageBox::information(this, tr("File not found"),
@@ -3417,7 +3426,7 @@ void GMainWindow::OnRestartGame() {
3417 // Make a copy since ShutdownGame edits game_path 3426 // Make a copy since ShutdownGame edits game_path
3418 const auto current_game = QString(current_game_path); 3427 const auto current_game = QString(current_game_path);
3419 ShutdownGame(); 3428 ShutdownGame();
3420 BootGame(current_game); 3429 BootGame(current_game, ApplicationAppletParameters());
3421 } 3430 }
3422} 3431}
3423 3432
@@ -3485,8 +3494,11 @@ void GMainWindow::OnLoadComplete() {
3485 3494
3486void GMainWindow::OnExecuteProgram(std::size_t program_index) { 3495void GMainWindow::OnExecuteProgram(std::size_t program_index) {
3487 ShutdownGame(); 3496 ShutdownGame();
3488 BootGame(last_filename_booted, 0, program_index, StartGameType::Normal, 3497
3489 AmLaunchType::ApplicationInitiated); 3498 auto params = ApplicationAppletParameters();
3499 params.program_index = static_cast<s32>(program_index);
3500 params.launch_type = Service::AM::LaunchType::ApplicationInitiated;
3501 BootGame(last_filename_booted, params);
3490} 3502}
3491 3503
3492void GMainWindow::OnExit() { 3504void GMainWindow::OnExit() {
@@ -4153,7 +4165,7 @@ void GMainWindow::OnToggleStatusBar() {
4153} 4165}
4154 4166
4155void GMainWindow::OnAlbum() { 4167void GMainWindow::OnAlbum() {
4156 constexpr u64 AlbumId = static_cast<u64>(Service::AM::Applets::AppletProgramId::PhotoViewer); 4168 constexpr u64 AlbumId = static_cast<u64>(Service::AM::AppletProgramId::PhotoViewer);
4157 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4169 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4158 if (!bis_system) { 4170 if (!bis_system) {
4159 QMessageBox::warning(this, tr("No firmware available"), 4171 QMessageBox::warning(this, tr("No firmware available"),
@@ -4168,15 +4180,15 @@ void GMainWindow::OnAlbum() {
4168 return; 4180 return;
4169 } 4181 }
4170 4182
4171 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); 4183 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer);
4172 4184
4173 const auto filename = QString::fromStdString(album_nca->GetFullPath()); 4185 const auto filename = QString::fromStdString(album_nca->GetFullPath());
4174 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4186 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4175 BootGame(filename, AlbumId); 4187 BootGame(filename, LibraryAppletParameters(AlbumId, Service::AM::AppletId::PhotoViewer));
4176} 4188}
4177 4189
4178void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { 4190void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
4179 constexpr u64 CabinetId = static_cast<u64>(Service::AM::Applets::AppletProgramId::Cabinet); 4191 constexpr u64 CabinetId = static_cast<u64>(Service::AM::AppletProgramId::Cabinet);
4180 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4192 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4181 if (!bis_system) { 4193 if (!bis_system) {
4182 QMessageBox::warning(this, tr("No firmware available"), 4194 QMessageBox::warning(this, tr("No firmware available"),
@@ -4191,16 +4203,16 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
4191 return; 4203 return;
4192 } 4204 }
4193 4205
4194 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Cabinet); 4206 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet);
4195 system->GetAppletManager().SetCabinetMode(mode); 4207 system->GetFrontendAppletHolder().SetCabinetMode(mode);
4196 4208
4197 const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); 4209 const auto filename = QString::fromStdString(cabinet_nca->GetFullPath());
4198 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4210 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4199 BootGame(filename, CabinetId); 4211 BootGame(filename, LibraryAppletParameters(CabinetId, Service::AM::AppletId::Cabinet));
4200} 4212}
4201 4213
4202void GMainWindow::OnMiiEdit() { 4214void GMainWindow::OnMiiEdit() {
4203 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); 4215 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
4204 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4216 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4205 if (!bis_system) { 4217 if (!bis_system) {
4206 QMessageBox::warning(this, tr("No firmware available"), 4218 QMessageBox::warning(this, tr("No firmware available"),
@@ -4215,16 +4227,15 @@ void GMainWindow::OnMiiEdit() {
4215 return; 4227 return;
4216 } 4228 }
4217 4229
4218 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); 4230 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit);
4219 4231
4220 const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); 4232 const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath()));
4221 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4233 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4222 BootGame(filename, MiiEditId); 4234 BootGame(filename, LibraryAppletParameters(MiiEditId, Service::AM::AppletId::MiiEdit));
4223} 4235}
4224 4236
4225void GMainWindow::OnOpenControllerMenu() { 4237void GMainWindow::OnOpenControllerMenu() {
4226 constexpr u64 ControllerAppletId = 4238 constexpr u64 ControllerAppletId = static_cast<u64>(Service::AM::AppletProgramId::Controller);
4227 static_cast<u64>(Service::AM::Applets::AppletProgramId::Controller);
4228 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4239 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4229 if (!bis_system) { 4240 if (!bis_system) {
4230 QMessageBox::warning(this, tr("No firmware available"), 4241 QMessageBox::warning(this, tr("No firmware available"),
@@ -4240,11 +4251,12 @@ void GMainWindow::OnOpenControllerMenu() {
4240 return; 4251 return;
4241 } 4252 }
4242 4253
4243 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); 4254 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller);
4244 4255
4245 const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); 4256 const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath()));
4246 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4257 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4247 BootGame(filename, ControllerAppletId); 4258 BootGame(filename,
4259 LibraryAppletParameters(ControllerAppletId, Service::AM::AppletId::Controller));
4248} 4260}
4249 4261
4250void GMainWindow::OnCaptureScreenshot() { 4262void GMainWindow::OnCaptureScreenshot() {
@@ -4564,7 +4576,7 @@ void GMainWindow::OnCheckFirmwareDecryption() {
4564} 4576}
4565 4577
4566bool GMainWindow::CheckFirmwarePresence() { 4578bool GMainWindow::CheckFirmwarePresence() {
4567 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); 4579 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
4568 4580
4569 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4581 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4570 if (!bis_system) { 4582 if (!bis_system) {
@@ -4727,7 +4739,7 @@ bool GMainWindow::DropAction(QDropEvent* event) {
4727 } else { 4739 } else {
4728 // Game 4740 // Game
4729 if (ConfirmChangeGame()) { 4741 if (ConfirmChangeGame()) {
4730 BootGame(filename); 4742 BootGame(filename, ApplicationAppletParameters());
4731 } 4743 }
4732 } 4744 }
4733 return true; 4745 return true;
@@ -4771,36 +4783,12 @@ void GMainWindow::RequestGameExit() {
4771 return; 4783 return;
4772 } 4784 }
4773 4785
4774 auto& sm{system->ServiceManager()};
4775 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
4776 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
4777 bool has_signalled = false;
4778
4779 system->SetExitRequested(true); 4786 system->SetExitRequested(true);
4780 4787 system->GetAppletManager().RequestExit();
4781 if (applet_oe != nullptr) {
4782 applet_oe->GetMessageQueue()->RequestExit();
4783 has_signalled = true;
4784 }
4785
4786 if (applet_ae != nullptr && !has_signalled) {
4787 applet_ae->GetMessageQueue()->RequestExit();
4788 }
4789} 4788}
4790 4789
4791void GMainWindow::RequestGameResume() { 4790void GMainWindow::RequestGameResume() {
4792 auto& sm{system->ServiceManager()}; 4791 system->GetAppletManager().RequestResume();
4793 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
4794 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
4795
4796 if (applet_oe != nullptr) {
4797 applet_oe->GetMessageQueue()->RequestResume();
4798 return;
4799 }
4800
4801 if (applet_ae != nullptr) {
4802 applet_ae->GetMessageQueue()->RequestResume();
4803 }
4804} 4792}
4805 4793
4806void GMainWindow::filterBarSetChecked(bool state) { 4794void GMainWindow::filterBarSetChecked(bool state) {
@@ -4942,6 +4930,22 @@ void GMainWindow::changeEvent(QEvent* event) {
4942 QWidget::changeEvent(event); 4930 QWidget::changeEvent(event);
4943} 4931}
4944 4932
4933Service::AM::FrontendAppletParameters GMainWindow::ApplicationAppletParameters() {
4934 return Service::AM::FrontendAppletParameters{
4935 .applet_id = Service::AM::AppletId::Application,
4936 .applet_type = Service::AM::AppletType::Application,
4937 };
4938}
4939
4940Service::AM::FrontendAppletParameters GMainWindow::LibraryAppletParameters(
4941 u64 program_id, Service::AM::AppletId applet_id) {
4942 return Service::AM::FrontendAppletParameters{
4943 .program_id = program_id,
4944 .applet_id = applet_id,
4945 .applet_type = Service::AM::AppletType::LibraryApplet,
4946 };
4947}
4948
4945void VolumeButton::wheelEvent(QWheelEvent* event) { 4949void VolumeButton::wheelEvent(QWheelEvent* event) {
4946 4950
4947 int num_degrees = event->angleDelta().y() / 8; 4951 int num_degrees = event->angleDelta().y() / 8;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 6b72094ff..aba61e388 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -64,11 +64,6 @@ enum class StartGameType {
64 Global, // Only uses global configuration 64 Global, // Only uses global configuration
65}; 65};
66 66
67enum class AmLaunchType {
68 UserInitiated,
69 ApplicationInitiated,
70};
71
72namespace Core { 67namespace Core {
73enum class SystemResultStatus : u32; 68enum class SystemResultStatus : u32;
74class System; 69class System;
@@ -101,12 +96,17 @@ namespace InputCommon {
101class InputSubsystem; 96class InputSubsystem;
102} 97}
103 98
104namespace Service::AM::Applets { 99namespace Service::AM {
100struct FrontendAppletParameters;
101enum class AppletId : u32;
102} // namespace Service::AM
103
104namespace Service::AM::Frontend {
105enum class SwkbdResult : u32; 105enum class SwkbdResult : u32;
106enum class SwkbdTextCheckResult : u32; 106enum class SwkbdTextCheckResult : u32;
107enum class SwkbdReplyType : u32; 107enum class SwkbdReplyType : u32;
108enum class WebExitReason : u32; 108enum class WebExitReason : u32;
109} // namespace Service::AM::Applets 109} // namespace Service::AM::Frontend
110 110
111namespace Service::NFC { 111namespace Service::NFC {
112class NfcDevice; 112class NfcDevice;
@@ -204,13 +204,13 @@ signals:
204 204
205 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); 205 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
206 206
207 void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result, 207 void SoftwareKeyboardSubmitNormalText(Service::AM::Frontend::SwkbdResult result,
208 std::u16string submitted_text, bool confirmed); 208 std::u16string submitted_text, bool confirmed);
209 void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 209 void SoftwareKeyboardSubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
210 std::u16string submitted_text, s32 cursor_position); 210 std::u16string submitted_text, s32 cursor_position);
211 211
212 void WebBrowserExtractOfflineRomFS(); 212 void WebBrowserExtractOfflineRomFS();
213 void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); 213 void WebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url);
214 214
215 void SigInterrupt(); 215 void SigInterrupt();
216 216
@@ -228,8 +228,9 @@ public slots:
228 void SoftwareKeyboardInitialize( 228 void SoftwareKeyboardInitialize(
229 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); 229 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters);
230 void SoftwareKeyboardShowNormal(); 230 void SoftwareKeyboardShowNormal();
231 void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 231 void SoftwareKeyboardShowTextCheck(
232 std::u16string text_check_message); 232 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
233 std::u16string text_check_message);
233 void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters); 234 void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters);
234 void SoftwareKeyboardHideInline(); 235 void SoftwareKeyboardHideInline();
235 void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); 236 void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
@@ -267,11 +268,10 @@ private:
267 void PreventOSSleep(); 268 void PreventOSSleep();
268 void AllowOSSleep(); 269 void AllowOSSleep();
269 270
270 bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index, 271 bool LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params);
271 AmLaunchType launch_type); 272 void BootGame(const QString& filename, Service::AM::FrontendAppletParameters params,
272 void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0, 273 StartGameType with_config = StartGameType::Normal);
273 StartGameType with_config = StartGameType::Normal, 274 void BootGameFromList(const QString& filename, StartGameType with_config);
274 AmLaunchType launch_type = AmLaunchType::UserInitiated);
275 void ShutdownGame(); 275 void ShutdownGame();
276 276
277 void ShowTelemetryCallout(); 277 void ShowTelemetryCallout();
@@ -324,6 +324,10 @@ private:
324 void SetGamemodeEnabled(bool state); 324 void SetGamemodeEnabled(bool state);
325#endif 325#endif
326 326
327 Service::AM::FrontendAppletParameters ApplicationAppletParameters();
328 Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id,
329 Service::AM::AppletId applet_id);
330
327private slots: 331private slots:
328 void OnStartGame(); 332 void OnStartGame();
329 void OnRestartGame(); 333 void OnRestartGame();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index c39ace2ec..3b321dad1 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -26,6 +26,7 @@
26#include "core/crypto/key_manager.h" 26#include "core/crypto/key_manager.h"
27#include "core/file_sys/registered_cache.h" 27#include "core/file_sys/registered_cache.h"
28#include "core/file_sys/vfs/vfs_real.h" 28#include "core/file_sys/vfs/vfs_real.h"
29#include "core/hle/service/am/applet_manager.h"
29#include "core/hle/service/filesystem/filesystem.h" 30#include "core/hle/service/filesystem/filesystem.h"
30#include "core/loader/loader.h" 31#include "core/loader/loader.h"
31#include "core/telemetry_session.h" 32#include "core/telemetry_session.h"
@@ -366,7 +367,10 @@ int main(int argc, char** argv) {
366 system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); 367 system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
367 system.GetUserChannel().clear(); 368 system.GetUserChannel().clear();
368 369
369 const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath)}; 370 Service::AM::FrontendAppletParameters load_parameters{
371 .applet_id = Service::AM::AppletId::Application,
372 };
373 const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath, load_parameters)};
370 374
371 switch (load_result) { 375 switch (load_result) {
372 case Core::SystemResultStatus::ErrorGetLoader: 376 case Core::SystemResultStatus::ErrorGetLoader: