am: rewrite IApplicationFunctions
This commit is contained in:
parent
af35057212
commit
44e7e85f23
|
@ -425,8 +425,6 @@ add_library(core STATIC
|
|||
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/common_state_getter.cpp
|
||||
hle/service/am/common_state_getter.h
|
||||
hle/service/am/debug_functions.cpp
|
||||
|
@ -465,6 +463,8 @@ add_library(core STATIC
|
|||
hle/service/am/service/all_system_applet_proxies_service.h
|
||||
hle/service/am/service/applet_common_functions.cpp
|
||||
hle/service/am/service/applet_common_functions.h
|
||||
hle/service/am/service/application_functions.cpp
|
||||
hle/service/am/service/application_functions.h
|
||||
hle/service/am/service/application_proxy_service.cpp
|
||||
hle/service/am/service/application_proxy_service.h
|
||||
hle/service/am/service/application_proxy.cpp
|
||||
|
|
|
@ -18,7 +18,7 @@ enum class AppletType {
|
|||
SystemApplet,
|
||||
};
|
||||
|
||||
enum class GameplayRecordingState : u32 {
|
||||
enum class GamePlayRecordingState : u32 {
|
||||
Disabled,
|
||||
Enabled,
|
||||
};
|
||||
|
@ -136,6 +136,11 @@ enum class LibraryAppletMode : u32 {
|
|||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
enum class LaunchParameterKind : u32 {
|
||||
UserChannel = 1,
|
||||
AccountPreselectedUser = 2,
|
||||
};
|
||||
|
||||
enum class CommonArgumentVersion : u32 {
|
||||
Version0,
|
||||
Version1,
|
||||
|
@ -152,6 +157,22 @@ enum class ThemeColor : u32 {
|
|||
BasicBlack = 3,
|
||||
};
|
||||
|
||||
enum class InputDetectionPolicy : u32 {
|
||||
Unknown0 = 0,
|
||||
Unknown1 = 1,
|
||||
};
|
||||
|
||||
enum class WindowOriginMode : u32 {
|
||||
LowerLeft = 0,
|
||||
UpperLeft = 1,
|
||||
};
|
||||
|
||||
enum class ProgramSpecifyKind : u32 {
|
||||
ExecuteProgram = 0,
|
||||
JumpToSubApplicationProgramForDevelopment = 1,
|
||||
RestartProgram = 2,
|
||||
};
|
||||
|
||||
struct CommonArguments {
|
||||
CommonArgumentVersion arguments_version;
|
||||
CommonArgumentSize size;
|
||||
|
@ -175,6 +196,21 @@ struct AppletAttribute {
|
|||
};
|
||||
static_assert(sizeof(AppletAttribute) == 0x80, "AppletAttribute has incorrect size.");
|
||||
|
||||
// This is nn::oe::DisplayVersion
|
||||
struct DisplayVersion {
|
||||
std::array<char, 0x10> string;
|
||||
};
|
||||
static_assert(sizeof(DisplayVersion) == 0x10, "DisplayVersion has incorrect size.");
|
||||
|
||||
// This is nn::pdm::ApplicationPlayStatistics
|
||||
struct ApplicationPlayStatistics {
|
||||
u64 application_id;
|
||||
u64 play_time_ns;
|
||||
u64 launch_count;
|
||||
};
|
||||
static_assert(sizeof(ApplicationPlayStatistics) == 0x18,
|
||||
"ApplicationPlayStatistics has incorrect size.");
|
||||
|
||||
using AppletResourceUserId = u64;
|
||||
using ProgramId = u64;
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@ struct Applet {
|
|||
u32 application_core_usage_mode{};
|
||||
|
||||
// Application functions
|
||||
bool gameplay_recording_supported{};
|
||||
GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled};
|
||||
bool game_play_recording_supported{};
|
||||
GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled};
|
||||
bool jit_service_launched{};
|
||||
bool is_running{};
|
||||
bool application_crash_report_enabled{};
|
||||
|
|
|
@ -1,594 +0,0 @@
|
|||
// 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
|
|
@ -1,58 +0,0 @@
|
|||
// 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,465 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/service/application_functions.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, D<&IApplicationFunctions::PopLaunchParameter>, "PopLaunchParameter"},
|
||||
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
|
||||
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
|
||||
{12, nullptr, "CreateApplicationAndRequestToStart"},
|
||||
{13, nullptr, "CreateApplicationAndRequestToStartForQuest"},
|
||||
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
|
||||
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
|
||||
{20, D<&IApplicationFunctions::EnsureSaveData>, "EnsureSaveData"},
|
||||
{21, D<&IApplicationFunctions::GetDesiredLanguage>, "GetDesiredLanguage"},
|
||||
{22, D<&IApplicationFunctions::SetTerminateResult>, "SetTerminateResult"},
|
||||
{23, D<&IApplicationFunctions::GetDisplayVersion>, "GetDisplayVersion"},
|
||||
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{25, D<&IApplicationFunctions::ExtendSaveData>, "ExtendSaveData"},
|
||||
{26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"},
|
||||
{27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"},
|
||||
{28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"},
|
||||
{29, nullptr, "GetCacheStorageMax"},
|
||||
{30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||
{31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"},
|
||||
{32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"},
|
||||
{33, D<&IApplicationFunctions::EndBlockingHomeButton>, "EndBlockingHomeButton"},
|
||||
{34, nullptr, "SelectApplicationLicense"},
|
||||
{35, nullptr, "GetDeviceSaveDataSizeMax"},
|
||||
{36, nullptr, "GetLimitedApplicationLicense"},
|
||||
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
|
||||
{40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"},
|
||||
{50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"},
|
||||
{60, nullptr, "SetMediaPlaybackStateForApplication"},
|
||||
{65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"},
|
||||
{66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"},
|
||||
{67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"},
|
||||
{68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
|
||||
{70, nullptr, "RequestToShutdown"},
|
||||
{71, nullptr, "RequestToReboot"},
|
||||
{72, nullptr, "RequestToSleep"},
|
||||
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
|
||||
{90, D<&IApplicationFunctions::EnableApplicationCrashReport>, "EnableApplicationCrashReport"},
|
||||
{100, D<&IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer>, "InitializeApplicationCopyrightFrameBuffer"},
|
||||
{101, D<&IApplicationFunctions::SetApplicationCopyrightImage>, "SetApplicationCopyrightImage"},
|
||||
{102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
|
||||
{110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
|
||||
{111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
|
||||
{120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
|
||||
{121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
|
||||
{122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
|
||||
{123, D<&IApplicationFunctions::GetPreviousProgramIndex>, "GetPreviousProgramIndex"},
|
||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{130, D<&IApplicationFunctions::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"},
|
||||
{131, nullptr, "SetDelayTimeToAbortOnGpuError"},
|
||||
{140, D<&IApplicationFunctions::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"},
|
||||
{141, D<&IApplicationFunctions::TryPopFromFriendInvitationStorageChannel>, "TryPopFromFriendInvitationStorageChannel"},
|
||||
{150, D<&IApplicationFunctions::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"},
|
||||
{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{160, D<&IApplicationFunctions::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
|
||||
Result IApplicationFunctions::PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage,
|
||||
LaunchParameterKind launch_parameter_kind) {
|
||||
LOG_INFO(Service_AM, "called, kind={}", launch_parameter_kind);
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
|
||||
auto& channel = launch_parameter_kind == LaunchParameterKind::UserChannel
|
||||
? m_applet->user_channel_launch_parameter
|
||||
: m_applet->preselected_user_launch_parameter;
|
||||
|
||||
if (channel.empty()) {
|
||||
LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!",
|
||||
launch_parameter_kind);
|
||||
R_THROW(AM::ResultNoDataInChannel);
|
||||
}
|
||||
|
||||
auto data = channel.back();
|
||||
channel.pop_back();
|
||||
|
||||
*out_storage = std::make_shared<IStorage>(system, std::move(data));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID user_id) {
|
||||
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
|
||||
|
||||
FileSys::SaveDataAttribute attribute{};
|
||||
attribute.title_id = m_applet->program_id;
|
||||
attribute.user_id = user_id.AsU128();
|
||||
attribute.type = FileSys::SaveDataType::SaveData;
|
||||
|
||||
FileSys::VirtualDir save_data{};
|
||||
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
||||
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
|
||||
|
||||
*out_size = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
|
||||
// FIXME: all of this stuff belongs to ns
|
||||
// TODO(bunnei): This should be configurable
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
// Get supported languages from NACP, if possible
|
||||
// Default to 0 (all languages supported)
|
||||
u32 supported_languages = 0;
|
||||
|
||||
const auto res = [this] {
|
||||
const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
if (res.first != nullptr) {
|
||||
supported_languages = res.first->GetSupportedLanguages();
|
||||
}
|
||||
|
||||
// Call IApplicationManagerInterface implementation.
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
|
||||
auto app_man = ns_am2->GetApplicationManagerInterface();
|
||||
|
||||
// Get desired application language
|
||||
u8 desired_language{};
|
||||
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
|
||||
|
||||
// Convert to settings language code.
|
||||
R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(out_language_code, desired_language));
|
||||
|
||||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *out_language_code);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(),
|
||||
static_cast<u32>(terminate_result.GetModule()) + 2000,
|
||||
terminate_result.GetDescription());
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->terminate_result = terminate_result;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
const auto res = [this] {
|
||||
const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
auto metadata = pm.GetControlMetadata();
|
||||
if (metadata.first != nullptr) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
|
||||
system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
if (res.first != nullptr) {
|
||||
const auto& version = res.first->GetVersionString();
|
||||
std::memcpy(out_display_version->string.data(), version.data(),
|
||||
std::min(version.size(), out_display_version->string.size()));
|
||||
} else {
|
||||
static constexpr char default_version[]{"1.0.0"};
|
||||
std::memcpy(out_display_version->string.data(), default_version, sizeof(default_version));
|
||||
}
|
||||
|
||||
out_display_version->string[out_display_version->string.size() - 1] = '\0';
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type,
|
||||
Common::UUID user_id, u64 normal_size,
|
||||
u64 journal_size) {
|
||||
LOG_DEBUG(Service_AM, "called with type={} user_id={} normal={:#x} journal={:#x}",
|
||||
static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size);
|
||||
|
||||
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
|
||||
type, m_applet->program_id, user_id.AsU128(), {normal_size, journal_size});
|
||||
|
||||
// The following value is used to indicate the amount of space remaining on failure
|
||||
// due to running out of space. Since we always succeed, this should be 0.
|
||||
*out_required_size = 0;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size,
|
||||
FileSys::SaveDataType type, Common::UUID user_id) {
|
||||
LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString());
|
||||
|
||||
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
|
||||
type, m_applet->program_id, user_id.AsU128());
|
||||
|
||||
*out_normal_size = size.normal;
|
||||
*out_journal_size = size.journal;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::CreateCacheStorage(Out<u32> out_target_media,
|
||||
Out<u64> out_required_size, u16 index,
|
||||
u64 normal_size, u64 journal_size) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called with index={} size={:#x} journal_size={:#x}", index,
|
||||
normal_size, journal_size);
|
||||
|
||||
*out_target_media = 1; // Nand
|
||||
*out_required_size = 0;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetSaveDataSizeMax(Out<u64> out_max_normal_size,
|
||||
Out<u64> out_max_journal_size) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
*out_max_normal_size = 0xFFFFFFF;
|
||||
*out_max_journal_size = 0xFFFFFFF;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->home_button_long_pressed_blocked = true;
|
||||
m_applet->home_button_short_pressed_blocked = true;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->home_button_long_pressed_blocked = false;
|
||||
m_applet->home_button_short_pressed_blocked = false;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::BeginBlockingHomeButton(s64 timeout_ns) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, timeout_ns={}", timeout_ns);
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->home_button_long_pressed_blocked = true;
|
||||
m_applet->home_button_short_pressed_blocked = true;
|
||||
m_applet->home_button_double_click_enabled = true;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::EndBlockingHomeButton() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->home_button_long_pressed_blocked = false;
|
||||
m_applet->home_button_short_pressed_blocked = false;
|
||||
m_applet->home_button_double_click_enabled = false;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_became_running = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_pseudo_device_id = {};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::IsGamePlayRecordingSupported(
|
||||
Out<bool> out_is_game_play_recording_supported) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_is_game_play_recording_supported = m_applet->game_play_recording_supported;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::InitializeGamePlayRecording(
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::SetGamePlayRecordingState(
|
||||
GamePlayRecordingState game_play_recording_state) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->game_play_recording_state = game_play_recording_state;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::EnableApplicationCrashReport(bool enabled) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->application_crash_report_enabled = enabled;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(
|
||||
s32 width, s32 height, u64 transfer_memory_size,
|
||||
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::SetApplicationCopyrightImage(
|
||||
s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode,
|
||||
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::SetApplicationCopyrightVisibility(bool visible) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", visible);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::QueryApplicationPlayStatistics(
|
||||
Out<s32> out_entries,
|
||||
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
|
||||
InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_entries = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::QueryApplicationPlayStatisticsByUid(
|
||||
Out<s32> out_entries,
|
||||
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
|
||||
Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_entries = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, kind={}, value={}", kind, value);
|
||||
ASSERT(kind == ProgramSpecifyKind::ExecuteProgram ||
|
||||
kind == ProgramSpecifyKind::RestartProgram);
|
||||
|
||||
// Copy user channel ownership into the system so that it will be preserved
|
||||
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
|
||||
system.ExecuteProgram(value);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::ClearUserChannel() {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
m_applet->user_channel_launch_parameter.clear();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::UnpopToUserChannel(SharedPointer<IStorage> storage) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
m_applet->user_channel_launch_parameter.push_back(storage->GetData());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetPreviousProgramIndex(Out<s32> out_previous_program_index) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_previous_program_index = m_applet->previous_program_index;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetGpuErrorDetectedSystemEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_event = m_applet->gpu_error_detected_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetFriendInvitationStorageChannelEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->friend_invitation_storage_channel_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
|
||||
Out<SharedPointer<IStorage>> out_storage) {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called");
|
||||
R_THROW(AM::ResultNoDataInChannel);
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetNotificationStorageChannelEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->notification_storage_channel_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->health_warning_disappeared_system_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::PrepareForJit() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->jit_service_launched = true;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
|
@ -0,0 +1,83 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace FileSys {
|
||||
enum class SaveDataType : u8;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KReadableEvent;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
class IStorage;
|
||||
|
||||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
|
||||
public:
|
||||
explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
|
||||
~IApplicationFunctions() override;
|
||||
|
||||
private:
|
||||
Result PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage,
|
||||
LaunchParameterKind launch_parameter_kind);
|
||||
Result EnsureSaveData(Out<u64> out_size, Common::UUID user_id);
|
||||
Result GetDesiredLanguage(Out<u64> out_language_code);
|
||||
Result SetTerminateResult(Result terminate_result);
|
||||
Result GetDisplayVersion(Out<DisplayVersion> out_display_version);
|
||||
Result ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type,
|
||||
Common::UUID user_id, u64 normal_size, u64 journal_size);
|
||||
Result GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size,
|
||||
FileSys::SaveDataType type, Common::UUID user_id);
|
||||
Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index,
|
||||
u64 normal_size, u64 journal_size);
|
||||
Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size);
|
||||
Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused);
|
||||
Result EndBlockingHomeButtonShortAndLongPressed();
|
||||
Result BeginBlockingHomeButton(s64 timeout_ns);
|
||||
Result EndBlockingHomeButton();
|
||||
Result NotifyRunning(Out<bool> out_became_running);
|
||||
Result GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id);
|
||||
Result IsGamePlayRecordingSupported(Out<bool> out_is_game_play_recording_supported);
|
||||
Result InitializeGamePlayRecording(
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
|
||||
Result SetGamePlayRecordingState(GamePlayRecordingState game_play_recording_state);
|
||||
Result EnableApplicationCrashReport(bool enabled);
|
||||
Result InitializeApplicationCopyrightFrameBuffer(
|
||||
s32 width, s32 height, u64 transfer_memory_size,
|
||||
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
|
||||
Result SetApplicationCopyrightImage(
|
||||
s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode,
|
||||
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data);
|
||||
Result SetApplicationCopyrightVisibility(bool visible);
|
||||
Result QueryApplicationPlayStatistics(
|
||||
Out<s32> out_entries,
|
||||
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
|
||||
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
|
||||
Result QueryApplicationPlayStatisticsByUid(
|
||||
Out<s32> out_entries,
|
||||
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
|
||||
Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids);
|
||||
Result ExecuteProgram(ProgramSpecifyKind kind, u64 value);
|
||||
Result ClearUserChannel();
|
||||
Result UnpopToUserChannel(SharedPointer<IStorage> storage);
|
||||
Result GetPreviousProgramIndex(Out<s32> out_previous_program_index);
|
||||
Result GetGpuErrorDetectedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetFriendInvitationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result TryPopFromFriendInvitationStorageChannel(Out<SharedPointer<IStorage>> out_storage);
|
||||
Result GetNotificationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result PrepareForJit();
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
|
@ -1,7 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/application_functions.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"
|
||||
|
@ -10,6 +9,7 @@
|
|||
#include "core/hle/service/am/process_winding_controller.h"
|
||||
#include "core/hle/service/am/self_controller.h"
|
||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||
#include "core/hle/service/am/service/application_functions.h"
|
||||
#include "core/hle/service/am/service/application_proxy.h"
|
||||
#include "core/hle/service/am/service/audio_controller.h"
|
||||
#include "core/hle/service/am/window_controller.h"
|
||||
|
|
Reference in New Issue