// 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/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am_results.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 "hid_core/hid_types.h"
namespace Service::AM {
namespace {
struct AppletIdentityInfo {
AppletId applet_id;
INSERT_PADDING_BYTES(0x4);
u64 application_id;
};
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
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 = applet->applet_id,
.application_id = 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_)},
storage{applet->caller_applet_storage} {
// 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, nullptr, "CanUseApplicationCore"},
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
{15, nullptr, "GetMainAppletApplicationControlProperty"},
{16, nullptr, "GetMainAppletStorageId"},
{17, nullptr, "GetCallerAppletIdentityInfoStack"},
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
{19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
{20, nullptr, "PopExtraStorage"},
{25, nullptr, "GetPopExtraStorageEvent"},
{30, nullptr, "UnpopInData"},
{31, nullptr, "UnpopExtraStorage"},
{40, nullptr, "GetIndirectLayerProducerHandle"},
{50, nullptr, "ReportVisibleError"},
{51, nullptr, "ReportVisibleErrorWithErrorContext"},
{60, nullptr, "GetMainAppletApplicationDesiredLanguage"},
{70, nullptr, "GetCurrentApplicationId"},
{80, nullptr, "RequestExitToSelf"},
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
{100, nullptr, "CreateGameMovieTrimmer"},
{101, nullptr, "ReserveResourceForMovieOperation"},
{102, nullptr, "UnreserveResourceForMovieOperation"},
{110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
{120, nullptr, "GetLaunchStorageInfoForDebug"},
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
{140, nullptr, "SetApplicationMemoryReservation"},
{150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
std::shared_ptr<IStorage> data;
const auto res = storage->in_data.PopData(&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};
storage->out_data.PushData(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 = storage->interactive_in_data.PopData(&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};
storage->interactive_out_data.PushData(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(storage->in_data.GetEvent());
}
void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(storage->interactive_in_data.GetEvent());
}
void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid);
{
std::scoped_lock lk{applet->lock};
applet->is_completed = true;
storage->state_changed_event.Signal();
}
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::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::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);
}
} // namespace Service::AM