diff --git a/src/core/core.cpp b/src/core/core.cpp index be856b90ef..eb37953351 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -350,7 +350,7 @@ struct System::Impl { // Register with applet manager // All threads are started, begin main process execution, now that we're in the clear - applet_manager.CreateAndInsertByFrontendAppletParameters(std::make_unique(*std::move(process)), params); + applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params); if (Settings::values.gamecard_inserted) { if (Settings::values.gamecard_current_game) { diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index 1121fe221e..9a3d7c7c7b 100644 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h @@ -109,6 +109,10 @@ struct Applet { std::list> child_applets{}; bool is_completed{}; + std::shared_ptr reserved_applet{}; + bool unwind_after_reserved{}; + bool is_winding{}; + // Self state bool exit_locked{}; s32 fatal_section_count{}; diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp index f75baac282..ac0246a666 100644 --- a/src/core/hle/service/am/applet_data_broker.cpp +++ b/src/core/hle/service/am/applet_data_broker.cpp @@ -25,6 +25,13 @@ void AppletStorageChannel::Push(Kernel::KernelCore& kernel, std::shared_ptr storage) { + std::scoped_lock lk{m_lock}; + + m_data.emplace_front(std::move(storage)); + m_event.Signal(kernel); +} + Result AppletStorageChannel::Pop(Kernel::KernelCore& kernel, std::shared_ptr* out_storage) { std::scoped_lock lk{m_lock}; diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h index 36ce8a24d4..1fbe89a385 100644 --- a/src/core/hle/service/am/applet_data_broker.h +++ b/src/core/hle/service/am/applet_data_broker.h @@ -26,6 +26,7 @@ public: ~AppletStorageChannel(); void Push(Kernel::KernelCore& kernel, std::shared_ptr storage); + void Unpop(Kernel::KernelCore& kernel, std::shared_ptr storage); Result Pop(Kernel::KernelCore& kernel, std::shared_ptr* out_storage); Kernel::KReadableEvent* GetEvent(); diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index 2388faa541..05bcf6cc05 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -267,7 +267,7 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) { if (Settings::values.enable_overlay && m_window_system->GetOverlayDisplayApplet() == nullptr) { if (auto overlay_process = CreateProcess(m_system, static_cast(AppletProgramId::OverlayDisplay), 0, 0)) { - auto overlay_applet = std::make_shared(m_system, std::make_unique(*std::move(overlay_process)), false); + auto overlay_applet = std::make_shared(m_system, std::move(overlay_process), false); overlay_applet->program_id = static_cast(AppletProgramId::OverlayDisplay); overlay_applet->applet_id = AppletId::OverlayDisplay; overlay_applet->type = AppletType::OverlayApplet; diff --git a/src/core/hle/service/am/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp index ea4bd8f45b..2613fc29a4 100644 --- a/src/core/hle/service/am/hid_registration.cpp +++ b/src/core/hle/service/am/hid_registration.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -12,7 +15,10 @@ namespace Service::AM { HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) { m_hid_server = system.ServiceManager().GetService("hid", true); + this->RegisterCurrentProcess(); +} +void HidRegistration::RegisterCurrentProcess() { if (m_process.IsInitialized()) { m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(), true); diff --git a/src/core/hle/service/am/hid_registration.h b/src/core/hle/service/am/hid_registration.h index 54f42af189..560266144f 100644 --- a/src/core/hle/service/am/hid_registration.h +++ b/src/core/hle/service/am/hid_registration.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -24,6 +27,7 @@ public: explicit HidRegistration(Core::System& system, Process& process); ~HidRegistration(); + void RegisterCurrentProcess(); void EnableAppletToGetInput(bool enable); private: diff --git a/src/core/hle/service/am/lifecycle_manager.cpp b/src/core/hle/service/am/lifecycle_manager.cpp index 8d6965a06c..4b003c4696 100644 --- a/src/core/hle/service/am/lifecycle_manager.cpp +++ b/src/core/hle/service/am/lifecycle_manager.cpp @@ -171,6 +171,18 @@ void LifecycleManager::SignalSystemEventIfNeeded(Kernel::KernelCore& kernel) { } } +void LifecycleManager::ResetForRelaunch() { + m_unordered_messages.clear(); + + m_activity_state = ActivityState::BackgroundVisible; + m_requested_focus_state = FocusState{}; + m_acknowledged_focus_state = FocusState{}; + m_has_focus_state_changed = true; + + m_suspend_mode = SuspendMode::NoOverride; + m_forced_suspend = false; +} + bool LifecycleManager::PopMessage(Kernel::KernelCore& kernel, AppletMessage* out_message) { const auto message = this->PopMessageInOrderOfPriority(); this->SignalSystemEventIfNeeded(kernel); diff --git a/src/core/hle/service/am/lifecycle_manager.h b/src/core/hle/service/am/lifecycle_manager.h index 615aeed591..ae041d3e29 100644 --- a/src/core/hle/service/am/lifecycle_manager.h +++ b/src/core/hle/service/am/lifecycle_manager.h @@ -138,6 +138,8 @@ public: void PushUnorderedMessage(Kernel::KernelCore& kernel, AppletMessage message); bool PopMessage(Kernel::KernelCore& kernel, AppletMessage* out_message); + void ResetForRelaunch(); + private: FocusState GetFocusStateWhileForegroundObscured() const; FocusState GetFocusStateWhileBackground(bool is_obscured) const; diff --git a/src/core/hle/service/am/process_creation.cpp b/src/core/hle/service/am/process_creation.cpp index e34e86a82c..60154fc301 100644 --- a/src/core/hle/service/am/process_creation.cpp +++ b/src/core/hle/service/am/process_creation.cpp @@ -40,23 +40,23 @@ namespace { } } -[[nodiscard]] inline std::optional CreateProcessImpl(std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) { +[[nodiscard]] inline std::unique_ptr CreateProcessImpl(std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) { // Get the appropriate loader to parse this NCA. out_loader = Loader::GetLoader(system, file, program_id, program_index); // Ensure we have a loader which can parse the NCA. if (out_loader) { // Try to load the process. - auto process = std::make_optional(system); + auto process = std::make_unique(system); if (process->Initialize(*out_loader, out_load_result)) { return process; } } - return std::nullopt; + return nullptr; } } // Anonymous namespace -std::optional CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) { +std::unique_ptr CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) { // Attempt to load program NCA. FileSys::VirtualFile nca_raw{}; @@ -66,7 +66,7 @@ std::optional CreateProcess(Core::System& system, u64 program_id, u8 mi // Ensure we retrieved a program NCA. if (!nca_raw) { - return std::nullopt; + return nullptr; } // Ensure we have a suitable version. @@ -76,7 +76,7 @@ std::optional CreateProcess(Core::System& system, u64 program_id, u8 mi (nca.GetKeyGeneration() < minimum_key_generation || nca.GetKeyGeneration() > maximum_key_generation)) { LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id, nca.GetKeyGeneration()); - return std::nullopt; + return nullptr; } } @@ -85,7 +85,7 @@ std::optional CreateProcess(Core::System& system, u64 program_id, u8 mi return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0); } -std::optional CreateApplicationProcess(std::vector& out_control, std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) { +std::unique_ptr CreateApplicationProcess(std::vector& out_control, std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) { if (auto process = CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index); process) { FileSys::NACP nacp; if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) { @@ -110,7 +110,23 @@ std::optional CreateApplicationProcess(std::vector& out_control, st system.GetARPManager().Register(launch.title_id, launch, out_control); return process; } - return std::nullopt; + return nullptr; +} + +bool ReinitializeProcess(Core::System& system, Process& process, u64 program_id) { + auto& storage = system.GetContentProviderUnion(); + const auto nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program); + if (!nca_raw) { + return false; + } + + auto loader = Loader::GetLoader(system, nca_raw, program_id, 0); + if (!loader) { + return false; + } + + Loader::ResultStatus status{}; + return process.Initialize(*loader, status); } } // namespace Service::AM diff --git a/src/core/hle/service/am/process_creation.h b/src/core/hle/service/am/process_creation.h index 57d8b8f815..20f0743740 100644 --- a/src/core/hle/service/am/process_creation.h +++ b/src/core/hle/service/am/process_creation.h @@ -27,7 +27,9 @@ class Process; namespace Service::AM { -std::optional CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation); -std::optional CreateApplicationProcess(std::vector& out_control, std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index); +std::unique_ptr CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation); +std::unique_ptr CreateApplicationProcess(std::vector& out_control, std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index); + +bool ReinitializeProcess(Core::System& system, Process& process, u64 program_id); } // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_creator.cpp b/src/core/hle/service/am/service/application_creator.cpp index 983ac700bc..e3bb92c3a4 100644 --- a/src/core/hle/service/am/service/application_creator.cpp +++ b/src/core/hle/service/am/service/application_creator.cpp @@ -35,9 +35,9 @@ Result CreateGuestApplication(SharedPointer* out_applicati std::unique_ptr loader; Loader::ResultStatus result; auto process = CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0); - R_UNLESS(process != std::nullopt, ResultUnknown); + R_UNLESS(process != nullptr, ResultUnknown); - const auto applet = std::make_shared(system, std::make_unique(*std::move(process)), true); + const auto applet = std::make_shared(system, std::move(process), true); applet->program_id = program_id; applet->applet_id = AppletId::Application; applet->type = AppletType::Application; @@ -88,9 +88,9 @@ Result IApplicationCreator::CreateSystemApplication( std::vector control; std::unique_ptr loader; auto process = CreateProcess(system, application_id, 1, 22); - R_UNLESS(process != std::nullopt, ResultUnknown); + R_UNLESS(process != nullptr, ResultUnknown); - const auto applet = std::make_shared(system, std::make_unique(*std::move(process)), true); + const auto applet = std::make_shared(system, std::move(process), true); applet->program_id = application_id; applet->applet_id = AppletId::Starter; applet->type = AppletType::LibraryApplet; diff --git a/src/core/hle/service/am/service/library_applet_accessor.cpp b/src/core/hle/service/am/service/library_applet_accessor.cpp index 366a26de0a..c49b1f3f05 100644 --- a/src/core/hle/service/am/service/library_applet_accessor.cpp +++ b/src/core/hle/service/am/service/library_applet_accessor.cpp @@ -75,7 +75,7 @@ ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, {105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"}, {106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"}, {110, nullptr, "NeedsToExitProcess"}, - {120, nullptr, "GetLibraryAppletInfo"}, + {120, D<&ILibraryAppletAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"}, {150, nullptr, "RequestForAppletToGetForeground"}, {160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"}, //2.0.0+ {170, D<&ILibraryAppletAccessor::Unknown170>, "Unknown170"}, //22.0.0+ @@ -218,6 +218,16 @@ Result ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(Out out_handl R_SUCCEED(); } +Result ILibraryAppletAccessor::GetLibraryAppletInfo( + Out 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 ILibraryAppletAccessor::Unknown170(OutCopyHandle out_event) { LOG_WARNING(Service_AM, "(STUBBED) called"); *out_event = m_applet->unknown_event.GetHandle(); diff --git a/src/core/hle/service/am/service/library_applet_accessor.h b/src/core/hle/service/am/service/library_applet_accessor.h index 02fcd07fd3..ad40bc76c7 100644 --- a/src/core/hle/service/am/service/library_applet_accessor.h +++ b/src/core/hle/service/am/service/library_applet_accessor.h @@ -6,6 +6,7 @@ #pragma once +#include "core/hle/service/am/service/library_applet_self_accessor.h" #include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" @@ -21,6 +22,10 @@ public: std::shared_ptr applet); ~ILibraryAppletAccessor(); + std::shared_ptr GetApplet() const { + return m_applet; + } + private: Result GetAppletStateChangedEvent(OutCopyHandle out_event); Result IsCompleted(Out out_is_completed); @@ -37,6 +42,7 @@ private: Result GetPopOutDataEvent(OutCopyHandle out_event); Result GetPopInteractiveOutDataEvent(OutCopyHandle out_event); Result GetIndirectLayerConsumerHandle(Out out_handle); + Result GetLibraryAppletInfo(Out out_library_applet_info); Result Unknown170(OutCopyHandle out_event); void FrontendExecute(); diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp index 92c9fd4ad9..c20a77f8c4 100644 --- a/src/core/hle/service/am/service/library_applet_creator.cpp +++ b/src/core/hle/service/am/service/library_applet_creator.cpp @@ -123,7 +123,7 @@ std::shared_ptr CreateGuestApplet(Core::System& system, auto process = CreateProcess(system, program_id, Firmware1400, Firmware2200); if (process) { - const auto applet = std::make_shared(system, std::make_unique(*std::move(process)), false); + const auto applet = std::make_shared(system, std::move(process), false); applet->program_id = program_id; applet->applet_id = applet_id; applet->type = AppletType::LibraryApplet; diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.cpp b/src/core/hle/service/am/service/library_applet_self_accessor.cpp index 473a4bc955..b16bf87979 100644 --- a/src/core/hle/service/am/service/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp @@ -233,8 +233,9 @@ Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext( R_SUCCEED(); } -Result ILibraryAppletSelfAccessor::UnpopInData() { - LOG_WARNING(Service_AM, "(STUBBED) called"); +Result ILibraryAppletSelfAccessor::UnpopInData(SharedPointer storage) { + LOG_INFO(Service_AM, "called"); + m_broker->GetInData().Unpop(system.Kernel(), storage); R_SUCCEED(); } diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.h b/src/core/hle/service/am/service/library_applet_self_accessor.h index 78864a94eb..d287f6b403 100644 --- a/src/core/hle/service/am/service/library_applet_self_accessor.h +++ b/src/core/hle/service/am/service/library_applet_self_accessor.h @@ -72,7 +72,7 @@ private: Result ReportVisibleError(ErrorCode error_code); Result ReportVisibleErrorWithErrorContext( ErrorCode error_code, InLargeData error_context); - Result UnpopInData(); + Result UnpopInData(SharedPointer storage); Result GetMainAppletApplicationDesiredLanguage(Out out_desired_language); Result GetCurrentApplicationId(Out out_application_id); Result GetMainAppletAvailableUsers(Out out_can_select_any_user, Out out_users_count, diff --git a/src/core/hle/service/am/service/process_winding_controller.cpp b/src/core/hle/service/am/service/process_winding_controller.cpp index 30529de550..e284aa2d89 100644 --- a/src/core/hle/service/am/service/process_winding_controller.cpp +++ b/src/core/hle/service/am/service/process_winding_controller.cpp @@ -1,9 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/core.h" +#include "core/hle/service/am/applet.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/service/library_applet_accessor.h" #include "core/hle/service/am/service/process_winding_controller.h" @@ -43,6 +45,18 @@ Result IProcessWindingController::OpenCallingLibraryApplet( Out> out_calling_library_applet) { LOG_INFO(Service_AM, "called"); + std::shared_ptr reserved_applet; + { + std::scoped_lock lk{m_applet->lock}; + reserved_applet = std::move(m_applet->reserved_applet); + } + + if (reserved_applet != nullptr) { + *out_calling_library_applet = std::make_shared( + system, reserved_applet->caller_applet_broker, reserved_applet); + R_SUCCEED(); + } + const auto caller_applet = m_applet->caller_applet.lock(); if (caller_applet == nullptr) { LOG_ERROR(Service_AM, "No caller applet available"); @@ -74,22 +88,82 @@ Result IProcessWindingController::PopContext(Out> out_co } Result IProcessWindingController::CancelWindingReservation() { - LOG_WARNING(Service_AM, "STUBBED"); + LOG_INFO(Service_AM, "called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->reserved_applet.reset(); + m_applet->unwind_after_reserved = false; + R_SUCCEED(); } Result IProcessWindingController::WindAndDoReserved() { - LOG_WARNING(Service_AM, "STUBBED"); + LOG_INFO(Service_AM, "called"); + + std::shared_ptr reserved_applet; + { + std::scoped_lock lk{m_applet->lock}; + + reserved_applet = m_applet->reserved_applet; + m_applet->display_layer_manager.SetWindowVisibility(false); + m_applet->exit_locked = false; + system.SetExitLocked(false); + } + + if (reserved_applet) { + { + std::scoped_lock lk{m_applet->lock}; + m_applet->is_winding = true; + } + + { + std::scoped_lock lk{reserved_applet->lock}; + reserved_applet->window_visible = true; + reserved_applet->process->Run(); + } + + if (reserved_applet->frontend) { + reserved_applet->frontend->Initialize(); + reserved_applet->frontend->Execute(); + } + } else { + LOG_WARNING(Service_AM, "called without a reserved applet to start"); + } + + m_applet->process->Terminate(); + R_SUCCEED(); } -Result IProcessWindingController::ReserveToStartAndWaitAndUnwindThis() { - LOG_WARNING(Service_AM, "STUBBED"); +Result IProcessWindingController::ReserveToStartAndWaitAndUnwindThis( + SharedPointer reserved_applet_accessor) { + LOG_INFO(Service_AM, "called"); + + if (reserved_applet_accessor == nullptr) { + LOG_ERROR(Service_AM, "No applet accessor provided"); + R_THROW(ResultUnknown); + } + + std::scoped_lock lk{m_applet->lock}; + m_applet->reserved_applet = reserved_applet_accessor->GetApplet(); + m_applet->unwind_after_reserved = true; + R_SUCCEED(); } -Result IProcessWindingController::ReserveToStartAndWait() { - LOG_WARNING(Service_AM, "STUBBED"); +Result IProcessWindingController::ReserveToStartAndWait( + SharedPointer reserved_applet_accessor) { + LOG_INFO(Service_AM, "called"); + + if (reserved_applet_accessor == nullptr) { + LOG_ERROR(Service_AM, "No applet accessor provided"); + R_THROW(ResultUnknown); + } + + std::scoped_lock lk{m_applet->lock}; + m_applet->reserved_applet = reserved_applet_accessor->GetApplet(); + m_applet->unwind_after_reserved = false; + R_SUCCEED(); } diff --git a/src/core/hle/service/am/service/process_winding_controller.h b/src/core/hle/service/am/service/process_winding_controller.h index 0d53223033..f3417bcd97 100644 --- a/src/core/hle/service/am/service/process_winding_controller.h +++ b/src/core/hle/service/am/service/process_winding_controller.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project @@ -29,8 +29,9 @@ private: Result PopContext(Out> out_context); Result CancelWindingReservation(); Result WindAndDoReserved(); - Result ReserveToStartAndWaitAndUnwindThis(); - Result ReserveToStartAndWait(); + Result ReserveToStartAndWaitAndUnwindThis( + SharedPointer reserved_applet_accessor); + Result ReserveToStartAndWait(SharedPointer reserved_applet_accessor); const std::shared_ptr m_applet; }; diff --git a/src/core/hle/service/am/window_system.cpp b/src/core/hle/service/am/window_system.cpp index 90115d73be..bbaea8ad12 100644 --- a/src/core/hle/service/am/window_system.cpp +++ b/src/core/hle/service/am/window_system.cpp @@ -9,6 +9,7 @@ #include "core/hle/service/am/applet.h" #include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/event_observer.h" +#include "core/hle/service/am/process_creation.h" #include "core/hle/service/am/window_system.h" namespace Service::AM { @@ -240,6 +241,37 @@ void WindowSystem::PruneTerminatedAppletsLocked() { continue; } + // A winding applet has had its own process killed but is kept alive as a transparent slot + // while the reserved applet running in its place finishes (see WindAndDoReserved()). + if (applet->is_winding) { + if (!applet->child_applets.empty()) { + it = std::next(it); + continue; + } + + const bool unwind = applet->unwind_after_reserved; + applet->is_winding = false; + applet->unwind_after_reserved = false; + + if (unwind && this->RestartAppletProcessLocked(applet.get())) { + const u64 new_aruid = applet->aruid.pid; + const auto next = std::next(it); + + if (new_aruid != aruid) { + auto node = m_applets.extract(it); + node.key() = new_aruid; + m_applets.insert(std::move(node)); + } + + applet->process->Run(); + m_event_observer->RequestUpdate(); + it = next; + continue; + } + + applet->reserved_applet.reset(); + } + // Terminated, so ensure all child applets are terminated. if (!applet->child_applets.empty()) { this->TerminateChildAppletsLocked(applet.get()); @@ -301,6 +333,28 @@ void WindowSystem::PruneTerminatedAppletsLocked() { } } +bool WindowSystem::RestartAppletProcessLocked(Applet* applet) { + if (!ReinitializeProcess(m_system, *applet->process, applet->program_id)) { + LOG_ERROR(Service_AM, "Failed to restart winding applet_id={}", + static_cast(applet->applet_id)); + return false; + } + + applet->aruid.pid = applet->process->GetProcessId(); + applet->is_process_running = false; + applet->is_completed = false; + + applet->hid_registration.RegisterCurrentProcess(); + + applet->lifecycle_manager.ResetForRelaunch(); + applet->is_activity_runnable = false; + + applet->launch_reason.flag = 1; + + m_event_observer->TrackAppletProcess(*applet); + return true; +} + bool WindowSystem::LockHomeMenuIntoForegroundLocked() { // If the home menu is not locked into foreground, then there's nothing to do. if (m_home_menu == nullptr || !m_home_menu_foreground_locked) { @@ -352,6 +406,9 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b const bool has_obscuring_child_applets = [&] { for (const auto& child_applet : applet->child_applets) { std::scoped_lock lk2{child_applet->lock}; + if (child_applet->is_winding) { + return true; + } const auto mode = child_applet->library_applet_mode; if (child_applet->is_process_running && child_applet->window_visible && (mode == LibraryAppletMode::AllForeground || diff --git a/src/core/hle/service/am/window_system.h b/src/core/hle/service/am/window_system.h index c331d10c92..485e57f902 100644 --- a/src/core/hle/service/am/window_system.h +++ b/src/core/hle/service/am/window_system.h @@ -61,6 +61,7 @@ public: private: void PruneTerminatedAppletsLocked(); + bool RestartAppletProcessLocked(Applet* applet); bool LockHomeMenuIntoForegroundLocked(); void TerminateChildAppletsLocked(Applet* applet); void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking = false);