Merge pull request #12760 from liamwhite/mp-am

am: rewrite for multiprocess support
master
Narr the Reg 2024-01-31 10:25:28 +07:00 committed by GitHub
commit 7cc7d027f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
132 changed files with 7088 additions and 4714 deletions

@ -261,7 +261,7 @@ object NativeLibrary {
/**
* Begins emulation.
*/
external fun run(path: String?, programIndex: Int = 0)
external fun run(path: String?, programIndex: Int, frontendInitiated: Boolean)
// Surface Handling
external fun surfaceChanged(surf: Surface?)

@ -927,7 +927,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
emulationThread.join()
emulationThread = Thread({
Log.debug("[EmulationFragment] Starting emulation thread.")
NativeLibrary.run(gamePath, programIndex)
NativeLibrary.run(gamePath, programIndex, false)
}, "NativeEmulation")
emulationThread.start()
}
@ -981,7 +981,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
State.STOPPED -> {
emulationThread = Thread({
Log.debug("[EmulationFragment] Starting emulation thread.")
NativeLibrary.run(gamePath, programIndex)
NativeLibrary.run(gamePath, programIndex, true)
}, "NativeEmulation")
emulationThread.start()
}

@ -82,7 +82,7 @@ AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobj
const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
return ResultData{GetJString(env, string),
static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField(
static_cast<Service::AM::Frontend::SwkbdResult>(env->GetIntField(
object, env->GetFieldID(s_keyboard_data_class, "result", "I")))};
}
@ -149,7 +149,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
}
void AndroidKeyboard::ShowTextCheckDialog(
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const {
LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog.");
}
@ -204,7 +204,7 @@ void AndroidKeyboard::InlineTextChanged(
"\ncursor_position={}",
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
text_parameters.input_text, text_parameters.cursor_position);
}
@ -219,7 +219,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
m_current_text += submitted_text;
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
m_current_text.size());
}
@ -236,12 +236,12 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
case KEYCODE_BACK:
case KEYCODE_ENTER:
m_is_inline_active = false;
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text,
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, m_current_text,
static_cast<s32>(m_current_text.size()));
break;
case KEYCODE_DEL:
m_current_text.pop_back();
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
m_current_text.size());
break;
}

@ -24,7 +24,7 @@ public:
void ShowNormalKeyboard() const override;
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const override;
void ShowInlineKeyboard(
@ -45,7 +45,7 @@ private:
static ResultData CreateFromFrontend(jobject object);
std::string text;
Service::AM::Applets::SwkbdResult result{};
Service::AM::Frontend::SwkbdResult result{};
};
void SubmitNormalText(const ResultData& result) const;

@ -42,14 +42,15 @@
#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/general.h"
#include "core/frontend/applets/mii_edit.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "frontend_common/config.h"
@ -211,8 +212,15 @@ void EmulationSession::InitializeSystem(bool reload) {
m_system.GetFileSystemController().CreateFactories(*m_vfs);
}
void EmulationSession::SetAppletId(int applet_id) {
m_applet_id = applet_id;
m_system.GetFrontendAppletHolder().SetCurrentAppletId(
static_cast<Service::AM::AppletId>(m_applet_id));
}
Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath,
const std::size_t program_index) {
const std::size_t program_index,
const bool frontend_initiated) {
std::scoped_lock lock(m_mutex);
// Create the render window.
@ -226,7 +234,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
m_system.ApplySettings();
Settings::LogSettings();
m_system.HIDCore().ReloadInputDevices();
m_system.SetAppletFrontendSet({
m_system.SetFrontendAppletSet({
nullptr, // Amiibo Settings
nullptr, // Controller Selector
nullptr, // Error Display
@ -242,8 +250,13 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
ConfigureFilesystemProvider(filepath);
// Load the ROM.
m_load_result =
m_system.Load(EmulationSession::GetInstance().Window(), filepath, 0, program_index);
Service::AM::FrontendAppletParameters params{
.applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
.launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
: Service::AM::LaunchType::ApplicationInitiated,
.program_index = static_cast<s32>(program_index),
};
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
if (m_load_result != Core::SystemResultStatus::Success) {
return m_load_result;
}
@ -339,6 +352,9 @@ void EmulationSession::RunEmulation() {
}
}
}
// Reset current applet ID.
m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
}
bool EmulationSession::IsHandheldOnly() {
@ -434,7 +450,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
}
static Core::SystemResultStatus RunEmulation(const std::string& filepath,
const size_t program_index = 0) {
const size_t program_index,
const bool frontend_initiated) {
MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); });
@ -447,7 +464,8 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index);
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
frontend_initiated);
if (result != Core::SystemResultStatus::Success) {
return result;
}
@ -744,10 +762,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
jint j_program_index) {
jint j_program_index,
jboolean j_frontend_initiated) {
const std::string path = GetJString(env, j_path);
const Core::SystemResultStatus result{RunEmulation(path, j_program_index)};
const Core::SystemResultStatus result{
RunEmulation(path, j_program_index, j_frontend_initiated)};
if (result != Core::SystemResultStatus::Success) {
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetExitEmulationActivity(), static_cast<int>(result));
@ -809,13 +829,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
jint jappletId) {
EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId(
static_cast<Service::AM::Applets::AppletId>(jappletId));
EmulationSession::GetInstance().SetAppletId(jappletId);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz,
jint jcabinetMode) {
EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode(
EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCabinetMode(
static_cast<Service::NFP::CabinetMode>(jcabinetMode));
}

@ -45,8 +45,10 @@ public:
const Core::PerfStatsResults& PerfStats();
void ConfigureFilesystemProvider(const std::string& filepath);
void InitializeSystem(bool reload);
void SetAppletId(int applet_id);
Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
const std::size_t program_index = 0);
const std::size_t program_index,
const bool frontend_initiated);
bool IsHandheldOnly();
void SetDeviceType([[maybe_unused]] int index, int type);
@ -79,6 +81,7 @@ private:
std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
int m_applet_id{1};
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;

