mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 02:34:11 +01:00 
			
		
		
		
	am: rewrite ILibraryAppletSelfAccessor
This commit is contained in:
		
							parent
							
								
									1c797a8048
								
							
						
					
					
						commit
						c7e94e2175
					
				| @ -429,8 +429,6 @@ add_library(core STATIC | ||||
|     hle/service/am/hid_registration.h | ||||
|     hle/service/am/idle.cpp | ||||
|     hle/service/am/idle.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 | ||||
| @ -475,6 +473,8 @@ add_library(core STATIC | ||||
|     hle/service/am/service/library_applet_creator.h | ||||
|     hle/service/am/service/library_applet_proxy.cpp | ||||
|     hle/service/am/service/library_applet_proxy.h | ||||
|     hle/service/am/service/library_applet_self_accessor.cpp | ||||
|     hle/service/am/service/library_applet_self_accessor.h | ||||
|     hle/service/am/service/system_applet_proxy.cpp | ||||
|     hle/service/am/service/system_applet_proxy.h | ||||
|     hle/service/am/system_buffer_manager.cpp | ||||
|  | ||||
| @ -1,338 +0,0 @@ | ||||
| // 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
 | ||||
| @ -1,44 +0,0 @@ | ||||
| // 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
 | ||||
| @ -1,7 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #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/service/applet_common_functions.h" | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #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/service/applet_common_functions.h" | ||||
| @ -13,6 +12,7 @@ | ||||
| #include "core/hle/service/am/service/home_menu_functions.h" | ||||
| #include "core/hle/service/am/service/library_applet_creator.h" | ||||
| #include "core/hle/service/am/service/library_applet_proxy.h" | ||||
| #include "core/hle/service/am/service/library_applet_self_accessor.h" | ||||
| #include "core/hle/service/am/window_controller.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										322
									
								
								src/core/hle/service/am/service/library_applet_self_accessor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								src/core/hle/service/am/service/library_applet_self_accessor.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,322 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/core_timing.h" | ||||
| #include "core/file_sys/control_metadata.h" | ||||
| #include "core/file_sys/patch_manager.h" | ||||
| #include "core/file_sys/registered_cache.h" | ||||
| #include "core/hle/service/acc/profile_manager.h" | ||||
| #include "core/hle/service/am/applet_data_broker.h" | ||||
| #include "core/hle/service/am/applet_manager.h" | ||||
| #include "core/hle/service/am/frontend/applets.h" | ||||
| #include "core/hle/service/am/service/library_applet_self_accessor.h" | ||||
| #include "core/hle/service/am/storage.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| #include "core/hle/service/filesystem/filesystem.h" | ||||
| #include "core/hle/service/glue/glue_manager.h" | ||||
| #include "core/hle/service/ns/ns.h" | ||||
| #include "core/hle/service/sm/sm.h" | ||||
| 
 | ||||
| namespace Service::AM { | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| AppletIdentityInfo GetCallerIdentity(Applet& applet) { | ||||
|     if (const auto caller_applet = applet.caller_applet.lock(); caller_applet) { | ||||
|         // TODO: is this actually the application ID?
 | ||||
|         return { | ||||
|             .applet_id = caller_applet->applet_id, | ||||
|             .application_id = caller_applet->program_id, | ||||
|         }; | ||||
|     } else { | ||||
|         return { | ||||
|             .applet_id = AppletId::QLaunch, | ||||
|             .application_id = 0x0100000000001000ull, | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, | ||||
|                                                        std::shared_ptr<Applet> applet) | ||||
|     : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, m_applet{std::move(applet)}, | ||||
|       m_broker{m_applet->caller_applet_broker} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&ILibraryAppletSelfAccessor::PopInData>, "PopInData"}, | ||||
|         {1, D<&ILibraryAppletSelfAccessor::PushOutData>, "PushOutData"}, | ||||
|         {2, D<&ILibraryAppletSelfAccessor::PopInteractiveInData>, "PopInteractiveInData"}, | ||||
|         {3, D<&ILibraryAppletSelfAccessor::PushInteractiveOutData>, "PushInteractiveOutData"}, | ||||
|         {5, D<&ILibraryAppletSelfAccessor::GetPopInDataEvent>, "GetPopInDataEvent"}, | ||||
|         {6, D<&ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent>, "GetPopInteractiveInDataEvent"}, | ||||
|         {10, D<&ILibraryAppletSelfAccessor::ExitProcessAndReturn>, "ExitProcessAndReturn"}, | ||||
|         {11, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"}, | ||||
|         {12, D<&ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo>, "GetMainAppletIdentityInfo"}, | ||||
|         {13, D<&ILibraryAppletSelfAccessor::CanUseApplicationCore>, "CanUseApplicationCore"}, | ||||
|         {14, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo>, "GetCallerAppletIdentityInfo"}, | ||||
|         {15, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty>, "GetMainAppletApplicationControlProperty"}, | ||||
|         {16, D<&ILibraryAppletSelfAccessor::GetMainAppletStorageId>, "GetMainAppletStorageId"}, | ||||
|         {17, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack>, "GetCallerAppletIdentityInfoStack"}, | ||||
|         {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, | ||||
|         {19, D<&ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout>, "GetDesirableKeyboardLayout"}, | ||||
|         {20, nullptr, "PopExtraStorage"}, | ||||
|         {25, nullptr, "GetPopExtraStorageEvent"}, | ||||
|         {30, nullptr, "UnpopInData"}, | ||||
|         {31, nullptr, "UnpopExtraStorage"}, | ||||
|         {40, nullptr, "GetIndirectLayerProducerHandle"}, | ||||
|         {50, D<&ILibraryAppletSelfAccessor::ReportVisibleError>, "ReportVisibleError"}, | ||||
|         {51, D<&ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext>, "ReportVisibleErrorWithErrorContext"}, | ||||
|         {60, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage>, "GetMainAppletApplicationDesiredLanguage"}, | ||||
|         {70, D<&ILibraryAppletSelfAccessor::GetCurrentApplicationId>, "GetCurrentApplicationId"}, | ||||
|         {80, nullptr, "RequestExitToSelf"}, | ||||
|         {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, | ||||
|         {100, nullptr, "CreateGameMovieTrimmer"}, | ||||
|         {101, nullptr, "ReserveResourceForMovieOperation"}, | ||||
|         {102, nullptr, "UnreserveResourceForMovieOperation"}, | ||||
|         {110, D<&ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers>, "GetMainAppletAvailableUsers"}, | ||||
|         {120, nullptr, "GetLaunchStorageInfoForDebug"}, | ||||
|         {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, | ||||
|         {140, nullptr, "SetApplicationMemoryReservation"}, | ||||
|         {150, D<&ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually>, "ShouldSetGpuTimeSliceManually"}, | ||||
|         {160, D<&ILibraryAppletSelfAccessor::Cmd160>, "Cmd160"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::PopInData(Out<SharedPointer<IStorage>> out_storage) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     R_RETURN(m_broker->GetInData().Pop(out_storage)); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::PushOutData(SharedPointer<IStorage> storage) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     m_broker->GetOutData().Push(storage); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     R_RETURN(m_broker->GetInteractiveInData().Pop(out_storage)); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::PushInteractiveOutData(SharedPointer<IStorage> storage) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     m_broker->GetInteractiveOutData().Push(storage); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetPopInDataEvent( | ||||
|     OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     *out_event = m_broker->GetInData().GetEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent( | ||||
|     OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     *out_event = m_broker->GetInteractiveInData().GetEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetLibraryAppletInfo( | ||||
|     Out<LibraryAppletInfo> out_library_applet_info) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     *out_library_applet_info = { | ||||
|         .applet_id = m_applet->applet_id, | ||||
|         .library_applet_mode = m_applet->library_applet_mode, | ||||
|     }; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo( | ||||
|     Out<AppletIdentityInfo> out_identity_info) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
|     *out_identity_info = { | ||||
|         .applet_id = AppletId::QLaunch, | ||||
|         .application_id = 0x0100000000001000ull, | ||||
|     }; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::CanUseApplicationCore(Out<bool> out_can_use_application_core) { | ||||
|     // TODO: This appears to read the NPDM from state and check the core mask of the applet.
 | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
|     *out_can_use_application_core = false; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty( | ||||
|     OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
| 
 | ||||
|     // TODO: this should be the main applet, not the caller applet
 | ||||
|     const auto application = GetCallerIdentity(*m_applet); | ||||
|     std::vector<u8> nacp; | ||||
|     const auto result = | ||||
|         system.GetARPManager().GetControlProperty(&nacp, application.application_id); | ||||
| 
 | ||||
|     if (R_SUCCEEDED(result)) { | ||||
|         std::memcpy(out_nacp->data(), nacp.data(), std::min(nacp.size(), out_nacp->size())); | ||||
|     } | ||||
| 
 | ||||
|     R_RETURN(result); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id) { | ||||
|     LOG_INFO(Service_AM, "(STUBBED) called"); | ||||
|     *out_storage_id = FileSys::StorageId::NandUser; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     system.GetAppletManager().TerminateAndRemoveApplet(m_applet->aruid); | ||||
|     m_broker->SignalCompletion(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo( | ||||
|     Out<AppletIdentityInfo> out_identity_info) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
|     *out_identity_info = GetCallerIdentity(*m_applet); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack( | ||||
|     Out<s32> out_count, OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info) { | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
| 
 | ||||
|     std::shared_ptr<Applet> applet = m_applet; | ||||
|     *out_count = 0; | ||||
| 
 | ||||
|     do { | ||||
|         if (*out_count >= static_cast<s32>(out_identity_info.size())) { | ||||
|             break; | ||||
|         } | ||||
|         out_identity_info[(*out_count)++] = GetCallerIdentity(*applet); | ||||
|     } while ((applet = applet->caller_applet.lock())); | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(Out<u32> out_desirable_layout) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
|     *out_desirable_layout = 0; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::ReportVisibleError(ErrorCode error_code) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category, | ||||
|                 error_code.number); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext( | ||||
|     ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category, | ||||
|                 error_code.number); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage( | ||||
|     Out<u64> out_desired_language) { | ||||
|     // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
 | ||||
|     // FIXME: all of this stuff belongs to ns
 | ||||
|     auto identity = GetCallerIdentity(*m_applet); | ||||
| 
 | ||||
|     // TODO(bunnei): This should be configurable
 | ||||
|     LOG_DEBUG(Service_AM, "called"); | ||||
| 
 | ||||
|     // Get supported languages from NACP, if possible
 | ||||
|     // Default to 0 (all languages supported)
 | ||||
|     u32 supported_languages = 0; | ||||
| 
 | ||||
|     const auto res = [this, identity] { | ||||
|         const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(), | ||||
|                                        system.GetContentProvider()}; | ||||
|         auto metadata = pm.GetControlMetadata(); | ||||
|         if (metadata.first != nullptr) { | ||||
|             return metadata; | ||||
|         } | ||||
| 
 | ||||
|         const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id), | ||||
|                                               system.GetFileSystemController(), | ||||
|                                               system.GetContentProvider()}; | ||||
|         return pm_update.GetControlMetadata(); | ||||
|     }(); | ||||
| 
 | ||||
|     if (res.first != nullptr) { | ||||
|         supported_languages = res.first->GetSupportedLanguages(); | ||||
|     } | ||||
| 
 | ||||
|     // Call IApplicationManagerInterface implementation.
 | ||||
|     auto& service_manager = system.ServiceManager(); | ||||
|     auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); | ||||
|     auto app_man = ns_am2->GetApplicationManagerInterface(); | ||||
| 
 | ||||
|     // Get desired application language
 | ||||
|     u8 desired_language{}; | ||||
|     R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); | ||||
| 
 | ||||
|     // Convert to settings language code.
 | ||||
|     u64 language_code{}; | ||||
|     R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language)); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); | ||||
| 
 | ||||
|     *out_desired_language = language_code; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_application_id) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
| 
 | ||||
|     // TODO: this should be the main applet, not the caller applet
 | ||||
|     const auto main_applet = GetCallerIdentity(*m_applet); | ||||
|     *out_application_id = main_applet.application_id; | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers( | ||||
|     Out<bool> out_no_users_available, Out<s32> out_users_count, | ||||
|     OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) { | ||||
|     const Service::Account::ProfileManager manager{}; | ||||
| 
 | ||||
|     *out_no_users_available = true; | ||||
|     *out_users_count = -1; | ||||
| 
 | ||||
|     LOG_INFO(Service_AM, "called"); | ||||
| 
 | ||||
|     if (manager.GetUserCount() > 0) { | ||||
|         *out_no_users_available = false; | ||||
|         *out_users_count = static_cast<s32>(manager.GetUserCount()); | ||||
| 
 | ||||
|         const auto users = manager.GetAllUsers(); | ||||
|         for (size_t i = 0; i < users.size() && i < out_users.size(); i++) { | ||||
|             out_users[i] = users[i]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually( | ||||
|     Out<bool> out_should_set_gpu_time_slice_manually) { | ||||
|     LOG_INFO(Service_AM, "(STUBBED) called"); | ||||
|     *out_should_set_gpu_time_slice_manually = false; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result ILibraryAppletSelfAccessor::Cmd160(Out<u64> out_unknown0) { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
|     *out_unknown0 = 0; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::AM
 | ||||
| @ -0,0 +1,83 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/uuid.h" | ||||
| #include "core/hle/service/am/am_types.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace FileSys { | ||||
| enum class StorageId : u8; | ||||
| } | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KReadableEvent; | ||||
| } | ||||
| 
 | ||||
| namespace Service::AM { | ||||
| 
 | ||||
| class AppletDataBroker; | ||||
| struct Applet; | ||||
| class IStorage; | ||||
| 
 | ||||
| struct LibraryAppletInfo { | ||||
|     AppletId applet_id; | ||||
|     LibraryAppletMode library_applet_mode; | ||||
| }; | ||||
| static_assert(sizeof(LibraryAppletInfo) == 0x8, "LibraryAppletInfo has incorrect size."); | ||||
| 
 | ||||
| struct ErrorCode { | ||||
|     u32 category; | ||||
|     u32 number; | ||||
| }; | ||||
| static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size."); | ||||
| 
 | ||||
| struct ErrorContext { | ||||
|     u8 type; | ||||
|     INSERT_PADDING_BYTES_NOINIT(0x7); | ||||
|     std::array<u8, 0x1f4> data; | ||||
|     Result result; | ||||
| }; | ||||
| static_assert(sizeof(ErrorContext) == 0x200, "ErrorContext has incorrect size."); | ||||
| 
 | ||||
| class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { | ||||
| public: | ||||
|     explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet); | ||||
|     ~ILibraryAppletSelfAccessor() override; | ||||
| 
 | ||||
| private: | ||||
|     Result PopInData(Out<SharedPointer<IStorage>> out_storage); | ||||
|     Result PushOutData(SharedPointer<IStorage> storage); | ||||
|     Result PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage); | ||||
|     Result PushInteractiveOutData(SharedPointer<IStorage> storage); | ||||
|     Result GetPopInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result GetPopInteractiveInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result GetLibraryAppletInfo(Out<LibraryAppletInfo> out_library_applet_info); | ||||
|     Result GetMainAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info); | ||||
|     Result CanUseApplicationCore(Out<bool> out_can_use_application_core); | ||||
|     Result GetMainAppletApplicationControlProperty( | ||||
|         OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp); | ||||
|     Result GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id); | ||||
|     Result ExitProcessAndReturn(); | ||||
|     Result GetCallerAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info); | ||||
|     Result GetCallerAppletIdentityInfoStack( | ||||
|         Out<s32> out_count, | ||||
|         OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info); | ||||
|     Result GetDesirableKeyboardLayout(Out<u32> out_desirable_layout); | ||||
|     Result ReportVisibleError(ErrorCode error_code); | ||||
|     Result ReportVisibleErrorWithErrorContext( | ||||
|         ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context); | ||||
|     Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language); | ||||
|     Result GetCurrentApplicationId(Out<u64> out_application_id); | ||||
|     Result GetMainAppletAvailableUsers(Out<bool> out_no_users_available, Out<s32> out_users_count, | ||||
|                                        OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users); | ||||
|     Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually); | ||||
|     Result Cmd160(Out<u64> out_unknown0); | ||||
| 
 | ||||
|     const std::shared_ptr<Applet> m_applet; | ||||
|     const std::shared_ptr<AppletDataBroker> m_broker; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::AM
 | ||||
| @ -2,7 +2,6 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/am/application_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/service/applet_common_functions.h" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user