summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/am/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/am/service')
-rw-r--r--src/core/hle/service/am/service/all_system_applet_proxies_service.cpp80
-rw-r--r--src/core/hle/service/am/service/all_system_applet_proxies_service.h47
-rw-r--r--src/core/hle/service/am/service/applet_common_functions.cpp63
-rw-r--r--src/core/hle/service/am/service/applet_common_functions.h26
-rw-r--r--src/core/hle/service/am/service/application_accessor.cpp138
-rw-r--r--src/core/hle/service/am/service/application_accessor.h40
-rw-r--r--src/core/hle/service/am/service/application_creator.cpp35
-rw-r--r--src/core/hle/service/am/service/application_creator.h23
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp465
-rw-r--r--src/core/hle/service/am/service/application_functions.h83
-rw-r--r--src/core/hle/service/am/service/application_proxy.cpp106
-rw-r--r--src/core/hle/service/am/service/application_proxy.h48
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.cpp43
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.h35
-rw-r--r--src/core/hle/service/am/service/audio_controller.cpp69
-rw-r--r--src/core/hle/service/am/service/audio_controller.h37
-rw-r--r--src/core/hle/service/am/service/common_state_getter.cpp277
-rw-r--r--src/core/hle/service/am/service/common_state_getter.h61
-rw-r--r--src/core/hle/service/am/service/cradle_firmware_updater.cpp52
-rw-r--r--src/core/hle/service/am/service/cradle_firmware_updater.h37
-rw-r--r--src/core/hle/service/am/service/debug_functions.cpp43
-rw-r--r--src/core/hle/service/am/service/debug_functions.h16
-rw-r--r--src/core/hle/service/am/service/display_controller.cpp105
-rw-r--r--src/core/hle/service/am/service/display_controller.h36
-rw-r--r--src/core/hle/service/am/service/global_state_controller.cpp61
-rw-r--r--src/core/hle/service/am/service/global_state_controller.h31
-rw-r--r--src/core/hle/service/am/service/home_menu_functions.cpp74
-rw-r--r--src/core/hle/service/am/service/home_menu_functions.h34
-rw-r--r--src/core/hle/service/am/service/library_applet_accessor.cpp157
-rw-r--r--src/core/hle/service/am/service/library_applet_accessor.h45
-rw-r--r--src/core/hle/service/am/service/library_applet_creator.cpp268
-rw-r--r--src/core/hle/service/am/service/library_applet_creator.h35
-rw-r--r--src/core/hle/service/am/service/library_applet_proxy.cpp134
-rw-r--r--src/core/hle/service/am/service/library_applet_proxy.h55
-rw-r--r--src/core/hle/service/am/service/library_applet_self_accessor.cpp322
-rw-r--r--src/core/hle/service/am/service/library_applet_self_accessor.h83
-rw-r--r--src/core/hle/service/am/service/lock_accessor.cpp75
-rw-r--r--src/core/hle/service/am/service/lock_accessor.h32
-rw-r--r--src/core/hle/service/am/service/process_winding_controller.cpp54
-rw-r--r--src/core/hle/service/am/service/process_winding_controller.h28
-rw-r--r--src/core/hle/service/am/service/self_controller.cpp393
-rw-r--r--src/core/hle/service/am/service/self_controller.h72
-rw-r--r--src/core/hle/service/am/service/storage.cpp48
-rw-r--r--src/core/hle/service/am/service/storage.h35
-rw-r--r--src/core/hle/service/am/service/storage_accessor.cpp68
-rw-r--r--src/core/hle/service/am/service/storage_accessor.h38
-rw-r--r--src/core/hle/service/am/service/system_applet_proxy.cpp133
-rw-r--r--src/core/hle/service/am/service/system_applet_proxy.h54
-rw-r--r--src/core/hle/service/am/service/window_controller.cpp86
-rw-r--r--src/core/hle/service/am/service/window_controller.h30
50 files changed, 4410 insertions, 0 deletions
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
new file mode 100644
index 000000000..eebd90ba2
--- /dev/null
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
@@ -0,0 +1,80 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
+#include "core/hle/service/am/service/library_applet_proxy.h"
+#include "core/hle/service/am/service/system_applet_proxy.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
+ Nvnflinger::Nvnflinger& nvnflinger)
+ : ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
+ {200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
+ {201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
+ {300, nullptr, "OpenOverlayAppletProxy"},
+ {350, nullptr, "OpenSystemApplicationProxy"},
+ {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
+ {410, nullptr, "GetSystemAppletControllerForDebug"},
+ {1000, nullptr, "GetDebugFunctions"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAllSystemAppletProxiesService::~IAllSystemAppletProxiesService() = default;
+
+Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
+ Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy, ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle) {
+ LOG_DEBUG(Service_AM, "called");
+
+ if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
+ *out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
+ system, applet, process_handle.Get(), m_nvnflinger);
+ R_SUCCEED();
+ } else {
+ UNIMPLEMENTED();
+ R_THROW(ResultUnknown);
+ }
+}
+
+Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
+ Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) {
+ LOG_DEBUG(Service_AM, "called");
+
+ if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
+ *out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
+ system, applet, process_handle.Get(), m_nvnflinger);
+ R_SUCCEED();
+ } else {
+ UNIMPLEMENTED();
+ R_THROW(ResultUnknown);
+ }
+}
+
+Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld(
+ Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle) {
+ LOG_DEBUG(Service_AM, "called");
+
+ AppletAttribute attribute{};
+ R_RETURN(
+ this->OpenLibraryAppletProxy(out_library_applet_proxy, pid, process_handle, attribute));
+}
+
+std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
+ ProcessId process_id) {
+ return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
new file mode 100644
index 000000000..38b1ca2ea
--- /dev/null
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+
+namespace Nvnflinger {
+class Nvnflinger;
+}
+
+namespace AM {
+
+struct Applet;
+struct AppletAttribute;
+class ILibraryAppletProxy;
+class ISystemAppletProxy;
+
+class IAllSystemAppletProxiesService final
+ : public ServiceFramework<IAllSystemAppletProxiesService> {
+public:
+ explicit IAllSystemAppletProxiesService(Core::System& system_,
+ Nvnflinger::Nvnflinger& nvnflinger);
+ ~IAllSystemAppletProxiesService() override;
+
+private:
+ Result OpenSystemAppletProxy(Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy,
+ ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle);
+ Result OpenLibraryAppletProxy(Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy,
+ ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
+ Result OpenLibraryAppletProxyOld(
+ Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle);
+
+private:
+ std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
+ Nvnflinger::Nvnflinger& m_nvnflinger;
+};
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/service/applet_common_functions.cpp b/src/core/hle/service/am/service/applet_common_functions.cpp
new file mode 100644
index 000000000..0f29ab285
--- /dev/null
+++ b/src/core/hle/service/am/service/applet_common_functions.cpp
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/service/applet_common_functions.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
+ std::shared_ptr<Applet> applet_)
+ : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "SetTerminateResult"},
+ {10, nullptr, "ReadThemeStorage"},
+ {11, nullptr, "WriteThemeStorage"},
+ {20, nullptr, "PushToAppletBoundChannel"},
+ {21, nullptr, "TryPopFromAppletBoundChannel"},
+ {40, nullptr, "GetDisplayLogicalResolution"},
+ {42, nullptr, "SetDisplayMagnification"},
+ {50, nullptr, "SetHomeButtonDoubleClickEnabled"},
+ {51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
+ {52, nullptr, "IsHomeButtonShortPressedBlocked"},
+ {60, nullptr, "IsVrModeCurtainRequired"},
+ {61, nullptr, "IsSleepRequiredByHighTemperature"},
+ {62, nullptr, "IsSleepRequiredByLowBattery"},
+ {70, D<&IAppletCommonFunctions::SetCpuBoostRequestPriority>, "SetCpuBoostRequestPriority"},
+ {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
+ {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
+ {90, nullptr, "OpenNamedChannelAsParent"},
+ {91, nullptr, "OpenNamedChannelAsChild"},
+ {100, nullptr, "SetApplicationCoreUsageMode"},
+ {300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAppletCommonFunctions::~IAppletCommonFunctions() = default;
+
+Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
+ Out<bool> out_home_button_double_click_enabled) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_home_button_double_click_enabled = false;
+ R_SUCCEED();
+}
+
+Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ std::scoped_lock lk{applet->lock};
+ applet->cpu_boost_request_priority = priority;
+ R_SUCCEED();
+}
+
+Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL;
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/applet_common_functions.h b/src/core/hle/service/am/service/applet_common_functions.h
new file mode 100644
index 000000000..4424fc83d
--- /dev/null
+++ b/src/core/hle/service/am/service/applet_common_functions.h
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+
+class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
+public:
+ explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
+ ~IAppletCommonFunctions() override;
+
+private:
+ Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
+ Result SetCpuBoostRequestPriority(s32 priority);
+ Result GetCurrentApplicationId(Out<u64> out_application_id);
+
+ const std::shared_ptr<Applet> applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_accessor.cpp b/src/core/hle/service/am/service/application_accessor.cpp
new file mode 100644
index 000000000..6e7d110e8
--- /dev/null
+++ b/src/core/hle/service/am/service/application_accessor.cpp
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/result.h"
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/applet_data_broker.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/service/application_accessor.h"
+#include "core/hle/service/am/service/library_applet_accessor.h"
+#include "core/hle/service/am/service/storage.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "IApplicationAccessor"}, m_applet(std::move(applet)) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
+ {1, nullptr, "IsCompleted"},
+ {10, D<&IApplicationAccessor::Start>, "Start"},
+ {20, D<&IApplicationAccessor::RequestExit>, "RequestExit"},
+ {25, D<&IApplicationAccessor::Terminate>, "Terminate"},
+ {30, D<&IApplicationAccessor::GetResult>, "GetResult"},
+ {101, D<&IApplicationAccessor::RequestForApplicationToGetForeground>, "RequestForApplicationToGetForeground"},
+ {110, nullptr, "TerminateAllLibraryApplets"},
+ {111, nullptr, "AreAnyLibraryAppletsLeft"},
+ {112, D<&IApplicationAccessor::GetCurrentLibraryApplet>, "GetCurrentLibraryApplet"},
+ {120, nullptr, "GetApplicationId"},
+ {121, D<&IApplicationAccessor::PushLaunchParameter>, "PushLaunchParameter"},
+ {122, D<&IApplicationAccessor::GetApplicationControlProperty>, "GetApplicationControlProperty"},
+ {123, nullptr, "GetApplicationLaunchProperty"},
+ {124, nullptr, "GetApplicationLaunchRequestInfo"},
+ {130, D<&IApplicationAccessor::SetUsers>, "SetUsers"},
+ {131, D<&IApplicationAccessor::CheckRightsEnvironmentAvailable>, "CheckRightsEnvironmentAvailable"},
+ {132, D<&IApplicationAccessor::GetNsRightsEnvironmentHandle>, "GetNsRightsEnvironmentHandle"},
+ {140, nullptr, "GetDesirableUids"},
+ {150, D<&IApplicationAccessor::ReportApplicationExitTimeout>, "ReportApplicationExitTimeout"},
+ {160, nullptr, "SetApplicationAttribute"},
+ {170, nullptr, "HasSaveDataAccessPermission"},
+ {180, nullptr, "PushToFriendInvitationStorageChannel"},
+ {190, nullptr, "PushToNotificationStorageChannel"},
+ {200, nullptr, "RequestApplicationSoftReset"},
+ {201, nullptr, "RestartApplicationTimer"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IApplicationAccessor::~IApplicationAccessor() = default;
+
+Result IApplicationAccessor::Start() {
+ LOG_INFO(Service_AM, "called");
+ m_applet->process->Run();
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::RequestExit() {
+ LOG_INFO(Service_AM, "called");
+ m_applet->message_queue.RequestExit();
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::Terminate() {
+ LOG_INFO(Service_AM, "called");
+ m_applet->process->Terminate();
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::GetResult() {
+ LOG_INFO(Service_AM, "called");
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::GetAppletStateChangedEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_AM, "called");
+ *out_event = m_applet->caller_applet_broker->GetStateChangedEvent().GetHandle();
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::PushLaunchParameter(LaunchParameterKind kind,
+ SharedPointer<IStorage> storage) {
+ LOG_INFO(Service_AM, "called, kind={}", kind);
+
+ switch (kind) {
+ case LaunchParameterKind::AccountPreselectedUser:
+ m_applet->preselected_user_launch_parameter.push_back(storage->GetData());
+ R_SUCCEED();
+ default:
+ R_THROW(ResultUnknown);
+ }
+}
+
+Result IApplicationAccessor::GetApplicationControlProperty(
+ OutBuffer<BufferAttr_HipcMapAlias> out_control_property) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_THROW(ResultUnknown);
+}
+
+Result IApplicationAccessor::SetUsers(bool enable,
+ InArray<Common::UUID, BufferAttr_HipcMapAlias> user_ids) {
+ LOG_INFO(Service_AM, "called, enable={} user_id_count={}", enable, user_ids.size());
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::GetCurrentLibraryApplet(
+ Out<SharedPointer<ILibraryAppletAccessor>> out_accessor) {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+ *out_accessor = nullptr;
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::RequestForApplicationToGetForeground() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_THROW(ResultUnknown);
+}
+
+Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_is_available = true;
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::GetNsRightsEnvironmentHandle(Out<u64> out_handle) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_handle = 0xdeadbeef;
+ R_SUCCEED();
+}
+
+Result IApplicationAccessor::ReportApplicationExitTimeout() {
+ LOG_ERROR(Service_AM, "called");
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_accessor.h b/src/core/hle/service/am/service/application_accessor.h
new file mode 100644
index 000000000..39a9b2153
--- /dev/null
+++ b/src/core/hle/service/am/service/application_accessor.h
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/uuid.h"
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+class ILibraryAppletAccessor;
+class IStorage;
+
+class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> {
+public:
+ explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
+ ~IApplicationAccessor() override;
+
+private:
+ Result Start();
+ Result RequestExit();
+ Result Terminate();
+ Result GetResult();
+ Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result PushLaunchParameter(LaunchParameterKind kind, SharedPointer<IStorage> storage);
+ Result GetApplicationControlProperty(OutBuffer<BufferAttr_HipcMapAlias> out_control_property);
+ Result SetUsers(bool enable, InArray<Common::UUID, BufferAttr_HipcMapAlias> user_ids);
+ Result GetCurrentLibraryApplet(Out<SharedPointer<ILibraryAppletAccessor>> out_accessor);
+ Result RequestForApplicationToGetForeground();
+ Result CheckRightsEnvironmentAvailable(Out<bool> out_is_available);
+ Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
+ Result ReportApplicationExitTimeout();
+
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_creator.cpp b/src/core/hle/service/am/service/application_creator.cpp
new file mode 100644
index 000000000..568bb0122
--- /dev/null
+++ b/src/core/hle/service/am/service/application_creator.cpp
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/service/application_accessor.h"
+#include "core/hle/service/am/service/application_creator.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IApplicationCreator::IApplicationCreator(Core::System& system_)
+ : ServiceFramework{system_, "IApplicationCreator"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
+ {1, nullptr, "PopLaunchRequestedApplication"},
+ {10, nullptr, "CreateSystemApplication"},
+ {100, nullptr, "PopFloatingApplicationForDevelopment"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IApplicationCreator::~IApplicationCreator() = default;
+
+Result IApplicationCreator::CreateApplication(
+ Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) {
+ LOG_ERROR(Service_NS, "called, application_id={:x}", application_id);
+ R_THROW(ResultUnknown);
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_creator.h b/src/core/hle/service/am/service/application_creator.h
new file mode 100644
index 000000000..9f939ebf6
--- /dev/null
+++ b/src/core/hle/service/am/service/application_creator.h
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class IApplicationAccessor;
+struct Applet;
+
+class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
+public:
+ explicit IApplicationCreator(Core::System& system_);
+ ~IApplicationCreator() override;
+
+private:
+ Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
new file mode 100644
index 000000000..b788fddd4
--- /dev/null
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -0,0 +1,465 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/settings.h"
+#include "common/uuid.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/service/am/am_results.h"
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/service/application_functions.h"
+#include "core/hle/service/am/service/storage.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/filesystem/save_data_controller.h"
+#include "core/hle/service/ns/ns.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::AM {
+
+IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, D<&IApplicationFunctions::PopLaunchParameter>, "PopLaunchParameter"},
+ {10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
+ {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
+ {12, nullptr, "CreateApplicationAndRequestToStart"},
+ {13, nullptr, "CreateApplicationAndRequestToStartForQuest"},
+ {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
+ {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
+ {20, D<&IApplicationFunctions::EnsureSaveData>, "EnsureSaveData"},
+ {21, D<&IApplicationFunctions::GetDesiredLanguage>, "GetDesiredLanguage"},
+ {22, D<&IApplicationFunctions::SetTerminateResult>, "SetTerminateResult"},
+ {23, D<&IApplicationFunctions::GetDisplayVersion>, "GetDisplayVersion"},
+ {24, nullptr, "GetLaunchStorageInfoForDebug"},
+ {25, D<&IApplicationFunctions::ExtendSaveData>, "ExtendSaveData"},
+ {26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"},
+ {27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"},
+ {28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"},
+ {29, nullptr, "GetCacheStorageMax"},
+ {30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"},
+ {31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"},
+ {32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"},
+ {33, D<&IApplicationFunctions::EndBlockingHomeButton>, "EndBlockingHomeButton"},
+ {34, nullptr, "SelectApplicationLicense"},
+ {35, nullptr, "GetDeviceSaveDataSizeMax"},
+ {36, nullptr, "GetLimitedApplicationLicense"},
+ {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
+ {40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"},
+ {50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"},
+ {60, nullptr, "SetMediaPlaybackStateForApplication"},
+ {65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"},
+ {66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"},
+ {67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"},
+ {68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
+ {70, nullptr, "RequestToShutdown"},
+ {71, nullptr, "RequestToReboot"},
+ {72, nullptr, "RequestToSleep"},
+ {80, nullptr, "ExitAndRequestToShowThanksMessage"},
+ {90, D<&IApplicationFunctions::EnableApplicationCrashReport>, "EnableApplicationCrashReport"},
+ {100, D<&IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer>, "InitializeApplicationCopyrightFrameBuffer"},
+ {101, D<&IApplicationFunctions::SetApplicationCopyrightImage>, "SetApplicationCopyrightImage"},
+ {102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
+ {110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
+ {111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
+ {120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
+ {121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
+ {122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
+ {123, D<&IApplicationFunctions::GetPreviousProgramIndex>, "GetPreviousProgramIndex"},
+ {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
+ {130, D<&IApplicationFunctions::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"},
+ {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
+ {140, D<&IApplicationFunctions::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"},
+ {141, D<&IApplicationFunctions::TryPopFromFriendInvitationStorageChannel>, "TryPopFromFriendInvitationStorageChannel"},
+ {150, D<&IApplicationFunctions::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"},
+ {151, nullptr, "TryPopFromNotificationStorageChannel"},
+ {160, D<&IApplicationFunctions::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"},
+ {170, nullptr, "SetHdcpAuthenticationActivated"},
+ {180, nullptr, "GetLaunchRequiredVersion"},
+ {181, nullptr, "UpgradeLaunchRequiredVersion"},
+ {190, nullptr, "SendServerMaintenanceOverlayNotification"},
+ {200, nullptr, "GetLastApplicationExitReason"},
+ {500, nullptr, "StartContinuousRecordingFlushForDebug"},
+ {1000, nullptr, "CreateMovieMaker"},
+ {1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IApplicationFunctions::~IApplicationFunctions() = default;
+
+Result IApplicationFunctions::PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage,
+ LaunchParameterKind launch_parameter_kind) {
+ LOG_INFO(Service_AM, "called, kind={}", launch_parameter_kind);
+
+ std::scoped_lock lk{m_applet->lock};
+
+ auto& channel = launch_parameter_kind == LaunchParameterKind::UserChannel
+ ? m_applet->user_channel_launch_parameter
+ : m_applet->preselected_user_launch_parameter;
+
+ if (channel.empty()) {
+ LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!",
+ launch_parameter_kind);
+ R_THROW(AM::ResultNoDataInChannel);
+ }
+
+ auto data = channel.back();
+ channel.pop_back();
+
+ *out_storage = std::make_shared<IStorage>(system, std::move(data));
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID user_id) {
+ LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
+
+ FileSys::SaveDataAttribute attribute{};
+ attribute.title_id = m_applet->program_id;
+ attribute.user_id = user_id.AsU128();
+ attribute.type = FileSys::SaveDataType::SaveData;
+
+ FileSys::VirtualDir save_data{};
+ R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
+ &save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
+
+ *out_size = 0;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
+ // FIXME: all of this stuff belongs to ns
+ // TODO(bunnei): This should be configurable
+ LOG_DEBUG(Service_AM, "called");
+
+ // Get supported languages from NACP, if possible
+ // Default to 0 (all languages supported)
+ u32 supported_languages = 0;
+
+ const auto res = [this] {
+ const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ auto metadata = pm.GetControlMetadata();
+ if (metadata.first != nullptr) {
+ return metadata;
+ }
+
+ const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
+ system.GetFileSystemController(),
+ system.GetContentProvider()};
+ return pm_update.GetControlMetadata();
+ }();
+
+ if (res.first != nullptr) {
+ supported_languages = res.first->GetSupportedLanguages();
+ }
+
+ // Call IApplicationManagerInterface implementation.
+ auto& service_manager = system.ServiceManager();
+ auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
+ auto app_man = ns_am2->GetApplicationManagerInterface();
+
+ // Get desired application language
+ u8 desired_language{};
+ R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
+
+ // Convert to settings language code.
+ R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(out_language_code, desired_language));
+
+ LOG_DEBUG(Service_AM, "got desired_language={:016X}", *out_language_code);
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
+ LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(),
+ static_cast<u32>(terminate_result.GetModule()) + 2000,
+ terminate_result.GetDescription());
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->terminate_result = terminate_result;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
+ LOG_DEBUG(Service_AM, "called");
+
+ const auto res = [this] {
+ const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ auto metadata = pm.GetControlMetadata();
+ if (metadata.first != nullptr) {
+ return metadata;
+ }
+
+ const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
+ system.GetFileSystemController(),
+ system.GetContentProvider()};
+ return pm_update.GetControlMetadata();
+ }();
+
+ if (res.first != nullptr) {
+ const auto& version = res.first->GetVersionString();
+ std::memcpy(out_display_version->string.data(), version.data(),
+ std::min(version.size(), out_display_version->string.size()));
+ } else {
+ static constexpr char default_version[]{"1.0.0"};
+ std::memcpy(out_display_version->string.data(), default_version, sizeof(default_version));
+ }
+
+ out_display_version->string[out_display_version->string.size() - 1] = '\0';
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type,
+ Common::UUID user_id, u64 normal_size,
+ u64 journal_size) {
+ LOG_DEBUG(Service_AM, "called with type={} user_id={} normal={:#x} journal={:#x}",
+ static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size);
+
+ system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
+ type, m_applet->program_id, user_id.AsU128(), {normal_size, journal_size});
+
+ // The following value is used to indicate the amount of space remaining on failure
+ // due to running out of space. Since we always succeed, this should be 0.
+ *out_required_size = 0;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size,
+ FileSys::SaveDataType type, Common::UUID user_id) {
+ LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString());
+
+ const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
+ type, m_applet->program_id, user_id.AsU128());
+
+ *out_normal_size = size.normal;
+ *out_journal_size = size.journal;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::CreateCacheStorage(Out<u32> out_target_media,
+ Out<u64> out_required_size, u16 index,
+ u64 normal_size, u64 journal_size) {
+ LOG_WARNING(Service_AM, "(STUBBED) called with index={} size={:#x} journal_size={:#x}", index,
+ normal_size, journal_size);
+
+ *out_target_media = 1; // Nand
+ *out_required_size = 0;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetSaveDataSizeMax(Out<u64> out_max_normal_size,
+ Out<u64> out_max_journal_size) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ *out_max_normal_size = 0xFFFFFFF;
+ *out_max_journal_size = 0xFFFFFFF;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->home_button_long_pressed_blocked = true;
+ m_applet->home_button_short_pressed_blocked = true;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->home_button_long_pressed_blocked = false;
+ m_applet->home_button_short_pressed_blocked = false;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::BeginBlockingHomeButton(s64 timeout_ns) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, timeout_ns={}", timeout_ns);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->home_button_long_pressed_blocked = true;
+ m_applet->home_button_short_pressed_blocked = true;
+ m_applet->home_button_double_click_enabled = true;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::EndBlockingHomeButton() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->home_button_long_pressed_blocked = false;
+ m_applet->home_button_short_pressed_blocked = false;
+ m_applet->home_button_double_click_enabled = false;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_became_running = true;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_pseudo_device_id = {};
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::IsGamePlayRecordingSupported(
+ Out<bool> out_is_game_play_recording_supported) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_is_game_play_recording_supported = m_applet->game_play_recording_supported;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::InitializeGamePlayRecording(
+ u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::SetGamePlayRecordingState(
+ GamePlayRecordingState game_play_recording_state) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->game_play_recording_state = game_play_recording_state;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::EnableApplicationCrashReport(bool enabled) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->application_crash_report_enabled = enabled;
+
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(
+ s32 width, s32 height, u64 transfer_memory_size,
+ InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::SetApplicationCopyrightImage(
+ s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode,
+ InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::SetApplicationCopyrightVisibility(bool visible) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", visible);
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::QueryApplicationPlayStatistics(
+ Out<s32> out_entries,
+ OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
+ InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_entries = 0;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::QueryApplicationPlayStatisticsByUid(
+ Out<s32> out_entries,
+ OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
+ Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_entries = 0;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, kind={}, value={}", kind, value);
+ ASSERT(kind == ProgramSpecifyKind::ExecuteProgram ||
+ kind == ProgramSpecifyKind::RestartProgram);
+
+ // Copy user channel ownership into the system so that it will be preserved
+ system.GetUserChannel() = m_applet->user_channel_launch_parameter;
+ system.ExecuteProgram(value);
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::ClearUserChannel() {
+ LOG_DEBUG(Service_AM, "called");
+ m_applet->user_channel_launch_parameter.clear();
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::UnpopToUserChannel(SharedPointer<IStorage> storage) {
+ LOG_DEBUG(Service_AM, "called");
+ m_applet->user_channel_launch_parameter.push_back(storage->GetData());
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetPreviousProgramIndex(Out<s32> out_previous_program_index) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_previous_program_index = m_applet->previous_program_index;
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetGpuErrorDetectedSystemEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_event = m_applet->gpu_error_detected_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetFriendInvitationStorageChannelEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = m_applet->friend_invitation_storage_channel_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
+ Out<SharedPointer<IStorage>> out_storage) {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+ R_THROW(AM::ResultNoDataInChannel);
+}
+
+Result IApplicationFunctions::GetNotificationStorageChannelEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = m_applet->notification_storage_channel_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = m_applet->health_warning_disappeared_system_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IApplicationFunctions::PrepareForJit() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->jit_service_launched = true;
+
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_functions.h b/src/core/hle/service/am/service/application_functions.h
new file mode 100644
index 000000000..3548202f8
--- /dev/null
+++ b/src/core/hle/service/am/service/application_functions.h
@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/uuid.h"
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace FileSys {
+enum class SaveDataType : u8;
+}
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::AM {
+
+struct Applet;
+class IStorage;
+
+class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
+public:
+ explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
+ ~IApplicationFunctions() override;
+
+private:
+ Result PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage,
+ LaunchParameterKind launch_parameter_kind);
+ Result EnsureSaveData(Out<u64> out_size, Common::UUID user_id);
+ Result GetDesiredLanguage(Out<u64> out_language_code);
+ Result SetTerminateResult(Result terminate_result);
+ Result GetDisplayVersion(Out<DisplayVersion> out_display_version);
+ Result ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type,
+ Common::UUID user_id, u64 normal_size, u64 journal_size);
+ Result GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size,
+ FileSys::SaveDataType type, Common::UUID user_id);
+ Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index,
+ u64 normal_size, u64 journal_size);
+ Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size);
+ Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused);
+ Result EndBlockingHomeButtonShortAndLongPressed();
+ Result BeginBlockingHomeButton(s64 timeout_ns);
+ Result EndBlockingHomeButton();
+ Result NotifyRunning(Out<bool> out_became_running);
+ Result GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id);
+ Result IsGamePlayRecordingSupported(Out<bool> out_is_game_play_recording_supported);
+ Result InitializeGamePlayRecording(
+ u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
+ Result SetGamePlayRecordingState(GamePlayRecordingState game_play_recording_state);
+ Result EnableApplicationCrashReport(bool enabled);
+ Result InitializeApplicationCopyrightFrameBuffer(
+ s32 width, s32 height, u64 transfer_memory_size,
+ InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
+ Result SetApplicationCopyrightImage(
+ s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode,
+ InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data);
+ Result SetApplicationCopyrightVisibility(bool visible);
+ Result QueryApplicationPlayStatistics(
+ Out<s32> out_entries,
+ OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
+ InArray<u64, BufferAttr_HipcMapAlias> application_ids);
+ Result QueryApplicationPlayStatisticsByUid(
+ Out<s32> out_entries,
+ OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
+ Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids);
+ Result ExecuteProgram(ProgramSpecifyKind kind, u64 value);
+ Result ClearUserChannel();
+ Result UnpopToUserChannel(SharedPointer<IStorage> storage);
+ Result GetPreviousProgramIndex(Out<s32> out_previous_program_index);
+ Result GetGpuErrorDetectedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetFriendInvitationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result TryPopFromFriendInvitationStorageChannel(Out<SharedPointer<IStorage>> out_storage);
+ Result GetNotificationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result PrepareForJit();
+
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp
new file mode 100644
index 000000000..776f4552b
--- /dev/null
+++ b/src/core/hle/service/am/service/application_proxy.cpp
@@ -0,0 +1,106 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/applet_common_functions.h"
+#include "core/hle/service/am/service/application_functions.h"
+#include "core/hle/service/am/service/application_proxy.h"
+#include "core/hle/service/am/service/audio_controller.h"
+#include "core/hle/service/am/service/common_state_getter.h"
+#include "core/hle/service/am/service/debug_functions.h"
+#include "core/hle/service/am/service/display_controller.h"
+#include "core/hle/service/am/service/library_applet_creator.h"
+#include "core/hle/service/am/service/process_winding_controller.h"
+#include "core/hle/service/am/service/self_controller.h"
+#include "core/hle/service/am/service/window_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
+ : ServiceFramework{system_, "IApplicationProxy"},
+ m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
+ {1, D<&IApplicationProxy::GetSelfController>, "GetSelfController"},
+ {2, D<&IApplicationProxy::GetWindowController>, "GetWindowController"},
+ {3, D<&IApplicationProxy::GetAudioController>, "GetAudioController"},
+ {4, D<&IApplicationProxy::GetDisplayController>, "GetDisplayController"},
+ {10, D<&IApplicationProxy::GetProcessWindingController>, "GetProcessWindingController"},
+ {11, D<&IApplicationProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
+ {20, D<&IApplicationProxy::GetApplicationFunctions>, "GetApplicationFunctions"},
+ {1000, D<&IApplicationProxy::GetDebugFunctions>, "GetDebugFunctions"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IApplicationProxy::~IApplicationProxy() = default;
+
+Result IApplicationProxy::GetAudioController(
+ Out<SharedPointer<IAudioController>> out_audio_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_audio_controller = std::make_shared<IAudioController>(system);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetDisplayController(
+ Out<SharedPointer<IDisplayController>> out_display_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetProcessWindingController(
+ Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetDebugFunctions(
+ Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_debug_functions = std::make_shared<IDebugFunctions>(system);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetWindowController(
+ Out<SharedPointer<IWindowController>> out_window_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_window_controller = std::make_shared<IWindowController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetSelfController(
+ Out<SharedPointer<ISelfController>> out_self_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_self_controller =
+ std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetCommonStateGetter(
+ Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetLibraryAppletCreator(
+ Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result IApplicationProxy::GetApplicationFunctions(
+ Out<SharedPointer<IApplicationFunctions>> out_application_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_application_functions = std::make_shared<IApplicationFunctions>(system, m_applet);
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h
new file mode 100644
index 000000000..1ebc593ba
--- /dev/null
+++ b/src/core/hle/service/am/service/application_proxy.h
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+class IAudioController;
+class IApplicationFunctions;
+class ICommonStateGetter;
+class IDebugFunctions;
+class IDisplayController;
+class ILibraryAppletCreator;
+class IProcessWindingController;
+class ISelfController;
+class IWindowController;
+
+class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
+public:
+ explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
+ ~IApplicationProxy();
+
+private:
+ Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
+ Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
+ Result GetProcessWindingController(
+ Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
+ Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
+ Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
+ Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
+ Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
+ Result GetLibraryAppletCreator(
+ Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
+ Result GetApplicationFunctions(
+ Out<SharedPointer<IApplicationFunctions>> out_application_functions);
+
+private:
+ Nvnflinger::Nvnflinger& m_nvnflinger;
+ Kernel::KProcess* const m_process;
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp
new file mode 100644
index 000000000..36d4478df
--- /dev/null
+++ b/src/core/hle/service/am/service/application_proxy_service.cpp
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/service/application_proxy.h"
+#include "core/hle/service/am/service/application_proxy_service.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IApplicationProxyService::IApplicationProxyService(Core::System& system_,
+ Nvnflinger::Nvnflinger& nvnflinger)
+ : ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
+ };
+ RegisterHandlers(functions);
+}
+
+IApplicationProxyService::~IApplicationProxyService() = default;
+
+Result IApplicationProxyService::OpenApplicationProxy(
+ Out<SharedPointer<IApplicationProxy>> out_application_proxy, ClientProcessId pid,
+ InCopyHandle<Kernel::KProcess> process_handle) {
+ LOG_DEBUG(Service_AM, "called");
+
+ if (const auto applet = this->GetAppletFromProcessId(pid)) {
+ *out_application_proxy =
+ std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger);
+ R_SUCCEED();
+ } else {
+ UNIMPLEMENTED();
+ R_THROW(ResultUnknown);
+ }
+}
+
+std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
+ return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_proxy_service.h b/src/core/hle/service/am/service/application_proxy_service.h
new file mode 100644
index 000000000..1c1d32d0b
--- /dev/null
+++ b/src/core/hle/service/am/service/application_proxy_service.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+
+namespace Nvnflinger {
+class Nvnflinger;
+}
+
+namespace AM {
+
+struct Applet;
+class IApplicationProxy;
+
+class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
+public:
+ explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
+ ~IApplicationProxyService() override;
+
+private:
+ Result OpenApplicationProxy(Out<SharedPointer<IApplicationProxy>> out_application_proxy,
+ ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle);
+
+private:
+ std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
+ Nvnflinger::Nvnflinger& m_nvnflinger;
+};
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/service/audio_controller.cpp b/src/core/hle/service/am/service/audio_controller.cpp
new file mode 100644
index 000000000..ad731c7bd
--- /dev/null
+++ b/src/core/hle/service/am/service/audio_controller.cpp
@@ -0,0 +1,69 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/audio_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IAudioController::IAudioController(Core::System& system_)
+ : ServiceFramework{system_, "IAudioController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioController::SetExpectedMasterVolume>, "SetExpectedMasterVolume"},
+ {1, D<&IAudioController::GetMainAppletExpectedMasterVolume>, "GetMainAppletExpectedMasterVolume"},
+ {2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
+ {3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
+ {4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioController::~IAudioController() = default;
+
+Result IAudioController::SetExpectedMasterVolume(f32 main_applet_volume,
+ f32 library_applet_volume) {
+ LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
+ main_applet_volume, library_applet_volume);
+
+ // Ensure the volume values remain within the 0-100% range
+ m_main_applet_volume = std::clamp(main_applet_volume, MinAllowedVolume, MaxAllowedVolume);
+ m_library_applet_volume = std::clamp(library_applet_volume, MinAllowedVolume, MaxAllowedVolume);
+
+ R_SUCCEED();
+}
+
+Result IAudioController::GetMainAppletExpectedMasterVolume(Out<f32> out_main_applet_volume) {
+ LOG_DEBUG(Service_AM, "called. main_applet_volume={}", m_main_applet_volume);
+ *out_main_applet_volume = m_main_applet_volume;
+ R_SUCCEED();
+}
+
+Result IAudioController::GetLibraryAppletExpectedMasterVolume(Out<f32> out_library_applet_volume) {
+ LOG_DEBUG(Service_AM, "called. library_applet_volume={}", m_library_applet_volume);
+ *out_library_applet_volume = m_library_applet_volume;
+ R_SUCCEED();
+}
+
+Result IAudioController::ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns) {
+ LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", volume, fade_time_ns);
+
+ m_main_applet_volume = std::clamp(volume, MinAllowedVolume, MaxAllowedVolume);
+ m_fade_time_ns = std::chrono::nanoseconds{fade_time_ns};
+
+ R_SUCCEED();
+}
+
+Result IAudioController::SetTransparentVolumeRate(f32 transparent_volume_rate) {
+ LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate);
+
+ // Clamp volume range to 0-100%.
+ m_transparent_volume_rate =
+ std::clamp(transparent_volume_rate, MinAllowedVolume, MaxAllowedVolume);
+
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/audio_controller.h b/src/core/hle/service/am/service/audio_controller.h
new file mode 100644
index 000000000..4b0f3f9ae
--- /dev/null
+++ b/src/core/hle/service/am/service/audio_controller.h
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class IAudioController final : public ServiceFramework<IAudioController> {
+public:
+ explicit IAudioController(Core::System& system_);
+ ~IAudioController() override;
+
+private:
+ Result SetExpectedMasterVolume(f32 main_applet_volume, f32 library_applet_volume);
+ Result GetMainAppletExpectedMasterVolume(Out<f32> out_main_applet_volume);
+ Result GetLibraryAppletExpectedMasterVolume(Out<f32> out_library_applet_volume);
+ Result ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns);
+ Result SetTransparentVolumeRate(f32 transparent_volume_rate);
+
+ static constexpr float MinAllowedVolume = 0.0f;
+ static constexpr float MaxAllowedVolume = 1.0f;
+
+ float m_main_applet_volume{0.25f};
+ float m_library_applet_volume{MaxAllowedVolume};
+ float m_transparent_volume_rate{MinAllowedVolume};
+
+ // Volume transition fade time in nanoseconds.
+ // e.g. If the main applet volume was 0% and was changed to 50%
+ // with a fade of 50ns, then over the course of 50ns,
+ // the volume will gradually fade up to 50%
+ std::chrono::nanoseconds m_fade_time_ns{0};
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/common_state_getter.cpp b/src/core/hle/service/am/service/common_state_getter.cpp
new file mode 100644
index 000000000..12d7e8cb1
--- /dev/null
+++ b/src/core/hle/service/am/service/common_state_getter.cpp
@@ -0,0 +1,277 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/settings.h"
+#include "core/hle/service/am/am_results.h"
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/service/common_state_getter.h"
+#include "core/hle/service/am/service/lock_accessor.h"
+#include "core/hle/service/apm/apm_interface.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/pm/pm.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/vi/vi.h"
+
+namespace Service::AM {
+
+ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "ICommonStateGetter"}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ICommonStateGetter::GetEventHandle>, "GetEventHandle"},
+ {1, D<&ICommonStateGetter::ReceiveMessage>, "ReceiveMessage"},
+ {2, nullptr, "GetThisAppletKind"},
+ {3, nullptr, "AllowToEnterSleep"},
+ {4, nullptr, "DisallowToEnterSleep"},
+ {5, D<&ICommonStateGetter::GetOperationMode>, "GetOperationMode"},
+ {6, D<&ICommonStateGetter::GetPerformanceMode>, "GetPerformanceMode"},
+ {7, nullptr, "GetCradleStatus"},
+ {8, D<&ICommonStateGetter::GetBootMode>, "GetBootMode"},
+ {9, D<&ICommonStateGetter::GetCurrentFocusState>, "GetCurrentFocusState"},
+ {10, D<&ICommonStateGetter::RequestToAcquireSleepLock>, "RequestToAcquireSleepLock"},
+ {11, nullptr, "ReleaseSleepLock"},
+ {12, nullptr, "ReleaseSleepLockTransiently"},
+ {13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"},
+ {14, nullptr, "GetWakeupCount"},
+ {20, nullptr, "PushToGeneralChannel"},
+ {30, nullptr, "GetHomeButtonReaderLockAccessor"},
+ {31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx"},
+ {32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx"},
+ {40, nullptr, "GetCradleFwVersion"},
+ {50, D<&ICommonStateGetter::IsVrModeEnabled>, "IsVrModeEnabled"},
+ {51, D<&ICommonStateGetter::SetVrModeEnabled>, "SetVrModeEnabled"},
+ {52, D<&ICommonStateGetter::SetLcdBacklighOffEnabled>, "SetLcdBacklighOffEnabled"},
+ {53, D<&ICommonStateGetter::BeginVrModeEx>, "BeginVrModeEx"},
+ {54, D<&ICommonStateGetter::EndVrModeEx>, "EndVrModeEx"},
+ {55, D<&ICommonStateGetter::IsInControllerFirmwareUpdateSection>, "IsInControllerFirmwareUpdateSection"},
+ {59, nullptr, "SetVrPositionForDebug"},
+ {60, D<&ICommonStateGetter::GetDefaultDisplayResolution>, "GetDefaultDisplayResolution"},
+ {61, D<&ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent>, "GetDefaultDisplayResolutionChangeEvent"},
+ {62, nullptr, "GetHdcpAuthenticationState"},
+ {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
+ {64, nullptr, "SetTvPowerStateMatchingMode"},
+ {65, nullptr, "GetApplicationIdByContentActionName"},
+ {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
+ {67, nullptr, "CancelCpuBoostMode"},
+ {68, D<&ICommonStateGetter::GetBuiltInDisplayType>, "GetBuiltInDisplayType"},
+ {80, D<&ICommonStateGetter::PerformSystemButtonPressingIfInFocus>, "PerformSystemButtonPressingIfInFocus"},
+ {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
+ {91, nullptr, "GetCurrentPerformanceConfiguration"},
+ {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
+ {110, nullptr, "OpenMyGpuErrorHandler"},
+ {120, D<&ICommonStateGetter::GetAppletLaunchedHistory>, "GetAppletLaunchedHistory"},
+ {200, D<&ICommonStateGetter::GetOperationModeSystemInfo>, "GetOperationModeSystemInfo"},
+ {300, D<&ICommonStateGetter::GetSettingsPlatformRegion>, "GetSettingsPlatformRegion"},
+ {400, nullptr, "ActivateMigrationService"},
+ {401, nullptr, "DeactivateMigrationService"},
+ {500, nullptr, "DisableSleepTillShutdown"},
+ {501, nullptr, "SuppressDisablingSleepTemporarily"},
+ {502, nullptr, "IsSleepEnabled"},
+ {503, nullptr, "IsDisablingSleepSuppressed"},
+ {900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ICommonStateGetter::~ICommonStateGetter() = default;
+
+Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = &m_applet->message_queue.GetMessageReceiveEvent();
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::ReceiveMessage(Out<AppletMessage> out_applet_message) {
+ LOG_DEBUG(Service_AM, "called");
+
+ *out_applet_message = m_applet->message_queue.PopMessage();
+ if (*out_applet_message == AppletMessage::None) {
+ LOG_ERROR(Service_AM, "Tried to pop message but none was available!");
+ R_THROW(AM::ResultNoMessages);
+ }
+
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetCurrentFocusState(Out<FocusState> out_focus_state) {
+ LOG_DEBUG(Service_AM, "called");
+
+ std::scoped_lock lk{m_applet->lock};
+ *out_focus_state = m_applet->focus_state;
+
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::RequestToAcquireSleepLock() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ // Sleep lock is acquired immediately.
+ m_applet->sleep_lock_event.Signal();
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetAcquiredSleepLockEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_AM, "called");
+ *out_event = m_applet->sleep_lock_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetReaderLockAccessorEx(
+ Out<SharedPointer<ILockAccessor>> out_lock_accessor, u32 button_type) {
+ LOG_INFO(Service_AM, "called, button_type={}", button_type);
+ *out_lock_accessor = std::make_shared<ILockAccessor>(system);
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetWriterLockAccessorEx(
+ Out<SharedPointer<ILockAccessor>> out_lock_accessor, u32 button_type) {
+ LOG_INFO(Service_AM, "called, button_type={}", button_type);
+ *out_lock_accessor = std::make_shared<ILockAccessor>(system);
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = &m_applet->message_queue.GetOperationModeChangedEvent();
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetOperationMode(Out<OperationMode> out_operation_mode) {
+ const bool use_docked_mode{Settings::IsDockedMode()};
+ LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
+ *out_operation_mode = use_docked_mode ? OperationMode::Docked : OperationMode::Handheld;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetPerformanceMode(Out<APM::PerformanceMode> out_performance_mode) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_performance_mode = system.GetAPMController().GetCurrentPerformanceMode();
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetBootMode(Out<PM::SystemBootMode> out_boot_mode) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_boot_mode = Service::PM::SystemBootMode::Normal;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::IsVrModeEnabled(Out<bool> out_is_vr_mode_enabled) {
+ LOG_DEBUG(Service_AM, "called");
+
+ std::scoped_lock lk{m_applet->lock};
+ *out_is_vr_mode_enabled = m_applet->vr_mode_enabled;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::SetVrModeEnabled(bool is_vr_mode_enabled) {
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->vr_mode_enabled = is_vr_mode_enabled;
+ LOG_WARNING(Service_AM, "VR Mode is {}", m_applet->vr_mode_enabled ? "on" : "off");
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::SetLcdBacklighOffEnabled(bool is_lcd_backlight_off_enabled) {
+ LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
+ is_lcd_backlight_off_enabled);
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::BeginVrModeEx() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->vr_mode_enabled = true;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::EndVrModeEx() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->vr_mode_enabled = false;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::IsInControllerFirmwareUpdateSection(
+ Out<bool> out_is_in_controller_firmware_update_section) {
+ LOG_INFO(Service_AM, "called");
+ *out_is_in_controller_firmware_update_section = false;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height) {
+ LOG_DEBUG(Service_AM, "called");
+
+ if (Settings::IsDockedMode()) {
+ *out_width = static_cast<u32>(Service::VI::DisplayResolution::DockedWidth);
+ *out_height = static_cast<u32>(Service::VI::DisplayResolution::DockedHeight);
+ } else {
+ *out_width = static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth);
+ *out_height = static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight);
+ }
+
+ R_SUCCEED();
+}
+
+void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
+
+ const auto& sm = system.ServiceManager();
+ const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
+ ASSERT(apm_sys != nullptr);
+
+ apm_sys->SetCpuBoostMode(ctx);
+}
+
+Result ICommonStateGetter::GetBuiltInDisplayType(Out<s32> out_display_type) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_display_type = 0;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::PerformSystemButtonPressingIfInFocus(SystemButtonType type) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, type={}", type);
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_operation_mode_system_info = 0;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetAppletLaunchedHistory(
+ Out<s32> out_count, OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids) {
+ LOG_INFO(Service_AM, "called");
+
+ std::shared_ptr<Applet> current_applet = m_applet;
+
+ for (*out_count = 0;
+ *out_count < static_cast<s32>(out_applet_ids.size()) && current_applet != nullptr;
+ /* ... */) {
+ out_applet_ids[(*out_count)++] = current_applet->applet_id;
+ current_applet = current_applet->caller_applet.lock();
+ }
+
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::GetSettingsPlatformRegion(
+ Out<SysPlatformRegion> out_settings_platform_region) {
+ LOG_INFO(Service_AM, "called");
+ *out_settings_platform_region = SysPlatformRegion::Global;
+ R_SUCCEED();
+}
+
+Result ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->request_exit_to_library_applet_at_execute_next_program_enabled = true;
+
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/common_state_getter.h b/src/core/hle/service/am/service/common_state_getter.h
new file mode 100644
index 000000000..5a8dca3d6
--- /dev/null
+++ b/src/core/hle/service/am/service/common_state_getter.h
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/apm/apm_controller.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/pm/pm.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::AM {
+
+struct Applet;
+class ILockAccessor;
+
+class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
+public:
+ explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_);
+ ~ICommonStateGetter() override;
+
+private:
+ Result GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result ReceiveMessage(Out<AppletMessage> out_applet_message);
+ Result GetCurrentFocusState(Out<FocusState> out_focus_state);
+ Result RequestToAcquireSleepLock();
+ Result GetAcquiredSleepLockEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetReaderLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor,
+ u32 button_type);
+ Result GetWriterLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor,
+ u32 button_type);
+ Result GetDefaultDisplayResolutionChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetOperationMode(Out<OperationMode> out_operation_mode);
+ Result GetPerformanceMode(Out<APM::PerformanceMode> out_performance_mode);
+ Result GetBootMode(Out<PM::SystemBootMode> out_boot_mode);
+ Result IsVrModeEnabled(Out<bool> out_is_vr_mode_enabled);
+ Result SetVrModeEnabled(bool is_vr_mode_enabled);
+ Result SetLcdBacklighOffEnabled(bool is_lcd_backlight_off_enabled);
+ Result BeginVrModeEx();
+ Result EndVrModeEx();
+ Result IsInControllerFirmwareUpdateSection(
+ Out<bool> out_is_in_controller_firmware_update_section);
+ Result GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height);
+ Result GetBuiltInDisplayType(Out<s32> out_display_type);
+ Result PerformSystemButtonPressingIfInFocus(SystemButtonType type);
+ Result GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info);
+ Result GetAppletLaunchedHistory(Out<s32> out_count,
+ OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids);
+ Result GetSettingsPlatformRegion(Out<SysPlatformRegion> out_settings_platform_region);
+ Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
+
+ void SetCpuBoostMode(HLERequestContext& ctx);
+
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/cradle_firmware_updater.cpp b/src/core/hle/service/am/service/cradle_firmware_updater.cpp
new file mode 100644
index 000000000..0a8af0858
--- /dev/null
+++ b/src/core/hle/service/am/service/cradle_firmware_updater.cpp
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/cradle_firmware_updater.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+ICradleFirmwareUpdater::ICradleFirmwareUpdater(Core::System& system_)
+ : ServiceFramework{system_, "ICradleFirmwareUpdater"},
+ m_context{system, "ICradleFirmwareUpdater"}, m_cradle_device_info_event{m_context} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ICradleFirmwareUpdater::StartUpdate>, "StartUpdate"},
+ {1, D<&ICradleFirmwareUpdater::FinishUpdate>, "FinishUpdate"},
+ {2, D<&ICradleFirmwareUpdater::GetCradleDeviceInfo>, "GetCradleDeviceInfo"},
+ {3, D<&ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent>, "GetCradleDeviceInfoChangeEvent"},
+ {4, nullptr, "GetUpdateProgressInfo"},
+ {5, nullptr, "GetLastInternalResult"},
+
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ICradleFirmwareUpdater::~ICradleFirmwareUpdater() = default;
+
+Result ICradleFirmwareUpdater::StartUpdate() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result ICradleFirmwareUpdater::FinishUpdate() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result ICradleFirmwareUpdater::GetCradleDeviceInfo(Out<CradleDeviceInfo> out_cradle_device_info) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_cradle_device_info = {};
+ R_SUCCEED();
+}
+
+Result ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_event = m_cradle_device_info_event.GetHandle();
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/cradle_firmware_updater.h b/src/core/hle/service/am/service/cradle_firmware_updater.h
new file mode 100644
index 000000000..3e803f0ae
--- /dev/null
+++ b/src/core/hle/service/am/service/cradle_firmware_updater.h
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct CradleDeviceInfo {
+ bool unknown0;
+ bool unknown1;
+ bool unknown2;
+ u64 unknown3;
+};
+static_assert(sizeof(CradleDeviceInfo) == 0x10, "CradleDeviceInfo has incorrect size");
+
+class ICradleFirmwareUpdater final : public ServiceFramework<ICradleFirmwareUpdater> {
+public:
+ explicit ICradleFirmwareUpdater(Core::System& system_);
+ ~ICradleFirmwareUpdater() override;
+
+private:
+ Result StartUpdate();
+ Result FinishUpdate();
+ Result GetCradleDeviceInfo(Out<CradleDeviceInfo> out_cradle_device_info);
+ Result GetCradleDeviceInfoChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+private:
+ KernelHelpers::ServiceContext m_context;
+ Event m_cradle_device_info_event;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/debug_functions.cpp b/src/core/hle/service/am/service/debug_functions.cpp
new file mode 100644
index 000000000..fcac4776d
--- /dev/null
+++ b/src/core/hle/service/am/service/debug_functions.cpp
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/debug_functions.h"
+
+namespace Service::AM {
+
+IDebugFunctions::IDebugFunctions(Core::System& system_)
+ : ServiceFramework{system_, "IDebugFunctions"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
+ {1, nullptr, "OpenMainApplication"},
+ {10, nullptr, "PerformSystemButtonPressing"},
+ {20, nullptr, "InvalidateTransitionLayer"},
+ {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
+ {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
+ {40, nullptr, "GetAppletResourceUsageInfo"},
+ {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
+ {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
+ {100, nullptr, "SetCpuBoostModeForApplet"},
+ {101, nullptr, "CancelCpuBoostModeForApplet"},
+ {110, nullptr, "PushToAppletBoundChannelForDebug"},
+ {111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
+ {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
+ {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
+ {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
+ {130, nullptr, "FriendInvitationSetApplicationParameter"},
+ {131, nullptr, "FriendInvitationClearApplicationParameter"},
+ {132, nullptr, "FriendInvitationPushApplicationParameter"},
+ {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
+ {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
+ {300, nullptr, "TerminateAllRunningApplicationsForDebug"},
+ {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IDebugFunctions::~IDebugFunctions() = default;
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/debug_functions.h b/src/core/hle/service/am/service/debug_functions.h
new file mode 100644
index 000000000..d55968743
--- /dev/null
+++ b/src/core/hle/service/am/service/debug_functions.h
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
+public:
+ explicit IDebugFunctions(Core::System& system_);
+ ~IDebugFunctions() override;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/display_controller.cpp b/src/core/hle/service/am/service/display_controller.cpp
new file mode 100644
index 000000000..249c73dfb
--- /dev/null
+++ b/src/core/hle/service/am/service/display_controller.cpp
@@ -0,0 +1,105 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/result.h"
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/service/display_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
+ : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetLastForegroundCaptureImage"},
+ {1, nullptr, "UpdateLastForegroundCaptureImage"},
+ {2, nullptr, "GetLastApplicationCaptureImage"},
+ {3, nullptr, "GetCallerAppletCaptureImage"},
+ {4, nullptr, "UpdateCallerAppletCaptureImage"},
+ {5, nullptr, "GetLastForegroundCaptureImageEx"},
+ {6, nullptr, "GetLastApplicationCaptureImageEx"},
+ {7, D<&IDisplayController::GetCallerAppletCaptureImageEx>, "GetCallerAppletCaptureImageEx"},
+ {8, D<&IDisplayController::TakeScreenShotOfOwnLayer>, "TakeScreenShotOfOwnLayer"},
+ {9, nullptr, "CopyBetweenCaptureBuffers"},
+ {10, nullptr, "AcquireLastApplicationCaptureBuffer"},
+ {11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
+ {12, nullptr, "AcquireLastForegroundCaptureBuffer"},
+ {13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
+ {14, nullptr, "AcquireCallerAppletCaptureBuffer"},
+ {15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
+ {16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
+ {17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
+ {18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
+ {20, D<&IDisplayController::ClearCaptureBuffer>, "ClearCaptureBuffer"},
+ {21, nullptr, "ClearAppletTransitionBuffer"},
+ {22, D<&IDisplayController::AcquireLastApplicationCaptureSharedBuffer>, "AcquireLastApplicationCaptureSharedBuffer"},
+ {23, D<&IDisplayController::ReleaseLastApplicationCaptureSharedBuffer>, "ReleaseLastApplicationCaptureSharedBuffer"},
+ {24, D<&IDisplayController::AcquireLastForegroundCaptureSharedBuffer>, "AcquireLastForegroundCaptureSharedBuffer"},
+ {25, D<&IDisplayController::ReleaseLastForegroundCaptureSharedBuffer>, "ReleaseLastForegroundCaptureSharedBuffer"},
+ {26, D<&IDisplayController::AcquireCallerAppletCaptureSharedBuffer>, "AcquireCallerAppletCaptureSharedBuffer"},
+ {27, D<&IDisplayController::ReleaseCallerAppletCaptureSharedBuffer>, "ReleaseCallerAppletCaptureSharedBuffer"},
+ {28, nullptr, "TakeScreenShotOfOwnLayerEx"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IDisplayController::~IDisplayController() = default;
+
+Result IDisplayController::GetCallerAppletCaptureImageEx(
+ Out<bool> out_was_written, OutBuffer<BufferAttr_HipcMapAlias> out_image_data) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_was_written = true;
+ R_SUCCEED();
+}
+
+Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_layer_index) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}",
+ unknown0, fbshare_layer_index, color);
+ R_SUCCEED();
+}
+
+Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
+ Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
+ out_fbshare_layer_index));
+}
+
+Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
+ Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
+ out_fbshare_layer_index));
+}
+
+Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
+ Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
+ out_fbshare_layer_index));
+}
+
+Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/display_controller.h b/src/core/hle/service/am/service/display_controller.h
new file mode 100644
index 000000000..406fae21a
--- /dev/null
+++ b/src/core/hle/service/am/service/display_controller.h
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+
+class IDisplayController final : public ServiceFramework<IDisplayController> {
+public:
+ explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_);
+ ~IDisplayController() override;
+
+private:
+ Result GetCallerAppletCaptureImageEx(Out<bool> out_was_written,
+ OutBuffer<BufferAttr_HipcMapAlias> out_image_data);
+ Result TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_layer_index);
+ Result ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color);
+ Result AcquireLastForegroundCaptureSharedBuffer(Out<bool> out_was_written,
+ Out<s32> out_fbshare_layer_index);
+ Result ReleaseLastForegroundCaptureSharedBuffer();
+ Result AcquireCallerAppletCaptureSharedBuffer(Out<bool> out_was_written,
+ Out<s32> out_fbshare_layer_index);
+ Result ReleaseCallerAppletCaptureSharedBuffer();
+ Result AcquireLastApplicationCaptureSharedBuffer(Out<bool> out_was_written,
+ Out<s32> out_fbshare_layer_index);
+ Result ReleaseLastApplicationCaptureSharedBuffer();
+
+ const std::shared_ptr<Applet> applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/global_state_controller.cpp b/src/core/hle/service/am/service/global_state_controller.cpp
new file mode 100644
index 000000000..dba5d3613
--- /dev/null
+++ b/src/core/hle/service/am/service/global_state_controller.cpp
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/cradle_firmware_updater.h"
+#include "core/hle/service/am/service/global_state_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IGlobalStateController::IGlobalStateController(Core::System& system_)
+ : ServiceFramework{system_, "IGlobalStateController"},
+ m_context{system_, "IGlobalStateController"}, m_hdcp_authentication_failed_event{m_context} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestToEnterSleep"},
+ {1, nullptr, "EnterSleep"},
+ {2, nullptr, "StartSleepSequence"},
+ {3, nullptr, "StartShutdownSequence"},
+ {4, nullptr, "StartRebootSequence"},
+ {9, nullptr, "IsAutoPowerDownRequested"},
+ {10, D<&IGlobalStateController::LoadAndApplyIdlePolicySettings>, "LoadAndApplyIdlePolicySettings"},
+ {11, nullptr, "NotifyCecSettingsChanged"},
+ {12, nullptr, "SetDefaultHomeButtonLongPressTime"},
+ {13, nullptr, "UpdateDefaultDisplayResolution"},
+ {14, D<&IGlobalStateController::ShouldSleepOnBoot>, "ShouldSleepOnBoot"},
+ {15, D<&IGlobalStateController::GetHdcpAuthenticationFailedEvent>, "GetHdcpAuthenticationFailedEvent"},
+ {30, D<&IGlobalStateController::OpenCradleFirmwareUpdater>, "OpenCradleFirmwareUpdater"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IGlobalStateController::~IGlobalStateController() = default;
+
+Result IGlobalStateController::LoadAndApplyIdlePolicySettings() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IGlobalStateController::ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot) {
+ LOG_INFO(Service_AM, "called");
+ *out_should_sleep_on_boot = false;
+ R_SUCCEED();
+}
+
+Result IGlobalStateController::GetHdcpAuthenticationFailedEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_AM, "called");
+ *out_event = m_hdcp_authentication_failed_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IGlobalStateController::OpenCradleFirmwareUpdater(
+ Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater) {
+ LOG_INFO(Service_AM, "called");
+ *out_cradle_firmware_updater = std::make_shared<ICradleFirmwareUpdater>(system);
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/global_state_controller.h b/src/core/hle/service/am/service/global_state_controller.h
new file mode 100644
index 000000000..67c753513
--- /dev/null
+++ b/src/core/hle/service/am/service/global_state_controller.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class ICradleFirmwareUpdater;
+
+class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
+public:
+ explicit IGlobalStateController(Core::System& system_);
+ ~IGlobalStateController() override;
+
+private:
+ Result LoadAndApplyIdlePolicySettings();
+ Result ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot);
+ Result GetHdcpAuthenticationFailedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result OpenCradleFirmwareUpdater(
+ Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater);
+
+ KernelHelpers::ServiceContext m_context;
+ Event m_hdcp_authentication_failed_event;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/home_menu_functions.cpp b/src/core/hle/service/am/service/home_menu_functions.cpp
new file mode 100644
index 000000000..0c4d24b58
--- /dev/null
+++ b/src/core/hle/service/am/service/home_menu_functions.cpp
@@ -0,0 +1,74 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/result.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/service/home_menu_functions.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "IHomeMenuFunctions"}, m_applet{std::move(applet)},
+ m_context{system, "IHomeMenuFunctions"}, m_pop_from_general_channel_event{m_context} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"},
+ {11, D<&IHomeMenuFunctions::LockForeground>, "LockForeground"},
+ {12, D<&IHomeMenuFunctions::UnlockForeground>, "UnlockForeground"},
+ {20, nullptr, "PopFromGeneralChannel"},
+ {21, D<&IHomeMenuFunctions::GetPopFromGeneralChannelEvent>, "GetPopFromGeneralChannelEvent"},
+ {30, nullptr, "GetHomeButtonWriterLockAccessor"},
+ {31, nullptr, "GetWriterLockAccessorEx"},
+ {40, nullptr, "IsSleepEnabled"},
+ {41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"},
+ {50, nullptr, "LaunchSystemApplet"},
+ {51, nullptr, "LaunchStarter"},
+ {100, nullptr, "PopRequestLaunchApplicationForDebug"},
+ {110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"},
+ {200, nullptr, "LaunchDevMenu"},
+ {1000, nullptr, "SetLastApplicationExitReason"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IHomeMenuFunctions::~IHomeMenuFunctions() = default;
+
+Result IHomeMenuFunctions::RequestToGetForeground() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IHomeMenuFunctions::LockForeground() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IHomeMenuFunctions::UnlockForeground() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IHomeMenuFunctions::GetPopFromGeneralChannelEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_AM, "called");
+ *out_event = m_pop_from_general_channel_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IHomeMenuFunctions::IsRebootEnabled(Out<bool> out_is_reboot_enbaled) {
+ LOG_INFO(Service_AM, "called");
+ *out_is_reboot_enbaled = true;
+ R_SUCCEED();
+}
+
+Result IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug(
+ Out<bool> out_is_force_terminate_application_disabled_for_debug) {
+ LOG_INFO(Service_AM, "called");
+ *out_is_force_terminate_application_disabled_for_debug = false;
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/home_menu_functions.h b/src/core/hle/service/am/service/home_menu_functions.h
new file mode 100644
index 000000000..caf6fbaab
--- /dev/null
+++ b/src/core/hle/service/am/service/home_menu_functions.h
@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+
+class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
+public:
+ explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
+ ~IHomeMenuFunctions() override;
+
+private:
+ Result RequestToGetForeground();
+ Result LockForeground();
+ Result UnlockForeground();
+ Result GetPopFromGeneralChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result IsRebootEnabled(Out<bool> out_is_reboot_enbaled);
+ Result IsForceTerminateApplicationDisabledForDebug(
+ Out<bool> out_is_force_terminate_application_disabled_for_debug);
+
+ const std::shared_ptr<Applet> m_applet;
+ KernelHelpers::ServiceContext m_context;
+ Event m_pop_from_general_channel_event;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_accessor.cpp b/src/core/hle/service/am/service/library_applet_accessor.cpp
new file mode 100644
index 000000000..0c2426d4b
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_accessor.cpp
@@ -0,0 +1,157 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/applet_data_broker.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/frontend/applets.h"
+#include "core/hle/service/am/service/library_applet_accessor.h"
+#include "core/hle/service/am/service/storage.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
+ std::shared_ptr<AppletDataBroker> broker,
+ std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "ILibraryAppletAccessor"}, m_broker{std::move(broker)},
+ m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ILibraryAppletAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
+ {1, D<&ILibraryAppletAccessor::IsCompleted>, "IsCompleted"},
+ {10, D<&ILibraryAppletAccessor::Start>, "Start"},
+ {20, D<&ILibraryAppletAccessor::RequestExit>, "RequestExit"},
+ {25, D<&ILibraryAppletAccessor::Terminate>, "Terminate"},
+ {30, D<&ILibraryAppletAccessor::GetResult>, "GetResult"},
+ {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
+ {60, D<&ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero>, "PresetLibraryAppletGpuTimeSliceZero"},
+ {100, D<&ILibraryAppletAccessor::PushInData>, "PushInData"},
+ {101, D<&ILibraryAppletAccessor::PopOutData>, "PopOutData"},
+ {102, nullptr, "PushExtraStorage"},
+ {103, D<&ILibraryAppletAccessor::PushInteractiveInData>, "PushInteractiveInData"},
+ {104, D<&ILibraryAppletAccessor::PopInteractiveOutData>, "PopInteractiveOutData"},
+ {105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"},
+ {106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"},
+ {110, nullptr, "NeedsToExitProcess"},
+ {120, nullptr, "GetLibraryAppletInfo"},
+ {150, nullptr, "RequestForAppletToGetForeground"},
+ {160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
+
+Result ILibraryAppletAccessor::GetAppletStateChangedEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = m_broker->GetStateChangedEvent().GetHandle();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_is_completed = m_broker->IsCompleted();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::GetResult(Out<Result> out_result) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_result = m_applet->terminate_result;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::Start() {
+ LOG_DEBUG(Service_AM, "called");
+ m_applet->process->Run();
+ FrontendExecute();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::RequestExit() {
+ LOG_DEBUG(Service_AM, "called");
+ m_applet->message_queue.RequestExit();
+ FrontendRequestExit();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::Terminate() {
+ LOG_DEBUG(Service_AM, "called");
+ m_applet->process->Terminate();
+ FrontendRequestExit();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
+ LOG_DEBUG(Service_AM, "called");
+ m_broker->GetInData().Push(storage);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
+ LOG_DEBUG(Service_AM, "called");
+ R_RETURN(m_broker->GetOutData().Pop(out_storage.Get()));
+}
+
+Result ILibraryAppletAccessor::PushInteractiveInData(SharedPointer<IStorage> storage) {
+ LOG_DEBUG(Service_AM, "called");
+ m_broker->GetInteractiveInData().Push(storage);
+ FrontendExecuteInteractive();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::PopInteractiveOutData(Out<SharedPointer<IStorage>> out_storage) {
+ LOG_DEBUG(Service_AM, "called");
+ R_RETURN(m_broker->GetInteractiveOutData().Pop(out_storage.Get()));
+}
+
+Result ILibraryAppletAccessor::GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = m_broker->GetOutData().GetEvent();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_event = m_broker->GetInteractiveOutData().GetEvent();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(Out<u64> out_handle) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
+ // actually used anywhere
+ *out_handle = 0xdeadbeef;
+ R_SUCCEED();
+}
+
+void ILibraryAppletAccessor::FrontendExecute() {
+ if (m_applet->frontend) {
+ m_applet->frontend->Initialize();
+ m_applet->frontend->Execute();
+ }
+}
+
+void ILibraryAppletAccessor::FrontendExecuteInteractive() {
+ if (m_applet->frontend) {
+ m_applet->frontend->ExecuteInteractive();
+ m_applet->frontend->Execute();
+ }
+}
+
+void ILibraryAppletAccessor::FrontendRequestExit() {
+ if (m_applet->frontend) {
+ m_applet->frontend->RequestExit();
+ }
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_accessor.h b/src/core/hle/service/am/service/library_applet_accessor.h
new file mode 100644
index 000000000..97d3b6c8a
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_accessor.h
@@ -0,0 +1,45 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class AppletDataBroker;
+struct Applet;
+class IStorage;
+
+class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
+public:
+ explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<AppletDataBroker> broker,
+ std::shared_ptr<Applet> applet);
+ ~ILibraryAppletAccessor();
+
+private:
+ Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result IsCompleted(Out<bool> out_is_completed);
+ Result GetResult(Out<Result> out_result);
+ Result PresetLibraryAppletGpuTimeSliceZero();
+ Result Start();
+ Result RequestExit();
+ Result Terminate();
+ Result PushInData(SharedPointer<IStorage> storage);
+ Result PopOutData(Out<SharedPointer<IStorage>> out_storage);
+ Result PushInteractiveInData(SharedPointer<IStorage> storage);
+ Result PopInteractiveOutData(Out<SharedPointer<IStorage>> out_storage);
+ Result GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetPopInteractiveOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetIndirectLayerConsumerHandle(Out<u64> out_handle);
+
+ void FrontendExecute();
+ void FrontendExecuteInteractive();
+ void FrontendRequestExit();
+
+ const std::shared_ptr<AppletDataBroker> m_broker;
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp
new file mode 100644
index 000000000..166637d60
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_creator.cpp
@@ -0,0 +1,268 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/settings.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/service/am/applet_data_broker.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/frontend/applets.h"
+#include "core/hle/service/am/library_applet_storage.h"
+#include "core/hle/service/am/service/library_applet_accessor.h"
+#include "core/hle/service/am/service/library_applet_creator.h"
+#include "core/hle/service/am/service/storage.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::AM {
+
+namespace {
+
+bool ShouldCreateGuestApplet(AppletId applet_id) {
+#define X(Name, name) \
+ if (applet_id == AppletId::Name && \
+ Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) { \
+ return false; \
+ }
+
+ X(Cabinet, cabinet)
+ X(Controller, controller)
+ X(DataErase, data_erase)
+ X(Error, error)
+ X(NetConnect, net_connect)
+ X(ProfileSelect, player_select)
+ X(SoftwareKeyboard, swkbd)
+ X(MiiEdit, mii_edit)
+ X(Web, web)
+ X(Shop, shop)
+ X(PhotoViewer, photo_viewer)
+ X(OfflineWeb, offline_web)
+ X(LoginShare, login_share)
+ X(WebAuth, wifi_web_auth)
+ X(MyPage, my_page)
+
+#undef X
+
+ return true;
+}
+
+AppletProgramId AppletIdToProgramId(AppletId applet_id) {
+ switch (applet_id) {
+ case AppletId::OverlayDisplay:
+ return AppletProgramId::OverlayDisplay;
+ case AppletId::QLaunch:
+ return AppletProgramId::QLaunch;
+ case AppletId::Starter:
+ return AppletProgramId::Starter;
+ case AppletId::Auth:
+ return AppletProgramId::Auth;
+ case AppletId::Cabinet:
+ return AppletProgramId::Cabinet;
+ case AppletId::Controller:
+ return AppletProgramId::Controller;
+ case AppletId::DataErase:
+ return AppletProgramId::DataErase;
+ case AppletId::Error:
+ return AppletProgramId::Error;
+ case AppletId::NetConnect:
+ return AppletProgramId::NetConnect;
+ case AppletId::ProfileSelect:
+ return AppletProgramId::ProfileSelect;
+ case AppletId::SoftwareKeyboard:
+ return AppletProgramId::SoftwareKeyboard;
+ case AppletId::MiiEdit:
+ return AppletProgramId::MiiEdit;
+ case AppletId::Web:
+ return AppletProgramId::Web;
+ case AppletId::Shop:
+ return AppletProgramId::Shop;
+ case AppletId::PhotoViewer:
+ return AppletProgramId::PhotoViewer;
+ case AppletId::Settings:
+ return AppletProgramId::Settings;
+ case AppletId::OfflineWeb:
+ return AppletProgramId::OfflineWeb;
+ case AppletId::LoginShare:
+ return AppletProgramId::LoginShare;
+ case AppletId::WebAuth:
+ return AppletProgramId::WebAuth;
+ case AppletId::MyPage:
+ return AppletProgramId::MyPage;
+ default:
+ return static_cast<AppletProgramId>(0);
+ }
+}
+
+std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
+ std::shared_ptr<Applet> caller_applet,
+ AppletId applet_id,
+ LibraryAppletMode mode) {
+ const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
+ if (program_id == 0) {
+ // Unknown applet
+ return {};
+ }
+
+ // TODO: enable other versions of applets
+ enum : u8 {
+ Firmware1400 = 14,
+ Firmware1500 = 15,
+ Firmware1600 = 16,
+ Firmware1700 = 17,
+ };
+
+ auto process = std::make_unique<Process>(system);
+ if (!process->Initialize(program_id, Firmware1400, Firmware1700)) {
+ // Couldn't initialize the guest process
+ return {};
+ }
+
+ const auto applet = std::make_shared<Applet>(system, std::move(process));
+ applet->program_id = program_id;
+ applet->applet_id = applet_id;
+ applet->type = AppletType::LibraryApplet;
+ applet->library_applet_mode = mode;
+
+ // Set focus state
+ switch (mode) {
+ case LibraryAppletMode::AllForeground:
+ case LibraryAppletMode::NoUi:
+ case LibraryAppletMode::PartialForeground:
+ case LibraryAppletMode::PartialForegroundIndirectDisplay:
+ applet->hid_registration.EnableAppletToGetInput(true);
+ applet->focus_state = FocusState::InFocus;
+ applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
+ break;
+ case LibraryAppletMode::AllForegroundInitiallyHidden:
+ applet->hid_registration.EnableAppletToGetInput(false);
+ applet->focus_state = FocusState::NotInFocus;
+ applet->system_buffer_manager.SetWindowVisibility(false);
+ applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
+ break;
+ }
+
+ auto broker = std::make_shared<AppletDataBroker>(system);
+ applet->caller_applet = caller_applet;
+ applet->caller_applet_broker = broker;
+
+ system.GetAppletManager().InsertApplet(applet);
+
+ return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
+}
+
+std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
+ std::shared_ptr<Applet> caller_applet,
+ AppletId applet_id,
+ LibraryAppletMode mode) {
+ const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
+
+ auto process = std::make_unique<Process>(system);
+ auto applet = std::make_shared<Applet>(system, std::move(process));
+ applet->program_id = program_id;
+ applet->applet_id = applet_id;
+ applet->type = AppletType::LibraryApplet;
+ applet->library_applet_mode = mode;
+
+ auto storage = std::make_shared<AppletDataBroker>(system);
+ applet->caller_applet = caller_applet;
+ applet->caller_applet_broker = storage;
+ applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
+
+ return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
+}
+
+} // namespace
+
+ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "ILibraryAppletCreator"}, m_applet{std::move(applet)} {
+ static const FunctionInfo functions[] = {
+ {0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
+ {1, nullptr, "TerminateAllLibraryApplets"},
+ {2, nullptr, "AreAnyLibraryAppletsLeft"},
+ {10, D<&ILibraryAppletCreator::CreateStorage>, "CreateStorage"},
+ {11, D<&ILibraryAppletCreator::CreateTransferMemoryStorage>, "CreateTransferMemoryStorage"},
+ {12, D<&ILibraryAppletCreator::CreateHandleStorage>, "CreateHandleStorage"},
+ };
+ RegisterHandlers(functions);
+}
+
+ILibraryAppletCreator::~ILibraryAppletCreator() = default;
+
+Result ILibraryAppletCreator::CreateLibraryApplet(
+ Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
+ LibraryAppletMode library_applet_mode) {
+ LOG_DEBUG(Service_AM, "called with applet_id={} applet_mode={}", applet_id,
+ library_applet_mode);
+
+ std::shared_ptr<ILibraryAppletAccessor> library_applet;
+ if (ShouldCreateGuestApplet(applet_id)) {
+ library_applet = CreateGuestApplet(system, m_applet, applet_id, library_applet_mode);
+ }
+ if (!library_applet) {
+ library_applet = CreateFrontendApplet(system, m_applet, applet_id, library_applet_mode);
+ }
+ if (!library_applet) {
+ LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
+ R_THROW(ResultUnknown);
+ }
+
+ // Applet is created, can now be launched.
+ m_applet->library_applet_launchable_event.Signal();
+ *out_library_applet_accessor = library_applet;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletCreator::CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size) {
+ LOG_DEBUG(Service_AM, "called, size={}", size);
+
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ R_THROW(ResultUnknown);
+ }
+
+ *out_storage = std::make_shared<IStorage>(system, AM::CreateStorage(std::vector<u8>(size)));
+ R_SUCCEED();
+}
+
+Result ILibraryAppletCreator::CreateTransferMemoryStorage(
+ Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,
+ InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
+ LOG_DEBUG(Service_AM, "called, is_writable={} size={}", is_writable, size);
+
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ R_THROW(ResultUnknown);
+ }
+
+ if (!transfer_memory_handle) {
+ LOG_ERROR(Service_AM, "transfer_memory_handle is null");
+ R_THROW(ResultUnknown);
+ }
+
+ *out_storage = std::make_shared<IStorage>(
+ system, AM::CreateTransferMemoryStorage(transfer_memory_handle->GetOwner()->GetMemory(),
+ transfer_memory_handle.Get(), is_writable, size));
+ R_SUCCEED();
+}
+
+Result ILibraryAppletCreator::CreateHandleStorage(
+ Out<SharedPointer<IStorage>> out_storage, s64 size,
+ InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
+ LOG_DEBUG(Service_AM, "called, size={}", size);
+
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ R_THROW(ResultUnknown);
+ }
+
+ if (!transfer_memory_handle) {
+ LOG_ERROR(Service_AM, "transfer_memory_handle is null");
+ R_THROW(ResultUnknown);
+ }
+
+ *out_storage = std::make_shared<IStorage>(
+ system, AM::CreateHandleStorage(transfer_memory_handle->GetOwner()->GetMemory(),
+ transfer_memory_handle.Get(), size));
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_creator.h b/src/core/hle/service/am/service/library_applet_creator.h
new file mode 100644
index 000000000..fe6d40eb3
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_creator.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+class ILibraryAppletAccessor;
+class IStorage;
+
+class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
+public:
+ explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet);
+ ~ILibraryAppletCreator() override;
+
+private:
+ Result CreateLibraryApplet(
+ Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
+ LibraryAppletMode library_applet_mode);
+ Result CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size);
+ Result CreateTransferMemoryStorage(
+ Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,
+ InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
+ Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size,
+ InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
+
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_proxy.cpp b/src/core/hle/service/am/service/library_applet_proxy.cpp
new file mode 100644
index 000000000..bcb44a71c
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_proxy.cpp
@@ -0,0 +1,134 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/applet_common_functions.h"
+#include "core/hle/service/am/service/audio_controller.h"
+#include "core/hle/service/am/service/common_state_getter.h"
+#include "core/hle/service/am/service/debug_functions.h"
+#include "core/hle/service/am/service/display_controller.h"
+#include "core/hle/service/am/service/global_state_controller.h"
+#include "core/hle/service/am/service/home_menu_functions.h"
+#include "core/hle/service/am/service/library_applet_creator.h"
+#include "core/hle/service/am/service/library_applet_proxy.h"
+#include "core/hle/service/am/service/library_applet_self_accessor.h"
+#include "core/hle/service/am/service/process_winding_controller.h"
+#include "core/hle/service/am/service/self_controller.h"
+#include "core/hle/service/am/service/window_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process,
+ Nvnflinger::Nvnflinger& nvnflinger)
+ : ServiceFramework{system_, "ILibraryAppletProxy"},
+ m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
+ {1, D<&ILibraryAppletProxy::GetSelfController>, "GetSelfController"},
+ {2, D<&ILibraryAppletProxy::GetWindowController>, "GetWindowController"},
+ {3, D<&ILibraryAppletProxy::GetAudioController>, "GetAudioController"},
+ {4, D<&ILibraryAppletProxy::GetDisplayController>, "GetDisplayController"},
+ {10, D<&ILibraryAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
+ {11, D<&ILibraryAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
+ {20, D<&ILibraryAppletProxy::OpenLibraryAppletSelfAccessor>, "OpenLibraryAppletSelfAccessor"},
+ {21, D<&ILibraryAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
+ {22, D<&ILibraryAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"},
+ {23, D<&ILibraryAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
+ {1000, D<&ILibraryAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ILibraryAppletProxy::~ILibraryAppletProxy() = default;
+
+Result ILibraryAppletProxy::GetAudioController(
+ Out<SharedPointer<IAudioController>> out_audio_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_audio_controller = std::make_shared<IAudioController>(system);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetDisplayController(
+ Out<SharedPointer<IDisplayController>> out_display_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetProcessWindingController(
+ Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetDebugFunctions(
+ Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_debug_functions = std::make_shared<IDebugFunctions>(system);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetWindowController(
+ Out<SharedPointer<IWindowController>> out_window_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_window_controller = std::make_shared<IWindowController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetSelfController(
+ Out<SharedPointer<ISelfController>> out_self_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_self_controller =
+ std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetCommonStateGetter(
+ Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetLibraryAppletCreator(
+ Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(
+ Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_library_applet_self_accessor =
+ std::make_shared<ILibraryAppletSelfAccessor>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetAppletCommonFunctions(
+ Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetHomeMenuFunctions(
+ Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletProxy::GetGlobalStateController(
+ Out<SharedPointer<IGlobalStateController>> out_global_state_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_global_state_controller = std::make_shared<IGlobalStateController>(system);
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_proxy.h b/src/core/hle/service/am/service/library_applet_proxy.h
new file mode 100644
index 000000000..23e64e295
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_proxy.h
@@ -0,0 +1,55 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+class IAppletCommonFunctions;
+class IAudioController;
+class ICommonStateGetter;
+class IDebugFunctions;
+class IDisplayController;
+class IHomeMenuFunctions;
+class IGlobalStateController;
+class ILibraryAppletCreator;
+class ILibraryAppletSelfAccessor;
+class IProcessWindingController;
+class ISelfController;
+class IWindowController;
+
+class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
+public:
+ explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
+ ~ILibraryAppletProxy();
+
+private:
+ Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
+ Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
+ Result GetProcessWindingController(
+ Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
+ Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
+ Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
+ Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
+ Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
+ Result GetLibraryAppletCreator(
+ Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
+ Result OpenLibraryAppletSelfAccessor(
+ Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor);
+ Result GetAppletCommonFunctions(
+ Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
+ Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions);
+ Result GetGlobalStateController(
+ Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
+
+ Nvnflinger::Nvnflinger& m_nvnflinger;
+ Kernel::KProcess* const m_process;
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.cpp b/src/core/hle/service/am/service/library_applet_self_accessor.cpp
new file mode 100644
index 000000000..7a3a86e88
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp
@@ -0,0 +1,322 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core_timing.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/hle/service/acc/profile_manager.h"
+#include "core/hle/service/am/applet_data_broker.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/frontend/applets.h"
+#include "core/hle/service/am/service/library_applet_self_accessor.h"
+#include "core/hle/service/am/service/storage.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/glue/glue_manager.h"
+#include "core/hle/service/ns/ns.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::AM {
+
+namespace {
+
+AppletIdentityInfo GetCallerIdentity(Applet& applet) {
+ if (const auto caller_applet = applet.caller_applet.lock(); caller_applet) {
+ // TODO: is this actually the application ID?
+ return {
+ .applet_id = caller_applet->applet_id,
+ .application_id = caller_applet->program_id,
+ };
+ } else {
+ return {
+ .applet_id = AppletId::QLaunch,
+ .application_id = 0x0100000000001000ull,
+ };
+ }
+}
+
+} // namespace
+
+ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
+ std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, m_applet{std::move(applet)},
+ m_broker{m_applet->caller_applet_broker} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ILibraryAppletSelfAccessor::PopInData>, "PopInData"},
+ {1, D<&ILibraryAppletSelfAccessor::PushOutData>, "PushOutData"},
+ {2, D<&ILibraryAppletSelfAccessor::PopInteractiveInData>, "PopInteractiveInData"},
+ {3, D<&ILibraryAppletSelfAccessor::PushInteractiveOutData>, "PushInteractiveOutData"},
+ {5, D<&ILibraryAppletSelfAccessor::GetPopInDataEvent>, "GetPopInDataEvent"},
+ {6, D<&ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent>, "GetPopInteractiveInDataEvent"},
+ {10, D<&ILibraryAppletSelfAccessor::ExitProcessAndReturn>, "ExitProcessAndReturn"},
+ {11, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"},
+ {12, D<&ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo>, "GetMainAppletIdentityInfo"},
+ {13, D<&ILibraryAppletSelfAccessor::CanUseApplicationCore>, "CanUseApplicationCore"},
+ {14, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo>, "GetCallerAppletIdentityInfo"},
+ {15, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty>, "GetMainAppletApplicationControlProperty"},
+ {16, D<&ILibraryAppletSelfAccessor::GetMainAppletStorageId>, "GetMainAppletStorageId"},
+ {17, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack>, "GetCallerAppletIdentityInfoStack"},
+ {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
+ {19, D<&ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout>, "GetDesirableKeyboardLayout"},
+ {20, nullptr, "PopExtraStorage"},
+ {25, nullptr, "GetPopExtraStorageEvent"},
+ {30, nullptr, "UnpopInData"},
+ {31, nullptr, "UnpopExtraStorage"},
+ {40, nullptr, "GetIndirectLayerProducerHandle"},
+ {50, D<&ILibraryAppletSelfAccessor::ReportVisibleError>, "ReportVisibleError"},
+ {51, D<&ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext>, "ReportVisibleErrorWithErrorContext"},
+ {60, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage>, "GetMainAppletApplicationDesiredLanguage"},
+ {70, D<&ILibraryAppletSelfAccessor::GetCurrentApplicationId>, "GetCurrentApplicationId"},
+ {80, nullptr, "RequestExitToSelf"},
+ {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
+ {100, nullptr, "CreateGameMovieTrimmer"},
+ {101, nullptr, "ReserveResourceForMovieOperation"},
+ {102, nullptr, "UnreserveResourceForMovieOperation"},
+ {110, D<&ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers>, "GetMainAppletAvailableUsers"},
+ {120, nullptr, "GetLaunchStorageInfoForDebug"},
+ {130, nullptr, "GetGpuErrorDetectedSystemEvent"},
+ {140, nullptr, "SetApplicationMemoryReservation"},
+ {150, D<&ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually>, "ShouldSetGpuTimeSliceManually"},
+ {160, D<&ILibraryAppletSelfAccessor::Cmd160>, "Cmd160"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+}
+
+ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
+
+Result ILibraryAppletSelfAccessor::PopInData(Out<SharedPointer<IStorage>> out_storage) {
+ LOG_INFO(Service_AM, "called");
+ R_RETURN(m_broker->GetInData().Pop(out_storage));
+}
+
+Result ILibraryAppletSelfAccessor::PushOutData(SharedPointer<IStorage> storage) {
+ LOG_INFO(Service_AM, "called");
+ m_broker->GetOutData().Push(storage);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage) {
+ LOG_INFO(Service_AM, "called");
+ R_RETURN(m_broker->GetInteractiveInData().Pop(out_storage));
+}
+
+Result ILibraryAppletSelfAccessor::PushInteractiveOutData(SharedPointer<IStorage> storage) {
+ LOG_INFO(Service_AM, "called");
+ m_broker->GetInteractiveOutData().Push(storage);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetPopInDataEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_AM, "called");
+ *out_event = m_broker->GetInData().GetEvent();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_AM, "called");
+ *out_event = m_broker->GetInteractiveInData().GetEvent();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetLibraryAppletInfo(
+ Out<LibraryAppletInfo> out_library_applet_info) {
+ LOG_INFO(Service_AM, "called");
+ *out_library_applet_info = {
+ .applet_id = m_applet->applet_id,
+ .library_applet_mode = m_applet->library_applet_mode,
+ };
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(
+ Out<AppletIdentityInfo> out_identity_info) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_identity_info = {
+ .applet_id = AppletId::QLaunch,
+ .application_id = 0x0100000000001000ull,
+ };
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::CanUseApplicationCore(Out<bool> out_can_use_application_core) {
+ // TODO: This appears to read the NPDM from state and check the core mask of the applet.
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_can_use_application_core = false;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty(
+ OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ // TODO: this should be the main applet, not the caller applet
+ const auto application = GetCallerIdentity(*m_applet);
+ std::vector<u8> nacp;
+ const auto result =
+ system.GetARPManager().GetControlProperty(&nacp, application.application_id);
+
+ if (R_SUCCEEDED(result)) {
+ std::memcpy(out_nacp->data(), nacp.data(), std::min(nacp.size(), out_nacp->size()));
+ }
+
+ R_RETURN(result);
+}
+
+Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id) {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+ *out_storage_id = FileSys::StorageId::NandUser;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() {
+ LOG_INFO(Service_AM, "called");
+ system.GetAppletManager().TerminateAndRemoveApplet(m_applet->aruid);
+ m_broker->SignalCompletion();
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(
+ Out<AppletIdentityInfo> out_identity_info) {
+ LOG_INFO(Service_AM, "called");
+ *out_identity_info = GetCallerIdentity(*m_applet);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack(
+ Out<s32> out_count, OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info) {
+ LOG_INFO(Service_AM, "called");
+
+ std::shared_ptr<Applet> applet = m_applet;
+ *out_count = 0;
+
+ do {
+ if (*out_count >= static_cast<s32>(out_identity_info.size())) {
+ break;
+ }
+ out_identity_info[(*out_count)++] = GetCallerIdentity(*applet);
+ } while ((applet = applet->caller_applet.lock()));
+
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(Out<u32> out_desirable_layout) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_desirable_layout = 0;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::ReportVisibleError(ErrorCode error_code) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category,
+ error_code.number);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext(
+ ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category,
+ error_code.number);
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
+ Out<u64> out_desired_language) {
+ // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
+ // FIXME: all of this stuff belongs to ns
+ auto identity = GetCallerIdentity(*m_applet);
+
+ // TODO(bunnei): This should be configurable
+ LOG_DEBUG(Service_AM, "called");
+
+ // Get supported languages from NACP, if possible
+ // Default to 0 (all languages supported)
+ u32 supported_languages = 0;
+
+ const auto res = [this, identity] {
+ const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ auto metadata = pm.GetControlMetadata();
+ if (metadata.first != nullptr) {
+ return metadata;
+ }
+
+ const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
+ system.GetFileSystemController(),
+ system.GetContentProvider()};
+ return pm_update.GetControlMetadata();
+ }();
+
+ if (res.first != nullptr) {
+ supported_languages = res.first->GetSupportedLanguages();
+ }
+
+ // Call IApplicationManagerInterface implementation.
+ auto& service_manager = system.ServiceManager();
+ auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
+ auto app_man = ns_am2->GetApplicationManagerInterface();
+
+ // Get desired application language
+ u8 desired_language{};
+ R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
+
+ // Convert to settings language code.
+ u64 language_code{};
+ R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language));
+
+ LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
+
+ *out_desired_language = language_code;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_application_id) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ // TODO: this should be the main applet, not the caller applet
+ const auto main_applet = GetCallerIdentity(*m_applet);
+ *out_application_id = main_applet.application_id;
+
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(
+ Out<bool> out_no_users_available, Out<s32> out_users_count,
+ OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) {
+ const Service::Account::ProfileManager manager{};
+
+ *out_no_users_available = true;
+ *out_users_count = -1;
+
+ LOG_INFO(Service_AM, "called");
+
+ if (manager.GetUserCount() > 0) {
+ *out_no_users_available = false;
+ *out_users_count = static_cast<s32>(manager.GetUserCount());
+
+ const auto users = manager.GetAllUsers();
+ for (size_t i = 0; i < users.size() && i < out_users.size(); i++) {
+ out_users[i] = users[i];
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(
+ Out<bool> out_should_set_gpu_time_slice_manually) {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+ *out_should_set_gpu_time_slice_manually = false;
+ R_SUCCEED();
+}
+
+Result ILibraryAppletSelfAccessor::Cmd160(Out<u64> out_unknown0) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ *out_unknown0 = 0;
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.h b/src/core/hle/service/am/service/library_applet_self_accessor.h
new file mode 100644
index 000000000..a9743569f
--- /dev/null
+++ b/src/core/hle/service/am/service/library_applet_self_accessor.h
@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/uuid.h"
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace FileSys {
+enum class StorageId : u8;
+}
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::AM {
+
+class AppletDataBroker;
+struct Applet;
+class IStorage;
+
+struct LibraryAppletInfo {
+ AppletId applet_id;
+ LibraryAppletMode library_applet_mode;
+};
+static_assert(sizeof(LibraryAppletInfo) == 0x8, "LibraryAppletInfo has incorrect size.");
+
+struct ErrorCode {
+ u32 category;
+ u32 number;
+};
+static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size.");
+
+struct ErrorContext {
+ u8 type;
+ INSERT_PADDING_BYTES_NOINIT(0x7);
+ std::array<u8, 0x1f4> data;
+ Result result;
+};
+static_assert(sizeof(ErrorContext) == 0x200, "ErrorContext has incorrect size.");
+
+class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
+public:
+ explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
+ ~ILibraryAppletSelfAccessor() override;
+
+private:
+ Result PopInData(Out<SharedPointer<IStorage>> out_storage);
+ Result PushOutData(SharedPointer<IStorage> storage);
+ Result PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage);
+ Result PushInteractiveOutData(SharedPointer<IStorage> storage);
+ Result GetPopInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetPopInteractiveInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetLibraryAppletInfo(Out<LibraryAppletInfo> out_library_applet_info);
+ Result GetMainAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info);
+ Result CanUseApplicationCore(Out<bool> out_can_use_application_core);
+ Result GetMainAppletApplicationControlProperty(
+ OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp);
+ Result GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id);
+ Result ExitProcessAndReturn();
+ Result GetCallerAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info);
+ Result GetCallerAppletIdentityInfoStack(
+ Out<s32> out_count,
+ OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info);
+ Result GetDesirableKeyboardLayout(Out<u32> out_desirable_layout);
+ Result ReportVisibleError(ErrorCode error_code);
+ Result ReportVisibleErrorWithErrorContext(
+ ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context);
+ Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language);
+ Result GetCurrentApplicationId(Out<u64> out_application_id);
+ Result GetMainAppletAvailableUsers(Out<bool> out_no_users_available, Out<s32> out_users_count,
+ OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users);
+ Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually);
+ Result Cmd160(Out<u64> out_unknown0);
+
+ const std::shared_ptr<Applet> m_applet;
+ const std::shared_ptr<AppletDataBroker> m_broker;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/lock_accessor.cpp b/src/core/hle/service/am/service/lock_accessor.cpp
new file mode 100644
index 000000000..8e556fdd6
--- /dev/null
+++ b/src/core/hle/service/am/service/lock_accessor.cpp
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/lock_accessor.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+ILockAccessor::ILockAccessor(Core::System& system_)
+ : ServiceFramework{system_, "ILockAccessor"}, m_context{system_, "ILockAccessor"},
+ m_event{m_context} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, D<&ILockAccessor::TryLock>, "TryLock"},
+ {2, D<&ILockAccessor::Unlock>, "Unlock"},
+ {3, D<&ILockAccessor::GetEvent>, "GetEvent"},
+ {4, D<&ILockAccessor::IsLocked>, "IsLocked"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+
+ m_event.Signal();
+}
+
+ILockAccessor::~ILockAccessor() = default;
+
+Result ILockAccessor::TryLock(Out<bool> out_is_locked,
+ OutCopyHandle<Kernel::KReadableEvent> out_handle,
+ bool return_handle) {
+ LOG_INFO(Service_AM, "called, return_handle={}", return_handle);
+
+ {
+ std::scoped_lock lk{m_mutex};
+ if (m_is_locked) {
+ *out_is_locked = false;
+ } else {
+ m_is_locked = true;
+ *out_is_locked = true;
+ }
+ }
+
+ if (return_handle) {
+ *out_handle = m_event.GetHandle();
+ }
+
+ R_SUCCEED();
+}
+
+Result ILockAccessor::Unlock() {
+ LOG_INFO(Service_AM, "called");
+
+ {
+ std::scoped_lock lk{m_mutex};
+ m_is_locked = false;
+ }
+
+ m_event.Signal();
+ R_SUCCEED();
+}
+
+Result ILockAccessor::GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle) {
+ LOG_INFO(Service_AM, "called");
+ *out_handle = m_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result ILockAccessor::IsLocked(Out<bool> out_is_locked) {
+ LOG_INFO(Service_AM, "called");
+ std::scoped_lock lk{m_mutex};
+ *out_is_locked = m_is_locked;
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/lock_accessor.h b/src/core/hle/service/am/service/lock_accessor.h
new file mode 100644
index 000000000..9bfb5c050
--- /dev/null
+++ b/src/core/hle/service/am/service/lock_accessor.h
@@ -0,0 +1,32 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class ILockAccessor final : public ServiceFramework<ILockAccessor> {
+public:
+ explicit ILockAccessor(Core::System& system_);
+ ~ILockAccessor() override;
+
+private:
+ Result TryLock(Out<bool> out_is_locked, OutCopyHandle<Kernel::KReadableEvent> out_handle,
+ bool return_handle);
+ Result Unlock();
+ Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle);
+ Result IsLocked(Out<bool> out_is_locked);
+
+private:
+ KernelHelpers::ServiceContext m_context;
+ Event m_event;
+ std::mutex m_mutex{};
+ bool m_is_locked{};
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/process_winding_controller.cpp b/src/core/hle/service/am/service/process_winding_controller.cpp
new file mode 100644
index 000000000..10df830d7
--- /dev/null
+++ b/src/core/hle/service/am/service/process_winding_controller.cpp
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/frontend/applets.h"
+#include "core/hle/service/am/service/library_applet_accessor.h"
+#include "core/hle/service/am/service/process_winding_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IProcessWindingController::IProcessWindingController(Core::System& system_,
+ std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "IProcessWindingController"}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"},
+ {11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"},
+ {21, nullptr, "PushContext"},
+ {22, nullptr, "PopContext"},
+ {23, nullptr, "CancelWindingReservation"},
+ {30, nullptr, "WindAndDoReserved"},
+ {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
+ {41, nullptr, "ReserveToStartAndWait"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IProcessWindingController::~IProcessWindingController() = default;
+
+Result IProcessWindingController::GetLaunchReason(
+ Out<AppletProcessLaunchReason> out_launch_reason) {
+ LOG_INFO(Service_AM, "called");
+ *out_launch_reason = m_applet->launch_reason;
+ R_SUCCEED();
+}
+
+Result IProcessWindingController::OpenCallingLibraryApplet(
+ Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet) {
+ LOG_INFO(Service_AM, "called");
+
+ const auto caller_applet = m_applet->caller_applet.lock();
+ if (caller_applet == nullptr) {
+ LOG_ERROR(Service_AM, "No caller applet available");
+ R_THROW(ResultUnknown);
+ }
+
+ *out_calling_library_applet = std::make_shared<ILibraryAppletAccessor>(
+ system, m_applet->caller_applet_broker, caller_applet);
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/process_winding_controller.h b/src/core/hle/service/am/service/process_winding_controller.h
new file mode 100644
index 000000000..4408af1f1
--- /dev/null
+++ b/src/core/hle/service/am/service/process_winding_controller.h
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+class ILibraryAppletAccessor;
+
+class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
+public:
+ explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_);
+ ~IProcessWindingController() override;
+
+private:
+ Result GetLaunchReason(Out<AppletProcessLaunchReason> out_launch_reason);
+ Result OpenCallingLibraryApplet(
+ Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet);
+
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/self_controller.cpp b/src/core/hle/service/am/service/self_controller.cpp
new file mode 100644
index 000000000..5c4c13de1
--- /dev/null
+++ b/src/core/hle/service/am/service/self_controller.cpp
@@ -0,0 +1,393 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/hle/result.h"
+#include "core/hle/service/am/am_results.h"
+#include "core/hle/service/am/frontend/applets.h"
+#include "core/hle/service/am/service/self_controller.h"
+#include "core/hle/service/caps/caps_su.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/vi/vi_results.h"
+
+namespace Service::AM {
+
+ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
+ : ServiceFramework{system_, "ISelfController"},
+ m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ISelfController::Exit>, "Exit"},
+ {1, D<&ISelfController::LockExit>, "LockExit"},
+ {2, D<&ISelfController::UnlockExit>, "UnlockExit"},
+ {3, D<&ISelfController::EnterFatalSection>, "EnterFatalSection"},
+ {4, D<&ISelfController::LeaveFatalSection>, "LeaveFatalSection"},
+ {9, D<&ISelfController::GetLibraryAppletLaunchableEvent>, "GetLibraryAppletLaunchableEvent"},
+ {10, D<&ISelfController::SetScreenShotPermission>, "SetScreenShotPermission"},
+ {11, D<&ISelfController::SetOperationModeChangedNotification>, "SetOperationModeChangedNotification"},
+ {12, D<&ISelfController::SetPerformanceModeChangedNotification>, "SetPerformanceModeChangedNotification"},
+ {13, D<&ISelfController::SetFocusHandlingMode>, "SetFocusHandlingMode"},
+ {14, D<&ISelfController::SetRestartMessageEnabled>, "SetRestartMessageEnabled"},
+ {15, D<&ISelfController::SetScreenShotAppletIdentityInfo>, "SetScreenShotAppletIdentityInfo"},
+ {16, D<&ISelfController::SetOutOfFocusSuspendingEnabled>, "SetOutOfFocusSuspendingEnabled"},
+ {17, nullptr, "SetControllerFirmwareUpdateSection"},
+ {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
+ {19, D<&ISelfController::SetAlbumImageOrientation>, "SetAlbumImageOrientation"},
+ {20, nullptr, "SetDesirableKeyboardLayout"},
+ {21, nullptr, "GetScreenShotProgramId"},
+ {40, D<&ISelfController::CreateManagedDisplayLayer>, "CreateManagedDisplayLayer"},
+ {41, D<&ISelfController::IsSystemBufferSharingEnabled>, "IsSystemBufferSharingEnabled"},
+ {42, D<&ISelfController::GetSystemSharedLayerHandle>, "GetSystemSharedLayerHandle"},
+ {43, D<&ISelfController::GetSystemSharedBufferHandle>, "GetSystemSharedBufferHandle"},
+ {44, D<&ISelfController::CreateManagedDisplaySeparableLayer>, "CreateManagedDisplaySeparableLayer"},
+ {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
+ {46, nullptr, "SetRecordingLayerCompositionEnabled"},
+ {50, D<&ISelfController::SetHandlesRequestToDisplay>, "SetHandlesRequestToDisplay"},
+ {51, D<&ISelfController::ApproveToDisplay>, "ApproveToDisplay"},
+ {60, D<&ISelfController::OverrideAutoSleepTimeAndDimmingTime>, "OverrideAutoSleepTimeAndDimmingTime"},
+ {61, D<&ISelfController::SetMediaPlaybackState>, "SetMediaPlaybackState"},
+ {62, D<&ISelfController::SetIdleTimeDetectionExtension>, "SetIdleTimeDetectionExtension"},
+ {63, D<&ISelfController::GetIdleTimeDetectionExtension>, "GetIdleTimeDetectionExtension"},
+ {64, nullptr, "SetInputDetectionSourceSet"},
+ {65, D<&ISelfController::ReportUserIsActive>, "ReportUserIsActive"},
+ {66, nullptr, "GetCurrentIlluminance"},
+ {67, nullptr, "IsIlluminanceAvailable"},
+ {68, D<&ISelfController::SetAutoSleepDisabled>, "SetAutoSleepDisabled"},
+ {69, D<&ISelfController::IsAutoSleepDisabled>, "IsAutoSleepDisabled"},
+ {70, nullptr, "ReportMultimediaError"},
+ {71, nullptr, "GetCurrentIlluminanceEx"},
+ {72, D<&ISelfController::SetInputDetectionPolicy>, "SetInputDetectionPolicy"},
+ {80, nullptr, "SetWirelessPriorityMode"},
+ {90, D<&ISelfController::GetAccumulatedSuspendedTickValue>, "GetAccumulatedSuspendedTickValue"},
+ {91, D<&ISelfController::GetAccumulatedSuspendedTickChangedEvent>, "GetAccumulatedSuspendedTickChangedEvent"},
+ {100, D<&ISelfController::SetAlbumImageTakenNotificationEnabled>, "SetAlbumImageTakenNotificationEnabled"},
+ {110, nullptr, "SetApplicationAlbumUserData"},
+ {120, D<&ISelfController::SaveCurrentScreenshot>, "SaveCurrentScreenshot"},
+ {130, D<&ISelfController::SetRecordVolumeMuted>, "SetRecordVolumeMuted"},
+ {1000, nullptr, "GetDebugStorageChannel"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ISelfController::~ISelfController() = default;
+
+Result ISelfController::Exit() {
+ LOG_DEBUG(Service_AM, "called");
+
+ // TODO
+ system.Exit();
+
+ R_SUCCEED();
+}
+
+Result ISelfController::LockExit() {
+ LOG_DEBUG(Service_AM, "called");
+
+ system.SetExitLocked(true);
+
+ R_SUCCEED();
+}
+
+Result ISelfController::UnlockExit() {
+ LOG_DEBUG(Service_AM, "called");
+
+ system.SetExitLocked(false);
+
+ if (system.GetExitRequested()) {
+ system.Exit();
+ }
+
+ R_SUCCEED();
+}
+
+Result ISelfController::EnterFatalSection() {
+ std::scoped_lock lk{m_applet->lock};
+
+ m_applet->fatal_section_count++;
+ LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", m_applet->fatal_section_count);
+
+ R_SUCCEED();
+}
+
+Result ISelfController::LeaveFatalSection() {
+ LOG_DEBUG(Service_AM, "called");
+
+ // Entry and exit of fatal sections must be balanced.
+ std::scoped_lock lk{m_applet->lock};
+ R_UNLESS(m_applet->fatal_section_count > 0, AM::ResultFatalSectionCountImbalance);
+ m_applet->fatal_section_count--;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::GetLibraryAppletLaunchableEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ m_applet->library_applet_launchable_event.Signal();
+ *out_event = m_applet->library_applet_launchable_event.GetHandle();
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetScreenShotPermission(ScreenshotPermission screen_shot_permission) {
+ LOG_DEBUG(Service_AM, "called, permission={}", screen_shot_permission);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->screenshot_permission = screen_shot_permission;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetOperationModeChangedNotification(bool enabled) {
+ LOG_INFO(Service_AM, "called, enabled={}", enabled);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->operation_mode_changed_notification_enabled = enabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetPerformanceModeChangedNotification(bool enabled) {
+ LOG_INFO(Service_AM, "called, enabled={}", enabled);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->performance_mode_changed_notification_enabled = enabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetFocusHandlingMode(bool notify, bool background, bool suspend) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, notify={} background={} suspend={}", notify,
+ background, suspend);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->focus_handling_mode = {notify, background, suspend};
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetRestartMessageEnabled(bool enabled) {
+ LOG_INFO(Service_AM, "called, enabled={}", enabled);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->restart_message_enabled = enabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetScreenShotAppletIdentityInfo(
+ AppletIdentityInfo screen_shot_applet_identity_info) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->screen_shot_identity = screen_shot_applet_identity_info;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetOutOfFocusSuspendingEnabled(bool enabled) {
+ LOG_INFO(Service_AM, "called, enabled={}", enabled);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->out_of_focus_suspension_enabled = enabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetAlbumImageOrientation(
+ Capture::AlbumImageOrientation album_image_orientation) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", album_image_orientation);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->album_image_orientation = album_image_orientation;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::IsSystemBufferSharingEnabled() {
+ LOG_INFO(Service_AM, "called");
+ R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize(
+ &m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode));
+ R_THROW(VI::ResultOperationFailed);
+}
+
+Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ R_TRY(this->IsSystemBufferSharingEnabled());
+
+ u64 layer_id;
+ m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id);
+ R_SUCCEED();
+}
+
+Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+
+ R_TRY(this->IsSystemBufferSharingEnabled());
+
+ m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id);
+ R_SUCCEED();
+}
+
+Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) {
+ LOG_INFO(Service_AM, "called");
+
+ m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
+ m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id);
+
+ R_SUCCEED();
+}
+
+Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
+ Out<u64> out_recording_layer_id) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
+ m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id,
+ out_recording_layer_id);
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetHandlesRequestToDisplay(bool enable) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, enable={}", enable);
+ R_SUCCEED();
+}
+
+Result ISelfController::ApproveToDisplay() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result ISelfController::SetMediaPlaybackState(bool state) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, state={}", state);
+ R_SUCCEED();
+}
+
+Result ISelfController::OverrideAutoSleepTimeAndDimmingTime(s32 a, s32 b, s32 c, s32 d) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, a={}, b={}, c={}, d={}", a, b, c, d);
+ R_SUCCEED();
+}
+
+Result ISelfController::SetIdleTimeDetectionExtension(
+ IdleTimeDetectionExtension idle_time_detection_extension) {
+ LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", idle_time_detection_extension);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->idle_time_detection_extension = idle_time_detection_extension;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::GetIdleTimeDetectionExtension(
+ Out<IdleTimeDetectionExtension> out_idle_time_detection_extension) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ std::scoped_lock lk{m_applet->lock};
+ *out_idle_time_detection_extension = m_applet->idle_time_detection_extension;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::ReportUserIsActive() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result ISelfController::SetAutoSleepDisabled(bool is_auto_sleep_disabled) {
+ LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled);
+
+ // On the system itself, if the previous state of is_auto_sleep_disabled
+ // differed from the current value passed in, it'd signify the internal
+ // window manager to update (and also increment some statistics like update counts)
+ //
+ // It'd also indicate this change to an idle handling context.
+ //
+ // However, given we're emulating this behavior, most of this can be ignored
+ // and it's sufficient to simply set the member variable for querying via
+ // IsAutoSleepDisabled().
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->auto_sleep_disabled = is_auto_sleep_disabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::IsAutoSleepDisabled(Out<bool> out_is_auto_sleep_disabled) {
+ LOG_DEBUG(Service_AM, "called.");
+
+ std::scoped_lock lk{m_applet->lock};
+ *out_is_auto_sleep_disabled = m_applet->auto_sleep_disabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetInputDetectionPolicy(InputDetectionPolicy input_detection_policy) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result ISelfController::GetAccumulatedSuspendedTickValue(
+ Out<u64> out_accumulated_suspended_tick_value) {
+ LOG_DEBUG(Service_AM, "called.");
+
+ // This command returns the total number of system ticks since ISelfController creation
+ // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
+ // can just always return 0 ticks.
+ std::scoped_lock lk{m_applet->lock};
+ *out_accumulated_suspended_tick_value = m_applet->suspended_ticks;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::GetAccumulatedSuspendedTickChangedEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_AM, "called.");
+
+ *out_event = m_applet->accumulated_suspended_tick_changed_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result ISelfController::SetAlbumImageTakenNotificationEnabled(bool enabled) {
+ LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
+
+ // This service call sets an internal flag whether a notification is shown when an image is
+ // captured. Currently we do not support capturing images via the capture button, so this can be
+ // stubbed for now.
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->album_image_taken_notification_enabled = enabled;
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option) {
+ LOG_INFO(Service_AM, "called, report_option={}", album_report_option);
+
+ const auto screenshot_service =
+ system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
+ "caps:su");
+
+ if (screenshot_service) {
+ screenshot_service->CaptureAndSaveScreenshot(album_report_option);
+ }
+
+ R_SUCCEED();
+}
+
+Result ISelfController::SetRecordVolumeMuted(bool muted) {
+ LOG_WARNING(Service_AM, "(STUBBED) called. muted={}", muted);
+
+ std::scoped_lock lk{m_applet->lock};
+ m_applet->record_volume_muted = muted;
+
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/self_controller.h b/src/core/hle/service/am/service/self_controller.h
new file mode 100644
index 000000000..01fa381a3
--- /dev/null
+++ b/src/core/hle/service/am/service/self_controller.h
@@ -0,0 +1,72 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/am/am_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Capture {
+enum class AlbumImageOrientation;
+enum class AlbumReportOption;
+} // namespace Service::Capture
+
+namespace Service::AM {
+
+struct Applet;
+
+class ISelfController final : public ServiceFramework<ISelfController> {
+public:
+ explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
+ ~ISelfController() override;
+
+private:
+ Result Exit();
+ Result LockExit();
+ Result UnlockExit();
+ Result EnterFatalSection();
+ Result LeaveFatalSection();
+ Result GetLibraryAppletLaunchableEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result SetScreenShotPermission(ScreenshotPermission screen_shot_permission);
+ Result SetOperationModeChangedNotification(bool enabled);
+ Result SetPerformanceModeChangedNotification(bool enabled);
+ Result SetFocusHandlingMode(bool notify, bool background, bool suspend);
+ Result SetRestartMessageEnabled(bool enabled);
+ Result SetScreenShotAppletIdentityInfo(AppletIdentityInfo screen_shot_applet_identity_info);
+ Result SetOutOfFocusSuspendingEnabled(bool enabled);
+ Result SetAlbumImageOrientation(Capture::AlbumImageOrientation album_image_orientation);
+ Result IsSystemBufferSharingEnabled();
+ Result GetSystemSharedBufferHandle(Out<u64> out_buffer_id);
+ Result GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id);
+ Result CreateManagedDisplayLayer(Out<u64> out_layer_id);
+ Result CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
+ Out<u64> out_recording_layer_id);
+ Result SetHandlesRequestToDisplay(bool enable);
+ Result ApproveToDisplay();
+ Result SetMediaPlaybackState(bool state);
+ Result OverrideAutoSleepTimeAndDimmingTime(s32 a, s32 b, s32 c, s32 d);
+ Result SetIdleTimeDetectionExtension(IdleTimeDetectionExtension idle_time_detection_extension);
+ Result GetIdleTimeDetectionExtension(
+ Out<IdleTimeDetectionExtension> out_idle_time_detection_extension);
+ Result ReportUserIsActive();
+ Result SetAutoSleepDisabled(bool is_auto_sleep_disabled);
+ Result IsAutoSleepDisabled(Out<bool> out_is_auto_sleep_disabled);
+ Result SetInputDetectionPolicy(InputDetectionPolicy input_detection_policy);
+ Result GetAccumulatedSuspendedTickValue(Out<u64> out_accumulated_suspended_tick_value);
+ Result GetAccumulatedSuspendedTickChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result SetAlbumImageTakenNotificationEnabled(bool enabled);
+ Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
+ Result SetRecordVolumeMuted(bool muted);
+
+ Nvnflinger::Nvnflinger& m_nvnflinger;
+ Kernel::KProcess* const m_process;
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/storage.cpp b/src/core/hle/service/am/service/storage.cpp
new file mode 100644
index 000000000..25ee0afbd
--- /dev/null
+++ b/src/core/hle/service/am/service/storage.cpp
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/am_results.h"
+#include "core/hle/service/am/library_applet_storage.h"
+#include "core/hle/service/am/service/storage.h"
+#include "core/hle/service/am/service/storage_accessor.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl)
+ : ServiceFramework{system_, "IStorage"}, m_impl{std::move(impl)} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IStorage::Open>, "Open"},
+ {1, D<&IStorage::OpenTransferStorage>, "OpenTransferStorage"},
+ };
+
+ RegisterHandlers(functions);
+}
+
+IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
+ : IStorage(system_, CreateStorage(std::move(data))) {}
+
+IStorage::~IStorage() = default;
+
+Result IStorage::Open(Out<SharedPointer<IStorageAccessor>> out_storage_accessor) {
+ LOG_DEBUG(Service_AM, "called");
+
+ R_UNLESS(m_impl->GetHandle() == nullptr, AM::ResultInvalidStorageType);
+
+ *out_storage_accessor = std::make_shared<IStorageAccessor>(system, m_impl);
+ R_SUCCEED();
+}
+
+Result IStorage::OpenTransferStorage(
+ Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor) {
+ R_UNLESS(m_impl->GetHandle() != nullptr, AM::ResultInvalidStorageType);
+
+ *out_transfer_storage_accessor = std::make_shared<ITransferStorageAccessor>(system, m_impl);
+ R_SUCCEED();
+}
+
+std::vector<u8> IStorage::GetData() const {
+ return m_impl->GetData();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/storage.h b/src/core/hle/service/am/service/storage.h
new file mode 100644
index 000000000..cde2ed0ea
--- /dev/null
+++ b/src/core/hle/service/am/service/storage.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class LibraryAppletStorage;
+class IStorageAccessor;
+class ITransferStorageAccessor;
+
+class IStorage final : public ServiceFramework<IStorage> {
+public:
+ explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl);
+ explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
+ ~IStorage() override;
+
+ std::shared_ptr<LibraryAppletStorage> GetImpl() const {
+ return m_impl;
+ }
+
+ std::vector<u8> GetData() const;
+
+private:
+ Result Open(Out<SharedPointer<IStorageAccessor>> out_storage_accessor);
+ Result OpenTransferStorage(
+ Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor);
+
+ const std::shared_ptr<LibraryAppletStorage> m_impl;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/storage_accessor.cpp b/src/core/hle/service/am/service/storage_accessor.cpp
new file mode 100644
index 000000000..84577fee4
--- /dev/null
+++ b/src/core/hle/service/am/service/storage_accessor.cpp
@@ -0,0 +1,68 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/service/am/library_applet_storage.h"
+#include "core/hle/service/am/service/storage_accessor.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IStorageAccessor::IStorageAccessor(Core::System& system_,
+ std::shared_ptr<LibraryAppletStorage> impl)
+ : ServiceFramework{system_, "IStorageAccessor"}, m_impl{std::move(impl)} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IStorageAccessor::GetSize>, "GetSize"},
+ {10, D<&IStorageAccessor::Write>, "Write"},
+ {11, D<&IStorageAccessor::Read>, "Read"},
+ };
+
+ RegisterHandlers(functions);
+}
+
+IStorageAccessor::~IStorageAccessor() = default;
+
+Result IStorageAccessor::GetSize(Out<s64> out_size) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_size = m_impl->GetSize();
+ R_SUCCEED();
+}
+
+Result IStorageAccessor::Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset) {
+ LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, buffer.size());
+ R_RETURN(m_impl->Write(offset, buffer.data(), buffer.size()));
+}
+
+Result IStorageAccessor::Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset) {
+ LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, out_buffer.size());
+ R_RETURN(m_impl->Read(offset, out_buffer.data(), out_buffer.size()));
+}
+
+ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_,
+ std::shared_ptr<LibraryAppletStorage> impl)
+ : ServiceFramework{system_, "ITransferStorageAccessor"}, m_impl{std::move(impl)} {
+ static const FunctionInfo functions[] = {
+ {0, D<&ITransferStorageAccessor::GetSize>, "GetSize"},
+ {1, D<&ITransferStorageAccessor::GetHandle>, "GetHandle"},
+ };
+
+ RegisterHandlers(functions);
+}
+
+ITransferStorageAccessor::~ITransferStorageAccessor() = default;
+
+Result ITransferStorageAccessor::GetSize(Out<s64> out_size) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_size = m_impl->GetSize();
+ R_SUCCEED();
+}
+
+Result ITransferStorageAccessor::GetHandle(Out<s64> out_size,
+ OutCopyHandle<Kernel::KTransferMemory> out_handle) {
+ LOG_INFO(Service_AM, "called");
+ *out_size = m_impl->GetSize();
+ *out_handle = m_impl->GetHandle();
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/storage_accessor.h b/src/core/hle/service/am/service/storage_accessor.h
new file mode 100644
index 000000000..1a01730e0
--- /dev/null
+++ b/src/core/hle/service/am/service/storage_accessor.h
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/am/library_applet_storage.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
+public:
+ explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl);
+ ~IStorageAccessor() override;
+
+private:
+ Result GetSize(Out<s64> out_size);
+ Result Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset);
+ Result Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset);
+
+ const std::shared_ptr<LibraryAppletStorage> m_impl;
+};
+
+class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> {
+public:
+ explicit ITransferStorageAccessor(Core::System& system_,
+ std::shared_ptr<LibraryAppletStorage> impl);
+ ~ITransferStorageAccessor() override;
+
+private:
+ Result GetSize(Out<s64> out_size);
+ Result GetHandle(Out<s64> out_size, OutCopyHandle<Kernel::KTransferMemory> out_handle);
+
+ const std::shared_ptr<LibraryAppletStorage> m_impl;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/system_applet_proxy.cpp b/src/core/hle/service/am/service/system_applet_proxy.cpp
new file mode 100644
index 000000000..5ec509d2e
--- /dev/null
+++ b/src/core/hle/service/am/service/system_applet_proxy.cpp
@@ -0,0 +1,133 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/service/applet_common_functions.h"
+#include "core/hle/service/am/service/application_creator.h"
+#include "core/hle/service/am/service/audio_controller.h"
+#include "core/hle/service/am/service/common_state_getter.h"
+#include "core/hle/service/am/service/debug_functions.h"
+#include "core/hle/service/am/service/display_controller.h"
+#include "core/hle/service/am/service/global_state_controller.h"
+#include "core/hle/service/am/service/home_menu_functions.h"
+#include "core/hle/service/am/service/library_applet_creator.h"
+#include "core/hle/service/am/service/process_winding_controller.h"
+#include "core/hle/service/am/service/self_controller.h"
+#include "core/hle/service/am/service/system_applet_proxy.h"
+#include "core/hle/service/am/service/window_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process,
+ Nvnflinger::Nvnflinger& nvnflinger)
+ : ServiceFramework{system_, "ISystemAppletProxy"},
+ m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
+ {1, D<&ISystemAppletProxy::GetSelfController>, "GetSelfController"},
+ {2, D<&ISystemAppletProxy::GetWindowController>, "GetWindowController"},
+ {3, D<&ISystemAppletProxy::GetAudioController>, "GetAudioController"},
+ {4, D<&ISystemAppletProxy::GetDisplayController>, "GetDisplayController"},
+ {10, D<&ISystemAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
+ {11, D<&ISystemAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
+ {20, D<&ISystemAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"},
+ {21, D<&ISystemAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
+ {22, D<&ISystemAppletProxy::GetApplicationCreator>, "GetApplicationCreator"},
+ {23, D<&ISystemAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
+ {1000, D<&ISystemAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ISystemAppletProxy::~ISystemAppletProxy() = default;
+
+Result ISystemAppletProxy::GetAudioController(
+ Out<SharedPointer<IAudioController>> out_audio_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_audio_controller = std::make_shared<IAudioController>(system);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetDisplayController(
+ Out<SharedPointer<IDisplayController>> out_display_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetProcessWindingController(
+ Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetDebugFunctions(
+ Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_debug_functions = std::make_shared<IDebugFunctions>(system);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetWindowController(
+ Out<SharedPointer<IWindowController>> out_window_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_window_controller = std::make_shared<IWindowController>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetSelfController(
+ Out<SharedPointer<ISelfController>> out_self_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_self_controller =
+ std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetCommonStateGetter(
+ Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetLibraryAppletCreator(
+ Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetApplicationCreator(
+ Out<SharedPointer<IApplicationCreator>> out_application_creator) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_application_creator = std::make_shared<IApplicationCreator>(system);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetAppletCommonFunctions(
+ Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetHomeMenuFunctions(
+ Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet);
+ R_SUCCEED();
+}
+
+Result ISystemAppletProxy::GetGlobalStateController(
+ Out<SharedPointer<IGlobalStateController>> out_global_state_controller) {
+ LOG_DEBUG(Service_AM, "called");
+ *out_global_state_controller = std::make_shared<IGlobalStateController>(system);
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/system_applet_proxy.h b/src/core/hle/service/am/service/system_applet_proxy.h
new file mode 100644
index 000000000..3d5040315
--- /dev/null
+++ b/src/core/hle/service/am/service/system_applet_proxy.h
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+class IAppletCommonFunctions;
+class IApplicationCreator;
+class IAudioController;
+class ICommonStateGetter;
+class IDebugFunctions;
+class IDisplayController;
+class IHomeMenuFunctions;
+class IGlobalStateController;
+class ILibraryAppletCreator;
+class IProcessWindingController;
+class ISelfController;
+class IWindowController;
+
+class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
+public:
+ explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
+ Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
+ ~ISystemAppletProxy();
+
+private:
+ Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
+ Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
+ Result GetProcessWindingController(
+ Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
+ Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
+ Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
+ Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
+ Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
+ Result GetLibraryAppletCreator(
+ Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
+ Result GetApplicationCreator(Out<SharedPointer<IApplicationCreator>> out_application_creator);
+ Result GetAppletCommonFunctions(
+ Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
+ Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions);
+ Result GetGlobalStateController(
+ Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
+
+ Nvnflinger::Nvnflinger& m_nvnflinger;
+ Kernel::KProcess* const m_process;
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/window_controller.cpp b/src/core/hle/service/am/service/window_controller.cpp
new file mode 100644
index 000000000..b874ecb91
--- /dev/null
+++ b/src/core/hle/service/am/service/window_controller.cpp
@@ -0,0 +1,86 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/am/applet.h"
+#include "core/hle/service/am/applet_manager.h"
+#include "core/hle/service/am/service/window_controller.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::AM {
+
+IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet)
+ : ServiceFramework{system_, "IWindowController"}, m_applet{std::move(applet)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "CreateWindow"},
+ {1, D<&IWindowController::GetAppletResourceUserId>, "GetAppletResourceUserId"},
+ {2, D<&IWindowController::GetAppletResourceUserIdOfCallerApplet>, "GetAppletResourceUserIdOfCallerApplet"},
+ {10, D<&IWindowController::AcquireForegroundRights>, "AcquireForegroundRights"},
+ {11, D<&IWindowController::ReleaseForegroundRights>, "ReleaseForegroundRights"},
+ {12, D<&IWindowController::RejectToChangeIntoBackground>, "RejectToChangeIntoBackground"},
+ {20, D<&IWindowController::SetAppletWindowVisibility>, "SetAppletWindowVisibility"},
+ {21, D<&IWindowController::SetAppletGpuTimeSlice>, "SetAppletGpuTimeSlice"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IWindowController::~IWindowController() = default;
+
+Result IWindowController::GetAppletResourceUserId(Out<AppletResourceUserId> out_aruid) {
+ LOG_INFO(Service_AM, "called");
+ *out_aruid = m_applet->aruid;
+ R_SUCCEED();
+}
+
+Result IWindowController::GetAppletResourceUserIdOfCallerApplet(
+ Out<AppletResourceUserId> out_aruid) {
+ LOG_INFO(Service_AM, "called");
+
+ if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet != nullptr) {
+ *out_aruid = caller_applet->aruid;
+ } else {
+ *out_aruid = AppletResourceUserId{};
+ }
+
+ R_SUCCEED();
+}
+
+Result IWindowController::AcquireForegroundRights() {
+ LOG_INFO(Service_AM, "called");
+ R_SUCCEED();
+}
+
+Result IWindowController::ReleaseForegroundRights() {
+ LOG_INFO(Service_AM, "called");
+ R_SUCCEED();
+}
+
+Result IWindowController::RejectToChangeIntoBackground() {
+ LOG_INFO(Service_AM, "called");
+ R_SUCCEED();
+}
+
+Result IWindowController::SetAppletWindowVisibility(bool visible) {
+ m_applet->system_buffer_manager.SetWindowVisibility(visible);
+ m_applet->hid_registration.EnableAppletToGetInput(visible);
+
+ if (visible) {
+ m_applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
+ m_applet->focus_state = FocusState::InFocus;
+ } else {
+ m_applet->focus_state = FocusState::NotInFocus;
+ }
+
+ m_applet->message_queue.PushMessage(AppletMessage::FocusStateChanged);
+
+ R_SUCCEED();
+}
+
+Result IWindowController::SetAppletGpuTimeSlice(s64 time_slice) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice);
+ R_SUCCEED();
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/window_controller.h b/src/core/hle/service/am/service/window_controller.h
new file mode 100644
index 000000000..bfbad9bcc
--- /dev/null
+++ b/src/core/hle/service/am/service/window_controller.h
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+struct Applet;
+
+class IWindowController final : public ServiceFramework<IWindowController> {
+public:
+ explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet);
+ ~IWindowController() override;
+
+private:
+ Result GetAppletResourceUserId(Out<AppletResourceUserId> out_aruid);
+ Result GetAppletResourceUserIdOfCallerApplet(Out<AppletResourceUserId> out_aruid);
+ Result AcquireForegroundRights();
+ Result ReleaseForegroundRights();
+ Result RejectToChangeIntoBackground();
+ Result SetAppletWindowVisibility(bool visible);
+ Result SetAppletGpuTimeSlice(s64 time_slice);
+
+ const std::shared_ptr<Applet> m_applet;
+};
+
+} // namespace Service::AM