@ -176,8 +176,8 @@ add_library(core STATIC
frontend/applets/controller.h
frontend/applets/error.cpp
frontend/applets/error.h
frontend/applets/general_frontend.cpp
frontend/applets/general_frontend.h
frontend/applets/general.cpp
frontend/applets/general.h
frontend/applets/mii_edit.cpp
frontend/applets/mii_edit.h
frontend/applets/profile_select.cpp
@ -390,39 +390,101 @@ add_library(core STATIC
hle/service/acc/errors.h
hle/service/acc/profile_manager.cpp
hle/service/acc/profile_manager.h
hle/service/am/frontend/applet_cabinet.cpp
hle/service/am/frontend/applet_cabinet.h
hle/service/am/frontend/applet_controller.cpp
hle/service/am/frontend/applet_controller.h
hle/service/am/frontend/applet_error.cpp
hle/service/am/frontend/applet_error.h
hle/service/am/frontend/applet_general.cpp
hle/service/am/frontend/applet_general.h
hle/service/am/frontend/applet_mii_edit.cpp
hle/service/am/frontend/applet_mii_edit.h
hle/service/am/frontend/applet_mii_edit_types.h
hle/service/am/frontend/applet_profile_select.cpp
hle/service/am/frontend/applet_profile_select.h
hle/service/am/frontend/applet_software_keyboard.cpp
hle/service/am/frontend/applet_software_keyboard.h
hle/service/am/frontend/applet_software_keyboard_types.h
hle/service/am/frontend/applet_web_browser.cpp
hle/service/am/frontend/applet_web_browser.h
hle/service/am/frontend/applet_web_browser_types.h
hle/service/am/frontend/applets.cpp
hle/service/am/frontend/applets.h
hle/service/am/am.cpp
hle/service/am/am.h
hle/service/am/am_results.h
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_ae.cpp
hle/service/am/applet_ae.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.h
hle/service/am/applet_oe.cpp
hle/service/am/applet_oe.h
hle/service/am/applets/applet_cabinet.cpp
hle/service/am/applets/applet_cabinet.h
hle/service/am/applets/applet_controller.cpp
hle/service/am/applets/applet_controller.h
hle/service/am/applets/applet_error.cpp
hle/service/am/applets/applet_error.h
hle/service/am/applets/applet_general_backend.cpp
hle/service/am/applets/applet_general_backend.h
hle/service/am/applets/applet_mii_edit.cpp
hle/service/am/applets/applet_mii_edit.h
hle/service/am/applets/applet_mii_edit_types.h
hle/service/am/applets/applet_profile_select.cpp
hle/service/am/applets/applet_profile_select.h
hle/service/am/applets/applet_software_keyboard.cpp
hle/service/am/applets/applet_software_keyboard.h
hle/service/am/applets/applet_software_keyboard_types.h
hle/service/am/applets/applet_web_browser.cpp
hle/service/am/applets/applet_web_browser.h
hle/service/am/applets/applet_web_browser_types.h
hle/service/am/applets/applets.cpp
hle/service/am/applets/applets.h
hle/service/am/applet_common_functions.cpp
hle/service/am/applet_common_functions.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/application_creator.cpp
hle/service/am/application_creator.h
hle/service/am/application_functions.cpp
hle/service/am/application_functions.h
hle/service/am/application_proxy.cpp
hle/service/am/application_proxy.h
hle/service/am/audio_controller.cpp
hle/service/am/audio_controller.h
hle/service/am/common_state_getter.cpp
hle/service/am/common_state_getter.h
hle/service/am/debug_functions.cpp
hle/service/am/debug_functions.h
hle/service/am/display_controller.cpp
hle/service/am/display_controller.h
hle/service/am/global_state_controller.cpp
hle/service/am/global_state_controller.h
hle/service/am/hid_registration.cpp
hle/service/am/hid_registration.h
hle/service/am/home_menu_functions.cpp
hle/service/am/home_menu_functions.h
hle/service/am/idle.cpp
hle/service/am/idle.h
hle/service/am/library_applet_accessor.cpp
hle/service/am/library_applet_accessor.h
hle/service/am/library_applet_creator.cpp
hle/service/am/library_applet_creator.h
hle/service/am/library_applet_proxy.cpp
hle/service/am/library_applet_proxy.h
hle/service/am/library_applet_self_accessor.cpp
hle/service/am/library_applet_self_accessor.h
hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h
hle/service/am/lock_accessor.cpp
hle/service/am/lock_accessor.h
hle/service/am/managed_layer_holder.cpp
hle/service/am/managed_layer_holder.h
hle/service/am/omm.cpp
hle/service/am/omm.h
hle/service/am/process_winding_controller.cpp
hle/service/am/process_winding_controller.h
hle/service/am/process.cpp
hle/service/am/process.h
hle/service/am/self_controller.cpp
hle/service/am/self_controller.h
hle/service/am/system_applet_proxy.cpp
hle/service/am/system_applet_proxy.h
hle/service/am/system_buffer_manager.cpp
hle/service/am/system_buffer_manager.h
hle/service/am/spsm.cpp
hle/service/am/spsm.h
hle/service/am/storage_accessor.cpp
hle/service/am/storage_accessor.h
hle/service/am/storage.cpp
hle/service/am/storage.h
hle/service/am/window_controller.cpp
hle/service/am/window_controller.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
@ -486,6 +548,8 @@ add_library(core STATIC
hle/service/es/es.h
hle/service/eupld/eupld.cpp
hle/service/eupld/eupld.h
hle/service/event.cpp
hle/service/event.h
hle/service/fatal/fatal.cpp
hle/service/fatal/fatal.h
hle/service/fatal/fatal_p.cpp

@ -36,7 +36,8 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
@ -135,8 +136,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, hid_core{}, room_network{},
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {}
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>();
@ -157,7 +158,7 @@ struct System::Impl {
}
// Create default implementations of applets if one is not provided.
applet_manager.SetDefaultAppletsIfMissing();
frontend_applets.SetDefaultAppletsIfMissing();
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
@ -330,16 +331,27 @@ struct System::Impl {
}
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath, u64 program_id,
std::size_t program_index) {
const std::string& filepath,
Service::AM::FrontendAppletParameters& params) {
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
program_id, program_index);
params.program_id, params.program_index);
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return SystemResultStatus::ErrorGetLoader;
}
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM!");
}
std::string name = "Unknown program";
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to read title for ROM!");
}
LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
InitializeKernel(system);
// Create the application process.
@ -373,9 +385,14 @@ struct System::Impl {
cheat_engine->Initialize();
}
// Register with applet manager.
applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
params);
// All threads are started, begin main process execution, now that we're in the clear.
main_process->Run(load_parameters->main_thread_priority,
load_parameters->main_thread_stack_size);
main_process->Close();
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
@ -386,21 +403,13 @@ struct System::Impl {
}
}
if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
}
perf_stats = std::make_unique<PerfStats>(program_id);
perf_stats = std::make_unique<PerfStats>(params.program_id);
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
perf_stats->BeginSystemFrame();
std::string name = "Unknown Game";
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
}
std::string title_version;
const FileSys::PatchManager pm(program_id, system.GetFileSystemController(),
const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(),
system.GetContentProvider());
const auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
@ -409,14 +418,15 @@ struct System::Impl {
if (auto room_member = room_network.GetRoomMember().lock()) {
Network::GameInfo game_info;
game_info.name = name;
game_info.id = program_id;
game_info.id = params.program_id;
game_info.version = title_version;
room_member->SendGameInfo(game_info);
}
// Workarounds:
// Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL;
Settings::values.renderer_amdvlk_depth_bias_workaround =
params.program_id == 0x1006A800016E000ULL;
status = SystemResultStatus::Success;
return status;
@ -455,6 +465,7 @@ struct System::Impl {
}
kernel.CloseServices();
kernel.ShutdownCores();
applet_manager.Reset();
services.reset();
service_manager.reset();
fs_controller.Reset();
@ -566,8 +577,9 @@ struct System::Impl {
std::unique_ptr<Tools::RenderdocAPI> renderdoc_api;
/// Frontend applets
Service::AM::Applets::AppletManager applet_manager;
/// Applets
Service::AM::AppletManager applet_manager;
Service::AM::Frontend::FrontendAppletHolder frontend_applets;
/// APM (Performance) services
Service::APM::Controller apm_controller{core_timing};
@ -680,8 +692,8 @@ void System::InitializeDebugger() {
}
SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
u64 program_id, std::size_t program_index) {
return impl->Load(*this, emu_window, filepath, program_id, program_index);
Service::AM::FrontendAppletParameters& params) {
return impl->Load(*this, emu_window, filepath, params);
}
bool System::IsPoweredOn() const {
@ -871,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
}
void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) {
impl->applet_manager.SetAppletFrontendSet(std::move(set));
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
impl->frontend_applets.SetFrontendAppletSet(std::move(set));
}
void System::SetDefaultAppletFrontendSet() {
impl->applet_manager.SetDefaultAppletFrontendSet();
Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
return impl->frontend_applets;
}
Service::AM::Applets::AppletManager& System::GetAppletManager() {
return impl->applet_manager;
const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
return impl->frontend_applets;
}
const Service::AM::Applets::AppletManager& System::GetAppletManager() const {
Service::AM::AppletManager& System::GetAppletManager() {
return impl->applet_manager;
}

@ -50,10 +50,15 @@ namespace Account {
class ProfileManager;
} // namespace Account
namespace AM::Applets {
struct AppletFrontendSet;
namespace AM {
struct FrontendAppletParameters;
class AppletManager;
} // namespace AM::Applets
} // namespace AM
namespace AM::Frontend {
struct FrontendAppletSet;
class FrontendAppletHolder;
} // namespace AM::Frontend
namespace APM {
class Controller;
@ -203,8 +208,8 @@ public:
* @returns SystemResultStatus code, indicating if the operation succeeded.
*/
[[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window,
const std::string& filepath, u64 program_id = 0,
std::size_t program_index = 0);
const std::string& filepath,
Service::AM::FrontendAppletParameters& params);
/**
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@ -344,11 +349,13 @@ public:
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
u64 main_region_size);
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
void SetDefaultAppletFrontendSet();
void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
[[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager();
[[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
[[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder();
[[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder()
const;
[[nodiscard]] Service::AM::AppletManager& GetAppletManager();
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/general.h"
namespace Core::Frontend {

@ -8,15 +8,15 @@
#include "common/uuid.h"
#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/frontend/applet_profile_select.h"
namespace Core::Frontend {
struct ProfileSelectParameters {
Service::AM::Applets::UiMode mode;
Service::AM::Frontend::UiMode mode;
std::array<Common::UUID, 8> invalid_uid_list;
Service::AM::Applets::UiSettingsDisplayOptions display_options;
Service::AM::Applets::UserSelectionPurpose purpose;
Service::AM::Frontend::UiSettingsDisplayOptions display_options;
Service::AM::Frontend::UserSelectionPurpose purpose;
};
class ProfileSelectApplet : public Applet {

@ -69,7 +69,7 @@ void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
}
void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
}
@ -118,7 +118,7 @@ void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_
"\ncursor_position={}",
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
text_parameters.input_text, text_parameters.cursor_position);
}
@ -127,22 +127,22 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
}
void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true);
submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true);
}
void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (std::size_t index = 0; index < text.size(); ++index) {
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
std::u16string(text.data(), text.data() + index + 1),
static_cast<s32>(index) + 1);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
static_cast<s32>(text.size()));
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter,
std::u16string(text), static_cast<s32>(text.size()));
}
} // namespace Core::Frontend

@ -8,7 +8,7 @@
#include "common/common_types.h"
#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
namespace Core::Frontend {
@ -23,10 +23,10 @@ struct KeyboardInitializeParameters {
u32 max_text_length;
u32 min_text_length;
s32 initial_cursor_position;
Service::AM::Applets::SwkbdType type;
Service::AM::Applets::SwkbdPasswordMode password_mode;
Service::AM::Applets::SwkbdTextDrawType text_draw_type;
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
Service::AM::Frontend::SwkbdType type;
Service::AM::Frontend::SwkbdPasswordMode password_mode;
Service::AM::Frontend::SwkbdTextDrawType text_draw_type;
Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
bool use_blur_background;
bool enable_backspace_button;
bool enable_return_button;
@ -40,8 +40,8 @@ struct InlineAppearParameters {
f32 key_top_scale_y;
f32 key_top_translate_x;
f32 key_top_translate_y;
Service::AM::Applets::SwkbdType type;
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
Service::AM::Frontend::SwkbdType type;
Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
bool key_top_as_floating;
bool enable_backspace_button;
bool enable_return_button;
@ -56,9 +56,9 @@ struct InlineTextParameters {
class SoftwareKeyboardApplet : public Applet {
public:
using SubmitInlineCallback =
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>;
std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>;
using SubmitNormalCallback =
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>;
std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>;
virtual ~SoftwareKeyboardApplet();
@ -69,7 +69,7 @@ public:
virtual void ShowNormalKeyboard() const = 0;
virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const = 0;
virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
@ -93,7 +93,7 @@ public:
void ShowNormalKeyboard() const override;
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const override;
void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;

@ -18,7 +18,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url,
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
local_url);
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
}
void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url,
@ -26,7 +26,7 @@ void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_ur
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
external_url);
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
}
} // namespace Core::Frontend

@ -6,7 +6,7 @@
#include <functional>
#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/applets/applet_web_browser_types.h"
#include "core/hle/service/am/frontend/applet_web_browser_types.h"
namespace Core::Frontend {
@ -14,7 +14,7 @@ class WebBrowserApplet : public Applet {
public:
using ExtractROMFSCallback = std::function<void()>;
using OpenWebPageCallback =
std::function<void(Service::AM::Applets::WebExitReason, std::string)>;
std::function<void(Service::AM::Frontend::WebExitReason, std::string)>;
virtual ~WebBrowserApplet();

@ -97,8 +97,14 @@ struct KernelCore::Impl {
RegisterHostThread(nullptr);
}
void TerminateApplicationProcess() {
application_process.load()->Terminate();
void TerminateAllProcesses() {
std::scoped_lock lk{process_list_lock};
for (auto& process : process_list) {
process->Terminate();
process->Close();
process = nullptr;
}
process_list.clear();
}
void Shutdown() {
@ -107,18 +113,9 @@ struct KernelCore::Impl {
CloseServices();
auto* old_process = application_process.exchange(nullptr);
if (old_process) {
old_process->Close();
}
{
std::scoped_lock lk{process_list_lock};
for (auto* const process : process_list) {
process->Terminate();
process->Close();
}
process_list.clear();
if (application_process) {
application_process->Close();
application_process = nullptr;
}
next_object_id = 0;
@ -354,6 +351,7 @@ struct KernelCore::Impl {
void MakeApplicationProcess(KProcess* process) {
application_process = process;
application_process->Open();
}
static inline thread_local u8 host_thread_id = UINT8_MAX;
@ -779,7 +777,7 @@ struct KernelCore::Impl {
// Lists all processes that exist in the current session.
std::mutex process_list_lock;
std::vector<KProcess*> process_list;
std::atomic<KProcess*> application_process{};
KProcess* application_process{};
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
@ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) {
}
void KernelCore::ShutdownCores() {
impl->TerminateApplicationProcess();
impl->TerminateAllProcesses();
KScopedSchedulerLock lk{*this};

File diff suppressed because it is too large Load Diff

@ -1,20 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <chrono>
#include <memory>
#include <queue>
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KernelCore;
class KReadableEvent;
class KTransferMemory;
} // namespace Kernel
namespace Core {
class System;
}
namespace Service::Nvnflinger {
class Nvnflinger;
@ -22,443 +13,6 @@ class Nvnflinger;
namespace Service::AM {
class AppletMessageQueue {
public:
// This is nn::am::AppletMessage
enum class AppletMessage : u32 {
None = 0,
ChangeIntoForeground = 1,
ChangeIntoBackground = 2,
Exit = 4,
ApplicationExited = 6,
FocusStateChanged = 15,
Resume = 16,
DetectShortPressingHomeButton = 20,
DetectLongPressingHomeButton = 21,
DetectShortPressingPowerButton = 22,
DetectMiddlePressingPowerButton = 23,
DetectLongPressingPowerButton = 24,
RequestToPrepareSleep = 25,
FinishedSleepSequence = 26,
SleepRequiredByHighTemperature = 27,
SleepRequiredByLowBattery = 28,
AutoPowerDown = 29,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
DetectReceivingCecSystemStandby = 32,
SdCardRemoved = 33,
LaunchApplicationRequested = 50,
RequestToDisplay = 51,
ShowApplicationLogo = 55,
HideApplicationLogo = 56,
ForceHideApplicationLogo = 57,
FloatingApplicationDetected = 60,
DetectShortPressingCaptureButton = 90,
AlbumScreenShotTaken = 92,
AlbumRecordingSaved = 93,
};
explicit AppletMessageQueue(Core::System& system);
~AppletMessageQueue();
Kernel::KReadableEvent& GetMessageReceiveEvent();
Kernel::KReadableEvent& GetOperationModeChangedEvent();
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
void RequestExit();
void RequestResume();
void FocusStateChanged();
void OperationModeChanged();
private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* on_new_message;
Kernel::KEvent* on_operation_mode_changed;
std::queue<AppletMessage> messages;
};
class IWindowController final : public ServiceFramework<IWindowController> {
public:
explicit IWindowController(Core::System& system_);
~IWindowController() override;
private:
void GetAppletResourceUserId(HLERequestContext& ctx);
void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
void AcquireForegroundRights(HLERequestContext& ctx);
};
class IAudioController final : public ServiceFramework<IAudioController> {
public:
explicit IAudioController(Core::System& system_);
~IAudioController() override;
private:
void SetExpectedMasterVolume(HLERequestContext& ctx);
void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
void SetTransparentAudioRate(HLERequestContext& ctx);
static constexpr float min_allowed_volume = 0.0f;
static constexpr float max_allowed_volume = 1.0f;
float main_applet_volume{0.25f};
float library_applet_volume{max_allowed_volume};
float transparent_volume_rate{min_allowed_volume};
// Volume transition fade time in nanoseconds.
// e.g. If the main applet volume was 0% and was changed to 50%
// with a fade of 50ns, then over the course of 50ns,
// the volume will gradually fade up to 50%
std::chrono::nanoseconds fade_time_ns{0};
};
class IDisplayController final : public ServiceFramework<IDisplayController> {
public:
explicit IDisplayController(Core::System& system_);
~IDisplayController() override;
private:
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
};
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
public:
explicit IDebugFunctions(Core::System& system_);
~IDebugFunctions() override;
};
class ISelfController final : public ServiceFramework<ISelfController> {
public:
explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_);
~ISelfController() override;
private:
void Exit(HLERequestContext& ctx);
void LockExit(HLERequestContext& ctx);
void UnlockExit(HLERequestContext& ctx);
void EnterFatalSection(HLERequestContext& ctx);
void LeaveFatalSection(HLERequestContext& ctx);
void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
void SetScreenShotPermission(HLERequestContext& ctx);
void SetOperationModeChangedNotification(HLERequestContext& ctx);
void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
void SetFocusHandlingMode(HLERequestContext& ctx);
void SetRestartMessageEnabled(HLERequestContext& ctx);
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
void SetAlbumImageOrientation(HLERequestContext& ctx);
void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
void GetSystemSharedBufferHandle(HLERequestContext& ctx);
void GetSystemSharedLayerHandle(HLERequestContext& ctx);
void CreateManagedDisplayLayer(HLERequestContext& ctx);
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
void ApproveToDisplay(HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
void ReportUserIsActive(HLERequestContext& ctx);
void SetAutoSleepDisabled(HLERequestContext& ctx);
void IsAutoSleepDisabled(HLERequestContext& ctx);
void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
void SaveCurrentScreenshot(HLERequestContext& ctx);
void SetRecordVolumeMuted(HLERequestContext& ctx);
Result EnsureBufferSharingEnabled();
enum class ScreenshotPermission : u32 {
Inherit = 0,
Enable = 1,
Disable = 2,
};
Nvnflinger::Nvnflinger& nvnflinger;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* launchable_event;
Kernel::KEvent* accumulated_suspended_tick_changed_event;
u32 idle_time_detection_extension = 0;
u64 num_fatal_sections_entered = 0;
u64 system_shared_buffer_id = 0;
u64 system_shared_layer_id = 0;
bool is_auto_sleep_disabled = false;
bool buffer_sharing_enabled = false;
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
};
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
public:
explicit ILockAccessor(Core::System& system_);
~ILockAccessor() override;
private:
void TryLock(HLERequestContext& ctx);
void Unlock(HLERequestContext& ctx);
void GetEvent(HLERequestContext& ctx);
void IsLocked(HLERequestContext& ctx);
bool is_locked{};
Kernel::KEvent* lock_event;
KernelHelpers::ServiceContext service_context;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
explicit ICommonStateGetter(Core::System& system_,
std::shared_ptr<AppletMessageQueue> msg_queue_);
~ICommonStateGetter() override;
private:
// This is nn::oe::FocusState
enum class FocusState : u8 {
InFocus = 1,
NotInFocus = 2,
Background = 3,
};
// This is nn::oe::OperationMode
enum class OperationMode : u8 {
Handheld = 0,
Docked = 1,
};
// This is nn::am::service::SystemButtonType
enum class SystemButtonType {
None,
HomeButtonShortPressing,
HomeButtonLongPressing,
PowerButtonShortPressing,
PowerButtonLongPressing,
ShutdownSystem,
CaptureButtonShortPressing,
CaptureButtonLongPressing,
};
enum class SysPlatformRegion : s32 {
Global = 1,
Terra = 2,
};
void GetEventHandle(HLERequestContext& ctx);
void ReceiveMessage(HLERequestContext& ctx);
void GetCurrentFocusState(HLERequestContext& ctx);
void RequestToAcquireSleepLock(HLERequestContext& ctx);
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
void GetReaderLockAccessorEx(HLERequestContext& ctx);
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
void GetOperationMode(HLERequestContext& ctx);
void GetPerformanceMode(HLERequestContext& ctx);
void GetBootMode(HLERequestContext& ctx);
void IsVrModeEnabled(HLERequestContext& ctx);
void SetVrModeEnabled(HLERequestContext& ctx);
void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
void BeginVrModeEx(HLERequestContext& ctx);
void EndVrModeEx(HLERequestContext& ctx);
void GetDefaultDisplayResolution(HLERequestContext& ctx);
void SetCpuBoostMode(HLERequestContext& ctx);
void GetBuiltInDisplayType(HLERequestContext& ctx);
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
void GetSettingsPlatformRegion(HLERequestContext& ctx);
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
std::shared_ptr<AppletMessageQueue> msg_queue;
bool vr_mode_state{};
Kernel::KEvent* sleep_lock_event;
KernelHelpers::ServiceContext service_context;
};
class IStorageImpl {
public:
virtual ~IStorageImpl();
virtual std::vector<u8>& GetData() = 0;
virtual const std::vector<u8>& GetData() const = 0;
virtual std::size_t GetSize() const = 0;
};
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
~IStorage() override;
std::vector<u8>& GetData() {
return impl->GetData();
}
const std::vector<u8>& GetData() const {
return impl->GetData();
}
std::size_t GetSize() const {
return impl->GetSize();
}
private:
void Register();
void Open(HLERequestContext& ctx);
std::shared_ptr<IStorageImpl> impl;
};
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
public:
explicit IStorageAccessor(Core::System& system_, IStorage& backing_);
~IStorageAccessor() override;
private:
void GetSize(HLERequestContext& ctx);
void Write(HLERequestContext& ctx);
void Read(HLERequestContext& ctx);
IStorage& backing;
};
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
explicit ILibraryAppletCreator(Core::System& system_);
~ILibraryAppletCreator() override;
private:
void CreateLibraryApplet(HLERequestContext& ctx);
void CreateStorage(HLERequestContext& ctx);
void CreateTransferMemoryStorage(HLERequestContext& ctx);
void CreateHandleStorage(HLERequestContext& ctx);
};
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
public:
explicit ILibraryAppletSelfAccessor(Core::System& system_);
~ILibraryAppletSelfAccessor() override;
private:
void PopInData(HLERequestContext& ctx);
void PushOutData(HLERequestContext& ctx);
void GetLibraryAppletInfo(HLERequestContext& ctx);
void GetMainAppletIdentityInfo(HLERequestContext& ctx);
void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
void GetMainAppletAvailableUsers(HLERequestContext& ctx);
void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
void PushInShowAlbum();
void PushInShowCabinetData();
void PushInShowMiiEditData();
void PushInShowSoftwareKeyboard();
void PushInShowController();
std::deque<std::vector<u8>> queue_data;
};
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
public:
explicit IAppletCommonFunctions(Core::System& system_);
~IAppletCommonFunctions() override;
private:
void SetCpuBoostRequestPriority(HLERequestContext& ctx);
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
explicit IApplicationFunctions(Core::System& system_);
~IApplicationFunctions() override;
private:
void PopLaunchParameter(HLERequestContext& ctx);
void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
void EnsureSaveData(HLERequestContext& ctx);
void SetTerminateResult(HLERequestContext& ctx);
void GetDisplayVersion(HLERequestContext& ctx);
void GetDesiredLanguage(HLERequestContext& ctx);
void IsGamePlayRecordingSupported(HLERequestContext& ctx);
void InitializeGamePlayRecording(HLERequestContext& ctx);
void SetGamePlayRecordingState(HLERequestContext& ctx);
void NotifyRunning(HLERequestContext& ctx);
void GetPseudoDeviceId(HLERequestContext& ctx);
void ExtendSaveData(HLERequestContext& ctx);
void GetSaveDataSize(HLERequestContext& ctx);
void CreateCacheStorage(HLERequestContext& ctx);
void GetSaveDataSizeMax(HLERequestContext& ctx);
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
void BeginBlockingHomeButton(HLERequestContext& ctx);
void EndBlockingHomeButton(HLERequestContext& ctx);
void EnableApplicationCrashReport(HLERequestContext& ctx);
void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
void SetApplicationCopyrightImage(HLERequestContext& ctx);
void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
void QueryApplicationPlayStatistics(HLERequestContext& ctx);
void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
void ExecuteProgram(HLERequestContext& ctx);
void ClearUserChannel(HLERequestContext& ctx);
void UnpopToUserChannel(HLERequestContext& ctx);
void GetPreviousProgramIndex(HLERequestContext& ctx);
void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
void PrepareForJit(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
bool launch_popped_account_preselect = false;
s32 previous_program_index{-1};
Kernel::KEvent* gpu_error_detected_event;
Kernel::KEvent* friend_invitation_storage_channel_event;
Kernel::KEvent* notification_storage_channel_event;
Kernel::KEvent* health_warning_disappeared_system_event;
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
public:
explicit IHomeMenuFunctions(Core::System& system_);
~IHomeMenuFunctions() override;
private:
void RequestToGetForeground(HLERequestContext& ctx);
void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* pop_from_general_channel_event;
};
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
public:
explicit IGlobalStateController(Core::System& system_);
~IGlobalStateController() override;
};
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public:
explicit IApplicationCreator(Core::System& system_);
~IApplicationCreator() override;
};
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
public:
explicit IProcessWindingController(Core::System& system_);
~IProcessWindingController() override;
private:
void GetLaunchReason(HLERequestContext& ctx);
void OpenCallingLibraryApplet(HLERequestContext& ctx);
};
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
} // namespace Service::AM

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::AM {
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
} // namespace Service::AM

@ -0,0 +1,178 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::AM {
namespace Frontend {
class FrontendApplet;
}
enum class AppletType {
Application,
LibraryApplet,
SystemApplet,
};
enum class GameplayRecordingState : u32 {
Disabled,
Enabled,
};
// This is nn::oe::FocusState
enum class FocusState : u8 {
InFocus = 1,
NotInFocus = 2,
Background = 3,
};
// This is nn::oe::OperationMode
enum class OperationMode : u8 {
Handheld = 0,
Docked = 1,
};
// This is nn::am::service::SystemButtonType
enum class SystemButtonType {
None,
HomeButtonShortPressing,
HomeButtonLongPressing,
PowerButtonShortPressing,
PowerButtonLongPressing,
ShutdownSystem,
CaptureButtonShortPressing,
CaptureButtonLongPressing,
};
enum class SysPlatformRegion : s32 {
Global = 1,
Terra = 2,
};
struct AppletProcessLaunchReason {
u8 flag;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
"AppletProcessLaunchReason is an invalid size");
enum class ScreenshotPermission : u32 {
Inherit = 0,
Enable = 1,
Disable = 2,
};
struct FocusHandlingMode {
bool unknown0;
bool unknown1;
bool unknown2;
bool unknown3;
};
enum class IdleTimeDetectionExtension : u32 {
Disabled = 0,
Extended = 1,
ExtendedUnsafe = 2,
};
enum class AppletId : u32 {
None = 0x00,
Application = 0x01,
OverlayDisplay = 0x02,
QLaunch = 0x03,
Starter = 0x04,
Auth = 0x0A,
Cabinet = 0x0B,
Controller = 0x0C,
DataErase = 0x0D,
Error = 0x0E,
NetConnect = 0x0F,
ProfileSelect = 0x10,
SoftwareKeyboard = 0x11,
MiiEdit = 0x12,
Web = 0x13,
Shop = 0x14,
PhotoViewer = 0x15,
Settings = 0x16,
OfflineWeb = 0x17,
LoginShare = 0x18,
WebAuth = 0x19,
MyPage = 0x1A,
};
enum class AppletProgramId : u64 {
QLaunch = 0x0100000000001000ull,
Auth = 0x0100000000001001ull,
Cabinet = 0x0100000000001002ull,
Controller = 0x0100000000001003ull,
DataErase = 0x0100000000001004ull,
Error = 0x0100000000001005ull,
NetConnect = 0x0100000000001006ull,
ProfileSelect = 0x0100000000001007ull,
SoftwareKeyboard = 0x0100000000001008ull,
MiiEdit = 0x0100000000001009ull,
Web = 0x010000000000100Aull,
Shop = 0x010000000000100Bull,
OverlayDisplay = 0x010000000000100Cull,
PhotoViewer = 0x010000000000100Dull,
Settings = 0x010000000000100Eull,
OfflineWeb = 0x010000000000100Full,
LoginShare = 0x0100000000001010ull,
WebAuth = 0x0100000000001011ull,
Starter = 0x0100000000001012ull,
MyPage = 0x0100000000001013ull,
MaxProgramId = 0x0100000000001FFFull,
};
enum class LibraryAppletMode : u32 {
AllForeground = 0,
Background = 1,
NoUI = 2,
BackgroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4,
};
enum class CommonArgumentVersion : u32 {
Version0,
Version1,
Version2,
Version3,
};
enum class CommonArgumentSize : u32 {
Version3 = 0x20,
};
enum class ThemeColor : u32 {
BasicWhite = 0,
BasicBlack = 3,
};
struct CommonArguments {
CommonArgumentVersion arguments_version;
CommonArgumentSize size;
u32 library_version;
ThemeColor theme_color;
bool play_startup_sound;
u64 system_tick;
};
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
struct AppletIdentityInfo {
AppletId applet_id;
INSERT_PADDING_BYTES(0x4);
u64 application_id;
};
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
using AppletResourceUserId = u64;
using ProgramId = u64;
struct Applet;
class AppletDataBroker;
} // namespace Service::AM

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
namespace Service::AM {
Applet::Applet(Core::System& system, std::unique_ptr<Process> process_)
: context(system, "Applet"), message_queue(system), process(std::move(process_)),
hid_registration(system, *process), gpu_error_detected_event(context),
friend_invitation_storage_channel_event(context), notification_storage_channel_event(context),
health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context),
pop_from_general_channel_event(context), library_applet_launchable_event(context),
accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) {
aruid = process->GetProcessId();
program_id = process->GetProgramId();
}
Applet::~Applet() = default;
} // namespace Service::AM

@ -0,0 +1,133 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <list>
#include <mutex>
#include "common/math_util.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/managed_layer_holder.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/system_buffer_manager.h"
namespace Service::AM {
struct Applet {
explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
~Applet();
// Lock
std::mutex lock{};
// Event creation helper
KernelHelpers::ServiceContext context;
// Applet message queue
AppletMessageQueue message_queue;
// Process
std::unique_ptr<Process> process;
// Creation state
AppletId applet_id{};
AppletResourceUserId aruid{};
AppletProcessLaunchReason launch_reason{};
AppletType type{};
ProgramId program_id{};
LibraryAppletMode library_applet_mode{};
s32 previous_program_index{-1};
ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable};
// TODO: some fields above can be AppletIdentityInfo
AppletIdentityInfo screen_shot_identity;
// hid state
HidRegistration hid_registration;
// vi state
SystemBufferManager system_buffer_manager{};
ManagedLayerHolder managed_layer_holder{};
// Applet common functions
Result terminate_result{};
s32 display_logical_width{};
s32 display_logical_height{};
Common::Rectangle<f32> display_magnification{0, 0, 1, 1};
bool home_button_double_click_enabled{};
bool home_button_short_pressed_blocked{};
bool home_button_long_pressed_blocked{};
bool vr_mode_curtain_required{};
bool sleep_required_by_high_temperature{};
bool sleep_required_by_low_battery{};
s32 cpu_boost_request_priority{-1};
bool handling_capture_button_short_pressed_message_enabled_for_applet{};
bool handling_capture_button_long_pressed_message_enabled_for_applet{};
u32 application_core_usage_mode{};
// Application functions
bool gameplay_recording_supported{};
GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled};
bool jit_service_launched{};
bool is_running{};
bool application_crash_report_enabled{};
// Common state
FocusState focus_state{};
bool sleep_lock_enabled{};
bool vr_mode_enabled{};
bool lcd_backlight_off_enabled{};
APM::CpuBoostMode boost_mode{};
bool request_exit_to_library_applet_at_execute_next_program_enabled{};
// Channels
std::deque<std::vector<u8>> user_channel_launch_parameter{};
std::deque<std::vector<u8>> preselected_user_launch_parameter{};
// Caller applet
std::weak_ptr<Applet> caller_applet{};
std::shared_ptr<AppletDataBroker> caller_applet_broker{};
// Self state
bool exit_locked{};
s32 fatal_section_count{};
bool operation_mode_changed_notification_enabled{true};
bool performance_mode_changed_notification_enabled{true};
FocusHandlingMode focus_handling_mode{};
bool restart_message_enabled{};
bool out_of_focus_suspension_enabled{true};
Capture::AlbumImageOrientation album_image_orientation{};
bool handles_request_to_display{};
ScreenshotPermission screenshot_permission{};
IdleTimeDetectionExtension idle_time_detection_extension{};
bool auto_sleep_disabled{};
u64 suspended_ticks{};
bool album_image_taken_notification_enabled{};
bool record_volume_muted{};
// Events
Event gpu_error_detected_event;
Event friend_invitation_storage_channel_event;
Event notification_storage_channel_event;
Event health_warning_disappeared_system_event;
Event acquired_sleep_lock_event;
Event pop_from_general_channel_event;
Event library_applet_launchable_event;
Event accumulated_suspended_tick_changed_event;
Event sleep_lock_event;
// Frontend state
std::shared_ptr<Frontend::FrontendApplet> frontend{};
};
} // namespace Service::AM

@ -1,291 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/library_applet_proxy.h"
#include "core/hle/service/am/system_applet_proxy.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_,
Core::System& system_)
: ServiceFramework{system_, "ILibraryAppletProxy"},
nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
{2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
{3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISelfController>(system, nvnflinger);
}
void GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IWindowController>(system);
}
void GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAudioController>(system);
}
void GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDisplayController>(system);
}
void GetProcessWindingController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IProcessWindingController>(system);
}
void GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system);
}
void GetAppletCommonFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAppletCommonFunctions>(system);
}
void GetHomeMenuFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHomeMenuFunctions>(system);
}
void GetGlobalStateController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IGlobalStateController>(system);
}
void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDebugFunctions>(system);
}
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_,
Core::System& system_)
: ServiceFramework{system_, "ISystemAppletProxy"},
nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
{2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
{3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
{4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
{10, nullptr, "GetProcessWindingController"},
{11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
{23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
{1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISelfController>(system, nvnflinger);
}
void GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IWindowController>(system);
}
void GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAudioController>(system);
}
void GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDisplayController>(system);
}
void GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetHomeMenuFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHomeMenuFunctions>(system);
}
void GetGlobalStateController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IGlobalStateController>(system);
}
void GetApplicationCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationCreator>(system);
}
void GetAppletCommonFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAppletCommonFunctions>(system);
}
void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDebugFunctions>(system);
}
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, msg_queue, system);
}
void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
}
void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
}
AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
: ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{
std::move(msg_queue_)} {
AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
: ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
@ -304,8 +29,45 @@ AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
AppletAE::~AppletAE() = default;
const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
return msg_queue;
void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = GetAppletFromContext(ctx)) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system);
} else {
UNIMPLEMENTED();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
}
}
void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = GetAppletFromContext(ctx)) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system);
} else {
UNIMPLEMENTED();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
}
}
void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
return OpenLibraryAppletProxy(ctx);
}
std::shared_ptr<Applet> AppletAE::GetAppletFromContext(HLERequestContext& ctx) {
const auto aruid = ctx.GetPID();
return system.GetAppletManager().GetByAppletResourceUserId(aruid);
}
} // namespace Service::AM

@ -18,23 +18,21 @@ class Nvnflinger;
namespace AM {
class AppletMessageQueue;
struct Applet;
class AppletAE final : public ServiceFramework<AppletAE> {
public:
explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
~AppletAE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
private:
void OpenSystemAppletProxy(HLERequestContext& ctx);
void OpenLibraryAppletProxy(HLERequestContext& ctx);
void OpenLibraryAppletProxyOld(HLERequestContext& ctx);
std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
} // namespace AM

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_common_functions.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetTerminateResult"},
{10, nullptr, "ReadThemeStorage"},
{11, nullptr, "WriteThemeStorage"},
{20, nullptr, "PushToAppletBoundChannel"},
{21, nullptr, "TryPopFromAppletBoundChannel"},
{40, nullptr, "GetDisplayLogicalResolution"},
{42, nullptr, "SetDisplayMagnification"},
{50, nullptr, "SetHomeButtonDoubleClickEnabled"},
{51, nullptr, "GetHomeButtonDoubleClickEnabled"},
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
{60, nullptr, "IsVrModeCurtainRequired"},
{61, nullptr, "IsSleepRequiredByHighTemperature"},
{62, nullptr, "IsSleepRequiredByLowBattery"},
{70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"},
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
{90, nullptr, "OpenNamedChannelAsParent"},
{91, nullptr, "OpenNamedChannelAsChild"},
{100, nullptr, "SetApplicationCoreUsageMode"},
{300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"},
};
// clang-format on
RegisterHandlers(functions);
}
IAppletCommonFunctions::~IAppletCommonFunctions() = default;
void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
std::scoped_lock lk{applet->lock};
applet->cpu_boost_request_priority = rp.Pop<s32>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetApplicationProcessProgramID() & ~0xFFFULL);
}
} // namespace Service::AM

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
public:
explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
~IAppletCommonFunctions() override;
private:
void SetCpuBoostRequestPriority(HLERequestContext& ctx);
void GetCurrentApplicationId(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
namespace Service::AM {
AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context)
: m_event(context) {}
AppletStorageChannel::~AppletStorageChannel() = default;
void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
std::scoped_lock lk{m_lock};
m_data.emplace_back(std::move(storage));
m_event.Signal();
}
Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
std::scoped_lock lk{m_lock};
SCOPE_EXIT({
if (m_data.empty()) {
m_event.Clear();
}
});
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
*out_storage = std::move(m_data.front());
m_data.pop_front();
R_SUCCEED();
}
Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
return m_event.GetHandle();
}
AppletDataBroker::AppletDataBroker(Core::System& system_)
: system(system_), context(system_, "AppletDataBroker"), in_data(context),
interactive_in_data(context), out_data(context), interactive_out_data(context),
state_changed_event(context), is_completed(false) {}
AppletDataBroker::~AppletDataBroker() = default;
void AppletDataBroker::SignalCompletion() {
{
std::scoped_lock lk{lock};
if (is_completed) {
return;
}
is_completed = true;
state_changed_event.Signal();
}
system.GetAppletManager().FocusStateChanged();
}
} // namespace Service::AM

@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <deque>
#include <memory>
#include <mutex>
#include "core/hle/service/event.h"
#include "core/hle/service/kernel_helpers.h"
union Result;
namespace Service::AM {
struct Applet;
class IStorage;
class AppletStorageChannel {
public:
explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx);
~AppletStorageChannel();
void Push(std::shared_ptr<IStorage> storage);
Result Pop(std::shared_ptr<IStorage>* out_storage);
Kernel::KReadableEvent* GetEvent();
private:
std::mutex m_lock{};
std::deque<std::shared_ptr<IStorage>> m_data{};
Event m_event;
};
class AppletDataBroker {
public:
explicit AppletDataBroker(Core::System& system_);
~AppletDataBroker();
AppletStorageChannel& GetInData() {
return in_data;
}
AppletStorageChannel& GetInteractiveInData() {
return interactive_in_data;
}
AppletStorageChannel& GetOutData() {
return out_data;
}
AppletStorageChannel& GetInteractiveOutData() {
return interactive_out_data;
}
Event& GetStateChangedEvent() {
return state_changed_event;
}
bool IsCompleted() const {
return is_completed;
}
void SignalCompletion();
private:
Core::System& system;
KernelHelpers::ServiceContext context;
AppletStorageChannel in_data;
AppletStorageChannel interactive_in_data;
AppletStorageChannel out_data;
AppletStorageChannel interactive_out_data;
Event state_changed_event;
std::mutex lock;
bool is_completed;
};
} // namespace Service::AM

@ -0,0 +1,361 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "common/uuid.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applet_cabinet.h"
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
namespace {
constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA;
struct LaunchParameterAccountPreselectedUser {
u32 magic;
u32 is_account_selected;
Common::UUID current_user;
INSERT_PADDING_BYTES(0x70);
};
static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system,
std::shared_ptr<Applet>& applet) {
applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system);
return applet->caller_applet_broker->GetInData();
}
void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = 1,
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<u8> argument_data(sizeof(arguments));
std::vector<u8> settings_data{2};
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
}
void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments common_args = {
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = static_cast<u32>(Frontend::ControllerAppletVersion::Version8),
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
Frontend::ControllerSupportArgNew user_args = {
.header = {.player_count_min = 1,
.player_count_max = 4,
.enable_take_over_connection = true,
.enable_left_justify = false,
.enable_permit_joy_dual = true,
.enable_single_mode = false,
.enable_identification_color = false},
.identification_colors = {},
.enable_explain_text = false,
.explain_text = {},
};
Frontend::ControllerSupportArgPrivate private_args = {
.arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate),
.arg_size = sizeof(Frontend::ControllerSupportArgNew),
.is_home_menu = true,
.flag_1 = true,
.mode = Frontend::ControllerSupportMode::ShowControllerSupport,
.caller = Frontend::ControllerSupportCaller::
Application, // switchbrew: Always zero except with
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
// which sets this to the input param
.style_set = Core::HID::NpadStyleSet::None,
.joy_hold_type = 0,
};
std::vector<u8> common_args_data(sizeof(common_args));
std::vector<u8> private_args_data(sizeof(private_args));
std::vector<u8> user_args_data(sizeof(user_args));
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
channel.Push(std::make_shared<IStorage>(system, std::move(common_args_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(private_args_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data)));
}
void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = static_cast<u32>(Frontend::CabinetAppletVersion::Version1),
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
const Frontend::StartParamForAmiiboSettings amiibo_settings{
.param_1 = 0,
.applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(),
.flags = Frontend::CabinetFlags::None,
.amiibo_settings_1 = 0,
.device_handle = 0,
.tag_info{},
.register_info{},
.amiibo_settings_3{},
};
std::vector<u8> argument_data(sizeof(arguments));
std::vector<u8> settings_data(sizeof(amiibo_settings));
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
}
void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) {
struct MiiEditV3 {
Frontend::MiiEditAppletInputCommon common;
Frontend::MiiEditAppletInputV3 input;
};
static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
MiiEditV3 mii_arguments{
.common =
{
.version = Frontend::MiiEditAppletVersion::Version3,
.applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit,
},
.input{},
};
std::vector<u8> argument_data(sizeof(mii_arguments));
std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
}
void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = static_cast<u32>(Frontend::SwkbdAppletVersion::Version524301),
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<char16_t> initial_string(0);
const Frontend::SwkbdConfigCommon swkbd_config{
.type = Frontend::SwkbdType::Qwerty,
.ok_text{},
.left_optional_symbol_key{},
.right_optional_symbol_key{},
.use_prediction = false,
.key_disable_flags{},
.initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start,
.header_text{},
.sub_text{},
.guide_text{},
.max_text_length = 500,
.min_text_length = 0,
.password_mode = Frontend::SwkbdPasswordMode::Disabled,
.text_draw_type = Frontend::SwkbdTextDrawType::Box,
.enable_return_button = true,
.use_utf8 = false,
.use_blur_background = true,
.initial_string_offset{},
.initial_string_length = static_cast<u32>(initial_string.size()),
.user_dictionary_offset{},
.user_dictionary_entries{},
.use_text_check = false,
};
Frontend::SwkbdConfigNew swkbd_config_new{};
std::vector<u8> argument_data(sizeof(arguments));
std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
sizeof(Frontend::SwkbdConfigNew));
std::memcpy(work_buffer.data(), initial_string.data(),
swkbd_config.initial_string_length * sizeof(char16_t));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(swkbd_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer)));
}
} // namespace
AppletManager::AppletManager(Core::System& system) : m_system(system) {}
AppletManager::~AppletManager() {
this->Reset();
}
void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) {
std::scoped_lock lk{m_lock};
m_applets.emplace(applet->aruid, std::move(applet));
}
void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) {
std::shared_ptr<Applet> applet;
bool should_stop = false;
{
std::scoped_lock lk{m_lock};
const auto it = m_applets.find(aruid);
if (it == m_applets.end()) {
return;
}
applet = it->second;
m_applets.erase(it);
should_stop = m_applets.empty();
}
// Terminate process.
applet->process->Terminate();
// If there were no applets left, stop emulation.
if (should_stop) {
m_system.Exit();
}
}
void AppletManager::CreateAndInsertByFrontendAppletParameters(
AppletResourceUserId aruid, const FrontendAppletParameters& params) {
// TODO: this should be run inside AM so that the events will have a parent process
// TODO: have am create the guest process
auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system));
applet->aruid = aruid;
applet->program_id = params.program_id;
applet->applet_id = params.applet_id;
applet->type = params.applet_type;
applet->previous_program_index = params.previous_program_index;
// Push UserChannel data from previous application
if (params.launch_type == LaunchType::ApplicationInitiated) {
applet->user_channel_launch_parameter.swap(m_system.GetUserChannel());
}
// TODO: Read whether we need a preselected user from NACP?
// TODO: This can be done quite easily from loader
{
LaunchParameterAccountPreselectedUser lp{};
lp.magic = LaunchParameterAccountPreselectedUserMagic;
lp.is_account_selected = 1;
Account::ProfileManager profile_manager{};
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
ASSERT(uuid.has_value() && uuid->IsValid());
lp.current_user = *uuid;
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
std::memcpy(buffer.data(), &lp, buffer.size());
applet->preselected_user_launch_parameter.push_back(std::move(buffer));
}
// Starting from frontend, some applets require input data.
switch (applet->applet_id) {
case AppletId::Cabinet:
PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::MiiEdit:
PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::PhotoViewer:
PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::SoftwareKeyboard:
PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::Controller:
PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
default:
break;
}
// Applet was started by frontend, so it is foreground.
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
applet->focus_state = FocusState::InFocus;
this->InsertApplet(std::move(applet));
}
std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const {
std::scoped_lock lk{m_lock};
if (const auto it = m_applets.find(aruid); it != m_applets.end()) {
return it->second;
}
return {};
}
void AppletManager::Reset() {
std::scoped_lock lk{m_lock};
m_applets.clear();
}
void AppletManager::RequestExit() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.RequestExit();
}
}
void AppletManager::RequestResume() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.RequestResume();
}
}
void AppletManager::OperationModeChanged() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.OperationModeChanged();
}
}
void AppletManager::FocusStateChanged() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.FocusStateChanged();
}
}
} // namespace Service::AM

@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <map>
#include <mutex>
#include "core/hle/service/am/applet.h"
namespace Core {
class System;
}
namespace Service::AM {
enum class LaunchType {
FrontendInitiated,
ApplicationInitiated,
};
struct FrontendAppletParameters {
ProgramId program_id{};
AppletId applet_id{};
AppletType applet_type{};
LaunchType launch_type{};
s32 program_index{};
s32 previous_program_index{-1};
};
class AppletManager {
public:
explicit AppletManager(Core::System& system);
~AppletManager();
void InsertApplet(std::shared_ptr<Applet> applet);
void TerminateAndRemoveApplet(AppletResourceUserId aruid);
void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
const FrontendAppletParameters& params);
std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
void Reset();
void RequestExit();
void RequestResume();
void OperationModeChanged();
void FocusStateChanged();
private:
Core::System& m_system;
mutable std::mutex m_lock{};
std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
// AudioController state goes here
};
} // namespace Service::AM

@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
AppletMessageQueue::AppletMessageQueue(Core::System& system)
: service_context{system, "AppletMessageQueue"} {
on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
}
AppletMessageQueue::~AppletMessageQueue() {
service_context.CloseEvent(on_new_message);
service_context.CloseEvent(on_operation_mode_changed);
}
Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
return on_new_message->GetReadableEvent();
}
Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
return on_operation_mode_changed->GetReadableEvent();
}
void AppletMessageQueue::PushMessage(AppletMessage msg) {
{
std::scoped_lock lk{lock};
messages.push(msg);
}
on_new_message->Signal();
}
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
std::scoped_lock lk{lock};
if (messages.empty()) {
on_new_message->Clear();
return AppletMessage::None;
}
auto msg = messages.front();
messages.pop();
if (messages.empty()) {
on_new_message->Clear();
}
return msg;
}
std::size_t AppletMessageQueue::GetMessageCount() const {
std::scoped_lock lk{lock};
return messages.size();
}
void AppletMessageQueue::RequestExit() {
PushMessage(AppletMessage::Exit);
}
void AppletMessageQueue::RequestResume() {
PushMessage(AppletMessage::Resume);
}
void AppletMessageQueue::FocusStateChanged() {
PushMessage(AppletMessage::FocusStateChanged);
}
void AppletMessageQueue::OperationModeChanged() {
PushMessage(AppletMessage::OperationModeChanged);
PushMessage(AppletMessage::PerformanceModeChanged);
on_operation_mode_changed->Signal();
}
} // namespace Service::AM

@ -0,0 +1,76 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <queue>
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KReadableEvent;
} // namespace Kernel
namespace Service::AM {
class AppletMessageQueue {
public:
// This is nn::am::AppletMessage
enum class AppletMessage : u32 {
None = 0,
ChangeIntoForeground = 1,
ChangeIntoBackground = 2,
Exit = 4,
ApplicationExited = 6,
FocusStateChanged = 15,
Resume = 16,
DetectShortPressingHomeButton = 20,
DetectLongPressingHomeButton = 21,
DetectShortPressingPowerButton = 22,
DetectMiddlePressingPowerButton = 23,
DetectLongPressingPowerButton = 24,
RequestToPrepareSleep = 25,
FinishedSleepSequence = 26,
SleepRequiredByHighTemperature = 27,
SleepRequiredByLowBattery = 28,
AutoPowerDown = 29,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
DetectReceivingCecSystemStandby = 32,
SdCardRemoved = 33,
LaunchApplicationRequested = 50,
RequestToDisplay = 51,
ShowApplicationLogo = 55,
HideApplicationLogo = 56,
ForceHideApplicationLogo = 57,
FloatingApplicationDetected = 60,
DetectShortPressingCaptureButton = 90,
AlbumScreenShotTaken = 92,
AlbumRecordingSaved = 93,
};
explicit AppletMessageQueue(Core::System& system);
~AppletMessageQueue();
Kernel::KReadableEvent& GetMessageReceiveEvent();
Kernel::KReadableEvent& GetOperationModeChangedEvent();
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
void RequestExit();
void RequestResume();
void FocusStateChanged();
void OperationModeChanged();
private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* on_new_message;
Kernel::KEvent* on_operation_mode_changed;
mutable std::mutex lock;
std::queue<AppletMessage> messages;
};
} // namespace Service::AM

@ -1,119 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/application_proxy.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_,
Core::System& system_)
: ServiceFramework{system_, "IApplicationProxy"},
nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &IApplicationProxy::GetSelfController, "GetSelfController"},
{2, &IApplicationProxy::GetWindowController, "GetWindowController"},
{3, &IApplicationProxy::GetAudioController, "GetAudioController"},
{4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
{10, nullptr, "GetProcessWindingController"},
{11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
{1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAudioController>(system);
}
void GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDisplayController>(system);
}
void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDebugFunctions>(system);
}
void GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IWindowController>(system);
}
void GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISelfController>(system, nvnflinger);
}
void GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetApplicationFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationFunctions>(system);
}
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system);
}
AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
: ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{
std::move(msg_queue_)} {
AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
: ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} {
static const FunctionInfo functions[] = {
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};
@ -122,8 +19,24 @@ AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
AppletOE::~AppletOE() = default;
const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
return msg_queue;
void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = GetAppletFromContext(ctx)) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system);
} else {
UNIMPLEMENTED();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
}
}
std::shared_ptr<Applet> AppletOE::GetAppletFromContext(HLERequestContext& ctx) {
const auto aruid = ctx.GetPID();
return system.GetAppletManager().GetByAppletResourceUserId(aruid);
}
} // namespace Service::AM

@ -18,21 +18,19 @@ class Nvnflinger;
namespace AM {
class AppletMessageQueue;
struct Applet;
class AppletOE final : public ServiceFramework<AppletOE> {
public:
explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
~AppletOE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
private:
void OpenApplicationProxy(HLERequestContext& ctx);
std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
} // namespace AM

@ -1,338 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/assert.h"
#include "core/core.h"
#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/mii_edit.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
#include "core/hle/service/am/applets/applet_mii_edit.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/applets/applet_software_keyboard.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM::Applets {
AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
: system{system_}, applet_mode{applet_mode_}, service_context{system,
"ILibraryAppletAccessor"} {
state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent");
pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent");
pop_interactive_out_data_event =
service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
}
AppletDataBroker::~AppletDataBroker() {
service_context.CloseEvent(state_changed_event);
service_context.CloseEvent(pop_out_data_event);
service_context.CloseEvent(pop_interactive_out_data_event);
}
AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
std::vector<std::vector<u8>> out_normal;
for (const auto& storage : in_channel) {
out_normal.push_back(storage->GetData());
}
std::vector<std::vector<u8>> out_interactive;
for (const auto& storage : in_interactive_channel) {
out_interactive.push_back(storage->GetData());
}
return {std::move(out_normal), std::move(out_interactive)};
}
std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
if (out_channel.empty())
return nullptr;
auto out = std::move(out_channel.front());
out_channel.pop_front();
pop_out_data_event->Clear();
return out;
}
std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
if (in_channel.empty())
return nullptr;
auto out = std::move(in_channel.front());
in_channel.pop_front();
return out;
}
std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
if (out_interactive_channel.empty())
return nullptr;
auto out = std::move(out_interactive_channel.front());
out_interactive_channel.pop_front();
pop_interactive_out_data_event->Clear();
return out;
}
std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
if (in_interactive_channel.empty())
return nullptr;
auto out = std::move(in_interactive_channel.front());
in_interactive_channel.pop_front();
return out;
}
void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
in_channel.emplace_back(std::move(storage));
}
void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
out_channel.emplace_back(std::move(storage));
pop_out_data_event->Signal();
}
void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
in_interactive_channel.emplace_back(std::move(storage));
}
void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
out_interactive_channel.emplace_back(std::move(storage));
pop_interactive_out_data_event->Signal();
}
void AppletDataBroker::SignalStateChanged() {
state_changed_event->Signal();
switch (applet_mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::AllForegroundInitiallyHidden: {
auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE");
auto applet_ae = system.ServiceManager().GetService<AppletAE>("appletAE");
if (applet_oe) {
applet_oe->GetMessageQueue()->FocusStateChanged();
break;
}
if (applet_ae) {
applet_ae->GetMessageQueue()->FocusStateChanged();
break;
}
break;
}
default:
break;
}
}
Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
return pop_out_data_event->GetReadableEvent();
}
Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
return pop_interactive_out_data_event->GetReadableEvent();
}
Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
return state_changed_event->GetReadableEvent();
}
Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
: broker{system_, applet_mode_}, applet_mode{applet_mode_} {}
Applet::~Applet() = default;
void Applet::Initialize() {
const auto common = broker.PopNormalDataToApplet();
ASSERT(common != nullptr);
const auto common_data = common->GetData();
ASSERT(common_data.size() >= sizeof(CommonArguments));
std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
initialized = true;
}
AppletFrontendSet::AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
ControllerApplet controller_applet, ErrorApplet error_applet,
MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet,
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
: cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
parental_controls{std::move(parental_controls_applet)},
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
AppletFrontendSet::~AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
AppletManager::AppletManager(Core::System& system_) : system{system_} {}
AppletManager::~AppletManager() = default;
const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
return frontend;
}
NFP::CabinetMode AppletManager::GetCabinetMode() const {
return cabinet_mode;
}
AppletId AppletManager::GetCurrentAppletId() const {
return current_applet_id;
}
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
if (set.cabinet != nullptr) {
frontend.cabinet = std::move(set.cabinet);
}
if (set.controller != nullptr) {
frontend.controller = std::move(set.controller);
}
if (set.error != nullptr) {
frontend.error = std::move(set.error);
}
if (set.mii_edit != nullptr) {
frontend.mii_edit = std::move(set.mii_edit);
}
if (set.parental_controls != nullptr) {
frontend.parental_controls = std::move(set.parental_controls);
}
if (set.photo_viewer != nullptr) {
frontend.photo_viewer = std::move(set.photo_viewer);
}
if (set.profile_select != nullptr) {
frontend.profile_select = std::move(set.profile_select);
}
if (set.software_keyboard != nullptr) {
frontend.software_keyboard = std::move(set.software_keyboard);
}
if (set.web_browser != nullptr) {
frontend.web_browser = std::move(set.web_browser);
}
}
void AppletManager::SetCabinetMode(NFP::CabinetMode mode) {
cabinet_mode = mode;
}
void AppletManager::SetCurrentAppletId(AppletId applet_id) {
current_applet_id = applet_id;
}
void AppletManager::SetDefaultAppletFrontendSet() {
ClearAll();
SetDefaultAppletsIfMissing();
}
void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.cabinet == nullptr) {
frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
}
if (frontend.controller == nullptr) {
frontend.controller =
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
}
if (frontend.error == nullptr) {
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
}
if (frontend.mii_edit == nullptr) {
frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
}
if (frontend.parental_controls == nullptr) {
frontend.parental_controls =
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
}
if (frontend.photo_viewer == nullptr) {
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
}
if (frontend.profile_select == nullptr) {
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
}
if (frontend.software_keyboard == nullptr) {
frontend.software_keyboard =
std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
}
if (frontend.web_browser == nullptr) {
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
}
}
void AppletManager::ClearAll() {
frontend = {};
}
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
case AppletId::Cabinet:
return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
case AppletId::Controller:
return std::make_shared<Controller>(system, mode, *frontend.controller);
case AppletId::Error:
return std::make_shared<Error>(system, mode, *frontend.error);
case AppletId::ProfileSelect:
return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
case AppletId::SoftwareKeyboard:
return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
case AppletId::MiiEdit:
return std::make_shared<MiiEdit>(system, mode, *frontend.mii_edit);
case AppletId::Web:
case AppletId::Shop:
case AppletId::OfflineWeb:
case AppletId::LoginShare:
case AppletId::WebAuth:
return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
case AppletId::PhotoViewer:
return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
default:
UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
static_cast<u8>(id));
return std::make_shared<StubApplet>(system, id, mode);
}
}
} // namespace Service::AM::Applets

@ -1,289 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <queue>
#include "common/swap.h"
#include "core/hle/service/kernel_helpers.h"
union Result;
namespace Core {
class System;
}
namespace Core::Frontend {
class CabinetApplet;
class ControllerApplet;
class ECommerceApplet;
class ErrorApplet;
class MiiEditApplet;
class ParentalControlsApplet;
class PhotoViewerApplet;
class ProfileSelectApplet;
class SoftwareKeyboardApplet;
class WebBrowserApplet;
} // namespace Core::Frontend
namespace Kernel {
class KernelCore;
class KEvent;
class KReadableEvent;
} // namespace Kernel
namespace Service::NFP {
enum class CabinetMode : u8;
} // namespace Service::NFP
namespace Service::AM {
class IStorage;
namespace Applets {
enum class AppletId : u32 {
None = 0x00,
Application = 0x01,
OverlayDisplay = 0x02,
QLaunch = 0x03,
Starter = 0x04,
Auth = 0x0A,
Cabinet = 0x0B,
Controller = 0x0C,
DataErase = 0x0D,
Error = 0x0E,
NetConnect = 0x0F,
ProfileSelect = 0x10,
SoftwareKeyboard = 0x11,
MiiEdit = 0x12,
Web = 0x13,
Shop = 0x14,
PhotoViewer = 0x15,
Settings = 0x16,
OfflineWeb = 0x17,
LoginShare = 0x18,
WebAuth = 0x19,
MyPage = 0x1A,
};
enum class AppletProgramId : u64 {
QLaunch = 0x0100000000001000ull,
Auth = 0x0100000000001001ull,
Cabinet = 0x0100000000001002ull,
Controller = 0x0100000000001003ull,
DataErase = 0x0100000000001004ull,
Error = 0x0100000000001005ull,
NetConnect = 0x0100000000001006ull,
ProfileSelect = 0x0100000000001007ull,
SoftwareKeyboard = 0x0100000000001008ull,
MiiEdit = 0x0100000000001009ull,
Web = 0x010000000000100Aull,
Shop = 0x010000000000100Bull,
OverlayDisplay = 0x010000000000100Cull,
PhotoViewer = 0x010000000000100Dull,
Settings = 0x010000000000100Eull,
OfflineWeb = 0x010000000000100Full,
LoginShare = 0x0100000000001010ull,
WebAuth = 0x0100000000001011ull,
Starter = 0x0100000000001012ull,
MyPage = 0x0100000000001013ull,
MaxProgramId = 0x0100000000001FFFull,
};
enum class LibraryAppletMode : u32 {
AllForeground = 0,
Background = 1,
NoUI = 2,
BackgroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4,
};
enum class CommonArgumentVersion : u32 {
Version0,
Version1,
Version2,
Version3,
};
enum class CommonArgumentSize : u32 {
Version3 = 0x20,
};
enum class ThemeColor : u32 {
BasicWhite = 0,
BasicBlack = 3,
};
struct CommonArguments {
CommonArgumentVersion arguments_version;
CommonArgumentSize size;
u32 library_version;
ThemeColor theme_color;
bool play_startup_sound;
u64_le system_tick;
};
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
class AppletDataBroker final {
public:
explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
~AppletDataBroker();
struct RawChannelData {
std::vector<std::vector<u8>> normal;
std::vector<std::vector<u8>> interactive;
};
// Retrieves but does not pop the data sent to applet.
RawChannelData PeekDataToAppletForDebug() const;
std::shared_ptr<IStorage> PopNormalDataToGame();
std::shared_ptr<IStorage> PopNormalDataToApplet();
std::shared_ptr<IStorage> PopInteractiveDataToGame();
std::shared_ptr<IStorage> PopInteractiveDataToApplet();
void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
void SignalStateChanged();
Kernel::KReadableEvent& GetNormalDataEvent();
Kernel::KReadableEvent& GetInteractiveDataEvent();
Kernel::KReadableEvent& GetStateChangedEvent();
private:
Core::System& system;
LibraryAppletMode applet_mode;
KernelHelpers::ServiceContext service_context;
// Queues are named from applet's perspective
// PopNormalDataToApplet and PushNormalDataFromGame
std::deque<std::shared_ptr<IStorage>> in_channel;
// PopNormalDataToGame and PushNormalDataFromApplet
std::deque<std::shared_ptr<IStorage>> out_channel;
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
Kernel::KEvent* state_changed_event;
// Signaled on PushNormalDataFromApplet
Kernel::KEvent* pop_out_data_event;
// Signaled on PushInteractiveDataFromApplet
Kernel::KEvent* pop_interactive_out_data_event;
};
class Applet {
public:
explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_);
virtual ~Applet();
virtual void Initialize();
virtual bool TransactionComplete() const = 0;
virtual Result GetStatus() const = 0;
virtual void ExecuteInteractive() = 0;
virtual void Execute() = 0;
virtual Result RequestExit() = 0;
AppletDataBroker& GetBroker() {
return broker;
}
const AppletDataBroker& GetBroker() const {
return broker;
}
LibraryAppletMode GetLibraryAppletMode() const {
return applet_mode;
}
bool IsInitialized() const {
return initialized;
}
protected:
CommonArguments common_args{};
AppletDataBroker broker;
LibraryAppletMode applet_mode;
bool initialized = false;
};
struct AppletFrontendSet {
using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
AppletFrontendSet();
AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
ErrorApplet error_applet, MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
WebBrowser web_browser_);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
AppletFrontendSet& operator=(const AppletFrontendSet&) = delete;
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
CabinetApplet cabinet;
ControllerApplet controller;
ErrorApplet error;
MiiEdit mii_edit;
ParentalControlsApplet parental_controls;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
WebBrowser web_browser;
};
class AppletManager {
public:
explicit AppletManager(Core::System& system_);
~AppletManager();
const AppletFrontendSet& GetAppletFrontendSet() const;
NFP::CabinetMode GetCabinetMode() const;
AppletId GetCurrentAppletId() const;
void SetAppletFrontendSet(AppletFrontendSet set);
void SetCabinetMode(NFP::CabinetMode mode);
void SetCurrentAppletId(AppletId applet_id);
void SetDefaultAppletFrontendSet();
void SetDefaultAppletsIfMissing();
void ClearAll();
std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
private:
AppletId current_applet_id{};
NFP::CabinetMode cabinet_mode{};
AppletFrontendSet frontend;
Core::System& system;
};
} // namespace Applets
} // namespace Service::AM

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/application_creator.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IApplicationCreator::IApplicationCreator(Core::System& system_)
: ServiceFramework{system_, "IApplicationCreator"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateApplication"},
{1, nullptr, "PopLaunchRequestedApplication"},
{10, nullptr, "CreateSystemApplication"},
{100, nullptr, "PopFloatingApplicationForDevelopment"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationCreator::~IApplicationCreator() = default;
} // namespace Service::AM

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public:
explicit IApplicationCreator(Core::System& system_);
~IApplicationCreator() override;
};
} // namespace Service::AM

@ -0,0 +1,594 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "common/uuid.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/savedata_factory.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/application_functions.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/save_data_controller.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
enum class LaunchParameterKind : u32 {
UserChannel = 1,
AccountPreselectedUser = 2,
};
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
{12, nullptr, "CreateApplicationAndRequestToStart"},
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
{20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
{23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
{24, nullptr, "GetLaunchStorageInfoForDebug"},
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
{27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
{28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
{29, nullptr, "GetCacheStorageMax"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
{33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
{34, nullptr, "SelectApplicationLicense"},
{35, nullptr, "GetDeviceSaveDataSizeMax"},
{36, nullptr, "GetLimitedApplicationLicense"},
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
{50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
{60, nullptr, "SetMediaPlaybackStateForApplication"},
{65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"},
{66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
{67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
{68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
{70, nullptr, "RequestToShutdown"},
{71, nullptr, "RequestToReboot"},
{72, nullptr, "RequestToSleep"},
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
{90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
{100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
{101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
{110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
{120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
{121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
{122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
{131, nullptr, "SetDelayTimeToAbortOnGpuError"},
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
{141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
{150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"},
{151, nullptr, "TryPopFromNotificationStorageChannel"},
{160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
{170, nullptr, "SetHdcpAuthenticationActivated"},
{180, nullptr, "GetLaunchRequiredVersion"},
{181, nullptr, "UpgradeLaunchRequiredVersion"},
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
{200, nullptr, "GetLastApplicationExitReason"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationFunctions::~IApplicationFunctions() = default;
void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->application_crash_report_enabled = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_visible = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->home_button_long_pressed_blocked = true;
applet->home_button_short_pressed_blocked = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->home_button_long_pressed_blocked = false;
applet->home_button_short_pressed_blocked = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->home_button_long_pressed_blocked = true;
applet->home_button_short_pressed_blocked = true;
applet->home_button_double_click_enabled = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->home_button_long_pressed_blocked = false;
applet->home_button_short_pressed_blocked = false;
applet->home_button_double_click_enabled = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto kind = rp.PopEnum<LaunchParameterKind>();
LOG_INFO(Service_AM, "called, kind={:08X}", kind);
std::scoped_lock lk{applet->lock};
auto& channel = kind == LaunchParameterKind::UserChannel
? applet->user_channel_launch_parameter
: applet->preselected_user_launch_parameter;
if (channel.empty()) {
LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultNoDataInChannel);
return;
}
auto data = channel.back();
channel.pop_back();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(system, std::move(data));
}
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 user_id = rp.PopRaw<u128>();
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
FileSys::SaveDataAttribute attribute{};
attribute.title_id = applet->program_id;
attribute.user_id = user_id;
attribute.type = FileSys::SaveDataType::SaveData;
FileSys::VirtualDir save_data{};
const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.Push<u64>(0);
}
void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
// For example, in some cases official apps use this with error 0x2A2 then
// uses svcBreak.
IPC::RequestParser rp{ctx};
u32 result = rp.Pop<u32>();
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
std::scoped_lock lk{applet->lock};
applet->terminate_result = Result(result);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
std::array<u8, 0x10> version_string{};
const auto res = [this] {
const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
const auto& version = res.first->GetVersionString();
std::copy(version.begin(), version.end(), version_string.begin());
} else {
static constexpr char default_version[]{"1.0.0"};
std::memcpy(version_string.data(), default_version, sizeof(default_version));
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(version_string);
}
void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = [this] {
const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
u8 desired_language{};
const auto res_lang =
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
if (res_lang != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_lang);
return;
}
// Convert to settings language code.
u64 language_code{};
const auto res_code =
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
if (res_code != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_code);
return;
}
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(language_code);
}
void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(applet->gameplay_recording_supported);
}
void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
std::scoped_lock lk{applet->lock};
applet->gameplay_recording_state = rp.PopRaw<GameplayRecordingState>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->is_running = true;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
}
void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
// Returns a 128-bit UUID
rb.Push<u64>(0);
rb.Push<u64>(0);
}
void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
struct Parameters {
FileSys::SaveDataType type;
u128 user_id;
u64 new_normal_size;
u64 new_journal_size;
};
static_assert(sizeof(Parameters) == 40);
IPC::RequestParser rp{ctx};
const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AM,
"called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
"new_journal={:016X}",
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
type, applet->program_id, user_id, {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
// The following value is used upon failure to help the system recover.
// Since we always succeed, this should be 0.
rb.Push<u64>(0);
}
void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
struct Parameters {
FileSys::SaveDataType type;
u128 user_id;
};
static_assert(sizeof(Parameters) == 24);
IPC::RequestParser rp{ctx};
const auto [type, user_id] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
user_id[0]);
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
type, applet->program_id, user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.Push(size.normal);
rb.Push(size.journal);
}
void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
struct InputParameters {
u16 index;
s64 size;
s64 journal_size;
};
static_assert(sizeof(InputParameters) == 24);
struct OutputParameters {
u32 storage_target;
u64 required_size;
};
static_assert(sizeof(OutputParameters) == 16);
IPC::RequestParser rp{ctx};
const auto params = rp.PopRaw<InputParameters>();
LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
params.index, params.size, params.journal_size);
const OutputParameters resp{
.storage_target = 1,
.required_size = 0,
};
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(resp);
}
void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
constexpr u64 size_max_normal = 0xFFFFFFF;
constexpr u64 size_max_journal = 0xFFFFFFF;
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.Push(size_max_normal);
rb.Push(size_max_journal);
}
void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
}
void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
}
void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
[[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
[[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
const auto program_index = rp.Pop<u64>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
// Swap user channel ownership into the system so that it will be preserved
system.GetUserChannel().swap(applet->user_channel_launch_parameter);
system.ExecuteProgram(program_index);
}
void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
applet->user_channel_launch_parameter.clear();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
const auto storage = rp.PopIpcInterface<IStorage>().lock();
if (storage) {
applet->user_channel_launch_parameter.push_back(storage->GetData());
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<s32>(applet->previous_program_index);
}
void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->gpu_error_detected_event.GetHandle());
}
void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle());
}
void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultNoDataInChannel);
}
void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->notification_storage_channel_event.GetHandle());
}
void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle());
}
void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->jit_service_launched = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
} // namespace Service::AM

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
~IApplicationFunctions() override;
private:
void PopLaunchParameter(HLERequestContext& ctx);
void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
void EnsureSaveData(HLERequestContext& ctx);
void SetTerminateResult(HLERequestContext& ctx);
void GetDisplayVersion(HLERequestContext& ctx);
void GetDesiredLanguage(HLERequestContext& ctx);
void IsGamePlayRecordingSupported(HLERequestContext& ctx);
void InitializeGamePlayRecording(HLERequestContext& ctx);
void SetGamePlayRecordingState(HLERequestContext& ctx);
void NotifyRunning(HLERequestContext& ctx);
void GetPseudoDeviceId(HLERequestContext& ctx);
void ExtendSaveData(HLERequestContext& ctx);
void GetSaveDataSize(HLERequestContext& ctx);
void CreateCacheStorage(HLERequestContext& ctx);
void GetSaveDataSizeMax(HLERequestContext& ctx);
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
void BeginBlockingHomeButton(HLERequestContext& ctx);
void EndBlockingHomeButton(HLERequestContext& ctx);
void EnableApplicationCrashReport(HLERequestContext& ctx);
void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
void SetApplicationCopyrightImage(HLERequestContext& ctx);
void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
void QueryApplicationPlayStatistics(HLERequestContext& ctx);
void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
void ExecuteProgram(HLERequestContext& ctx);
void ClearUserChannel(HLERequestContext& ctx);
void UnpopToUserChannel(HLERequestContext& ctx);
void GetPreviousProgramIndex(HLERequestContext& ctx);
void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
void PrepareForJit(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,115 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet_common_functions.h"
#include "core/hle/service/am/application_functions.h"
#include "core/hle/service/am/application_proxy.h"
#include "core/hle/service/am/audio_controller.h"
#include "core/hle/service/am/common_state_getter.h"
#include "core/hle/service/am/debug_functions.h"
#include "core/hle/service/am/display_controller.h"
#include "core/hle/service/am/library_applet_creator.h"
#include "core/hle/service/am/library_applet_self_accessor.h"
#include "core/hle/service/am/process_winding_controller.h"
#include "core/hle/service/am/self_controller.h"
#include "core/hle/service/am/window_controller.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<Applet> applet_, Core::System& system_)
: ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &IApplicationProxy::GetSelfController, "GetSelfController"},
{2, &IApplicationProxy::GetWindowController, "GetWindowController"},
{3, &IApplicationProxy::GetAudioController, "GetAudioController"},
{4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
{10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"},
{11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
{1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationProxy::~IApplicationProxy() = default;
void IApplicationProxy::GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAudioController>(system);
}
void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDisplayController>(system, applet);
}
void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IProcessWindingController>(system, applet);
}
void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDebugFunctions>(system);
}
void IApplicationProxy::GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IWindowController>(system, applet);
}
void IApplicationProxy::GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
}
void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ICommonStateGetter>(system, applet);
}
void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
}
void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationFunctions>(system, applet);
}
} // namespace Service::AM

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<Applet> msg_queue_, Core::System& system_);
~IApplicationProxy();
private:
void GetAudioController(HLERequestContext& ctx);
void GetDisplayController(HLERequestContext& ctx);
void GetProcessWindingController(HLERequestContext& ctx);
void GetDebugFunctions(HLERequestContext& ctx);
void GetWindowController(HLERequestContext& ctx);
void GetSelfController(HLERequestContext& ctx);
void GetCommonStateGetter(HLERequestContext& ctx);
void GetLibraryAppletCreator(HLERequestContext& ctx);
void GetApplicationFunctions(HLERequestContext& ctx);
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/audio_controller.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IAudioController::IAudioController(Core::System& system_)
: ServiceFramework{system_, "IAudioController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
{1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
{2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
{3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
{4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
};
// clang-format on
RegisterHandlers(functions);
}
IAudioController::~IAudioController() = default;
void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const float main_applet_volume_tmp = rp.Pop<float>();
const float library_applet_volume_tmp = rp.Pop<float>();
LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
main_applet_volume_tmp, library_applet_volume_tmp);
// Ensure the volume values remain within the 0-100% range
main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
library_applet_volume =
std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(main_applet_volume);
}
void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(library_applet_volume);
}
void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
struct Parameters {
float volume;
s64 fade_time_ns;
};
static_assert(sizeof(Parameters) == 16);
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
parameters.fade_time_ns);
main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const float transparent_volume_rate_tmp = rp.Pop<float>();
LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
// Clamp volume range to 0-100%.
transparent_volume_rate =
std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
} // namespace Service::AM

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class IAudioController final : public ServiceFramework<IAudioController> {
public:
explicit IAudioController(Core::System& system_);
~IAudioController() override;
private:
void SetExpectedMasterVolume(HLERequestContext& ctx);
void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
void SetTransparentAudioRate(HLERequestContext& ctx);
static constexpr float min_allowed_volume = 0.0f;
static constexpr float max_allowed_volume = 1.0f;
float main_applet_volume{0.25f};
float library_applet_volume{max_allowed_volume};
float transparent_volume_rate{min_allowed_volume};
// Volume transition fade time in nanoseconds.
// e.g. If the main applet volume was 0% and was changed to 50%
// with a fade of 50ns, then over the course of 50ns,
// the volume will gradually fade up to 50%
std::chrono::nanoseconds fade_time_ns{0};
};
} // namespace Service::AM

@ -0,0 +1,314 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/common_state_getter.h"
#include "core/hle/service/am/lock_accessor.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/apm/apm_interface.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
namespace Service::AM {
ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
{1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
{2, nullptr, "GetThisAppletKind"},
{3, nullptr, "AllowToEnterSleep"},
{4, nullptr, "DisallowToEnterSleep"},
{5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
{6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
{7, nullptr, "GetCradleStatus"},
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
{10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
{11, nullptr, "ReleaseSleepLock"},
{12, nullptr, "ReleaseSleepLockTransiently"},
{13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
{14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
{32, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"},
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
{51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
{52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
{53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
{54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
{59, nullptr, "SetVrPositionForDebug"},
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
{64, nullptr, "SetTvPowerStateMatchingMode"},
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"},
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
{110, nullptr, "OpenMyGpuErrorHandler"},
{120, &ICommonStateGetter::GetAppletLaunchedHistory, "GetAppletLaunchedHistory"},
{200, nullptr, "GetOperationModeSystemInfo"},
{300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
{400, nullptr, "ActivateMigrationService"},
{401, nullptr, "DeactivateMigrationService"},
{500, nullptr, "DisableSleepTillShutdown"},
{501, nullptr, "SuppressDisablingSleepTemporarily"},
{502, nullptr, "IsSleepEnabled"},
{503, nullptr, "IsDisablingSleepSuppressed"},
{900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
};
// clang-format on
RegisterHandlers(functions);
}
ICommonStateGetter::~ICommonStateGetter() = default;
void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
}
void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent());
}
void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
const auto message = applet->message_queue.PopMessage();
IPC::ResponseBuilder rb{ctx, 3};
if (message == AppletMessageQueue::AppletMessage::None) {
LOG_ERROR(Service_AM, "Message queue is empty");
rb.Push(AM::ResultNoMessages);
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
return;
}
rb.Push(ResultSuccess);
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
}
void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u8>(applet->focus_state));
}
void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
const bool use_docked_mode{Settings::IsDockedMode()};
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
}
void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
}
void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// Sleep lock is acquired immediately.
applet->sleep_lock_event.Signal();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown = rp.Pop<u32>();
LOG_INFO(Service_AM, "called, unknown={}", unknown);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILockAccessor>(system);
}
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->sleep_lock_event.GetHandle());
}
void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{applet->lock};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(applet->vr_mode_enabled);
}
void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
std::scoped_lock lk{applet->lock};
applet->vr_mode_enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "on" : "off");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
is_lcd_backlight_off_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->vr_mode_enabled = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->vr_mode_enabled = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->message_queue.GetOperationModeChangedEvent());
}
void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
if (Settings::IsDockedMode()) {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
} else {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
}
}
void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
const auto& sm = system.ServiceManager();
const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
ASSERT(apm_sys != nullptr);
apm_sys->SetCpuBoostMode(ctx);
}
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto system_button{rp.PopEnum<SystemButtonType>()};
LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::shared_ptr<Applet> current_applet = applet;
std::vector<AppletId> result;
const size_t count = ctx.GetWriteBufferNumElements<AppletId>();
size_t i;
for (i = 0; i < count && current_applet != nullptr; i++) {
result.push_back(current_applet->applet_id);
current_applet = current_applet->caller_applet.lock();
}
ctx.WriteBuffer(result);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(i));
}
void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(SysPlatformRegion::Global);
}
void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->request_exit_to_library_applet_at_execute_next_program_enabled = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
} // namespace Service::AM

@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
#include "core/hle/service/am/applet_message_queue.h"
namespace Service::AM {
struct Applet;
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_);
~ICommonStateGetter() override;
private:
// This is nn::oe::FocusState
enum class FocusState : u8 {
InFocus = 1,
NotInFocus = 2,
Background = 3,
};
// This is nn::oe::OperationMode
enum class OperationMode : u8 {
Handheld = 0,
Docked = 1,
};
// This is nn::am::service::SystemButtonType
enum class SystemButtonType {
None,
HomeButtonShortPressing,
HomeButtonLongPressing,
PowerButtonShortPressing,
PowerButtonLongPressing,
ShutdownSystem,
CaptureButtonShortPressing,
CaptureButtonLongPressing,
};
enum class SysPlatformRegion : s32 {
Global = 1,
Terra = 2,
};
void GetEventHandle(HLERequestContext& ctx);
void ReceiveMessage(HLERequestContext& ctx);
void GetCurrentFocusState(HLERequestContext& ctx);
void RequestToAcquireSleepLock(HLERequestContext& ctx);
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
void GetReaderLockAccessorEx(HLERequestContext& ctx);
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
void GetOperationMode(HLERequestContext& ctx);
void GetPerformanceMode(HLERequestContext& ctx);
void GetBootMode(HLERequestContext& ctx);
void IsVrModeEnabled(HLERequestContext& ctx);
void SetVrModeEnabled(HLERequestContext& ctx);
void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
void BeginVrModeEx(HLERequestContext& ctx);
void EndVrModeEx(HLERequestContext& ctx);
void GetDefaultDisplayResolution(HLERequestContext& ctx);
void SetCpuBoostMode(HLERequestContext& ctx);
void GetBuiltInDisplayType(HLERequestContext& ctx);
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
void GetAppletLaunchedHistory(HLERequestContext& ctx);
void GetSettingsPlatformRegion(HLERequestContext& ctx);
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/debug_functions.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IDebugFunctions::IDebugFunctions(Core::System& system_)
: ServiceFramework{system_, "IDebugFunctions"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "NotifyMessageToHomeMenuForDebug"},
{1, nullptr, "OpenMainApplication"},
{10, nullptr, "PerformSystemButtonPressing"},
{20, nullptr, "InvalidateTransitionLayer"},
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
{31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
{40, nullptr, "GetAppletResourceUsageInfo"},
{50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
{51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
{100, nullptr, "SetCpuBoostModeForApplet"},
{101, nullptr, "CancelCpuBoostModeForApplet"},
{110, nullptr, "PushToAppletBoundChannelForDebug"},
{111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
{120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
{121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
{122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
{130, nullptr, "FriendInvitationSetApplicationParameter"},
{131, nullptr, "FriendInvitationClearApplicationParameter"},
{132, nullptr, "FriendInvitationPushApplicationParameter"},
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
{300, nullptr, "TerminateAllRunningApplicationsForDebug"},
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
};
// clang-format on
RegisterHandlers(functions);
}
IDebugFunctions::~IDebugFunctions() = default;
} // namespace Service::AM

@ -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

@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/display_controller.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
namespace {
struct OutputParameters {
bool was_written;
s32 fbshare_layer_index;
};
static_assert(sizeof(OutputParameters) == 8, "OutputParameters has wrong size");
} // namespace
IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLastForegroundCaptureImage"},
{1, nullptr, "UpdateLastForegroundCaptureImage"},
{2, nullptr, "GetLastApplicationCaptureImage"},
{3, nullptr, "GetCallerAppletCaptureImage"},
{4, nullptr, "UpdateCallerAppletCaptureImage"},
{5, nullptr, "GetLastForegroundCaptureImageEx"},
{6, nullptr, "GetLastApplicationCaptureImageEx"},
{7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
{8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
{9, nullptr, "CopyBetweenCaptureBuffers"},
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
{11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
{12, nullptr, "AcquireLastForegroundCaptureBuffer"},
{13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
{14, nullptr, "AcquireCallerAppletCaptureBuffer"},
{15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
{16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
{17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
{18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
{20, nullptr, "ClearCaptureBuffer"},
{21, nullptr, "ClearAppletTransitionBuffer"},
{22, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"},
{23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "ReleaseLastApplicationCaptureSharedBuffer"},
{24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
{25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
{26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
{27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
};
// clang-format on
RegisterHandlers(functions);
}
IDisplayController::~IDisplayController() = default;
void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
OutputParameters params{};
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
&params.was_written, &params.fbshare_layer_index);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw(params);
}
void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IDisplayController::AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
OutputParameters params{};
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
&params.was_written, &params.fbshare_layer_index);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw(params);
}
void IDisplayController::ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
OutputParameters params{};
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
&params.was_written, &params.fbshare_layer_index);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw(params);
}
void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
OutputParameters params{};
const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
&params.was_written, &params.fbshare_layer_index);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.PushRaw(params);
}
void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
} // namespace Service::AM

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IDisplayController final : public ServiceFramework<IDisplayController> {
public:
explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_);
~IDisplayController() override;
private:
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -8,16 +8,17 @@
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/am/frontend/applet_cabinet.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfc/common/device.h"
#include "hid_core/hid_core.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::CabinetApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{
Cabinet::Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_)
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{
system_,
"CabinetApplet"} {
@ -30,7 +31,7 @@ Cabinet::~Cabinet() {
};
void Cabinet::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
@ -41,7 +42,7 @@ void Cabinet::Initialize() {
common_args.play_startup_sound, common_args.size, common_args.system_tick,
common_args.theme_color);
const auto storage = broker.PopNormalDataToApplet();
std::shared_ptr<IStorage> storage = PopInData();
ASSERT(storage != nullptr);
const auto applet_input_data = storage->GetData();
@ -51,10 +52,6 @@ void Cabinet::Initialize() {
sizeof(StartParamForAmiiboSettings));
}
bool Cabinet::TransactionComplete() const {
return is_complete;
}
Result Cabinet::GetStatus() const {
return ResultSuccess;
}
@ -160,8 +157,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
is_complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
Exit();
}
void Cabinet::Cancel() {
@ -175,8 +172,8 @@ void Cabinet::Cancel() {
is_complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
Exit();
}
Result Cabinet::RequestExit() {
@ -184,4 +181,4 @@ Result Cabinet::RequestExit() {
R_SUCCEED();
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -6,7 +6,7 @@
#include <array>
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfp/nfp_types.h"
@ -23,7 +23,7 @@ namespace Service::NFC {
class NfcDevice;
}
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
enum class CabinetAppletVersion : u32 {
Version1 = 0x1,
@ -84,15 +84,15 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
"ReturnValueForAmiiboSettings is an invalid size");
#pragma pack(pop)
class Cabinet final : public Applet {
class Cabinet final : public FrontendApplet {
public:
explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
explicit Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::CabinetApplet& frontend_);
~Cabinet() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -102,7 +102,6 @@ public:
private:
const Core::Frontend::CabinetApplet& frontend;
Core::System& system;
bool is_complete{false};
std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
@ -111,4 +110,4 @@ private:
StartParamForAmiiboSettings applet_input_common{};
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -11,13 +11,14 @@
#include "core/frontend/applets/controller.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/storage.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/npad/npad.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101};
[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID,
@ -46,14 +47,15 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
};
}
Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
Controller::Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::ControllerApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
Controller::~Controller() = default;
void Controller::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
LOG_INFO(Service_HID, "Initializing Controller Applet.");
@ -66,7 +68,7 @@ void Controller::Initialize() {
controller_applet_version = ControllerAppletVersion{common_args.library_version};
const auto private_arg_storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> private_arg_storage = PopInData();
ASSERT(private_arg_storage != nullptr);
const auto& private_arg = private_arg_storage->GetData();
@ -116,7 +118,7 @@ void Controller::Initialize() {
switch (controller_private_arg.mode) {
case ControllerSupportMode::ShowControllerSupport:
case ControllerSupportMode::ShowControllerStrapGuide: {
const auto user_arg_storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> user_arg_storage = PopInData();
ASSERT(user_arg_storage != nullptr);
const auto& user_arg = user_arg_storage->GetData();
@ -142,7 +144,7 @@ void Controller::Initialize() {
break;
}
case ControllerSupportMode::ShowControllerFirmwareUpdate: {
const auto update_arg_storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> update_arg_storage = PopInData();
ASSERT(update_arg_storage != nullptr);
const auto& update_arg = update_arg_storage->GetData();
@ -152,7 +154,7 @@ void Controller::Initialize() {
break;
}
case ControllerSupportMode::ShowControllerKeyRemappingForSystem: {
const auto remapping_arg_storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> remapping_arg_storage = PopInData();
ASSERT(remapping_arg_storage != nullptr);
const auto& remapping_arg = remapping_arg_storage->GetData();
@ -168,10 +170,6 @@ void Controller::Initialize() {
}
}
bool Controller::TransactionComplete() const {
return complete;
}
Result Controller::GetStatus() const {
return status;
}
@ -260,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) {
complete = true;
out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
std::memcpy(out_data.data(), &result_info, out_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
Exit();
}
Result Controller::RequestExit() {
@ -269,4 +268,4 @@ Result Controller::RequestExit() {
R_SUCCEED();
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -9,7 +9,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
@ -19,7 +19,7 @@ namespace Core::HID {
enum class NpadStyleSet : u32;
}
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
using IdentificationColor = std::array<u8, 4>;
using ExplainText = std::array<char, 0x81>;
@ -122,15 +122,15 @@ struct ControllerSupportResultInfo {
static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
"ControllerSupportResultInfo has incorrect size.");
class Controller final : public Applet {
class Controller final : public FrontendApplet {
public:
explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
explicit Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::ControllerApplet& frontend_);
~Controller() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -140,7 +140,6 @@ public:
private:
const Core::Frontend::ControllerApplet& frontend;
Core::System& system;
ControllerAppletVersion controller_applet_version;
ControllerSupportArgPrivate controller_private_arg;
@ -154,4 +153,4 @@ private:
std::vector<u8> out_data;
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -9,10 +9,11 @@
#include "core/core.h"
#include "core/frontend/applets/error.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/hle/service/am/frontend/applet_error.h"
#include "core/hle/service/am/storage.h"
#include "core/reporter.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
struct ErrorCode {
u32 error_category{};
@ -103,18 +104,18 @@ Result Decode64BitError(u64 error) {
} // Anonymous namespace
Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
Error::Error(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
const Core::Frontend::ErrorApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
Error::~Error() = default;
void Error::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
args = std::make_unique<ErrorArguments>();
complete = false;
const auto storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> storage = PopInData();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
@ -152,10 +153,6 @@ void Error::Initialize() {
}
}
bool Error::TransactionComplete() const {
return complete;
}
Result Error::GetStatus() const {
return ResultSuccess;
}
@ -210,8 +207,8 @@ void Error::Execute() {
void Error::DisplayCompleted() {
complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
Exit();
}
Result Error::RequestExit() {
@ -219,4 +216,4 @@ Result Error::RequestExit() {
R_SUCCEED();
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -4,13 +4,13 @@
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
enum class ErrorAppletMode : u8 {
ShowError = 0,
@ -22,15 +22,14 @@ enum class ErrorAppletMode : u8 {
ShowUpdateEula = 8,
};
class Error final : public Applet {
class Error final : public FrontendApplet {
public:
explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ErrorApplet& frontend_);
explicit Error(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_);
~Error() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -47,7 +46,6 @@ private:
std::unique_ptr<ErrorArguments> args;
bool complete = false;
Core::System& system;
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -5,27 +5,28 @@
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/general.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/frontend/applet_general.h"
#include "core/hle/service/am/storage.h"
#include "core/reporter.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
static void LogCurrentStorage(std::shared_ptr<Applet> applet, std::string_view prefix) {
std::shared_ptr<IStorage> storage;
while (R_SUCCEEDED(applet->caller_applet_broker->GetInData().Pop(&storage))) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
"called (STUBBED), during {} received normal data with size={:08X}, data={}",
prefix, data.size(), Common::HexToString(data));
}
storage = broker.PopInteractiveDataToApplet();
for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
while (R_SUCCEEDED(applet->caller_applet_broker->GetInteractiveInData().Pop(&storage))) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
"called (STUBBED), during {} received interactive data with size={:08X}, data={}",
@ -33,17 +34,17 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
}
}
Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
Auth::Auth(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
Core::Frontend::ParentalControlsApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
Auth::~Auth() = default;
void Auth::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
complete = false;
const auto storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> storage = PopInData();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
ASSERT(data.size() >= 0xC);
@ -67,10 +68,6 @@ void Auth::Initialize() {
arg2 = arg.arg2;
}
bool Auth::TransactionComplete() const {
return complete;
}
Result Auth::GetStatus() const {
return successful ? ResultSuccess : ERROR_INVALID_PIN;
}
@ -146,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) {
std::vector<u8> out(sizeof(Return));
std::memcpy(out.data(), &return_, sizeof(Return));
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out)));
Exit();
}
Result Auth::RequestExit() {
@ -155,27 +152,24 @@ Result Auth::RequestExit() {
R_SUCCEED();
}
PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::PhotoViewerApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
PhotoViewer::~PhotoViewer() = default;
void PhotoViewer::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
complete = false;
const auto storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> storage = PopInData();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
ASSERT(!data.empty());
mode = static_cast<PhotoViewerAppletMode>(data[0]);
}
bool PhotoViewer::TransactionComplete() const {
return complete;
}
Result PhotoViewer::GetStatus() const {
return ResultSuccess;
}
@ -203,8 +197,8 @@ void PhotoViewer::Execute() {
}
void PhotoViewer::ViewFinished() {
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>{}));
Exit();
}
Result PhotoViewer::RequestExit() {
@ -212,27 +206,17 @@ Result PhotoViewer::RequestExit() {
R_SUCCEED();
}
StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
: Applet{system_, applet_mode_}, id{id_}, system{system_} {}
StubApplet::StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
LibraryAppletMode applet_mode_)
: FrontendApplet{system_, applet_, applet_mode_}, id{id_} {}
StubApplet::~StubApplet() = default;
void StubApplet::Initialize() {
LOG_WARNING(Service_AM, "called (STUBBED)");
Applet::Initialize();
FrontendApplet::Initialize();
const auto data = broker.PeekDataToAppletForDebug();
system.GetReporter().SaveUnimplementedAppletReport(
static_cast<u32>(id), static_cast<u32>(common_args.arguments_version),
common_args.library_version, static_cast<u32>(common_args.theme_color),
common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive);
LogCurrentStorage(broker, "Initialize");
}
bool StubApplet::TransactionComplete() const {
LOG_WARNING(Service_AM, "called (STUBBED)");
return true;
LogCurrentStorage(applet.lock(), "Initialize");
}
Result StubApplet::GetStatus() const {
@ -242,22 +226,20 @@ Result StubApplet::GetStatus() const {
void StubApplet::ExecuteInteractive() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "ExecuteInteractive");
LogCurrentStorage(applet.lock(), "ExecuteInteractive");
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.PushInteractiveDataFromApplet(
std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
Exit();
}
void StubApplet::Execute() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "Execute");
LogCurrentStorage(applet.lock(), "Execute");
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.PushInteractiveDataFromApplet(
std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
Exit();
}
Result StubApplet::RequestExit() {
@ -265,4 +247,4 @@ Result StubApplet::RequestExit() {
R_SUCCEED();
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -3,13 +3,13 @@
#pragma once
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
enum class AuthAppletType : u32 {
ShowParentalAuthentication,
@ -17,14 +17,14 @@ enum class AuthAppletType : u32 {
ChangeParentalPasscode,
};
class Auth final : public Applet {
class Auth final : public FrontendApplet {
public:
explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
explicit Auth(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
Core::Frontend::ParentalControlsApplet& frontend_);
~Auth() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -34,7 +34,6 @@ public:
private:
Core::Frontend::ParentalControlsApplet& frontend;
Core::System& system;
bool complete = false;
bool successful = false;
@ -49,14 +48,14 @@ enum class PhotoViewerAppletMode : u8 {
AllApps = 1,
};
class PhotoViewer final : public Applet {
class PhotoViewer final : public FrontendApplet {
public:
explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
explicit PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::PhotoViewerApplet& frontend_);
~PhotoViewer() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -68,17 +67,16 @@ private:
const Core::Frontend::PhotoViewerApplet& frontend;
bool complete = false;
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
Core::System& system;
};
class StubApplet final : public Applet {
class StubApplet final : public FrontendApplet {
public:
explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
explicit StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
LibraryAppletMode applet_mode_);
~StubApplet() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -86,7 +84,6 @@ public:
private:
AppletId id;
Core::System& system;
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -6,16 +6,17 @@
#include "core/core.h"
#include "core/frontend/applets/mii_edit.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_mii_edit.h"
#include "core/hle/service/am/frontend/applet_mii_edit.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/mii/mii.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::MiiEditApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_)
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
MiiEdit::~MiiEdit() = default;
@ -24,7 +25,7 @@ void MiiEdit::Initialize() {
// Instead, it is initialized by an AppletInput storage with size 0x100 bytes.
// Do NOT call Applet::Initialize() here.
const auto storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> storage = PopInData();
ASSERT(storage != nullptr);
const auto applet_input_data = storage->GetData();
@ -66,10 +67,6 @@ void MiiEdit::Initialize() {
manager->Initialize(metadata);
}
bool MiiEdit::TransactionComplete() const {
return is_complete;
}
Result MiiEdit::GetStatus() const {
return ResultSuccess;
}
@ -152,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) {
is_complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
Exit();
}
void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
@ -168,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
is_complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
Exit();
}
Result MiiEdit::RequestExit() {
@ -177,4 +174,4 @@ Result MiiEdit::RequestExit() {
R_SUCCEED();
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -4,8 +4,8 @@
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
@ -16,17 +16,17 @@ struct DatabaseSessionMetadata;
class MiiManager;
} // namespace Service::Mii
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
class MiiEdit final : public Applet {
class MiiEdit final : public FrontendApplet {
public:
explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_,
explicit MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::MiiEditApplet& frontend_);
~MiiEdit() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -38,7 +38,6 @@ public:
private:
const Core::Frontend::MiiEditApplet& frontend;
Core::System& system;
MiiEditAppletInputCommon applet_input_common{};
MiiEditAppletInputV3 applet_input_v3{};
@ -49,4 +48,4 @@ private:
Mii::DatabaseSessionMetadata metadata{};
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -10,7 +10,7 @@
#include "common/uuid.h"
#include "core/hle/service/mii/types/char_info.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
enum class MiiEditAppletVersion : s32 {
Version3 = 0x3, // 1.0.0 - 10.1.1
@ -80,4 +80,4 @@ struct MiiEditAppletOutputForCharInfoEditing {
static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80,
"MiiEditAppletOutputForCharInfoEditing has incorrect size.");
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -9,13 +9,15 @@
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/errors.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/frontend/applet_profile_select.h"
#include "core/hle/service/am/storage.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
ProfileSelect::~ProfileSelect() = default;
@ -24,10 +26,10 @@ void ProfileSelect::Initialize() {
status = ResultSuccess;
final_data.clear();
Applet::Initialize();
FrontendApplet::Initialize();
profile_select_version = ProfileSelectAppletVersion{common_args.library_version};
const auto user_config_storage = broker.PopNormalDataToApplet();
const std::shared_ptr<IStorage> user_config_storage = PopInData();
ASSERT(user_config_storage != nullptr);
const auto& user_config = user_config_storage->GetData();
@ -50,10 +52,6 @@ void ProfileSelect::Initialize() {
}
}
bool ProfileSelect::TransactionComplete() const {
return complete;
}
Result ProfileSelect::GetStatus() const {
return status;
}
@ -64,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() {
void ProfileSelect::Execute() {
if (complete) {
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
Exit();
return;
}
@ -111,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
final_data = std::vector<u8>(sizeof(UiReturnArg));
std::memcpy(final_data.data(), &output, final_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
Exit();
}
Result ProfileSelect::RequestExit() {
@ -120,4 +120,4 @@ Result ProfileSelect::RequestExit() {
R_SUCCEED();
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -8,13 +8,13 @@
#include "common/common_funcs.h"
#include "common/uuid.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
enum class ProfileSelectAppletVersion : u32 {
Version1 = 0x1, // 1.0.0+
@ -111,15 +111,15 @@ struct UiReturnArg {
};
static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size.");
class ProfileSelect final : public Applet {
class ProfileSelect final : public FrontendApplet {
public:
explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
explicit ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_);
~ProfileSelect() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -137,7 +137,6 @@ private:
bool complete = false;
Result status = ResultSuccess;
std::vector<u8> final_data;
Core::System& system;
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -5,9 +5,10 @@
#include "core/core.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_software_keyboard.h"
#include "core/hle/service/am/frontend/applet_software_keyboard.h"
#include "core/hle/service/am/storage.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
namespace {
@ -41,14 +42,15 @@ void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply
} // Anonymous namespace
SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
Core::Frontend::SoftwareKeyboardApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
SoftwareKeyboard::~SoftwareKeyboard() = default;
void SoftwareKeyboard::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
applet_mode);
@ -76,10 +78,6 @@ void SoftwareKeyboard::Initialize() {
}
}
bool SoftwareKeyboard::TransactionComplete() const {
return complete;
}
Result SoftwareKeyboard::GetStatus() const {
return status;
}
@ -184,7 +182,7 @@ void SoftwareKeyboard::InitializeForeground() {
is_background = false;
const auto swkbd_config_storage = broker.PopNormalDataToApplet();
const auto swkbd_config_storage = PopInData();
ASSERT(swkbd_config_storage != nullptr);
const auto& swkbd_config_data = swkbd_config_storage->GetData();
@ -221,7 +219,7 @@ void SoftwareKeyboard::InitializeForeground() {
break;
}
const auto work_buffer_storage = broker.PopNormalDataToApplet();
const auto work_buffer_storage = PopInData();
ASSERT(work_buffer_storage != nullptr);
if (swkbd_config_common.initial_string_length == 0) {
@ -250,7 +248,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
is_background = true;
const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet();
const auto swkbd_inline_initialize_arg_storage = PopInData();
ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
@ -267,7 +265,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
}
void SoftwareKeyboard::ProcessTextCheck() {
const auto text_check_storage = broker.PopInteractiveDataToApplet();
const auto text_check_storage = PopInteractiveInData();
ASSERT(text_check_storage != nullptr);
const auto& text_check_data = text_check_storage->GetData();
@ -314,7 +312,7 @@ void SoftwareKeyboard::ProcessTextCheck() {
}
void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
const auto request_data_storage = broker.PopInteractiveDataToApplet();
const auto request_data_storage = PopInteractiveInData();
ASSERT(request_data_storage != nullptr);
const auto& request_data = request_data_storage->GetData();
@ -377,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
submitted_text.size() * sizeof(char16_t));
}
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
ExitKeyboard();
}
@ -410,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
current_text.size() * sizeof(char16_t));
}
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(out_data)));
}
void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
@ -767,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() {
frontend.ExitKeyboard();
broker.SignalStateChanged();
Exit();
}
Result SoftwareKeyboard::RequestExit() {
@ -967,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() {
SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyDefault() {
@ -977,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() {
SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyChangedString() {
@ -999,7 +997,7 @@ void SoftwareKeyboard::ReplyChangedString() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
sizeof(SwkbdChangedStringArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyMovedCursor() {
@ -1019,7 +1017,7 @@ void SoftwareKeyboard::ReplyMovedCursor() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
sizeof(SwkbdMovedCursorArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyMovedTab() {
@ -1039,7 +1037,7 @@ void SoftwareKeyboard::ReplyMovedTab() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
sizeof(SwkbdMovedTabArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyDecidedEnter() {
@ -1058,7 +1056,7 @@ void SoftwareKeyboard::ReplyDecidedEnter() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
sizeof(SwkbdDecidedEnterArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
HideInlineKeyboard();
}
@ -1070,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() {
SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
HideInlineKeyboard();
}
@ -1095,7 +1093,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
sizeof(SwkbdChangedStringArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyMovedCursorUtf8() {
@ -1116,7 +1114,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
sizeof(SwkbdMovedCursorArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
@ -1136,7 +1134,7 @@ void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
sizeof(SwkbdDecidedEnterArg));
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
HideInlineKeyboard();
}
@ -1148,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
@ -1158,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
@ -1168,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyChangedStringV2() {
@ -1194,7 +1192,7 @@ void SoftwareKeyboard::ReplyChangedStringV2() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
&flag, 1);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyMovedCursorV2() {
@ -1218,7 +1216,7 @@ void SoftwareKeyboard::ReplyMovedCursorV2() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
&flag, 1);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
@ -1245,7 +1243,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
&flag, 1);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
@ -1270,7 +1268,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
&flag, 1);
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -5,8 +5,8 @@
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
@ -17,17 +17,17 @@ struct KeyboardInitializeParameters;
struct InlineAppearParameters;
} // namespace Core::Frontend
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
class SoftwareKeyboard final : public Applet {
class SoftwareKeyboard final : public FrontendApplet {
public:
explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
Core::Frontend::SoftwareKeyboardApplet& frontend_);
~SoftwareKeyboard() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -156,7 +156,6 @@ private:
void ReplyMovedCursorUtf8V2();
Core::Frontend::SoftwareKeyboardApplet& frontend;
Core::System& system;
SwkbdAppletVersion swkbd_applet_version;
@ -184,4 +183,4 @@ private:
Result status{ResultSuccess};
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -11,7 +11,7 @@
#include "common/swap.h"
#include "common/uuid.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
@ -351,4 +351,4 @@ struct SwkbdDecidedEnterArg {
};
static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -19,12 +19,13 @@
#include "core/frontend/applets/web_browser.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
#include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/iplatform_service_manager.h"
#include "core/loader/loader.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
namespace {
@ -223,14 +224,15 @@ void ExtractSharedFonts(Core::System& system) {
} // namespace
WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_,
const Core::Frontend::WebBrowserApplet& frontend_)
: Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {}
: FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {}
WebBrowser::~WebBrowser() = default;
void WebBrowser::Initialize() {
Applet::Initialize();
FrontendApplet::Initialize();
LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
@ -243,7 +245,7 @@ void WebBrowser::Initialize() {
web_applet_version = WebAppletVersion{common_args.library_version};
const auto web_arg_storage = broker.PopNormalDataToApplet();
const auto web_arg_storage = PopInData();
ASSERT(web_arg_storage != nullptr);
const auto& web_arg = web_arg_storage->GetData();
@ -284,10 +286,6 @@ void WebBrowser::Initialize() {
}
}
bool WebBrowser::TransactionComplete() const {
return complete;
}
Result WebBrowser::GetStatus() const {
return status;
}
@ -358,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url)
complete = true;
std::vector<u8> out_data(sizeof(WebCommonReturnValue));
std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
Exit();
}
Result WebBrowser::RequestExit() {
@ -504,4 +502,4 @@ void WebBrowser::ExecuteLobby() {
LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed);
}
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -9,8 +9,8 @@
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applet_web_browser_types.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/frontend/applet_web_browser_types.h"
#include "core/hle/service/am/frontend/applets.h"
namespace Core {
class System;
@ -20,18 +20,17 @@ namespace FileSys {
enum class ContentRecordType : u8;
}
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
class WebBrowser final : public Applet {
class WebBrowser final : public FrontendApplet {
public:
WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::WebBrowserApplet& frontend_);
WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_);
~WebBrowser() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
@ -80,8 +79,6 @@ private:
FileSys::VirtualFile offline_romfs;
std::string external_url;
Core::System& system;
};
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -11,7 +11,7 @@
#include "common/common_types.h"
#include "common/swap.h"
namespace Service::AM::Applets {
namespace Service::AM::Frontend {
enum class WebAppletVersion : u32_le {
Version0 = 0x0, // Only used by WifiWebAuthApplet
@ -174,4 +174,4 @@ static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has
using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
} // namespace Service::AM::Applets
} // namespace Service::AM::Frontend

@ -0,0 +1,240 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include "common/assert.h"
#include "core/core.h"
#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general.h"
#include "core/frontend/applets/mii_edit.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/frontend/applet_cabinet.h"
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/frontend/applet_error.h"
#include "core/hle/service/am/frontend/applet_general.h"
#include "core/hle/service/am/frontend/applet_mii_edit.h"
#include "core/hle/service/am/frontend/applet_profile_select.h"
#include "core/hle/service/am/frontend/applet_software_keyboard.h"
#include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM::Frontend {
FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_)
: system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {}
FrontendApplet::~FrontendApplet() = default;
void FrontendApplet::Initialize() {
std::shared_ptr<IStorage> common = PopInData();
ASSERT(common != nullptr);
const auto common_data = common->GetData();
ASSERT(common_data.size() >= sizeof(CommonArguments));
std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
initialized = true;
}
std::shared_ptr<IStorage> FrontendApplet::PopInData() {
std::shared_ptr<IStorage> ret;
applet.lock()->caller_applet_broker->GetInData().Pop(&ret);
return ret;
}
std::shared_ptr<IStorage> FrontendApplet::PopInteractiveInData() {
std::shared_ptr<IStorage> ret;
applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret);
return ret;
}
void FrontendApplet::PushOutData(std::shared_ptr<IStorage> storage) {
applet.lock()->caller_applet_broker->GetOutData().Push(storage);
}
void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage);
}
void FrontendApplet::Exit() {
applet.lock()->caller_applet_broker->SignalCompletion();
}
FrontendAppletSet::FrontendAppletSet() = default;
FrontendAppletSet::FrontendAppletSet(CabinetApplet cabinet_applet,
ControllerApplet controller_applet, ErrorApplet error_applet,
MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet,
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
: cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
parental_controls{std::move(parental_controls_applet)},
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
FrontendAppletSet::~FrontendAppletSet() = default;
FrontendAppletSet::FrontendAppletSet(FrontendAppletSet&&) noexcept = default;
FrontendAppletSet& FrontendAppletSet::operator=(FrontendAppletSet&&) noexcept = default;
FrontendAppletHolder::FrontendAppletHolder(Core::System& system_) : system{system_} {}
FrontendAppletHolder::~FrontendAppletHolder() = default;
const FrontendAppletSet& FrontendAppletHolder::GetFrontendAppletSet() const {
return frontend;
}
NFP::CabinetMode FrontendAppletHolder::GetCabinetMode() const {
return cabinet_mode;
}
AppletId FrontendAppletHolder::GetCurrentAppletId() const {
return current_applet_id;
}
void FrontendAppletHolder::SetFrontendAppletSet(FrontendAppletSet set) {
if (set.cabinet != nullptr) {
frontend.cabinet = std::move(set.cabinet);
}
if (set.controller != nullptr) {
frontend.controller = std::move(set.controller);
}
if (set.error != nullptr) {
frontend.error = std::move(set.error);
}
if (set.mii_edit != nullptr) {
frontend.mii_edit = std::move(set.mii_edit);
}
if (set.parental_controls != nullptr) {
frontend.parental_controls = std::move(set.parental_controls);
}
if (set.photo_viewer != nullptr) {
frontend.photo_viewer = std::move(set.photo_viewer);
}
if (set.profile_select != nullptr) {
frontend.profile_select = std::move(set.profile_select);
}
if (set.software_keyboard != nullptr) {
frontend.software_keyboard = std::move(set.software_keyboard);
}
if (set.web_browser != nullptr) {
frontend.web_browser = std::move(set.web_browser);
}
}
void FrontendAppletHolder::SetCabinetMode(NFP::CabinetMode mode) {
cabinet_mode = mode;
}
void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) {
current_applet_id = applet_id;
}
void FrontendAppletHolder::SetDefaultAppletsIfMissing() {
if (frontend.cabinet == nullptr) {
frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
}
if (frontend.controller == nullptr) {
frontend.controller =
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
}
if (frontend.error == nullptr) {
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
}
if (frontend.mii_edit == nullptr) {
frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
}
if (frontend.parental_controls == nullptr) {
frontend.parental_controls =
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
}
if (frontend.photo_viewer == nullptr) {
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
}
if (frontend.profile_select == nullptr) {
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
}
if (frontend.software_keyboard == nullptr) {
frontend.software_keyboard =
std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
}
if (frontend.web_browser == nullptr) {
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
}
}
void FrontendAppletHolder::ClearAll() {
frontend = {};
}
std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<Applet> applet,
AppletId id,
LibraryAppletMode mode) const {
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(system, applet, mode, *frontend.parental_controls);
case AppletId::Cabinet:
return std::make_shared<Cabinet>(system, applet, mode, *frontend.cabinet);
case AppletId::Controller:
return std::make_shared<Controller>(system, applet, mode, *frontend.controller);
case AppletId::Error:
return std::make_shared<Error>(system, applet, mode, *frontend.error);
case AppletId::ProfileSelect:
return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select);
case AppletId::SoftwareKeyboard:
return std::make_shared<SoftwareKeyboard>(system, applet, mode,
*frontend.software_keyboard);
case AppletId::MiiEdit:
return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit);
case AppletId::Web:
case AppletId::Shop:
case AppletId::OfflineWeb:
case AppletId::LoginShare:
case AppletId::WebAuth:
return std::make_shared<WebBrowser>(system, applet, mode, *frontend.web_browser);
case AppletId::PhotoViewer:
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
default:
UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
static_cast<u8>(id));
return std::make_shared<StubApplet>(system, applet, id, mode);
}
}
} // namespace Service::AM::Frontend

@ -0,0 +1,146 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <queue>
#include "common/swap.h"
#include "core/hle/service/am/applet.h"
union Result;
namespace Core {
class System;
}
namespace Core::Frontend {
class CabinetApplet;
class ControllerApplet;
class ECommerceApplet;
class ErrorApplet;
class MiiEditApplet;
class ParentalControlsApplet;
class PhotoViewerApplet;
class ProfileSelectApplet;
class SoftwareKeyboardApplet;
class WebBrowserApplet;
} // namespace Core::Frontend
namespace Kernel {
class KernelCore;
class KEvent;
class KReadableEvent;
} // namespace Kernel
namespace Service::NFP {
enum class CabinetMode : u8;
} // namespace Service::NFP
namespace Service::AM {
class IStorage;
namespace Frontend {
class FrontendApplet {
public:
explicit FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
LibraryAppletMode applet_mode_);
virtual ~FrontendApplet();
virtual void Initialize();
virtual Result GetStatus() const = 0;
virtual void ExecuteInteractive() = 0;
virtual void Execute() = 0;
virtual Result RequestExit() = 0;
LibraryAppletMode GetLibraryAppletMode() const {
return applet_mode;
}
bool IsInitialized() const {
return initialized;
}
protected:
std::shared_ptr<IStorage> PopInData();
std::shared_ptr<IStorage> PopInteractiveInData();
void PushOutData(std::shared_ptr<IStorage> storage);
void PushInteractiveOutData(std::shared_ptr<IStorage> storage);
void Exit();
protected:
Core::System& system;
CommonArguments common_args{};
std::weak_ptr<Applet> applet{};
LibraryAppletMode applet_mode{};
bool initialized{false};
};
struct FrontendAppletSet {
using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
FrontendAppletSet();
FrontendAppletSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
ErrorApplet error_applet, MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
WebBrowser web_browser_);
~FrontendAppletSet();
FrontendAppletSet(const FrontendAppletSet&) = delete;
FrontendAppletSet& operator=(const FrontendAppletSet&) = delete;
FrontendAppletSet(FrontendAppletSet&&) noexcept;
FrontendAppletSet& operator=(FrontendAppletSet&&) noexcept;
CabinetApplet cabinet;
ControllerApplet controller;
ErrorApplet error;
MiiEdit mii_edit;
ParentalControlsApplet parental_controls;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
WebBrowser web_browser;
};
class FrontendAppletHolder {
public:
explicit FrontendAppletHolder(Core::System& system_);
~FrontendAppletHolder();
const FrontendAppletSet& GetFrontendAppletSet() const;
NFP::CabinetMode GetCabinetMode() const;
AppletId GetCurrentAppletId() const;
void SetFrontendAppletSet(FrontendAppletSet set);
void SetCabinetMode(NFP::CabinetMode mode);
void SetCurrentAppletId(AppletId applet_id);
void SetDefaultAppletsIfMissing();
void ClearAll();
std::shared_ptr<FrontendApplet> GetApplet(std::shared_ptr<Applet> applet, AppletId id,
LibraryAppletMode mode) const;
private:
AppletId current_applet_id{};
NFP::CabinetMode cabinet_mode{};
FrontendAppletSet frontend;
Core::System& system;
};
} // namespace Frontend
} // namespace Service::AM

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/global_state_controller.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IGlobalStateController::IGlobalStateController(Core::System& system_)
: ServiceFramework{system_, "IGlobalStateController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestToEnterSleep"},
{1, nullptr, "EnterSleep"},
{2, nullptr, "StartSleepSequence"},
{3, nullptr, "StartShutdownSequence"},
{4, nullptr, "StartRebootSequence"},
{9, nullptr, "IsAutoPowerDownRequested"},
{10, nullptr, "LoadAndApplyIdlePolicySettings"},
{11, nullptr, "NotifyCecSettingsChanged"},
{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
{13, nullptr, "UpdateDefaultDisplayResolution"},
{14, nullptr, "ShouldSleepOnBoot"},
{15, nullptr, "GetHdcpAuthenticationFailedEvent"},
{30, nullptr, "OpenCradleFirmwareUpdater"},
};
// clang-format on
RegisterHandlers(functions);
}
IGlobalStateController::~IGlobalStateController() = default;
} // namespace Service::AM

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
public:
explicit IGlobalStateController(Core::System& system_);
~IGlobalStateController() override;
};
} // namespace Service::AM

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/resource_manager.h"
namespace Service::AM {
HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid");
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
true);
}
}
HidRegistration::~HidRegistration() {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
m_process.GetProcessId());
}
}
void HidRegistration::EnableAppletToGetInput(bool enable) {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
}
}
} // namespace Service::AM

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
namespace Core {
class System;
}
namespace Service::HID {
class IHidServer;
}
namespace Service::AM {
class Process;
class HidRegistration {
public:
explicit HidRegistration(Core::System& system, Process& process);
~HidRegistration();
void EnableAppletToGetInput(bool enable);
private:
Process& m_process;
std::shared_ptr<Service::HID::IHidServer> m_hid_server;
};
} // namespace Service::AM

@ -0,0 +1,57 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/home_menu_functions.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
: ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
"IHomeMenuFunctions"} {
// clang-format off
static const FunctionInfo functions[] = {
{10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
{11, nullptr, "LockForeground"},
{12, nullptr, "UnlockForeground"},
{20, nullptr, "PopFromGeneralChannel"},
{21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "IsSleepEnabled"},
{41, nullptr, "IsRebootEnabled"},
{50, nullptr, "LaunchSystemApplet"},
{51, nullptr, "LaunchStarter"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
{110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
{200, nullptr, "LaunchDevMenu"},
{1000, nullptr, "SetLastApplicationExitReason"},
};
// clang-format on
RegisterHandlers(functions);
pop_from_general_channel_event =
service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
}
IHomeMenuFunctions::~IHomeMenuFunctions() {
service_context.CloseEvent(pop_from_general_channel_event);
}
void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
}
} // namespace Service::AM

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
public:
explicit IHomeMenuFunctions(Core::System& system_);
~IHomeMenuFunctions() override;
private:
void RequestToGetForeground(HLERequestContext& ctx);
void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* pop_from_general_channel_event;
};
} // namespace Service::AM

@ -0,0 +1,202 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_accessor.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
std::shared_ptr<AppletDataBroker> broker_,
std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)},
applet{std::move(applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
{1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
{10, &ILibraryAppletAccessor::Start, "Start"},
{20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
{25, nullptr, "Terminate"},
{30, &ILibraryAppletAccessor::GetResult, "GetResult"},
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
{60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},
{100, &ILibraryAppletAccessor::PushInData, "PushInData"},
{101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
{102, nullptr, "PushExtraStorage"},
{103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
{104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
{105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
{106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
{110, nullptr, "NeedsToExitProcess"},
{120, nullptr, "GetLibraryAppletInfo"},
{150, nullptr, "RequestForAppletToGetForeground"},
{160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(broker->GetStateChangedEvent().GetHandle());
}
void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{applet->lock};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(broker->IsCompleted());
}
void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(applet->terminate_result);
}
void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletAccessor::Start(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
applet->process->Run();
FrontendExecute();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
ASSERT(applet != nullptr);
applet->message_queue.RequestExit();
FrontendRequestExit();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
broker->GetInData().Push(rp.PopIpcInterface<IStorage>().lock());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
std::shared_ptr<IStorage> data;
const auto res = broker->GetOutData().Pop(&data);
if (res.IsSuccess()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface(std::move(data));
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
}
void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
broker->GetInteractiveInData().Push(rp.PopIpcInterface<IStorage>().lock());
FrontendExecuteInteractive();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
std::shared_ptr<IStorage> data;
const auto res = broker->GetInteractiveOutData().Pop(&data);
if (res.IsSuccess()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface(std::move(data));
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
}
void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(broker->GetOutData().GetEvent());
}
void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent());
}
void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
// actually used anywhere
constexpr u64 handle = 0xdeadbeef;
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(handle);
}
void ILibraryAppletAccessor::FrontendExecute() {
if (applet->frontend) {
applet->frontend->Initialize();
applet->frontend->Execute();
}
}
void ILibraryAppletAccessor::FrontendExecuteInteractive() {
if (applet->frontend) {
applet->frontend->ExecuteInteractive();
applet->frontend->Execute();
}
}
void ILibraryAppletAccessor::FrontendRequestExit() {
if (applet->frontend) {
applet->frontend->RequestExit();
}
}
} // namespace Service::AM

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class AppletDataBroker;
struct Applet;
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
public:
explicit ILibraryAppletAccessor(Core::System& system_,
std::shared_ptr<AppletDataBroker> broker_,
std::shared_ptr<Applet> applet_);
~ILibraryAppletAccessor();
protected:
void GetAppletStateChangedEvent(HLERequestContext& ctx);
void IsCompleted(HLERequestContext& ctx);
void GetResult(HLERequestContext& ctx);
void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx);
void Start(HLERequestContext& ctx);
void RequestExit(HLERequestContext& ctx);
void PushInData(HLERequestContext& ctx);
void PopOutData(HLERequestContext& ctx);
void PushInteractiveInData(HLERequestContext& ctx);
void PopInteractiveOutData(HLERequestContext& ctx);
void GetPopOutDataEvent(HLERequestContext& ctx);
void GetPopInteractiveOutDataEvent(HLERequestContext& ctx);
void GetIndirectLayerConsumerHandle(HLERequestContext& ctx);
void FrontendExecute();
void FrontendExecuteInteractive();
void FrontendRequestExit();
const std::shared_ptr<AppletDataBroker> broker;
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,271 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_accessor.h"
#include "core/hle/service/am/library_applet_creator.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
namespace {
AppletProgramId AppletIdToProgramId(AppletId applet_id) {
switch (applet_id) {
case AppletId::OverlayDisplay:
return AppletProgramId::OverlayDisplay;
case AppletId::QLaunch:
return AppletProgramId::QLaunch;
case AppletId::Starter:
return AppletProgramId::Starter;
case AppletId::Auth:
return AppletProgramId::Auth;
case AppletId::Cabinet:
return AppletProgramId::Cabinet;
case AppletId::Controller:
return AppletProgramId::Controller;
case AppletId::DataErase:
return AppletProgramId::DataErase;
case AppletId::Error:
return AppletProgramId::Error;
case AppletId::NetConnect:
return AppletProgramId::NetConnect;
case AppletId::ProfileSelect:
return AppletProgramId::ProfileSelect;
case AppletId::SoftwareKeyboard:
return AppletProgramId::SoftwareKeyboard;
case AppletId::MiiEdit:
return AppletProgramId::MiiEdit;
case AppletId::Web:
return AppletProgramId::Web;
case AppletId::Shop:
return AppletProgramId::Shop;
case AppletId::PhotoViewer:
return AppletProgramId::PhotoViewer;
case AppletId::Settings:
return AppletProgramId::Settings;
case AppletId::OfflineWeb:
return AppletProgramId::OfflineWeb;
case AppletId::LoginShare:
return AppletProgramId::LoginShare;
case AppletId::WebAuth:
return AppletProgramId::WebAuth;
case AppletId::MyPage:
return AppletProgramId::MyPage;
default:
return static_cast<AppletProgramId>(0);
}
}
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
if (program_id == 0) {
// Unknown applet
return {};
}
auto process = std::make_unique<Process>(system);
if (!process->Initialize(program_id)) {
// Couldn't initialize the guest process
return {};
}
const auto applet = std::make_shared<Applet>(system, std::move(process));
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
// Set focus state
switch (mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::NoUI:
applet->focus_state = FocusState::InFocus;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->system_buffer_manager.SetWindowVisibility(false);
applet->focus_state = FocusState::NotInFocus;
applet->hid_registration.EnableAppletToGetInput(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::Background:
case LibraryAppletMode::BackgroundIndirectDisplay:
default:
applet->focus_state = FocusState::Background;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
}
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
system.GetAppletManager().InsertApplet(applet);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
auto process = std::make_unique<Process>(system);
auto applet = std::make_shared<Applet>(system, std::move(process));
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
auto storage = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = storage;
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
}
} // namespace
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
{2, nullptr, "AreAnyLibraryAppletsLeft"},
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
{12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
};
RegisterHandlers(functions);
}
ILibraryAppletCreator::~ILibraryAppletCreator() = default;
void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_id = rp.PopRaw<AppletId>();
const auto applet_mode = rp.PopRaw<LibraryAppletMode>();
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
applet_mode);
auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
// Applet is created, can now be launched.
applet->library_applet_launchable_event.Signal();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletAccessor>(library_applet);
}
void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s64 size{rp.Pop<s64>()};
LOG_DEBUG(Service_AM, "called, size={}", size);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
std::vector<u8> data(size);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data)));
}
void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool is_writable;
s64 size;
};
const auto params{rp.PopRaw<Parameters>()};
const auto handle{ctx.GetCopyHandle(0)};
LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable,
params.size, handle);
if (params.size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(
system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(),
params.is_writable, params.size));
}
void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s64 size{rp.Pop<s64>()};
const auto handle{ctx.GetCopyHandle(0)};
LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(
system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size));
}
} // namespace Service::AM

@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_);
~ILibraryAppletCreator() override;
private:
void CreateLibraryApplet(HLERequestContext& ctx);
void CreateStorage(HLERequestContext& ctx);
void CreateTransferMemoryStorage(HLERequestContext& ctx);
void CreateHandleStorage(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,143 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet_common_functions.h"
#include "core/hle/service/am/audio_controller.h"
#include "core/hle/service/am/common_state_getter.h"
#include "core/hle/service/am/debug_functions.h"
#include "core/hle/service/am/display_controller.h"
#include "core/hle/service/am/global_state_controller.h"
#include "core/hle/service/am/home_menu_functions.h"
#include "core/hle/service/am/library_applet_creator.h"
#include "core/hle/service/am/library_applet_proxy.h"
#include "core/hle/service/am/library_applet_self_accessor.h"
#include "core/hle/service/am/process_winding_controller.h"
#include "core/hle/service/am/self_controller.h"
#include "core/hle/service/am/window_controller.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<Applet> applet_, Core::System& system_)
: ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
{2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
{3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletProxy::~ILibraryAppletProxy() = default;
void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ICommonStateGetter>(system, applet);
}
void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
}
void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IWindowController>(system, applet);
}
void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAudioController>(system);
}
void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDisplayController>(system, applet);
}
void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IProcessWindingController>(system, applet);
}
void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
}
void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet);
}
void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IAppletCommonFunctions>(system, applet);
}
void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHomeMenuFunctions>(system);
}
void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IGlobalStateController>(system);
}
void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDebugFunctions>(system);
}
} // namespace Service::AM

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<Applet> applet_, Core::System& system_);
~ILibraryAppletProxy();
private:
void GetCommonStateGetter(HLERequestContext& ctx);
void GetSelfController(HLERequestContext& ctx);
void GetWindowController(HLERequestContext& ctx);
void GetAudioController(HLERequestContext& ctx);
void GetDisplayController(HLERequestContext& ctx);
void GetProcessWindingController(HLERequestContext& ctx);
void GetLibraryAppletCreator(HLERequestContext& ctx);
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx);
void GetAppletCommonFunctions(HLERequestContext& ctx);
void GetHomeMenuFunctions(HLERequestContext& ctx);
void GetGlobalStateController(HLERequestContext& ctx);
void GetDebugFunctions(HLERequestContext& ctx);
Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,338 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core_timing.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applet_cabinet.h"
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_self_accessor.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
namespace {
AppletIdentityInfo GetCallerIdentity(std::shared_ptr<Applet> applet) {
if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) {
// TODO: is this actually the application ID?
return {
.applet_id = caller_applet->applet_id,
.application_id = caller_applet->program_id,
};
} else {
return {
.applet_id = AppletId::QLaunch,
.application_id = 0x0100000000001000ull,
};
}
}
} // namespace
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)},
broker{applet->caller_applet_broker} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"},
{1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"},
{2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"},
{3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"},
{5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"},
{6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"},
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
{12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
{13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "CanUseApplicationCore"},
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
{15, nullptr, "GetMainAppletApplicationControlProperty"},
{16, nullptr, "GetMainAppletStorageId"},
{17, nullptr, "GetCallerAppletIdentityInfoStack"},
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
{19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
{20, nullptr, "PopExtraStorage"},
{25, nullptr, "GetPopExtraStorageEvent"},
{30, nullptr, "UnpopInData"},
{31, nullptr, "UnpopExtraStorage"},
{40, nullptr, "GetIndirectLayerProducerHandle"},
{50, nullptr, "ReportVisibleError"},
{51, nullptr, "ReportVisibleErrorWithErrorContext"},
{60, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"},
{70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "GetCurrentApplicationId"},
{80, nullptr, "RequestExitToSelf"},
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
{100, nullptr, "CreateGameMovieTrimmer"},
{101, nullptr, "ReserveResourceForMovieOperation"},
{102, nullptr, "UnreserveResourceForMovieOperation"},
{110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
{120, nullptr, "GetLaunchStorageInfoForDebug"},
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
{140, nullptr, "SetApplicationMemoryReservation"},
{150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
{160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
std::shared_ptr<IStorage> data;
const auto res = broker->GetInData().Pop(&data);
if (res.IsSuccess()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface(std::move(data));
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
}
void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::RequestParser rp{ctx};
broker->GetOutData().Push(rp.PopIpcInterface<IStorage>().lock());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
std::shared_ptr<IStorage> data;
const auto res = broker->GetInteractiveInData().Pop(&data);
if (res.IsSuccess()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface(std::move(data));
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
}
void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::RequestParser rp{ctx};
broker->GetInteractiveOutData().Push(rp.PopIpcInterface<IStorage>().lock());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(broker->GetInData().GetEvent());
}
void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent());
}
void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid);
broker->SignalCompletion();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
struct LibraryAppletInfo {
AppletId applet_id;
LibraryAppletMode library_applet_mode;
};
LOG_WARNING(Service_AM, "(STUBBED) called");
const LibraryAppletInfo applet_info{
.applet_id = applet->applet_id,
.library_applet_mode = applet->library_applet_mode,
};
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushRaw(applet_info);
}
void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
const AppletIdentityInfo applet_info{
.applet_id = AppletId::QLaunch,
.application_id = 0x0100000000001000ull,
};
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(applet_info);
}
void ILibraryAppletSelfAccessor::CanUseApplicationCore(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// TODO: This appears to read the NPDM from state and check the core mask of the applet.
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(0);
}
void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(GetCallerIdentity(applet));
}
void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
}
void ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx) {
// FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
auto identity = GetCallerIdentity(applet);
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = [this, identity] {
const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
u8 desired_language{};
const auto res_lang =
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
if (res_lang != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_lang);
return;
}
// Convert to settings language code.
u64 language_code{};
const auto res_code =
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
if (res_code != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_code);
return;
}
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(language_code);
}
void ILibraryAppletSelfAccessor::GetCurrentApplicationId(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
u64 application_id = 0;
if (auto caller_applet = applet->caller_applet.lock(); caller_applet) {
application_id = caller_applet->program_id;
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(application_id);
}
void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
const Service::Account::ProfileManager manager{};
bool is_empty{true};
s32 user_count{-1};
LOG_INFO(Service_AM, "called");
if (manager.GetUserCount() > 0) {
is_empty = false;
user_count = static_cast<s32>(manager.GetUserCount());
ctx.WriteBuffer(manager.GetAllUsers());
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u8>(is_empty);
rb.Push(user_count);
}
void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(0);
}
void ILibraryAppletSelfAccessor::Cmd160(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(0);
}
} // namespace Service::AM

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <deque>
#include <vector>
#include "core/hle/service/service.h"
namespace Service::AM {
class AppletDataBroker;
struct Applet;
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
public:
explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet_);
~ILibraryAppletSelfAccessor() override;
private:
void PopInData(HLERequestContext& ctx);
void PushOutData(HLERequestContext& ctx);
void PopInteractiveInData(HLERequestContext& ctx);
void PushInteractiveOutData(HLERequestContext& ctx);
void GetPopInDataEvent(HLERequestContext& ctx);
void GetPopInteractiveInDataEvent(HLERequestContext& ctx);
void GetLibraryAppletInfo(HLERequestContext& ctx);
void GetMainAppletIdentityInfo(HLERequestContext& ctx);
void CanUseApplicationCore(HLERequestContext& ctx);
void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
void GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx);
void GetCurrentApplicationId(HLERequestContext& ctx);
void GetMainAppletAvailableUsers(HLERequestContext& ctx);
void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
void Cmd160(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
const std::shared_ptr<AppletDataBroker> broker;
};
} // namespace Service::AM

@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/memory.h"
namespace Service::AM {
namespace {
Result ValidateOffset(s64 offset, size_t size, size_t data_size) {
R_UNLESS(offset >= 0, AM::ResultInvalidOffset);
const size_t begin = offset;
const size_t end = begin + size;
R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset);
R_SUCCEED();
}
class BufferLibraryAppletStorage final : public LibraryAppletStorage {
public:
explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {}
~BufferLibraryAppletStorage() = default;
Result Read(s64 offset, void* buffer, size_t size) override {
R_TRY(ValidateOffset(offset, size, m_data.size()));
std::memcpy(buffer, m_data.data() + offset, size);
R_SUCCEED();
}
Result Write(s64 offset, const void* buffer, size_t size) override {
R_TRY(ValidateOffset(offset, size, m_data.size()));
std::memcpy(m_data.data() + offset, buffer, size);
R_SUCCEED();
}
s64 GetSize() override {
return m_data.size();
}
Kernel::KTransferMemory* GetHandle() override {
return nullptr;
}
private:
std::vector<u8> m_data;
};
class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage {
public:
explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory,
Kernel::KTransferMemory* trmem, bool is_writable,
s64 size)
: m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) {
m_trmem->Open();
}
~TransferMemoryLibraryAppletStorage() {
m_trmem->Close();
m_trmem = nullptr;
}
Result Read(s64 offset, void* buffer, size_t size) override {
R_TRY(ValidateOffset(offset, size, m_size));
m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size);
R_SUCCEED();
}
Result Write(s64 offset, const void* buffer, size_t size) override {
R_UNLESS(m_is_writable, ResultUnknown);
R_TRY(ValidateOffset(offset, size, m_size));
m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size);
R_SUCCEED();
}
s64 GetSize() override {
return m_size;
}
Kernel::KTransferMemory* GetHandle() override {
return nullptr;
}
protected:
Core::Memory::Memory& m_memory;
Kernel::KTransferMemory* m_trmem;
bool m_is_writable;
s64 m_size;
};
class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage {
public:
explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory,
Kernel::KTransferMemory* trmem, s64 size)
: TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {}
~HandleLibraryAppletStorage() = default;
Kernel::KTransferMemory* GetHandle() override {
return m_trmem;
}
};
} // namespace
LibraryAppletStorage::~LibraryAppletStorage() = default;
std::vector<u8> LibraryAppletStorage::GetData() {
std::vector<u8> data(this->GetSize());
this->Read(0, data.data(), data.size());
return data;
}
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) {
return std::make_shared<BufferLibraryAppletStorage>(std::move(data));
}
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
Kernel::KTransferMemory* trmem,
bool is_writable, s64 size) {
return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size);
}
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
Kernel::KTransferMemory* trmem,
s64 size) {
return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size);
}
} // namespace Service::AM

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Core::Memory {
class Memory;
}
namespace Kernel {
class KTransferMemory;
}
namespace Service::AM {
class LibraryAppletStorage {
public:
virtual ~LibraryAppletStorage();
virtual Result Read(s64 offset, void* buffer, size_t size) = 0;
virtual Result Write(s64 offset, const void* buffer, size_t size) = 0;
virtual s64 GetSize() = 0;
virtual Kernel::KTransferMemory* GetHandle() = 0;
std::vector<u8> GetData();
};
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data);
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
Kernel::KTransferMemory* trmem,
bool is_writable, s64 size);
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
Kernel::KTransferMemory* trmem, s64 size);
} // namespace Service::AM

@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/lock_accessor.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
ILockAccessor::ILockAccessor(Core::System& system_)
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &ILockAccessor::TryLock, "TryLock"},
{2, &ILockAccessor::Unlock, "Unlock"},
{3, &ILockAccessor::GetEvent, "GetEvent"},
{4,&ILockAccessor::IsLocked, "IsLocked"},
};
// clang-format on
RegisterHandlers(functions);
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
}
ILockAccessor::~ILockAccessor() {
service_context.CloseEvent(lock_event);
};
void ILockAccessor::TryLock(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto return_handle = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
// TODO: When return_handle is true this function should return the lock handle
is_locked = true;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_locked);
}
void ILockAccessor::Unlock(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
is_locked = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILockAccessor::GetEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
lock_event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(lock_event->GetReadableEvent());
}
void ILockAccessor::IsLocked(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push<u8>(is_locked);
}
} // namespace Service::AM

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
public:
explicit ILockAccessor(Core::System& system_);
~ILockAccessor() override;
private:
void TryLock(HLERequestContext& ctx);
void Unlock(HLERequestContext& ctx);
void GetEvent(HLERequestContext& ctx);
void IsLocked(HLERequestContext& ctx);
bool is_locked{};
Kernel::KEvent* lock_event;
KernelHelpers::ServiceContext service_context;
};
} // namespace Service::AM

@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/managed_layer_holder.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
namespace Service::AM {
ManagedLayerHolder::ManagedLayerHolder() = default;
ManagedLayerHolder::~ManagedLayerHolder() {
if (!m_nvnflinger) {
return;
}
for (const auto& layer : m_managed_display_layers) {
m_nvnflinger->DestroyLayer(layer);
}
for (const auto& layer : m_managed_display_recording_layers) {
m_nvnflinger->DestroyLayer(layer);
}
m_nvnflinger = nullptr;
}
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
m_nvnflinger = nvnflinger;
}
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
const auto display_id = m_nvnflinger->OpenDisplay("Default");
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
m_managed_display_layers.emplace(*layer_id);
*out_layer = *layer_id;
}
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
u64* out_recording_layer) {
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
// side effects.
// TODO: Support multiple layers
const auto display_id = m_nvnflinger->OpenDisplay("Default");
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
m_managed_display_layers.emplace(*layer_id);
*out_layer = *layer_id;
*out_recording_layer = 0;
}
} // namespace Service::AM

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <set>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::Nvnflinger {
class Nvnflinger;
}
namespace Service::AM {
class ManagedLayerHolder {
public:
ManagedLayerHolder();
~ManagedLayerHolder();
void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
void CreateManagedDisplayLayer(u64* out_layer);
void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
private:
Nvnflinger::Nvnflinger* m_nvnflinger{};
std::set<u64> m_managed_display_layers{};
std::set<u64> m_managed_display_recording_layers{};
};
} // namespace Service::AM

@ -0,0 +1,138 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
namespace Service::AM {
Process::Process(Core::System& system)
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
m_program_id(), m_process_started() {}
Process::~Process() {
this->Finalize();
}
bool Process::Initialize(u64 program_id) {
// First, ensure we are not holding another process.
this->Finalize();
// Get the filesystem controller.
auto& fsc = m_system.GetFileSystemController();
// Attempt to load program NCA.
const FileSys::RegisteredCache* bis_system{};
FileSys::VirtualFile nca{};
// Get the program NCA from built-in storage.
bis_system = fsc.GetSystemNANDContents();
if (bis_system) {
nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
}
// Ensure we retrieved a program NCA.
if (!nca) {
return false;
}
// Get the appropriate loader to parse this NCA.
auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
// Ensure we have a loader which can parse the NCA.
if (!app_loader) {
return false;
}
// Create the process.
auto* const process = Kernel::KProcess::Create(m_system.Kernel());
Kernel::KProcess::Register(m_system.Kernel(), process);
// On exit, ensure we free the additional reference to the process.
SCOPE_EXIT({ process->Close(); });
// Insert process modules into memory.
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
// Ensure loading was successful.
if (load_result != Loader::ResultStatus::Success) {
return false;
}
// TODO: remove this, kernel already tracks this
m_system.Kernel().AppendNewProcess(process);
// Note the load parameters from NPDM.
m_main_thread_priority = load_parameters->main_thread_priority;
m_main_thread_stack_size = load_parameters->main_thread_stack_size;
// This process has not started yet.
m_process_started = false;
// Take ownership of the process object.
m_process = process;
m_process->Open();
// We succeeded.
return true;
}
void Process::Finalize() {
// Terminate, if we are currently holding a process.
this->Terminate();
// Close the process.
if (m_process) {
m_process->Close();
// TODO: remove this, kernel already tracks this
m_system.Kernel().RemoveProcess(m_process);
}
// Clean up.
m_process = nullptr;
m_main_thread_priority = 0;
m_main_thread_stack_size = 0;
m_program_id = 0;
m_process_started = false;
}
bool Process::Run() {
// If we already started the process, don't start again.
if (m_process_started) {
return false;
}
// Start.
if (m_process) {
m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
}
// Mark as started.
m_process_started = true;
// We succeeded.
return true;
}
void Process::Terminate() {
if (m_process) {
m_process->Terminate();
}
}
u64 Process::GetProcessId() const {
if (m_process) {
return m_process->GetProcessId();
}
return 0;
}
} // namespace Service::AM

@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Kernel {
class KProcess;
}
namespace Core {
class System;
}
namespace Service::AM {
class Process {
public:
explicit Process(Core::System& system);
~Process();
bool Initialize(u64 program_id);
void Finalize();
bool Run();
void Terminate();
bool IsInitialized() const {
return m_process != nullptr;
}
u64 GetProcessId() const;
u64 GetProgramId() const {
return m_program_id;
}
Kernel::KProcess* GetProcess() const {
return m_process;
}
private:
Core::System& m_system;
Kernel::KProcess* m_process{};
s32 m_main_thread_priority{};
u64 m_main_thread_stack_size{};
u64 m_program_id{};
bool m_process_started{};
};
} // namespace Service::AM

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_accessor.h"
#include "core/hle/service/am/process_winding_controller.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IProcessWindingController::IProcessWindingController(Core::System& system_,
std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"},
{11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"},
{21, nullptr, "PushContext"},
{22, nullptr, "PopContext"},
{23, nullptr, "CancelWindingReservation"},
{30, nullptr, "WindAndDoReserved"},
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
{41, nullptr, "ReserveToStartAndWait"},
};
// clang-format on
RegisterHandlers(functions);
}
IProcessWindingController::~IProcessWindingController() = default;
void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(applet->launch_reason);
}
void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
const auto caller_applet = applet->caller_applet.lock();
if (caller_applet == nullptr) {
LOG_ERROR(Service_AM, "No calling applet available");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_broker,
caller_applet);
}
} // namespace Service::AM

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
public:
explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_);
~IProcessWindingController() override;
private:
void GetLaunchReason(HLERequestContext& ctx);
void OpenCallingLibraryApplet(HLERequestContext& ctx);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,456 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/self_controller.h"
#include "core/hle/service/caps/caps_su.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi_results.h"
namespace Service::AM {
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
Nvnflinger::Nvnflinger& nvnflinger_)
: ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move(
applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISelfController::Exit, "Exit"},
{1, &ISelfController::LockExit, "LockExit"},
{2, &ISelfController::UnlockExit, "UnlockExit"},
{3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
{4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
{9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
{10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
{11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
{12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
{13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
{14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
{15, &ISelfController::SetScreenShotAppletIdentityInfo, "SetScreenShotAppletIdentityInfo"},
{16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
{17, nullptr, "SetControllerFirmwareUpdateSection"},
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
{19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
{20, nullptr, "SetDesirableKeyboardLayout"},
{21, nullptr, "GetScreenShotProgramId"},
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
{41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
{42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
{43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
{44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
{61, nullptr, "SetMediaPlaybackState"},
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
{64, nullptr, "SetInputDetectionSourceSet"},
{65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"},
{66, nullptr, "GetCurrentIlluminance"},
{67, nullptr, "IsIlluminanceAvailable"},
{68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
{69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
{70, nullptr, "ReportMultimediaError"},
{71, nullptr, "GetCurrentIlluminanceEx"},
{72, nullptr, "SetInputDetectionPolicy"},
{80, nullptr, "SetWirelessPriorityMode"},
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
{100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
{110, nullptr, "SetApplicationAlbumUserData"},
{120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
{130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"},
{1000, nullptr, "GetDebugStorageChannel"},
};
// clang-format on
RegisterHandlers(functions);
}
ISelfController::~ISelfController() = default;
void ISelfController::Exit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
// TODO
system.Exit();
}
void ISelfController::LockExit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
system.SetExitLocked(true);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::UnlockExit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
system.SetExitLocked(false);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
if (system.GetExitRequested()) {
system.Exit();
}
}
void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
std::scoped_lock lk{applet->lock};
applet->fatal_section_count++;
LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", applet->fatal_section_count);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
// Entry and exit of fatal sections must be balanced.
std::scoped_lock lk{applet->lock};
if (applet->fatal_section_count == 0) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultFatalSectionCountImbalance);
return;
}
applet->fatal_section_count--;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
applet->library_applet_launchable_event.Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle());
}
void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto permission = rp.PopEnum<ScreenshotPermission>();
LOG_DEBUG(Service_AM, "called, permission={}", permission);
std::scoped_lock lk{applet->lock};
applet->screenshot_permission = permission;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const bool notification_enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
std::scoped_lock lk{applet->lock};
applet->operation_mode_changed_notification_enabled = notification_enabled;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const bool notification_enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
std::scoped_lock lk{applet->lock};
applet->performance_mode_changed_notification_enabled = notification_enabled;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flags = rp.PopRaw<FocusHandlingMode>();
LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
flags.unknown0, flags.unknown1, flags.unknown2);
std::scoped_lock lk{applet->lock};
applet->focus_handling_mode = flags;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->restart_message_enabled = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetScreenShotAppletIdentityInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
std::scoped_lock lk{applet->lock};
applet->screen_shot_identity = rp.PopRaw<AppletIdentityInfo>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const bool enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
std::scoped_lock lk{applet->lock};
ASSERT(applet->type == AppletType::Application);
applet->out_of_focus_suspension_enabled = enabled;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto orientation = rp.PopRaw<Capture::AlbumImageOrientation>();
LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast<s32>(orientation));
std::scoped_lock lk{applet->lock};
applet->album_image_orientation = orientation;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
u64 layer_id{};
applet->managed_layer_holder.Initialize(&nvnflinger);
applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(layer_id);
}
void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
}
void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
u64 buffer_id, layer_id;
applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
rb.Push<s64>(buffer_id);
rb.Push<s64>(layer_id);
}
void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
u64 buffer_id, layer_id;
applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
rb.Push<s64>(buffer_id);
}
Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
return ResultSuccess;
}
return VI::ResultOperationFailed;
}
void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
u64 layer_id{};
u64 recording_layer_id{};
applet->managed_layer_holder.Initialize(&nvnflinger);
applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.Push(layer_id);
rb.Push(recording_layer_id);
}
void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto extension = rp.PopRaw<IdleTimeDetectionExtension>();
LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", extension);
std::scoped_lock lk{applet->lock};
applet->idle_time_detection_extension = extension;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw<IdleTimeDetectionExtension>(applet->idle_time_detection_extension);
}
void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
std::scoped_lock lk{applet->lock};
applet->auto_sleep_disabled = rp.Pop<bool>();
// On the system itself, if the previous state of is_auto_sleep_disabled
// differed from the current value passed in, it'd signify the internal
// window manager to update (and also increment some statistics like update counts)
//
// It'd also indicate this change to an idle handling context.
//
// However, given we're emulating this behavior, most of this can be ignored
// and it's sufficient to simply set the member variable for querying via
// IsAutoSleepDisabled().
LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", applet->auto_sleep_disabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
std::scoped_lock lk{applet->lock};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(applet->auto_sleep_disabled);
}
void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
std::scoped_lock lk{applet->lock};
// This command returns the total number of system ticks since ISelfController creation
// where the game was suspended. Since Yuzu doesn't implement game suspension, this command
// can just always return 0 ticks.
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(applet->suspended_ticks);
}
void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle());
}
void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
// This service call sets an internal flag whether a notification is shown when an image is
// captured. Currently we do not support capturing images via the capture button, so this can be
// stubbed for now.
const bool enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
std::scoped_lock lk{applet->lock};
applet->album_image_taken_notification_enabled = enabled;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
LOG_INFO(Service_AM, "called, report_option={}", report_option);
const auto screenshot_service =
system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
"caps:su");
if (screenshot_service) {
screenshot_service->CaptureAndSaveScreenshot(report_option);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
std::scoped_lock lk{applet->lock};
applet->record_volume_muted = enabled;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
} // namespace Service::AM

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class ISelfController final : public ServiceFramework<ISelfController> {
public:
explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
Nvnflinger::Nvnflinger& nvnflinger_);
~ISelfController() override;
private:
void Exit(HLERequestContext& ctx);
void LockExit(HLERequestContext& ctx);
void UnlockExit(HLERequestContext& ctx);
void EnterFatalSection(HLERequestContext& ctx);
void LeaveFatalSection(HLERequestContext& ctx);
void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
void SetScreenShotPermission(HLERequestContext& ctx);
void SetOperationModeChangedNotification(HLERequestContext& ctx);
void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
void SetFocusHandlingMode(HLERequestContext& ctx);
void SetRestartMessageEnabled(HLERequestContext& ctx);
void SetScreenShotAppletIdentityInfo(HLERequestContext& ctx);
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
void SetAlbumImageOrientation(HLERequestContext& ctx);
void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
void GetSystemSharedBufferHandle(HLERequestContext& ctx);
void GetSystemSharedLayerHandle(HLERequestContext& ctx);
void CreateManagedDisplayLayer(HLERequestContext& ctx);
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
void ApproveToDisplay(HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
void ReportUserIsActive(HLERequestContext& ctx);
void SetAutoSleepDisabled(HLERequestContext& ctx);
void IsAutoSleepDisabled(HLERequestContext& ctx);
void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
void SaveCurrentScreenshot(HLERequestContext& ctx);
void SetRecordVolumeMuted(HLERequestContext& ctx);
Result EnsureBufferSharingEnabled(Kernel::KProcess* process);
Nvnflinger::Nvnflinger& nvnflinger;
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/storage_accessor.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_)
: ServiceFramework{system_, "IStorage"}, impl{std::move(impl_)} {
static const FunctionInfo functions[] = {
{0, &IStorage::Open, "Open"},
{1, &IStorage::OpenTransferStorage, "OpenTransferStorage"},
};
RegisterHandlers(functions);
}
IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
: IStorage(system_, CreateStorage(std::move(data))) {}
IStorage::~IStorage() = default;
void IStorage::Open(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
if (impl->GetHandle() != nullptr) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultInvalidStorageType);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorageAccessor>(system, impl);
}
void IStorage::OpenTransferStorage(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
if (impl->GetHandle() == nullptr) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultInvalidStorageType);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ITransferStorageAccessor>(system, impl);
}
std::vector<u8> IStorage::GetData() const {
return impl->GetData();
}
} // namespace Service::AM

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class LibraryAppletStorage;
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_);
explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
~IStorage() override;
std::shared_ptr<LibraryAppletStorage> GetImpl() const {
return impl;
}
std::vector<u8> GetData() const;
private:
void Open(HLERequestContext& ctx);
void OpenTransferStorage(HLERequestContext& ctx);
const std::shared_ptr<LibraryAppletStorage> impl;
};
} // namespace Service::AM

Some files were not shown because too many files have changed in this diff Show More