aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpineappleEA <pineaea@gmail.com>2024-02-25 08:13:37 +0100
committerpineappleEA <pineaea@gmail.com>2024-02-25 08:13:37 +0100
commitf6a418b34e06f8f79d3092fd46ff1fb3b92ff4f3 (patch)
tree12b8a865ffc34193a92520c54cba7cb4fdb6822a
parentb9d9dc3c7109dec9b529a34be8eed644bd76e722 (diff)
early-access version 4168EA-4168
-rwxr-xr-xREADME.md2
-rwxr-xr-xsrc/core/CMakeLists.txt20
-rwxr-xr-xsrc/core/core.cpp109
-rwxr-xr-xsrc/core/hle/service/am/am.cpp15
-rwxr-xr-xsrc/core/hle/service/am/am_results.h1
-rwxr-xr-xsrc/core/hle/service/am/am_types.h7
-rwxr-xr-xsrc/core/hle/service/am/applet.cpp66
-rwxr-xr-xsrc/core/hle/service/am/applet.h33
-rwxr-xr-xsrc/core/hle/service/am/applet_data_broker.cpp18
-rwxr-xr-xsrc/core/hle/service/am/applet_data_broker.h14
-rwxr-xr-xsrc/core/hle/service/am/applet_manager.cpp124
-rwxr-xr-xsrc/core/hle/service/am/applet_manager.h33
-rwxr-xr-xsrc/core/hle/service/am/button_poller.cpp89
-rwxr-xr-xsrc/core/hle/service/am/button_poller.h43
-rwxr-xr-xsrc/core/hle/service/am/event_observer.cpp162
-rwxr-xr-xsrc/core/hle/service/am/event_observer.h74
-rwxr-xr-xsrc/core/hle/service/am/frontend/applets.cpp6
-rwxr-xr-xsrc/core/hle/service/am/hid_registration.cpp10
-rwxr-xr-xsrc/core/hle/service/am/hid_registration.h6
-rwxr-xr-xsrc/core/hle/service/am/lifecycle_manager.cpp379
-rwxr-xr-xsrc/core/hle/service/am/lifecycle_manager.h183
-rwxr-xr-xsrc/core/hle/service/am/process_creation.cpp130
-rwxr-xr-xsrc/core/hle/service/am/process_creation.h35
-rwxr-xr-xsrc/core/hle/service/am/process_holder.cpp15
-rwxr-xr-xsrc/core/hle/service/am/process_holder.h34
-rwxr-xr-xsrc/core/hle/service/am/service/all_system_applet_proxies_service.cpp16
-rwxr-xr-xsrc/core/hle/service/am/service/all_system_applet_proxies_service.h5
-rwxr-xr-xsrc/core/hle/service/am/service/applet_common_functions.cpp9
-rwxr-xr-xsrc/core/hle/service/am/service/applet_common_functions.h1
-rwxr-xr-xsrc/core/hle/service/am/service/application_accessor.cpp39
-rwxr-xr-xsrc/core/hle/service/am/service/application_accessor.h5
-rwxr-xr-xsrc/core/hle/service/am/service/application_creator.cpp49
-rwxr-xr-xsrc/core/hle/service/am/service/application_creator.h5
-rwxr-xr-xsrc/core/hle/service/am/service/application_functions.cpp3
-rwxr-xr-xsrc/core/hle/service/am/service/application_proxy.cpp11
-rwxr-xr-xsrc/core/hle/service/am/service/application_proxy.h4
-rwxr-xr-xsrc/core/hle/service/am/service/application_proxy_service.cpp12
-rwxr-xr-xsrc/core/hle/service/am/service/application_proxy_service.h5
-rwxr-xr-xsrc/core/hle/service/am/service/common_state_getter.cpp9
-rwxr-xr-xsrc/core/hle/service/am/service/home_menu_functions.cpp18
-rwxr-xr-xsrc/core/hle/service/am/service/home_menu_functions.h5
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_accessor.cpp16
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_accessor.h2
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_creator.cpp49
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_creator.h5
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_proxy.cpp14
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_proxy.h4
-rwxr-xr-xsrc/core/hle/service/am/service/library_applet_self_accessor.cpp3
-rwxr-xr-xsrc/core/hle/service/am/service/self_controller.cpp37
-rwxr-xr-xsrc/core/hle/service/am/service/system_applet_proxy.cpp16
-rwxr-xr-xsrc/core/hle/service/am/service/system_applet_proxy.h4
-rwxr-xr-xsrc/core/hle/service/am/service/window_controller.cpp19
-rwxr-xr-xsrc/core/hle/service/am/service/window_controller.h5
-rwxr-xr-xsrc/core/hle/service/am/window_system.cpp315
-rwxr-xr-xsrc/core/hle/service/am/window_system.h83
-rwxr-xr-xsrc/core/hle/service/glue/time/manager.cpp7
-rwxr-xr-xsrc/core/hle/service/hid/hid.cpp4
-rwxr-xr-xsrc/core/hle/service/os/process.cpp152
-rwxr-xr-xsrc/core/hle/service/os/process.h58
-rwxr-xr-xsrc/yuzu/main.cpp7
-rwxr-xr-xsrc/yuzu/main.h1
61 files changed, 2208 insertions, 397 deletions
diff --git a/README.md b/README.md
index c7ded9519..47109b677 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
1yuzu emulator early access 1yuzu emulator early access
2============= 2=============
3 3
4This is the source code for early-access 4167. 4This is the source code for early-access 4168.
5 5
6## Legal Notice 6## Legal Notice
7 7
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 3ecc30637..d9d5cd804 100755
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -401,14 +401,16 @@ add_library(core STATIC
401 hle/service/am/am_types.h 401 hle/service/am/am_types.h
402 hle/service/am/applet.cpp 402 hle/service/am/applet.cpp
403 hle/service/am/applet.h 403 hle/service/am/applet.h
404 hle/service/am/applet_manager.cpp
404 hle/service/am/applet_data_broker.cpp 405 hle/service/am/applet_data_broker.cpp
405 hle/service/am/applet_data_broker.h 406 hle/service/am/applet_data_broker.h
406 hle/service/am/applet_manager.cpp
407 hle/service/am/applet_manager.h 407 hle/service/am/applet_manager.h
408 hle/service/am/applet_message_queue.cpp 408 hle/service/am/button_poller.cpp
409 hle/service/am/applet_message_queue.h 409 hle/service/am/button_poller.h
410 hle/service/am/display_layer_manager.cpp 410 hle/service/am/display_layer_manager.cpp
411 hle/service/am/display_layer_manager.h 411 hle/service/am/display_layer_manager.h
412 hle/service/am/event_observer.cpp
413 hle/service/am/event_observer.h
412 hle/service/am/frontend/applet_cabinet.cpp 414 hle/service/am/frontend/applet_cabinet.cpp
413 hle/service/am/frontend/applet_cabinet.h 415 hle/service/am/frontend/applet_cabinet.h
414 hle/service/am/frontend/applet_controller.cpp 416 hle/service/am/frontend/applet_controller.cpp
@@ -434,8 +436,12 @@ add_library(core STATIC
434 hle/service/am/hid_registration.h 436 hle/service/am/hid_registration.h
435 hle/service/am/library_applet_storage.cpp 437 hle/service/am/library_applet_storage.cpp
436 hle/service/am/library_applet_storage.h 438 hle/service/am/library_applet_storage.h
437 hle/service/am/process.cpp 439 hle/service/am/lifecycle_manager.cpp
438 hle/service/am/process.h 440 hle/service/am/lifecycle_manager.h
441 hle/service/am/process_creation.cpp
442 hle/service/am/process_creation.h
443 hle/service/am/process_holder.cpp
444 hle/service/am/process_holder.h
439 hle/service/am/service/all_system_applet_proxies_service.cpp 445 hle/service/am/service/all_system_applet_proxies_service.cpp
440 hle/service/am/service/all_system_applet_proxies_service.h 446 hle/service/am/service/all_system_applet_proxies_service.h
441 hle/service/am/service/applet_common_functions.cpp 447 hle/service/am/service/applet_common_functions.cpp
@@ -486,6 +492,8 @@ add_library(core STATIC
486 hle/service/am/service/system_applet_proxy.h 492 hle/service/am/service/system_applet_proxy.h
487 hle/service/am/service/window_controller.cpp 493 hle/service/am/service/window_controller.cpp
488 hle/service/am/service/window_controller.h 494 hle/service/am/service/window_controller.h
495 hle/service/am/window_system.cpp
496 hle/service/am/window_system.h
489 hle/service/aoc/addon_content_manager.cpp 497 hle/service/aoc/addon_content_manager.cpp
490 hle/service/aoc/addon_content_manager.h 498 hle/service/aoc/addon_content_manager.h
491 hle/service/aoc/purchase_event_manager.cpp 499 hle/service/aoc/purchase_event_manager.cpp
@@ -914,6 +922,8 @@ add_library(core STATIC
914 hle/service/os/multi_wait_utils.h 922 hle/service/os/multi_wait_utils.h
915 hle/service/os/mutex.cpp 923 hle/service/os/mutex.cpp
916 hle/service/os/mutex.h 924 hle/service/os/mutex.h
925 hle/service/os/process.cpp
926 hle/service/os/process.h
917 hle/service/pcie/pcie.cpp 927 hle/service/pcie/pcie.cpp
918 hle/service/pcie/pcie.h 928 hle/service/pcie/pcie.h
919 hle/service/pctl/parental_control_service_factory.cpp 929 hle/service/pctl/parental_control_service_factory.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 56f5dd67d..a51d3447b 100755
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -3,7 +3,6 @@
3 3
4#include <array> 4#include <array>
5#include <atomic> 5#include <atomic>
6#include <exception>
7#include <memory> 6#include <memory>
8#include <utility> 7#include <utility>
9 8
@@ -20,7 +19,6 @@
20#include "core/cpu_manager.h" 19#include "core/cpu_manager.h"
21#include "core/debugger/debugger.h" 20#include "core/debugger/debugger.h"
22#include "core/device_memory.h" 21#include "core/device_memory.h"
23#include "core/file_sys/bis_factory.h"
24#include "core/file_sys/fs_filesystem.h" 22#include "core/file_sys/fs_filesystem.h"
25#include "core/file_sys/patch_manager.h" 23#include "core/file_sys/patch_manager.h"
26#include "core/file_sys/registered_cache.h" 24#include "core/file_sys/registered_cache.h"
@@ -38,6 +36,7 @@
38#include "core/hle/service/acc/profile_manager.h" 36#include "core/hle/service/acc/profile_manager.h"
39#include "core/hle/service/am/applet_manager.h" 37#include "core/hle/service/am/applet_manager.h"
40#include "core/hle/service/am/frontend/applets.h" 38#include "core/hle/service/am/frontend/applets.h"
39#include "core/hle/service/am/process_creation.h"
41#include "core/hle/service/apm/apm_controller.h" 40#include "core/hle/service/apm/apm_controller.h"
42#include "core/hle/service/filesystem/filesystem.h" 41#include "core/hle/service/filesystem/filesystem.h"
43#include "core/hle/service/glue/glue_manager.h" 42#include "core/hle/service/glue/glue_manager.h"
@@ -72,30 +71,6 @@ MICROPROFILE_DEFINE(ARM_CPU3, "ARM", "CPU 3", MP_RGB(255, 64, 64));
72 71
73namespace Core { 72namespace Core {
74 73
75namespace {
76
77FileSys::StorageId GetStorageIdForFrontendSlot(
78 std::optional<FileSys::ContentProviderUnionSlot> slot) {
79 if (!slot.has_value()) {
80 return FileSys::StorageId::None;
81 }
82
83 switch (*slot) {
84 case FileSys::ContentProviderUnionSlot::UserNAND:
85 return FileSys::StorageId::NandUser;
86 case FileSys::ContentProviderUnionSlot::SysNAND:
87 return FileSys::StorageId::NandSystem;
88 case FileSys::ContentProviderUnionSlot::SDMC:
89 return FileSys::StorageId::SdCard;
90 case FileSys::ContentProviderUnionSlot::FrontendManual:
91 return FileSys::StorageId::Host;
92 default:
93 return FileSys::StorageId::None;
94 }
95}
96
97} // Anonymous namespace
98
99FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, 74FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
100 const std::string& path) { 75 const std::string& path) {
101 // To account for split 00+01+etc files. 76 // To account for split 00+01+etc files.
@@ -297,9 +272,6 @@ struct System::Impl {
297 } 272 }
298 273
299 SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { 274 SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
300 /// Reset all glue registrations
301 arp_manager.ResetAll();
302
303 telemetry_session = std::make_unique<Core::TelemetrySession>(); 275 telemetry_session = std::make_unique<Core::TelemetrySession>();
304 276
305 host1x_core = std::make_unique<Tegra::Host1x::Host1x>(system); 277 host1x_core = std::make_unique<Tegra::Host1x::Host1x>(system);
@@ -335,8 +307,24 @@ struct System::Impl {
335 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, 307 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
336 const std::string& filepath, 308 const std::string& filepath,
337 Service::AM::FrontendAppletParameters& params) { 309 Service::AM::FrontendAppletParameters& params) {
338 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), 310 InitializeKernel(system);
339 params.program_id, params.program_index); 311
312 const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
313
314 // Create the application process
315 Loader::ResultStatus load_result{};
316 std::vector<u8> control;
317 auto process =
318 Service::AM::CreateApplicationProcess(control, app_loader, load_result, system, file,
319 params.program_id, params.program_index);
320
321 if (load_result != Loader::ResultStatus::Success) {
322 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
323 ShutdownMainProcess();
324
325 return static_cast<SystemResultStatus>(
326 static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
327 }
340 328
341 if (!app_loader) { 329 if (!app_loader) {
342 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 330 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
@@ -344,7 +332,7 @@ struct System::Impl {
344 } 332 }
345 333
346 if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) { 334 if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
347 LOG_ERROR(Core, "Failed to find title id for ROM!"); 335 LOG_ERROR(Core, "Failed to find program id for ROM!");
348 } 336 }
349 337
350 std::string name = "Unknown program"; 338 std::string name = "Unknown program";
@@ -352,23 +340,10 @@ struct System::Impl {
352 LOG_ERROR(Core, "Failed to read title for ROM!"); 340 LOG_ERROR(Core, "Failed to read title for ROM!");
353 } 341 }
354 342
355 LOG_INFO(Core, "Loading {} ({})", name, params.program_id); 343 LOG_INFO(Core, "Loading {} ({:016X}) ...", name, params.program_id);
356 344
357 InitializeKernel(system); 345 // Make the process created be the application
358 346 kernel.MakeApplicationProcess(process->GetHandle());
359 // Create the application process.
360 auto main_process = Kernel::KProcess::Create(system.Kernel());
361 Kernel::KProcess::Register(system.Kernel(), main_process);
362 kernel.AppendNewProcess(main_process);
363 kernel.MakeApplicationProcess(main_process);
364 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
365 if (load_result != Loader::ResultStatus::Success) {
366 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
367 ShutdownMainProcess();
368
369 return static_cast<SystemResultStatus>(
370 static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
371 }
372 347
373 // Set up the rest of the system. 348 // Set up the rest of the system.
374 SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; 349 SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
@@ -379,7 +354,6 @@ struct System::Impl {
379 return init_result; 354 return init_result;
380 } 355 }
381 356
382 AddGlueRegistrationForProcess(*app_loader, *main_process);
383 telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); 357 telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
384 358
385 // Initialize cheat engine 359 // Initialize cheat engine
@@ -388,13 +362,7 @@ struct System::Impl {
388 } 362 }
389 363
390 // Register with applet manager. 364 // Register with applet manager.
391 applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(), 365 applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
392 params);
393
394 // All threads are started, begin main process execution, now that we're in the clear.
395 main_process->Run(load_parameters->main_thread_priority,
396 load_parameters->main_thread_stack_size);
397 main_process->Close();
398 366
399 if (Settings::values.gamecard_inserted) { 367 if (Settings::values.gamecard_inserted) {
400 if (Settings::values.gamecard_current_game) { 368 if (Settings::values.gamecard_current_game) {
@@ -466,7 +434,6 @@ struct System::Impl {
466 kernel.SuspendEmulation(true); 434 kernel.SuspendEmulation(true);
467 kernel.CloseServices(); 435 kernel.CloseServices();
468 kernel.ShutdownCores(); 436 kernel.ShutdownCores();
469 applet_manager.Reset();
470 services.reset(); 437 services.reset();
471 service_manager.reset(); 438 service_manager.reset();
472 fs_controller.Reset(); 439 fs_controller.Reset();
@@ -492,6 +459,9 @@ struct System::Impl {
492 // Workarounds 459 // Workarounds
493 Settings::values.renderer_amdvlk_depth_bias_workaround = false; 460 Settings::values.renderer_amdvlk_depth_bias_workaround = false;
494 461
462 // Reset all glue registrations
463 arp_manager.ResetAll();
464
495 LOG_DEBUG(Core, "Shutdown OK"); 465 LOG_DEBUG(Core, "Shutdown OK");
496 } 466 }
497 467
@@ -509,31 +479,6 @@ struct System::Impl {
509 return app_loader->ReadTitle(out); 479 return app_loader->ReadTitle(out);
510 } 480 }
511 481
512 void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
513 std::vector<u8> nacp_data;
514 FileSys::NACP nacp;
515 if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
516 nacp_data = nacp.GetRawBytes();
517 } else {
518 nacp_data.resize(sizeof(FileSys::RawNACP));
519 }
520
521 Service::Glue::ApplicationLaunchProperty launch{};
522 launch.title_id = process.GetProgramId();
523
524 FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
525 launch.version = pm.GetGameVersion().value_or(0);
526
527 // TODO(DarkLordZach): When FSController/Game Card Support is added, if
528 // current_process_game_card use correct StorageId
529 launch.base_game_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
530 launch.title_id, FileSys::ContentRecordType::Program));
531 launch.update_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
532 FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
533
534 arp_manager.Register(launch.title_id, launch, std::move(nacp_data));
535 }
536
537 void SetStatus(SystemResultStatus new_status, const char* details = nullptr) { 482 void SetStatus(SystemResultStatus new_status, const char* details = nullptr) {
538 status = new_status; 483 status = new_status;
539 if (details) { 484 if (details) {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index df2e7abd7..9ec5bb48c 100755
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -2,19 +2,26 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/am/am.h" 4#include "core/hle/service/am/am.h"
5#include "core/hle/service/am/button_poller.h"
6#include "core/hle/service/am/event_observer.h"
5#include "core/hle/service/am/service/all_system_applet_proxies_service.h" 7#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
6#include "core/hle/service/am/service/application_proxy_service.h" 8#include "core/hle/service/am/service/application_proxy_service.h"
9#include "core/hle/service/am/window_system.h"
7#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
8 11
9namespace Service::AM { 12namespace Service::AM {
10 13
11void LoopProcess(Core::System& system) { 14void LoopProcess(Core::System& system) {
15 WindowSystem window_system(system);
16 ButtonPoller button_poller(system, window_system);
17 EventObserver event_observer(system, window_system);
18
12 auto server_manager = std::make_unique<ServerManager>(system); 19 auto server_manager = std::make_unique<ServerManager>(system);
13 20
14 server_manager->RegisterNamedService("appletAE", 21 server_manager->RegisterNamedService(
15 std::make_shared<IAllSystemAppletProxiesService>(system)); 22 "appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, window_system));
16 server_manager->RegisterNamedService("appletOE", 23 server_manager->RegisterNamedService(
17 std::make_shared<IApplicationProxyService>(system)); 24 "appletOE", std::make_shared<IApplicationProxyService>(system, window_system));
18 ServerManager::RunServer(std::move(server_manager)); 25 ServerManager::RunServer(std::move(server_manager));
19} 26}
20 27
diff --git a/src/core/hle/service/am/am_results.h b/src/core/hle/service/am/am_results.h
index a2afc9eec..44846aa2e 100755
--- a/src/core/hle/service/am/am_results.h
+++ b/src/core/hle/service/am/am_results.h
@@ -9,6 +9,7 @@ namespace Service::AM {
9 9
10constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; 10constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
11constexpr Result ResultNoMessages{ErrorModule::AM, 3}; 11constexpr Result ResultNoMessages{ErrorModule::AM, 3};
12constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
12constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; 13constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
13constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511}; 14constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
14constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512}; 15constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h
index 46afb3996..65320c493 100755
--- a/src/core/hle/service/am/am_types.h
+++ b/src/core/hle/service/am/am_types.h
@@ -66,12 +66,6 @@ enum class ScreenshotPermission : u32 {
66 Disable = 2, 66 Disable = 2,
67}; 67};
68 68
69struct FocusHandlingMode {
70 bool notify;
71 bool background;
72 bool suspend;
73};
74
75enum class IdleTimeDetectionExtension : u32 { 69enum class IdleTimeDetectionExtension : u32 {
76 Disabled = 0, 70 Disabled = 0,
77 Extended = 1, 71 Extended = 1,
@@ -244,7 +238,6 @@ struct ApplicationPlayStatistics {
244static_assert(sizeof(ApplicationPlayStatistics) == 0x18, 238static_assert(sizeof(ApplicationPlayStatistics) == 0x18,
245 "ApplicationPlayStatistics has incorrect size."); 239 "ApplicationPlayStatistics has incorrect size.");
246 240
247using AppletResourceUserId = u64;
248using ProgramId = u64; 241using ProgramId = u64;
249 242
250struct Applet; 243struct Applet;
diff --git a/src/core/hle/service/am/applet.cpp b/src/core/hle/service/am/applet.cpp
index 5b9056c12..6847f250c 100755
--- a/src/core/hle/service/am/applet.cpp
+++ b/src/core/hle/service/am/applet.cpp
@@ -1,27 +1,71 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/scope_exit.h"
5
6#include "core/core.h" 4#include "core/core.h"
7#include "core/hle/service/am/am_results.h"
8#include "core/hle/service/am/applet.h" 5#include "core/hle/service/am/applet.h"
9#include "core/hle/service/am/applet_manager.h" 6#include "core/hle/service/am/applet_manager.h"
10 7
11namespace Service::AM { 8namespace Service::AM {
12 9
13Applet::Applet(Core::System& system, std::unique_ptr<Process> process_) 10Applet::Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_application)
14 : context(system, "Applet"), message_queue(system), process(std::move(process_)), 11 : context(system, "Applet"), lifecycle_manager(system, context, is_application),
15 hid_registration(system, *process), gpu_error_detected_event(context), 12 process(std::move(process_)), hid_registration(system, *process),
16 friend_invitation_storage_channel_event(context), notification_storage_channel_event(context), 13 gpu_error_detected_event(context), friend_invitation_storage_channel_event(context),
17 health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context), 14 notification_storage_channel_event(context), health_warning_disappeared_system_event(context),
18 pop_from_general_channel_event(context), library_applet_launchable_event(context), 15 acquired_sleep_lock_event(context), pop_from_general_channel_event(context),
19 accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) { 16 library_applet_launchable_event(context), accumulated_suspended_tick_changed_event(context),
17 sleep_lock_event(context), state_changed_event(context) {
20 18
21 aruid = process->GetProcessId(); 19 aruid.pid = process->GetProcessId();
22 program_id = process->GetProgramId(); 20 program_id = process->GetProgramId();
23} 21}
24 22
25Applet::~Applet() = default; 23Applet::~Applet() = default;
26 24
25void Applet::UpdateSuspensionStateLocked(bool force_message) {
26 // Remove any forced resumption.
27 lifecycle_manager.RemoveForceResumeIfPossible();
28
29 // Check if we're runnable.
30 const bool curr_activity_runnable = lifecycle_manager.IsRunnable();
31 const bool prev_activity_runnable = is_activity_runnable;
32 const bool was_changed = curr_activity_runnable != prev_activity_runnable;
33
34 if (was_changed) {
35 if (curr_activity_runnable) {
36 process->Suspend(false);
37 } else {
38 process->Suspend(true);
39 lifecycle_manager.RequestResumeNotification();
40 }
41
42 is_activity_runnable = curr_activity_runnable;
43 }
44
45 if (lifecycle_manager.GetForcedSuspend()) {
46 // TODO: why is this allowed?
47 return;
48 }
49
50 // Signal if the focus state was changed or the process state was changed.
51 if (lifecycle_manager.UpdateRequestedFocusState() || was_changed || force_message) {
52 lifecycle_manager.SignalSystemEventIfNeeded();
53 }
54}
55
56void Applet::SetInteractibleLocked(bool interactible) {
57 if (is_interactible == interactible) {
58 return;
59 }
60
61 is_interactible = interactible;
62
63 hid_registration.EnableAppletToGetInput(interactible && !lifecycle_manager.GetExitRequested());
64}
65
66void Applet::OnProcessTerminatedLocked() {
67 is_completed = true;
68 state_changed_event.Signal();
69}
70
27} // namespace Service::AM 71} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h
index ad602153e..571904fab 100755
--- a/src/core/hle/service/am/applet.h
+++ b/src/core/hle/service/am/applet.h
@@ -3,25 +3,28 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <deque>
6#include <mutex> 7#include <mutex>
7 8
8#include "common/math_util.h" 9#include "common/math_util.h"
9#include "core/hle/service/apm/apm_controller.h" 10#include "core/hle/service/apm/apm_controller.h"
10#include "core/hle/service/caps/caps_types.h" 11#include "core/hle/service/caps/caps_types.h"
12#include "core/hle/service/cmif_types.h"
11#include "core/hle/service/kernel_helpers.h" 13#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/os/event.h" 14#include "core/hle/service/os/event.h"
15#include "core/hle/service/os/process.h"
13#include "core/hle/service/service.h" 16#include "core/hle/service/service.h"
14 17
15#include "core/hle/service/am/am_types.h" 18#include "core/hle/service/am/am_types.h"
16#include "core/hle/service/am/applet_message_queue.h"
17#include "core/hle/service/am/display_layer_manager.h" 19#include "core/hle/service/am/display_layer_manager.h"
18#include "core/hle/service/am/hid_registration.h" 20#include "core/hle/service/am/hid_registration.h"
19#include "core/hle/service/am/process.h" 21#include "core/hle/service/am/lifecycle_manager.h"
22#include "core/hle/service/am/process_holder.h"
20 23
21namespace Service::AM { 24namespace Service::AM {
22 25
23struct Applet { 26struct Applet {
24 explicit Applet(Core::System& system, std::unique_ptr<Process> process_); 27 explicit Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_application);
25 ~Applet(); 28 ~Applet();
26 29
27 // Lock 30 // Lock
@@ -30,11 +33,13 @@ struct Applet {
30 // Event creation helper 33 // Event creation helper
31 KernelHelpers::ServiceContext context; 34 KernelHelpers::ServiceContext context;
32 35
33 // Applet message queue 36 // Lifecycle manager
34 AppletMessageQueue message_queue; 37 LifecycleManager lifecycle_manager;
35 38
36 // Process 39 // Process
37 std::unique_ptr<Process> process; 40 std::unique_ptr<Process> process;
41 std::optional<ProcessHolder> process_holder;
42 bool is_process_running{};
38 43
39 // Creation state 44 // Creation state
40 AppletId applet_id{}; 45 AppletId applet_id{};
@@ -75,11 +80,9 @@ struct Applet {
75 bool game_play_recording_supported{}; 80 bool game_play_recording_supported{};
76 GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled}; 81 GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled};
77 bool jit_service_launched{}; 82 bool jit_service_launched{};
78 bool is_running{};
79 bool application_crash_report_enabled{}; 83 bool application_crash_report_enabled{};
80 84
81 // Common state 85 // Common state
82 FocusState focus_state{};
83 bool sleep_lock_enabled{}; 86 bool sleep_lock_enabled{};
84 bool vr_mode_enabled{}; 87 bool vr_mode_enabled{};
85 bool lcd_backlight_off_enabled{}; 88 bool lcd_backlight_off_enabled{};
@@ -93,15 +96,12 @@ struct Applet {
93 // Caller applet 96 // Caller applet
94 std::weak_ptr<Applet> caller_applet{}; 97 std::weak_ptr<Applet> caller_applet{};
95 std::shared_ptr<AppletDataBroker> caller_applet_broker{}; 98 std::shared_ptr<AppletDataBroker> caller_applet_broker{};
99 std::list<std::shared_ptr<Applet>> child_applets{};
100 bool is_completed{};
96 101
97 // Self state 102 // Self state
98 bool exit_locked{}; 103 bool exit_locked{};
99 s32 fatal_section_count{}; 104 s32 fatal_section_count{};
100 bool operation_mode_changed_notification_enabled{true};
101 bool performance_mode_changed_notification_enabled{true};
102 FocusHandlingMode focus_handling_mode{};
103 bool restart_message_enabled{};
104 bool out_of_focus_suspension_enabled{true};
105 Capture::AlbumImageOrientation album_image_orientation{}; 105 Capture::AlbumImageOrientation album_image_orientation{};
106 bool handles_request_to_display{}; 106 bool handles_request_to_display{};
107 ScreenshotPermission screenshot_permission{}; 107 ScreenshotPermission screenshot_permission{};
@@ -110,6 +110,9 @@ struct Applet {
110 u64 suspended_ticks{}; 110 u64 suspended_ticks{};
111 bool album_image_taken_notification_enabled{}; 111 bool album_image_taken_notification_enabled{};
112 bool record_volume_muted{}; 112 bool record_volume_muted{};
113 bool is_activity_runnable{};
114 bool is_interactible{true};
115 bool window_visible{true};
113 116
114 // Events 117 // Events
115 Event gpu_error_detected_event; 118 Event gpu_error_detected_event;
@@ -121,9 +124,15 @@ struct Applet {
121 Event library_applet_launchable_event; 124 Event library_applet_launchable_event;
122 Event accumulated_suspended_tick_changed_event; 125 Event accumulated_suspended_tick_changed_event;
123 Event sleep_lock_event; 126 Event sleep_lock_event;
127 Event state_changed_event;
124 128
125 // Frontend state 129 // Frontend state
126 std::shared_ptr<Frontend::FrontendApplet> frontend{}; 130 std::shared_ptr<Frontend::FrontendApplet> frontend{};
131
132 // Process state management
133 void UpdateSuspensionStateLocked(bool force_message);
134 void SetInteractibleLocked(bool interactible);
135 void OnProcessTerminatedLocked();
127}; 136};
128 137
129} // namespace Service::AM 138} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp
index 9057244a9..fff78c5af 100755
--- a/src/core/hle/service/am/applet_data_broker.cpp
+++ b/src/core/hle/service/am/applet_data_broker.cpp
@@ -44,24 +44,8 @@ Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
44 44
45AppletDataBroker::AppletDataBroker(Core::System& system_) 45AppletDataBroker::AppletDataBroker(Core::System& system_)
46 : system(system_), context(system_, "AppletDataBroker"), in_data(context), 46 : system(system_), context(system_, "AppletDataBroker"), in_data(context),
47 interactive_in_data(context), out_data(context), interactive_out_data(context), 47 interactive_in_data(context), out_data(context), interactive_out_data(context) {}
48 state_changed_event(context), is_completed(false) {}
49 48
50AppletDataBroker::~AppletDataBroker() = default; 49AppletDataBroker::~AppletDataBroker() = default;
51 50
52void AppletDataBroker::SignalCompletion() {
53 {
54 std::scoped_lock lk{lock};
55
56 if (is_completed) {
57 return;
58 }
59
60 is_completed = true;
61 state_changed_event.Signal();
62 }
63
64 system.GetAppletManager().FocusStateChanged();
65}
66
67} // namespace Service::AM 51} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h
index 5a1d43c11..2718f608a 100755
--- a/src/core/hle/service/am/applet_data_broker.h
+++ b/src/core/hle/service/am/applet_data_broker.h
@@ -53,16 +53,6 @@ public:
53 return interactive_out_data; 53 return interactive_out_data;
54 } 54 }
55 55
56 Event& GetStateChangedEvent() {
57 return state_changed_event;
58 }
59
60 bool IsCompleted() const {
61 return is_completed;
62 }
63
64 void SignalCompletion();
65
66private: 56private:
67 Core::System& system; 57 Core::System& system;
68 KernelHelpers::ServiceContext context; 58 KernelHelpers::ServiceContext context;
@@ -71,10 +61,6 @@ private:
71 AppletStorageChannel interactive_in_data; 61 AppletStorageChannel interactive_in_data;
72 AppletStorageChannel out_data; 62 AppletStorageChannel out_data;
73 AppletStorageChannel interactive_out_data; 63 AppletStorageChannel interactive_out_data;
74 Event state_changed_event;
75
76 std::mutex lock;
77 bool is_completed;
78}; 64};
79 65
80} // namespace Service::AM 66} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp
index 2e109181d..c6b7ec8bb 100755
--- a/src/core/hle/service/am/applet_manager.cpp
+++ b/src/core/hle/service/am/applet_manager.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/service/am/frontend/applet_mii_edit_types.h" 13#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
14#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" 14#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
15#include "core/hle/service/am/service/storage.h" 15#include "core/hle/service/am/service/storage.h"
16#include "core/hle/service/am/window_system.h"
16#include "hid_core/hid_types.h" 17#include "hid_core/hid_types.h"
17 18
18namespace Service::AM { 19namespace Service::AM {
@@ -225,49 +226,46 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan
225} // namespace 226} // namespace
226 227
227AppletManager::AppletManager(Core::System& system) : m_system(system) {} 228AppletManager::AppletManager(Core::System& system) : m_system(system) {}
228AppletManager::~AppletManager() { 229AppletManager::~AppletManager() = default;
229 this->Reset();
230}
231
232void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) {
233 std::scoped_lock lk{m_lock};
234 230
235 m_applets.emplace(applet->aruid, std::move(applet)); 231void AppletManager::CreateAndInsertByFrontendAppletParameters(
236} 232 std::unique_ptr<Process> process, const FrontendAppletParameters& params) {
237
238void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) {
239 std::shared_ptr<Applet> applet;
240 bool should_stop = false;
241 { 233 {
242 std::scoped_lock lk{m_lock}; 234 std::scoped_lock lk{m_lock};
235 m_pending_process = std::move(process);
236 m_pending_parameters = params;
237 }
238 m_cv.notify_all();
239}
243 240
244 const auto it = m_applets.find(aruid); 241void AppletManager::RequestExit() {
245 if (it == m_applets.end()) { 242 std::scoped_lock lk{m_lock};
246 return; 243 if (m_window_system) {
247 } 244 m_window_system->OnExitRequested();
248 245 }
249 applet = it->second; 246}
250 m_applets.erase(it);
251 247
252 should_stop = m_applets.empty(); 248void AppletManager::OperationModeChanged() {
249 std::scoped_lock lk{m_lock};
250 if (m_window_system) {
251 m_window_system->OnOperationModeChanged();
253 } 252 }
253}
254 254
255 // Terminate process. 255void AppletManager::SetWindowSystem(WindowSystem* window_system) {
256 applet->process->Terminate(); 256 std::unique_lock lk{m_lock};
257 257
258 // If there were no applets left, stop emulation. 258 m_window_system = window_system;
259 if (should_stop) { 259 if (!m_window_system) {
260 m_system.Exit(); 260 return;
261 } 261 }
262}
263 262
264void AppletManager::CreateAndInsertByFrontendAppletParameters( 263 m_cv.wait(lk, [&] { return m_pending_process != nullptr; });
265 AppletResourceUserId aruid, const FrontendAppletParameters& params) { 264
266 // TODO: this should be run inside AM so that the events will have a parent process 265 const auto& params = m_pending_parameters;
267 // TODO: have am create the guest process 266 auto applet = std::make_shared<Applet>(m_system, std::move(m_pending_process),
268 auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system)); 267 params.applet_id == AppletId::Application);
269 268
270 applet->aruid = aruid;
271 applet->program_id = params.program_id; 269 applet->program_id = params.program_id;
272 applet->applet_id = params.applet_id; 270 applet->applet_id = params.applet_id;
273 applet->type = params.applet_type; 271 applet->type = params.applet_type;
@@ -322,59 +320,19 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters(
322 } 320 }
323 321
324 // Applet was started by frontend, so it is foreground. 322 // Applet was started by frontend, so it is foreground.
325 applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground); 323 applet->lifecycle_manager.SetFocusState(FocusState::InFocus);
326 applet->message_queue.PushMessage(AppletMessage::FocusStateChanged); 324
327 applet->focus_state = FocusState::InFocus; 325 if (applet->applet_id == AppletId::QLaunch) {
328 326 applet->lifecycle_manager.SetFocusHandlingMode(false);
329 this->InsertApplet(std::move(applet)); 327 applet->lifecycle_manager.SetOutOfFocusSuspendingEnabled(false);
330} 328 m_window_system->TrackApplet(applet, false);
331 329 m_window_system->RequestHomeMenuToGetForeground();
332std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const { 330 } else {
333 std::scoped_lock lk{m_lock}; 331 m_window_system->TrackApplet(applet, true);
334 332 m_window_system->RequestApplicationToGetForeground();
335 if (const auto it = m_applets.find(aruid); it != m_applets.end()) {
336 return it->second;
337 }
338
339 return {};
340}
341
342void AppletManager::Reset() {
343 std::scoped_lock lk{m_lock};
344
345 m_applets.clear();
346}
347
348void AppletManager::RequestExit() {
349 std::scoped_lock lk{m_lock};
350
351 for (const auto& [aruid, applet] : m_applets) {
352 applet->message_queue.RequestExit();
353 } 333 }
354}
355
356void AppletManager::RequestResume() {
357 std::scoped_lock lk{m_lock};
358 334
359 for (const auto& [aruid, applet] : m_applets) { 335 applet->process->Run();
360 applet->message_queue.RequestResume();
361 }
362}
363
364void AppletManager::OperationModeChanged() {
365 std::scoped_lock lk{m_lock};
366
367 for (const auto& [aruid, applet] : m_applets) {
368 applet->message_queue.OperationModeChanged();
369 }
370}
371
372void AppletManager::FocusStateChanged() {
373 std::scoped_lock lk{m_lock};
374
375 for (const auto& [aruid, applet] : m_applets) {
376 applet->message_queue.FocusStateChanged();
377 }
378} 336}
379 337
380} // namespace Service::AM 338} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_manager.h b/src/core/hle/service/am/applet_manager.h
index 4875de309..fbdc77140 100755
--- a/src/core/hle/service/am/applet_manager.h
+++ b/src/core/hle/service/am/applet_manager.h
@@ -3,17 +3,23 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <map> 6#include <condition_variable>
7#include <mutex> 7#include <mutex>
8 8
9#include "core/hle/service/am/applet.h" 9#include "core/hle/service/am/am_types.h"
10 10
11namespace Core { 11namespace Core {
12class System; 12class System;
13} 13}
14 14
15namespace Service {
16class Process;
17}
18
15namespace Service::AM { 19namespace Service::AM {
16 20
21class WindowSystem;
22
17enum class LaunchType { 23enum class LaunchType {
18 FrontendInitiated, 24 FrontendInitiated,
19 ApplicationInitiated, 25 ApplicationInitiated,
@@ -33,27 +39,24 @@ public:
33 explicit AppletManager(Core::System& system); 39 explicit AppletManager(Core::System& system);
34 ~AppletManager(); 40 ~AppletManager();
35 41
36 void InsertApplet(std::shared_ptr<Applet> applet); 42 void CreateAndInsertByFrontendAppletParameters(std::unique_ptr<Process> process,
37 void TerminateAndRemoveApplet(AppletResourceUserId aruid);
38
39 void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
40 const FrontendAppletParameters& params); 43 const FrontendAppletParameters& params);
41 std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
42
43 void Reset();
44
45 void RequestExit(); 44 void RequestExit();
46 void RequestResume();
47 void OperationModeChanged(); 45 void OperationModeChanged();
48 void FocusStateChanged(); 46
47public:
48 void SetWindowSystem(WindowSystem* window_system);
49 49
50private: 50private:
51 Core::System& m_system; 51 Core::System& m_system;
52 52
53 mutable std::mutex m_lock{}; 53 std::mutex m_lock;
54 std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{}; 54 std::condition_variable m_cv;
55
56 WindowSystem* m_window_system{};
55 57
56 // AudioController state goes here 58 FrontendAppletParameters m_pending_parameters{};
59 std::unique_ptr<Process> m_pending_process{};
57}; 60};
58 61
59} // namespace Service::AM 62} // namespace Service::AM
diff --git a/src/core/hle/service/am/button_poller.cpp b/src/core/hle/service/am/button_poller.cpp
new file mode 100755
index 000000000..aab397085
--- /dev/null
+++ b/src/core/hle/service/am/button_poller.cpp
@@ -0,0 +1,89 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/am/button_poller.h"
6#include "core/hle/service/am/window_system.h"
7#include "hid_core/frontend/emulated_controller.h"
8#include "hid_core/hid_core.h"
9#include "hid_core/hid_types.h"
10
11namespace Service::AM {
12
13namespace {
14
15ButtonPressDuration ClassifyPressDuration(std::chrono::steady_clock::time_point start) {
16 using namespace std::chrono_literals;
17
18 const auto dur = std::chrono::steady_clock::now() - start;
19
20 // TODO: determine actual thresholds
21 // TODO: these are likely different for each button
22 if (dur < 500ms) {
23 return ButtonPressDuration::ShortPressing;
24 } else if (dur < 1000ms) {
25 return ButtonPressDuration::MiddlePressing;
26 } else {
27 return ButtonPressDuration::LongPressing;
28 }
29}
30
31} // namespace
32
33ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system)
34 : m_window_system(window_system) {
35 // TODO: am reads this from the home button state in hid, which is controller-agnostic.
36 Core::HID::ControllerUpdateCallback engine_callback{
37 .on_change =
38 [this](Core::HID::ControllerTriggerType type) {
39 if (type == Core::HID::ControllerTriggerType::Button) {
40 this->OnButtonStateChanged();
41 }
42 },
43 .is_npad_service = true,
44 };
45
46 m_handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
47 m_handheld_key = m_handheld->SetCallback(engine_callback);
48 m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
49 m_player1_key = m_player1->SetCallback(engine_callback);
50}
51
52ButtonPoller::~ButtonPoller() {
53 m_handheld->DeleteCallback(m_handheld_key);
54 m_player1->DeleteCallback(m_player1_key);
55}
56
57void ButtonPoller::OnButtonStateChanged() {
58 const bool home_button =
59 m_handheld->GetHomeButtons().home.Value() || m_player1->GetHomeButtons().home.Value();
60 const bool capture_button = m_handheld->GetCaptureButtons().capture.Value() ||
61 m_player1->GetCaptureButtons().capture.Value();
62
63 // Buttons pressed which were not previously pressed
64 if (home_button && !m_home_button_press_start) {
65 m_home_button_press_start = std::chrono::steady_clock::now();
66 }
67 if (capture_button && !m_capture_button_press_start) {
68 m_capture_button_press_start = std::chrono::steady_clock::now();
69 }
70 // if (power_button && !m_power_button_press_start) {
71 // m_power_button_press_start = std::chrono::steady_clock::now();
72 // }
73
74 // Buttons released which were previously held
75 if (!home_button && m_home_button_press_start) {
76 m_window_system.OnHomeButtonPressed(ClassifyPressDuration(*m_home_button_press_start));
77 m_home_button_press_start = std::nullopt;
78 }
79 if (!capture_button && m_capture_button_press_start) {
80 // TODO
81 m_capture_button_press_start = std::nullopt;
82 }
83 // if (!power_button && m_power_button_press_start) {
84 // // TODO
85 // m_power_button_press_start = std::nullopt;
86 // }
87}
88
89} // namespace Service::AM
diff --git a/src/core/hle/service/am/button_poller.h b/src/core/hle/service/am/button_poller.h
new file mode 100755
index 000000000..b1c39aad3
--- /dev/null
+++ b/src/core/hle/service/am/button_poller.h
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <chrono>
7#include <optional>
8#include "hid_core/frontend/emulated_controller.h"
9
10namespace Core {
11namespace HID {
12class EmulatedController;
13}
14
15class System;
16} // namespace Core
17
18namespace Service::AM {
19
20class WindowSystem;
21
22class ButtonPoller {
23public:
24 explicit ButtonPoller(Core::System& system, WindowSystem& window_system);
25 ~ButtonPoller();
26
27private:
28 void OnButtonStateChanged();
29
30private:
31 WindowSystem& m_window_system;
32
33 Core::HID::EmulatedController* m_handheld{};
34 int m_handheld_key{};
35 Core::HID::EmulatedController* m_player1{};
36 int m_player1_key{};
37
38 std::optional<std::chrono::steady_clock::time_point> m_home_button_press_start{};
39 std::optional<std::chrono::steady_clock::time_point> m_capture_button_press_start{};
40 std::optional<std::chrono::steady_clock::time_point> m_power_button_press_start{};
41};
42
43} // namespace Service::AM
diff --git a/src/core/hle/service/am/event_observer.cpp b/src/core/hle/service/am/event_observer.cpp
new file mode 100755
index 000000000..5d1d303ed
--- /dev/null
+++ b/src/core/hle/service/am/event_observer.cpp
@@ -0,0 +1,162 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/kernel/k_event.h"
6#include "core/hle/service/am/applet.h"
7#include "core/hle/service/am/event_observer.h"
8#include "core/hle/service/am/window_system.h"
9
10namespace Service::AM {
11
12enum class UserDataTag : u32 {
13 WakeupEvent,
14 AppletProcess,
15};
16
17EventObserver::EventObserver(Core::System& system, WindowSystem& window_system)
18 : m_system(system), m_context(system, "am:EventObserver"), m_window_system(window_system),
19 m_wakeup_event(m_context), m_wakeup_holder(m_wakeup_event.GetHandle()) {
20 m_window_system.SetEventObserver(this);
21 m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent));
22 m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait));
23 m_thread = std::thread([&] { this->ThreadFunc(); });
24}
25
26EventObserver::~EventObserver() {
27 // Signal thread and wait for processing to finish.
28 m_stop_source.request_stop();
29 m_wakeup_event.Signal();
30 m_thread.join();
31
32 // Free remaining owned sessions.
33 auto it = m_process_holder_list.begin();
34 while (it != m_process_holder_list.end()) {
35 // Get the holder.
36 auto* const holder = std::addressof(*it);
37
38 // Remove from the list.
39 it = m_process_holder_list.erase(it);
40
41 // Free the holder.
42 delete holder;
43 }
44}
45
46void EventObserver::TrackAppletProcess(Applet& applet) {
47 // Don't observe dummy processes.
48 if (!applet.process->IsInitialized()) {
49 return;
50 }
51
52 // Allocate new holder.
53 auto* holder = new ProcessHolder(applet, *applet.process);
54 holder->SetUserData(static_cast<uintptr_t>(UserDataTag::AppletProcess));
55
56 // Insert into list.
57 {
58 std::scoped_lock lk{m_lock};
59 m_process_holder_list.push_back(*holder);
60 holder->LinkToMultiWait(std::addressof(m_deferred_wait_list));
61 }
62
63 // Signal wakeup.
64 m_wakeup_event.Signal();
65}
66
67void EventObserver::RequestUpdate() {
68 m_wakeup_event.Signal();
69}
70
71void EventObserver::LinkDeferred() {
72 std::scoped_lock lk{m_lock};
73 m_multi_wait.MoveAll(std::addressof(m_deferred_wait_list));
74}
75
76MultiWaitHolder* EventObserver::WaitSignaled() {
77 while (true) {
78 this->LinkDeferred();
79
80 // If we're done, return before we start waiting.
81 if (m_stop_source.stop_requested()) {
82 return nullptr;
83 }
84
85 auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
86 if (selected != std::addressof(m_wakeup_holder)) {
87 // Unlink the process.
88 selected->UnlinkFromMultiWait();
89 }
90
91 return selected;
92 }
93}
94
95void EventObserver::Process(MultiWaitHolder* holder) {
96 switch (static_cast<UserDataTag>(holder->GetUserData())) {
97 case UserDataTag::WakeupEvent:
98 this->OnWakeupEvent(holder);
99 break;
100 case UserDataTag::AppletProcess:
101 this->OnProcessEvent(static_cast<ProcessHolder*>(holder));
102 break;
103 default:
104 UNREACHABLE();
105 }
106}
107
108void EventObserver::OnWakeupEvent(MultiWaitHolder* holder) {
109 m_wakeup_event.Clear();
110
111 // Perform recalculation.
112 m_window_system.Update();
113}
114
115void EventObserver::OnProcessEvent(ProcessHolder* holder) {
116 // Check process state.
117 auto& applet = holder->GetApplet();
118 auto& process = holder->GetProcess();
119
120 {
121 std::scoped_lock lk{m_lock, applet.lock};
122 if (process.IsTerminated()) {
123 // Destroy the holder.
124 this->DestroyAppletProcessHolderLocked(holder);
125 } else {
126 // Reset signaled state.
127 process.ResetSignal();
128
129 // Relink wakeup event.
130 holder->LinkToMultiWait(std::addressof(m_deferred_wait_list));
131 }
132
133 // Set running.
134 applet.is_process_running = process.IsRunning();
135 }
136
137 // Perform recalculation.
138 m_window_system.Update();
139}
140
141void EventObserver::DestroyAppletProcessHolderLocked(ProcessHolder* holder) {
142 // Remove from owned list.
143 m_process_holder_list.erase(m_process_holder_list.iterator_to(*holder));
144
145 // Destroy and free.
146 delete holder;
147}
148
149void EventObserver::ThreadFunc() {
150 Common::SetCurrentThreadName("am:EventObserver");
151
152 while (true) {
153 auto* signaled_holder = this->WaitSignaled();
154 if (!signaled_holder) {
155 break;
156 }
157
158 this->Process(signaled_holder);
159 }
160}
161
162} // namespace Service::AM
diff --git a/src/core/hle/service/am/event_observer.h b/src/core/hle/service/am/event_observer.h
new file mode 100755
index 000000000..3e52e8494
--- /dev/null
+++ b/src/core/hle/service/am/event_observer.h
@@ -0,0 +1,74 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/polyfill_thread.h"
7#include "common/thread.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/os/event.h"
10#include "core/hle/service/os/multi_wait.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::AM {
17
18struct Applet;
19class ProcessHolder;
20class WindowSystem;
21
22class EventObserver {
23public:
24 explicit EventObserver(Core::System& system, WindowSystem& window_system);
25 ~EventObserver();
26
27 void TrackAppletProcess(Applet& applet);
28 void RequestUpdate();
29
30private:
31 void LinkDeferred();
32 MultiWaitHolder* WaitSignaled();
33 void Process(MultiWaitHolder* holder);
34 bool WaitAndProcessImpl();
35 void LoopProcess();
36
37private:
38 void OnWakeupEvent(MultiWaitHolder* holder);
39 void OnProcessEvent(ProcessHolder* holder);
40
41private:
42 void DestroyAppletProcessHolderLocked(ProcessHolder* holder);
43
44private:
45 void ThreadFunc();
46
47private:
48 // System reference and context.
49 Core::System& m_system;
50 KernelHelpers::ServiceContext m_context;
51
52 // Window manager.
53 WindowSystem& m_window_system;
54
55 // Guest event handle to wake up the event loop processor.
56 Event m_wakeup_event;
57 MultiWaitHolder m_wakeup_holder;
58
59 // Mutex to protect remaining members.
60 std::mutex m_lock{};
61
62 // List of owned process holders.
63 Common::IntrusiveListBaseTraits<ProcessHolder>::ListType m_process_holder_list;
64
65 // Multi-wait objects for new tasks.
66 MultiWait m_multi_wait;
67 MultiWait m_deferred_wait_list;
68
69 // Processing thread.
70 std::thread m_thread{};
71 std::stop_source m_stop_source{};
72};
73
74} // namespace Service::AM
diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp
index e662c6cd6..cdd431857 100755
--- a/src/core/hle/service/am/frontend/applets.cpp
+++ b/src/core/hle/service/am/frontend/applets.cpp
@@ -69,7 +69,11 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
69} 69}
70 70
71void FrontendApplet::Exit() { 71void FrontendApplet::Exit() {
72 applet.lock()->caller_applet_broker->SignalCompletion(); 72 auto applet_ = applet.lock();
73
74 std::scoped_lock lk{applet_->lock};
75 applet_->is_completed = true;
76 applet_->state_changed_event.Signal();
73} 77}
74 78
75FrontendAppletSet::FrontendAppletSet() = default; 79FrontendAppletSet::FrontendAppletSet() = default;
diff --git a/src/core/hle/service/am/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp
index 8ed49bac1..ea4bd8f45 100755
--- a/src/core/hle/service/am/hid_registration.cpp
+++ b/src/core/hle/service/am/hid_registration.cpp
@@ -3,24 +3,28 @@
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/service/am/hid_registration.h" 5#include "core/hle/service/am/hid_registration.h"
6#include "core/hle/service/am/process.h"
7#include "core/hle/service/hid/hid_server.h" 6#include "core/hle/service/hid/hid_server.h"
7#include "core/hle/service/os/process.h"
8#include "core/hle/service/sm/sm.h" 8#include "core/hle/service/sm/sm.h"
9#include "hid_core/resource_manager.h" 9#include "hid_core/resource_manager.h"
10 10
11namespace Service::AM { 11namespace Service::AM {
12 12
13HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) { 13HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
14 m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid"); 14 m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid", true);
15 15
16 if (m_process.IsInitialized()) { 16 if (m_process.IsInitialized()) {
17 m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(), 17 m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
18 true); 18 true);
19 m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
20 true);
19 } 21 }
20} 22}
21 23
22HidRegistration::~HidRegistration() { 24HidRegistration::~HidRegistration() {
23 if (m_process.IsInitialized()) { 25 if (m_process.IsInitialized()) {
26 m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
27 false);
24 m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId( 28 m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
25 m_process.GetProcessId()); 29 m_process.GetProcessId());
26 } 30 }
@@ -28,6 +32,8 @@ HidRegistration::~HidRegistration() {
28 32
29void HidRegistration::EnableAppletToGetInput(bool enable) { 33void HidRegistration::EnableAppletToGetInput(bool enable) {
30 if (m_process.IsInitialized()) { 34 if (m_process.IsInitialized()) {
35 m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
36 enable);
31 m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable); 37 m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
32 } 38 }
33} 39}
diff --git a/src/core/hle/service/am/hid_registration.h b/src/core/hle/service/am/hid_registration.h
index 67cd84961..54f42af18 100755
--- a/src/core/hle/service/am/hid_registration.h
+++ b/src/core/hle/service/am/hid_registration.h
@@ -13,9 +13,11 @@ namespace Service::HID {
13class IHidServer; 13class IHidServer;
14} 14}
15 15
16namespace Service::AM { 16namespace Service {
17
18class Process; 17class Process;
18}
19
20namespace Service::AM {
19 21
20class HidRegistration { 22class HidRegistration {
21public: 23public:
diff --git a/src/core/hle/service/am/lifecycle_manager.cpp b/src/core/hle/service/am/lifecycle_manager.cpp
new file mode 100755
index 000000000..0dac27ed0
--- /dev/null
+++ b/src/core/hle/service/am/lifecycle_manager.cpp
@@ -0,0 +1,379 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "core/hle/service/am/lifecycle_manager.h"
6
7namespace Service::AM {
8
9LifecycleManager::LifecycleManager(Core::System& system, KernelHelpers::ServiceContext& context,
10 bool is_application)
11 : m_system_event(context), m_operation_mode_changed_system_event(context),
12 m_is_application(is_application) {}
13
14LifecycleManager::~LifecycleManager() = default;
15
16Event& LifecycleManager::GetSystemEvent() {
17 return m_system_event;
18}
19
20Event& LifecycleManager::GetOperationModeChangedSystemEvent() {
21 return m_operation_mode_changed_system_event;
22}
23
24void LifecycleManager::PushUnorderedMessage(AppletMessage message) {
25 m_unordered_messages.push_back(message);
26 this->SignalSystemEventIfNeeded();
27}
28
29AppletMessage LifecycleManager::PopMessageInOrderOfPriority() {
30 if (m_has_resume) {
31 m_has_resume = false;
32 return AppletMessage::Resume;
33 }
34
35 if (m_has_acknowledged_exit != m_has_requested_exit) {
36 m_has_acknowledged_exit = m_has_requested_exit;
37 return AppletMessage::Exit;
38 }
39
40 if (m_focus_state_changed_notification_enabled) {
41 if (!m_is_application) {
42 if (m_requested_focus_state != m_acknowledged_focus_state) {
43 m_acknowledged_focus_state = m_requested_focus_state;
44 switch (m_requested_focus_state) {
45 case FocusState::InFocus:
46 return AppletMessage::ChangeIntoForeground;
47 case FocusState::NotInFocus:
48 return AppletMessage::ChangeIntoBackground;
49 default:
50 ASSERT(false);
51 }
52 }
53 } else if (m_has_focus_state_changed) {
54 m_has_focus_state_changed = false;
55 return AppletMessage::FocusStateChanged;
56 }
57 }
58
59 if (m_has_requested_request_to_prepare_sleep != m_has_acknowledged_request_to_prepare_sleep) {
60 m_has_acknowledged_request_to_prepare_sleep = true;
61 return AppletMessage::RequestToPrepareSleep;
62 }
63
64 if (m_requested_request_to_display_state != m_acknowledged_request_to_display_state) {
65 m_acknowledged_request_to_display_state = m_requested_request_to_display_state;
66 return AppletMessage::RequestToDisplay;
67 }
68
69 if (m_has_operation_mode_changed) {
70 m_has_operation_mode_changed = false;
71 return AppletMessage::OperationModeChanged;
72 }
73
74 if (m_has_performance_mode_changed) {
75 m_has_performance_mode_changed = false;
76 return AppletMessage::PerformanceModeChanged;
77 }
78
79 if (m_has_sd_card_removed) {
80 m_has_sd_card_removed = false;
81 return AppletMessage::SdCardRemoved;
82 }
83
84 if (m_has_sleep_required_by_high_temperature) {
85 m_has_sleep_required_by_high_temperature = false;
86 return AppletMessage::SleepRequiredByHighTemperature;
87 }
88
89 if (m_has_sleep_required_by_low_battery) {
90 m_has_sleep_required_by_low_battery = false;
91 return AppletMessage::SleepRequiredByLowBattery;
92 }
93
94 if (m_has_auto_power_down) {
95 m_has_auto_power_down = false;
96 return AppletMessage::AutoPowerDown;
97 }
98
99 if (m_has_album_screen_shot_taken) {
100 m_has_album_screen_shot_taken = false;
101 return AppletMessage::AlbumScreenShotTaken;
102 }
103
104 if (m_has_album_recording_saved) {
105 m_has_album_recording_saved = false;
106 return AppletMessage::AlbumRecordingSaved;
107 }
108
109 if (!m_unordered_messages.empty()) {
110 const auto message = m_unordered_messages.front();
111 m_unordered_messages.pop_front();
112 return message;
113 }
114
115 return AppletMessage::None;
116}
117
118bool LifecycleManager::ShouldSignalSystemEvent() {
119 if (m_focus_state_changed_notification_enabled) {
120 if (!m_is_application) {
121 if (m_requested_focus_state != m_acknowledged_focus_state) {
122 return true;
123 }
124 } else if (m_has_focus_state_changed) {
125 return true;
126 }
127 }
128
129 return !m_unordered_messages.empty() || m_has_resume ||
130 (m_has_requested_exit != m_has_acknowledged_exit) ||
131 (m_has_requested_request_to_prepare_sleep !=
132 m_has_acknowledged_request_to_prepare_sleep) ||
133 m_has_operation_mode_changed || m_has_performance_mode_changed ||
134 m_has_sd_card_removed || m_has_sleep_required_by_high_temperature ||
135 m_has_sleep_required_by_low_battery || m_has_auto_power_down ||
136 (m_requested_request_to_display_state != m_acknowledged_request_to_display_state) ||
137 m_has_album_screen_shot_taken || m_has_album_recording_saved;
138}
139
140void LifecycleManager::OnOperationAndPerformanceModeChanged() {
141 if (m_operation_mode_changed_notification_enabled) {
142 m_has_operation_mode_changed = true;
143 }
144 if (m_performance_mode_changed_notification_enabled) {
145 m_has_performance_mode_changed = true;
146 }
147 m_operation_mode_changed_system_event.Signal();
148 this->SignalSystemEventIfNeeded();
149}
150
151void LifecycleManager::SignalSystemEventIfNeeded() {
152 // Check our cached value for the system event.
153 const bool applet_message_available = m_applet_message_available;
154
155 // If it's not current, we need to do an update, either clearing or signaling.
156 if (applet_message_available != this->ShouldSignalSystemEvent()) {
157 if (!applet_message_available) {
158 m_system_event.Signal();
159 m_applet_message_available = true;
160 } else {
161 m_system_event.Clear();
162 m_applet_message_available = false;
163 }
164 }
165}
166
167bool LifecycleManager::PopMessage(AppletMessage* out_message) {
168 const auto message = this->PopMessageInOrderOfPriority();
169 this->SignalSystemEventIfNeeded();
170
171 *out_message = message;
172 return message != AppletMessage::None;
173}
174
175void LifecycleManager::SetFocusHandlingMode(bool suspend) {
176 switch (m_focus_handling_mode) {
177 case FocusHandlingMode::AlwaysSuspend:
178 case FocusHandlingMode::SuspendHomeSleep:
179 if (!suspend) {
180 // Disallow suspension.
181 m_focus_handling_mode = FocusHandlingMode::NoSuspend;
182 }
183 break;
184 case FocusHandlingMode::NoSuspend:
185 if (suspend) {
186 // Allow suspension temporally.
187 m_focus_handling_mode = FocusHandlingMode::SuspendHomeSleep;
188 }
189 break;
190 }
191}
192
193void LifecycleManager::SetOutOfFocusSuspendingEnabled(bool enabled) {
194 switch (m_focus_handling_mode) {
195 case FocusHandlingMode::AlwaysSuspend:
196 if (!enabled) {
197 // Allow suspension temporally.
198 m_focus_handling_mode = FocusHandlingMode::SuspendHomeSleep;
199 }
200 break;
201 case FocusHandlingMode::SuspendHomeSleep:
202 case FocusHandlingMode::NoSuspend:
203 if (enabled) {
204 // Allow suspension.
205 m_focus_handling_mode = FocusHandlingMode::AlwaysSuspend;
206 }
207 break;
208 }
209}
210
211void LifecycleManager::RemoveForceResumeIfPossible() {
212 // If resume is not forced, we have nothing to do.
213 if (m_suspend_mode != SuspendMode::ForceResume) {
214 return;
215 }
216
217 // Check activity state.
218 // If we are already resumed, we can remove the forced state.
219 switch (m_activity_state) {
220 case ActivityState::ForegroundVisible:
221 case ActivityState::ForegroundObscured:
222 m_suspend_mode = SuspendMode::NoOverride;
223 return;
224
225 default:
226 break;
227 }
228
229 // Check focus handling mode.
230 switch (m_focus_handling_mode) {
231 case FocusHandlingMode::AlwaysSuspend:
232 case FocusHandlingMode::SuspendHomeSleep:
233 // If the applet allows suspension, we can remove the forced state.
234 m_suspend_mode = SuspendMode::NoOverride;
235 break;
236
237 case FocusHandlingMode::NoSuspend:
238 // If the applet is not an application, we can remove the forced state.
239 // Only applications can be forced to resume.
240 if (!m_is_application) {
241 m_suspend_mode = SuspendMode::NoOverride;
242 }
243 }
244}
245
246bool LifecycleManager::IsRunnable() const {
247 // If suspend is forced, return that.
248 if (m_forced_suspend) {
249 return false;
250 }
251
252 // Check suspend mode override.
253 switch (m_suspend_mode) {
254 case SuspendMode::NoOverride:
255 // Continue processing.
256 break;
257
258 case SuspendMode::ForceResume:
259 // The applet is runnable during forced resumption when its exit is requested.
260 return m_has_requested_exit;
261
262 case SuspendMode::ForceSuspend:
263 // The applet is never runnable during forced suspension.
264 return false;
265 }
266
267 // Always run if exit is requested.
268 if (m_has_requested_exit) {
269 return true;
270 }
271
272 if (m_activity_state == ActivityState::ForegroundVisible) {
273 // The applet is runnable now.
274 return true;
275 }
276
277 if (m_activity_state == ActivityState::ForegroundObscured) {
278 switch (m_focus_handling_mode) {
279 case FocusHandlingMode::AlwaysSuspend:
280 // The applet is not runnable while running the applet.
281 return false;
282
283 case FocusHandlingMode::SuspendHomeSleep:
284 // The applet is runnable while running the applet.
285 return true;
286
287 case FocusHandlingMode::NoSuspend:
288 // The applet is always runnable.
289 return true;
290 }
291 }
292
293 // The activity is a suspended one.
294 // The applet should be suspended unless it has disabled suspension.
295 return m_focus_handling_mode == FocusHandlingMode::NoSuspend;
296}
297
298FocusState LifecycleManager::GetFocusStateWhileForegroundObscured() const {
299 switch (m_focus_handling_mode) {
300 case FocusHandlingMode::AlwaysSuspend:
301 // The applet never learns it has lost focus.
302 return FocusState::InFocus;
303
304 case FocusHandlingMode::SuspendHomeSleep:
305 // The applet learns it has lost focus when launching a child applet.
306 return FocusState::NotInFocus;
307
308 case FocusHandlingMode::NoSuspend:
309 // The applet always learns it has lost focus.
310 return FocusState::NotInFocus;
311
312 default:
313 UNREACHABLE();
314 }
315}
316
317FocusState LifecycleManager::GetFocusStateWhileBackground(bool is_obscured) const {
318 switch (m_focus_handling_mode) {
319 case FocusHandlingMode::AlwaysSuspend:
320 // The applet never learns it has lost focus.
321 return FocusState::InFocus;
322
323 case FocusHandlingMode::SuspendHomeSleep:
324 // The applet learns it has lost focus when launching a child applet.
325 return is_obscured ? FocusState::NotInFocus : FocusState::InFocus;
326
327 case FocusHandlingMode::NoSuspend:
328 // The applet always learns it has lost focus.
329 return m_is_application ? FocusState::Background : FocusState::NotInFocus;
330
331 default:
332 UNREACHABLE();
333 }
334}
335
336bool LifecycleManager::UpdateRequestedFocusState() {
337 FocusState new_state{};
338
339 if (m_suspend_mode == SuspendMode::NoOverride) {
340 // With no forced suspend or resume, we take the focus state designated
341 // by the combination of the activity flag and the focus handling mode.
342 switch (m_activity_state) {
343 case ActivityState::ForegroundVisible:
344 new_state = FocusState::InFocus;
345 break;
346
347 case ActivityState::ForegroundObscured:
348 new_state = this->GetFocusStateWhileForegroundObscured();
349 break;
350
351 case ActivityState::BackgroundVisible:
352 new_state = this->GetFocusStateWhileBackground(false);
353 break;
354
355 case ActivityState::BackgroundObscured:
356 new_state = this->GetFocusStateWhileBackground(true);
357 break;
358
359 default:
360 UNREACHABLE();
361 }
362 } else {
363 // With forced suspend or resume, the applet is guaranteed to be background.
364 new_state = this->GetFocusStateWhileBackground(false);
365 }
366
367 if (new_state != m_requested_focus_state) {
368 // Mark the focus state as ready for update.
369 m_requested_focus_state = new_state;
370
371 // We changed the focus state.
372 return true;
373 }
374
375 // We didn't change the focus state.
376 return false;
377}
378
379} // namespace Service::AM
diff --git a/src/core/hle/service/am/lifecycle_manager.h b/src/core/hle/service/am/lifecycle_manager.h
new file mode 100755
index 000000000..7c70434a1
--- /dev/null
+++ b/src/core/hle/service/am/lifecycle_manager.h
@@ -0,0 +1,183 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <list>
7
8#include "core/hle/service/am/am_types.h"
9#include "core/hle/service/os/event.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::AM {
16
17enum class ActivityState : u32 {
18 ForegroundVisible = 0,
19 ForegroundObscured = 1,
20 BackgroundVisible = 2,
21 BackgroundObscured = 3,
22};
23
24enum class FocusHandlingMode : u32 {
25 AlwaysSuspend = 0,
26 SuspendHomeSleep = 1,
27 NoSuspend = 2,
28};
29
30enum class SuspendMode : u32 {
31 NoOverride = 0,
32 ForceResume = 1,
33 ForceSuspend = 2,
34};
35
36class LifecycleManager {
37public:
38 explicit LifecycleManager(Core::System& system, KernelHelpers::ServiceContext& context,
39 bool is_application);
40 ~LifecycleManager();
41
42public:
43 Event& GetSystemEvent();
44 Event& GetOperationModeChangedSystemEvent();
45
46public:
47 bool IsApplication() {
48 return m_is_application;
49 }
50
51 bool GetForcedSuspend() {
52 return m_forced_suspend;
53 }
54
55 bool GetExitRequested() {
56 return m_has_requested_exit;
57 }
58
59 ActivityState GetActivityState() {
60 return m_activity_state;
61 }
62
63 FocusState GetAndClearFocusState() {
64 m_acknowledged_focus_state = m_requested_focus_state;
65 return m_acknowledged_focus_state;
66 }
67
68 void SetFocusState(FocusState state) {
69 if (m_requested_focus_state != state) {
70 m_has_focus_state_changed = true;
71 }
72 m_requested_focus_state = state;
73 this->SignalSystemEventIfNeeded();
74 }
75
76 void RequestExit() {
77 m_has_requested_exit = true;
78 this->SignalSystemEventIfNeeded();
79 }
80
81 void RequestResumeNotification() {
82 // NOTE: this appears to be a bug in am.
83 // If an applet makes a concurrent request to receive resume notifications
84 // while it is being suspended, the first resume notification will be lost.
85 // This is not the case with other notification types.
86 if (m_resume_notification_enabled) {
87 m_has_resume = true;
88 }
89 }
90
91 void OnOperationAndPerformanceModeChanged();
92
93public:
94 void SetFocusStateChangedNotificationEnabled(bool enabled) {
95 m_focus_state_changed_notification_enabled = enabled;
96 this->SignalSystemEventIfNeeded();
97 }
98
99 void SetOperationModeChangedNotificationEnabled(bool enabled) {
100 m_operation_mode_changed_notification_enabled = enabled;
101 this->SignalSystemEventIfNeeded();
102 }
103
104 void SetPerformanceModeChangedNotificationEnabled(bool enabled) {
105 m_performance_mode_changed_notification_enabled = enabled;
106 this->SignalSystemEventIfNeeded();
107 }
108
109 void SetResumeNotificationEnabled(bool enabled) {
110 m_resume_notification_enabled = enabled;
111 }
112
113 void SetActivityState(ActivityState state) {
114 m_activity_state = state;
115 }
116
117 void SetSuspendMode(SuspendMode mode) {
118 m_suspend_mode = mode;
119 }
120
121 void SetForcedSuspend(bool enabled) {
122 m_forced_suspend = enabled;
123 }
124
125public:
126 void SetFocusHandlingMode(bool suspend);
127 void SetOutOfFocusSuspendingEnabled(bool enabled);
128 void RemoveForceResumeIfPossible();
129 bool IsRunnable() const;
130 bool UpdateRequestedFocusState();
131 void SignalSystemEventIfNeeded();
132
133public:
134 void PushUnorderedMessage(AppletMessage message);
135 bool PopMessage(AppletMessage* out_message);
136
137private:
138 FocusState GetFocusStateWhileForegroundObscured() const;
139 FocusState GetFocusStateWhileBackground(bool is_obscured) const;
140
141private:
142 AppletMessage PopMessageInOrderOfPriority();
143 bool ShouldSignalSystemEvent();
144
145private:
146 Event m_system_event;
147 Event m_operation_mode_changed_system_event;
148
149 std::list<AppletMessage> m_unordered_messages{};
150
151 bool m_is_application{};
152 bool m_focus_state_changed_notification_enabled{true};
153 bool m_operation_mode_changed_notification_enabled{true};
154 bool m_performance_mode_changed_notification_enabled{true};
155 bool m_resume_notification_enabled{};
156
157 bool m_requested_request_to_display_state{};
158 bool m_acknowledged_request_to_display_state{};
159 bool m_has_resume{};
160 bool m_has_focus_state_changed{true};
161 bool m_has_album_recording_saved{};
162 bool m_has_album_screen_shot_taken{};
163 bool m_has_auto_power_down{};
164 bool m_has_sleep_required_by_low_battery{};
165 bool m_has_sleep_required_by_high_temperature{};
166 bool m_has_sd_card_removed{};
167 bool m_has_performance_mode_changed{};
168 bool m_has_operation_mode_changed{};
169 bool m_has_requested_request_to_prepare_sleep{};
170 bool m_has_acknowledged_request_to_prepare_sleep{};
171 bool m_has_requested_exit{};
172 bool m_has_acknowledged_exit{};
173 bool m_applet_message_available{};
174
175 bool m_forced_suspend{};
176 FocusHandlingMode m_focus_handling_mode{FocusHandlingMode::SuspendHomeSleep};
177 ActivityState m_activity_state{ActivityState::ForegroundVisible};
178 SuspendMode m_suspend_mode{SuspendMode::NoOverride};
179 FocusState m_requested_focus_state{};
180 FocusState m_acknowledged_focus_state{};
181};
182
183} // namespace Service::AM
diff --git a/src/core/hle/service/am/process_creation.cpp b/src/core/hle/service/am/process_creation.cpp
new file mode 100755
index 000000000..237151d06
--- /dev/null
+++ b/src/core/hle/service/am/process_creation.cpp
@@ -0,0 +1,130 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/file_sys/content_archive.h"
6#include "core/file_sys/nca_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/registered_cache.h"
9#include "core/file_sys/romfs_factory.h"
10#include "core/hle/service/am/process_creation.h"
11#include "core/hle/service/glue/glue_manager.h"
12#include "core/hle/service/os/process.h"
13#include "core/loader/loader.h"
14
15namespace Service::AM {
16
17namespace {
18
19FileSys::StorageId GetStorageIdForFrontendSlot(
20 std::optional<FileSys::ContentProviderUnionSlot> slot) {
21 if (!slot.has_value()) {
22 return FileSys::StorageId::None;
23 }
24
25 switch (*slot) {
26 case FileSys::ContentProviderUnionSlot::UserNAND:
27 return FileSys::StorageId::NandUser;
28 case FileSys::ContentProviderUnionSlot::SysNAND:
29 return FileSys::StorageId::NandSystem;
30 case FileSys::ContentProviderUnionSlot::SDMC:
31 return FileSys::StorageId::SdCard;
32 case FileSys::ContentProviderUnionSlot::FrontendManual:
33 return FileSys::StorageId::Host;
34 default:
35 return FileSys::StorageId::None;
36 }
37}
38
39std::unique_ptr<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader,
40 Loader::ResultStatus& out_load_result,
41 Core::System& system, FileSys::VirtualFile file,
42 u64 program_id, u64 program_index) {
43 // Get the appropriate loader to parse this NCA.
44 out_loader = Loader::GetLoader(system, file, program_id, program_index);
45
46 // Ensure we have a loader which can parse the NCA.
47 if (!out_loader) {
48 return nullptr;
49 }
50
51 // Try to load the process.
52 auto process = std::make_unique<Process>(system);
53 if (process->Initialize(*out_loader, out_load_result)) {
54 return process;
55 }
56
57 return nullptr;
58}
59
60} // Anonymous namespace
61
62std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
63 u8 minimum_key_generation, u8 maximum_key_generation) {
64 // Attempt to load program NCA.
65 FileSys::VirtualFile nca_raw{};
66
67 // Get the program NCA from storage.
68 auto& storage = system.GetContentProviderUnion();
69 nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
70
71 // Ensure we retrieved a program NCA.
72 if (!nca_raw) {
73 return nullptr;
74 }
75
76 // Ensure we have a suitable version.
77 if (minimum_key_generation > 0) {
78 FileSys::NCA nca(nca_raw);
79 if (nca.GetStatus() == Loader::ResultStatus::Success &&
80 (nca.GetKeyGeneration() < minimum_key_generation ||
81 nca.GetKeyGeneration() > maximum_key_generation)) {
82 LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
83 nca.GetKeyGeneration());
84 return nullptr;
85 }
86 }
87
88 std::unique_ptr<Loader::AppLoader> loader;
89 Loader::ResultStatus status;
90 return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
91}
92
93std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
94 std::unique_ptr<Loader::AppLoader>& out_loader,
95 Loader::ResultStatus& out_load_result,
96 Core::System& system, FileSys::VirtualFile file,
97 u64 program_id, u64 program_index) {
98 auto process =
99 CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
100 if (!process) {
101 return nullptr;
102 }
103
104 FileSys::NACP nacp;
105 if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
106 out_control = nacp.GetRawBytes();
107 } else {
108 out_control.resize(sizeof(FileSys::RawNACP));
109 }
110
111 auto& storage = system.GetContentProviderUnion();
112 Service::Glue::ApplicationLaunchProperty launch{};
113 launch.title_id = process->GetProgramId();
114
115 FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
116 launch.version = pm.GetGameVersion().value_or(0);
117
118 // TODO(DarkLordZach): When FSController/Game Card Support is added, if
119 // current_process_game_card use correct StorageId
120 launch.base_game_storage_id = GetStorageIdForFrontendSlot(
121 storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
122 launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(
123 FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
124
125 system.GetARPManager().Register(launch.title_id, launch, out_control);
126
127 return process;
128}
129
130} // namespace Service::AM
diff --git a/src/core/hle/service/am/process_creation.h b/src/core/hle/service/am/process_creation.h
new file mode 100755
index 000000000..8cfb9e0c9
--- /dev/null
+++ b/src/core/hle/service/am/process_creation.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <vector>
8
9#include "common/common_types.h"
10#include "core/file_sys/vfs/vfs_types.h"
11
12namespace Core {
13class System;
14}
15
16namespace Loader {
17class AppLoader;
18enum class ResultStatus : u16;
19} // namespace Loader
20
21namespace Service {
22class Process;
23}
24
25namespace Service::AM {
26
27std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
28 u8 minimum_key_generation, u8 maximum_key_generation);
29std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
30 std::unique_ptr<Loader::AppLoader>& out_loader,
31 Loader::ResultStatus& out_load_result,
32 Core::System& system, FileSys::VirtualFile file,
33 u64 program_id, u64 program_index);
34
35} // namespace Service::AM
diff --git a/src/core/hle/service/am/process_holder.cpp b/src/core/hle/service/am/process_holder.cpp
new file mode 100755
index 000000000..21ef5bf83
--- /dev/null
+++ b/src/core/hle/service/am/process_holder.cpp
@@ -0,0 +1,15 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_process.h"
5#include "core/hle/service/am/process_holder.h"
6#include "core/hle/service/os/process.h"
7
8namespace Service::AM {
9
10ProcessHolder::ProcessHolder(Applet& applet, Process& process)
11 : MultiWaitHolder(process.GetHandle()), m_applet(applet), m_process(process) {}
12
13ProcessHolder::~ProcessHolder() = default;
14
15} // namespace Service::AM
diff --git a/src/core/hle/service/am/process_holder.h b/src/core/hle/service/am/process_holder.h
new file mode 100755
index 000000000..3a9b81dfb
--- /dev/null
+++ b/src/core/hle/service/am/process_holder.h
@@ -0,0 +1,34 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/os/multi_wait_holder.h"
7
8namespace Service {
9class Process;
10}
11
12namespace Service::AM {
13
14struct Applet;
15
16class ProcessHolder : public MultiWaitHolder, public Common::IntrusiveListBaseNode<ProcessHolder> {
17public:
18 explicit ProcessHolder(Applet& applet, Process& process);
19 ~ProcessHolder();
20
21 Applet& GetApplet() const {
22 return m_applet;
23 }
24
25 Process& GetProcess() const {
26 return m_process;
27 }
28
29private:
30 Applet& m_applet;
31 Process& m_process;
32};
33
34} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
index 21747783a..bc9c86c55 100755
--- a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
@@ -6,12 +6,14 @@
6#include "core/hle/service/am/service/all_system_applet_proxies_service.h" 6#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
7#include "core/hle/service/am/service/library_applet_proxy.h" 7#include "core/hle/service/am/service/library_applet_proxy.h"
8#include "core/hle/service/am/service/system_applet_proxy.h" 8#include "core/hle/service/am/service/system_applet_proxy.h"
9#include "core/hle/service/am/window_system.h"
9#include "core/hle/service/cmif_serialization.h" 10#include "core/hle/service/cmif_serialization.h"
10 11
11namespace Service::AM { 12namespace Service::AM {
12 13
13IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_) 14IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
14 : ServiceFramework{system_, "appletAE"} { 15 WindowSystem& window_system)
16 : ServiceFramework{system_, "appletAE"}, m_window_system{window_system} {
15 // clang-format off 17 // clang-format off
16 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
17 {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"}, 19 {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
@@ -36,8 +38,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
36 LOG_DEBUG(Service_AM, "called"); 38 LOG_DEBUG(Service_AM, "called");
37 39
38 if (const auto applet = this->GetAppletFromProcessId(pid); applet) { 40 if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
39 *out_system_applet_proxy = 41 *out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
40 std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get()); 42 system, applet, process_handle.Get(), m_window_system);
41 R_SUCCEED(); 43 R_SUCCEED();
42 } else { 44 } else {
43 UNIMPLEMENTED(); 45 UNIMPLEMENTED();
@@ -52,8 +54,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
52 LOG_DEBUG(Service_AM, "called"); 54 LOG_DEBUG(Service_AM, "called");
53 55
54 if (const auto applet = this->GetAppletFromProcessId(pid); applet) { 56 if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
55 *out_library_applet_proxy = 57 *out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
56 std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get()); 58 system, applet, process_handle.Get(), m_window_system);
57 R_SUCCEED(); 59 R_SUCCEED();
58 } else { 60 } else {
59 UNIMPLEMENTED(); 61 UNIMPLEMENTED();
@@ -73,7 +75,7 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld(
73 75
74std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId( 76std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
75 ProcessId process_id) { 77 ProcessId process_id) {
76 return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid); 78 return m_window_system.GetByAppletResourceUserId(process_id.pid);
77} 79}
78 80
79} // namespace Service::AM 81} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
index 0e2dcb86d..e3e79dc4f 100755
--- a/src/core/hle/service/am/service/all_system_applet_proxies_service.h
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
@@ -14,11 +14,12 @@ struct Applet;
14struct AppletAttribute; 14struct AppletAttribute;
15class ILibraryAppletProxy; 15class ILibraryAppletProxy;
16class ISystemAppletProxy; 16class ISystemAppletProxy;
17class WindowSystem;
17 18
18class IAllSystemAppletProxiesService final 19class IAllSystemAppletProxiesService final
19 : public ServiceFramework<IAllSystemAppletProxiesService> { 20 : public ServiceFramework<IAllSystemAppletProxiesService> {
20public: 21public:
21 explicit IAllSystemAppletProxiesService(Core::System& system_); 22 explicit IAllSystemAppletProxiesService(Core::System& system_, WindowSystem& window_system);
22 ~IAllSystemAppletProxiesService() override; 23 ~IAllSystemAppletProxiesService() override;
23 24
24private: 25private:
@@ -35,6 +36,8 @@ private:
35 36
36private: 37private:
37 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); 38 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
39
40 WindowSystem& m_window_system;
38}; 41};
39 42
40} // namespace AM 43} // namespace AM
diff --git a/src/core/hle/service/am/service/applet_common_functions.cpp b/src/core/hle/service/am/service/applet_common_functions.cpp
index 0f29ab285..a051000af 100755
--- a/src/core/hle/service/am/service/applet_common_functions.cpp
+++ b/src/core/hle/service/am/service/applet_common_functions.cpp
@@ -19,7 +19,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
19 {21, nullptr, "TryPopFromAppletBoundChannel"}, 19 {21, nullptr, "TryPopFromAppletBoundChannel"},
20 {40, nullptr, "GetDisplayLogicalResolution"}, 20 {40, nullptr, "GetDisplayLogicalResolution"},
21 {42, nullptr, "SetDisplayMagnification"}, 21 {42, nullptr, "SetDisplayMagnification"},
22 {50, nullptr, "SetHomeButtonDoubleClickEnabled"}, 22 {50, D<&IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled>, "SetHomeButtonDoubleClickEnabled"},
23 {51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"}, 23 {51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
24 {52, nullptr, "IsHomeButtonShortPressedBlocked"}, 24 {52, nullptr, "IsHomeButtonShortPressedBlocked"},
25 {60, nullptr, "IsVrModeCurtainRequired"}, 25 {60, nullptr, "IsVrModeCurtainRequired"},
@@ -40,6 +40,13 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
40 40
41IAppletCommonFunctions::~IAppletCommonFunctions() = default; 41IAppletCommonFunctions::~IAppletCommonFunctions() = default;
42 42
43Result IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled(
44 bool home_button_double_click_enabled) {
45 LOG_WARNING(Service_AM, "(STUBBED) called, home_button_double_click_enabled={}",
46 home_button_double_click_enabled);
47 R_SUCCEED();
48}
49
43Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled( 50Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
44 Out<bool> out_home_button_double_click_enabled) { 51 Out<bool> out_home_button_double_click_enabled) {
45 LOG_WARNING(Service_AM, "(STUBBED) called"); 52 LOG_WARNING(Service_AM, "(STUBBED) called");
diff --git a/src/core/hle/service/am/service/applet_common_functions.h b/src/core/hle/service/am/service/applet_common_functions.h
index 4424fc83d..376f85acf 100755
--- a/src/core/hle/service/am/service/applet_common_functions.h
+++ b/src/core/hle/service/am/service/applet_common_functions.h
@@ -16,6 +16,7 @@ public:
16 ~IAppletCommonFunctions() override; 16 ~IAppletCommonFunctions() override;
17 17
18private: 18private:
19 Result SetHomeButtonDoubleClickEnabled(bool home_button_double_click_enabled);
19 Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled); 20 Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
20 Result SetCpuBoostRequestPriority(s32 priority); 21 Result SetCpuBoostRequestPriority(s32 priority);
21 Result GetCurrentApplicationId(Out<u64> out_application_id); 22 Result GetCurrentApplicationId(Out<u64> out_application_id);
diff --git a/src/core/hle/service/am/service/application_accessor.cpp b/src/core/hle/service/am/service/application_accessor.cpp
index 6e7d110e8..986abc716 100755
--- a/src/core/hle/service/am/service/application_accessor.cpp
+++ b/src/core/hle/service/am/service/application_accessor.cpp
@@ -9,12 +9,16 @@
9#include "core/hle/service/am/service/application_accessor.h" 9#include "core/hle/service/am/service/application_accessor.h"
10#include "core/hle/service/am/service/library_applet_accessor.h" 10#include "core/hle/service/am/service/library_applet_accessor.h"
11#include "core/hle/service/am/service/storage.h" 11#include "core/hle/service/am/service/storage.h"
12#include "core/hle/service/am/window_system.h"
12#include "core/hle/service/cmif_serialization.h" 13#include "core/hle/service/cmif_serialization.h"
14#include "core/hle/service/glue/glue_manager.h"
13 15
14namespace Service::AM { 16namespace Service::AM {
15 17
16IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet) 18IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
17 : ServiceFramework{system_, "IApplicationAccessor"}, m_applet(std::move(applet)) { 19 WindowSystem& window_system)
20 : ServiceFramework{system_, "IApplicationAccessor"}, m_window_system(window_system),
21 m_applet(std::move(applet)) {
18 // clang-format off 22 // clang-format off
19 static const FunctionInfo functions[] = { 23 static const FunctionInfo functions[] = {
20 {0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"}, 24 {0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
@@ -59,7 +63,15 @@ Result IApplicationAccessor::Start() {
59 63
60Result IApplicationAccessor::RequestExit() { 64Result IApplicationAccessor::RequestExit() {
61 LOG_INFO(Service_AM, "called"); 65 LOG_INFO(Service_AM, "called");
62 m_applet->message_queue.RequestExit(); 66
67 std::scoped_lock lk{m_applet->lock};
68 if (m_applet->exit_locked) {
69 m_applet->lifecycle_manager.RequestExit();
70 m_applet->UpdateSuspensionStateLocked(true);
71 } else {
72 m_applet->process->Terminate();
73 }
74
63 R_SUCCEED(); 75 R_SUCCEED();
64} 76}
65 77
@@ -71,13 +83,14 @@ Result IApplicationAccessor::Terminate() {
71 83
72Result IApplicationAccessor::GetResult() { 84Result IApplicationAccessor::GetResult() {
73 LOG_INFO(Service_AM, "called"); 85 LOG_INFO(Service_AM, "called");
74 R_SUCCEED(); 86 std::scoped_lock lk{m_applet->lock};
87 R_RETURN(m_applet->terminate_result);
75} 88}
76 89
77Result IApplicationAccessor::GetAppletStateChangedEvent( 90Result IApplicationAccessor::GetAppletStateChangedEvent(
78 OutCopyHandle<Kernel::KReadableEvent> out_event) { 91 OutCopyHandle<Kernel::KReadableEvent> out_event) {
79 LOG_INFO(Service_AM, "called"); 92 LOG_INFO(Service_AM, "called");
80 *out_event = m_applet->caller_applet_broker->GetStateChangedEvent().GetHandle(); 93 *out_event = m_applet->state_changed_event.GetHandle();
81 R_SUCCEED(); 94 R_SUCCEED();
82} 95}
83 96
@@ -96,8 +109,15 @@ Result IApplicationAccessor::PushLaunchParameter(LaunchParameterKind kind,
96 109
97Result IApplicationAccessor::GetApplicationControlProperty( 110Result IApplicationAccessor::GetApplicationControlProperty(
98 OutBuffer<BufferAttr_HipcMapAlias> out_control_property) { 111 OutBuffer<BufferAttr_HipcMapAlias> out_control_property) {
99 LOG_WARNING(Service_AM, "(STUBBED) called"); 112 LOG_INFO(Service_AM, "called");
100 R_THROW(ResultUnknown); 113
114 std::vector<u8> nacp;
115 R_TRY(system.GetARPManager().GetControlProperty(&nacp, m_applet->program_id));
116
117 std::memcpy(out_control_property.data(), nacp.data(),
118 std::min(out_control_property.size(), nacp.size()));
119
120 R_SUCCEED();
101} 121}
102 122
103Result IApplicationAccessor::SetUsers(bool enable, 123Result IApplicationAccessor::SetUsers(bool enable,
@@ -114,8 +134,9 @@ Result IApplicationAccessor::GetCurrentLibraryApplet(
114} 134}
115 135
116Result IApplicationAccessor::RequestForApplicationToGetForeground() { 136Result IApplicationAccessor::RequestForApplicationToGetForeground() {
117 LOG_WARNING(Service_AM, "(STUBBED) called"); 137 LOG_INFO(Service_AM, "called");
118 R_THROW(ResultUnknown); 138 m_window_system.RequestApplicationToGetForeground();
139 R_SUCCEED();
119} 140}
120 141
121Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) { 142Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) {
diff --git a/src/core/hle/service/am/service/application_accessor.h b/src/core/hle/service/am/service/application_accessor.h
index 39a9b2153..b9797bcc0 100755
--- a/src/core/hle/service/am/service/application_accessor.h
+++ b/src/core/hle/service/am/service/application_accessor.h
@@ -13,10 +13,12 @@ namespace Service::AM {
13struct Applet; 13struct Applet;
14class ILibraryAppletAccessor; 14class ILibraryAppletAccessor;
15class IStorage; 15class IStorage;
16class WindowSystem;
16 17
17class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> { 18class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> {
18public: 19public:
19 explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet); 20 explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
21 WindowSystem& window_system);
20 ~IApplicationAccessor() override; 22 ~IApplicationAccessor() override;
21 23
22private: 24private:
@@ -34,6 +36,7 @@ private:
34 Result GetNsRightsEnvironmentHandle(Out<u64> out_handle); 36 Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
35 Result ReportApplicationExitTimeout(); 37 Result ReportApplicationExitTimeout();
36 38
39 WindowSystem& m_window_system;
37 const std::shared_ptr<Applet> m_applet; 40 const std::shared_ptr<Applet> m_applet;
38}; 41};
39 42
diff --git a/src/core/hle/service/am/service/application_creator.cpp b/src/core/hle/service/am/service/application_creator.cpp
index 568bb0122..8994f1914 100755
--- a/src/core/hle/service/am/service/application_creator.cpp
+++ b/src/core/hle/service/am/service/application_creator.cpp
@@ -1,17 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/nca_metadata.h"
5#include "core/file_sys/registered_cache.h"
4#include "core/hle/service/am/am_types.h" 6#include "core/hle/service/am/am_types.h"
5#include "core/hle/service/am/applet.h" 7#include "core/hle/service/am/applet.h"
6#include "core/hle/service/am/applet_manager.h" 8#include "core/hle/service/am/applet_manager.h"
9#include "core/hle/service/am/process_creation.h"
7#include "core/hle/service/am/service/application_accessor.h" 10#include "core/hle/service/am/service/application_accessor.h"
8#include "core/hle/service/am/service/application_creator.h" 11#include "core/hle/service/am/service/application_creator.h"
12#include "core/hle/service/am/window_system.h"
9#include "core/hle/service/cmif_serialization.h" 13#include "core/hle/service/cmif_serialization.h"
14#include "core/loader/loader.h"
10 15
11namespace Service::AM { 16namespace Service::AM {
12 17
13IApplicationCreator::IApplicationCreator(Core::System& system_) 18namespace {
14 : ServiceFramework{system_, "IApplicationCreator"} { 19
20Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_application_accessor,
21 Core::System& system, WindowSystem& window_system, u64 program_id) {
22 FileSys::VirtualFile nca_raw{};
23
24 // Get the program NCA from storage.
25 auto& storage = system.GetContentProviderUnion();
26 nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
27
28 // Ensure we retrieved a program NCA.
29 R_UNLESS(nca_raw != nullptr, ResultUnknown);
30
31 std::vector<u8> control;
32 std::unique_ptr<Loader::AppLoader> loader;
33 Loader::ResultStatus result;
34 auto process =
35 CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
36 R_UNLESS(process != nullptr, ResultUnknown);
37
38 const auto applet = std::make_shared<Applet>(system, std::move(process), true);
39 applet->program_id = program_id;
40 applet->applet_id = AppletId::Application;
41 applet->type = AppletType::Application;
42 applet->library_applet_mode = LibraryAppletMode::AllForeground;
43
44 window_system.TrackApplet(applet, true);
45
46 *out_application_accessor =
47 std::make_shared<IApplicationAccessor>(system, applet, window_system);
48 R_SUCCEED();
49}
50
51} // namespace
52
53IApplicationCreator::IApplicationCreator(Core::System& system_, WindowSystem& window_system)
54 : ServiceFramework{system_, "IApplicationCreator"}, m_window_system{window_system} {
15 // clang-format off 55 // clang-format off
16 static const FunctionInfo functions[] = { 56 static const FunctionInfo functions[] = {
17 {0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"}, 57 {0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
@@ -28,8 +68,9 @@ IApplicationCreator::~IApplicationCreator() = default;
28 68
29Result IApplicationCreator::CreateApplication( 69Result IApplicationCreator::CreateApplication(
30 Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) { 70 Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) {
31 LOG_ERROR(Service_NS, "called, application_id={:x}", application_id); 71 LOG_INFO(Service_NS, "called, application_id={:016X}", application_id);
32 R_THROW(ResultUnknown); 72 R_RETURN(
73 CreateGuestApplication(out_application_accessor, system, m_window_system, application_id));
33} 74}
34 75
35} // namespace Service::AM 76} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_creator.h b/src/core/hle/service/am/service/application_creator.h
index 9f939ebf6..287745af8 100755
--- a/src/core/hle/service/am/service/application_creator.h
+++ b/src/core/hle/service/am/service/application_creator.h
@@ -10,14 +10,17 @@ namespace Service::AM {
10 10
11class IApplicationAccessor; 11class IApplicationAccessor;
12struct Applet; 12struct Applet;
13class WindowSystem;
13 14
14class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { 15class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
15public: 16public:
16 explicit IApplicationCreator(Core::System& system_); 17 explicit IApplicationCreator(Core::System& system_, WindowSystem& window_system);
17 ~IApplicationCreator() override; 18 ~IApplicationCreator() override;
18 19
19private: 20private:
20 Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id); 21 Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
22
23 WindowSystem& m_window_system;
21}; 24};
22 25
23} // namespace Service::AM 26} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index bfccb6b09..3bab5ac5f 100755
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -181,7 +181,8 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
181} 181}
182 182
183Result IApplicationFunctions::SetTerminateResult(Result terminate_result) { 183Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
184 LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(), 184 LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({:04}-{:04})",
185 terminate_result.GetInnerValue(),
185 static_cast<u32>(terminate_result.GetModule()) + 2000, 186 static_cast<u32>(terminate_result.GetModule()) + 2000,
186 terminate_result.GetDescription()); 187 terminate_result.GetDescription());
187 188
diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp
index 19d6a3b89..6e1328fee 100755
--- a/src/core/hle/service/am/service/application_proxy.cpp
+++ b/src/core/hle/service/am/service/application_proxy.cpp
@@ -17,9 +17,9 @@
17namespace Service::AM { 17namespace Service::AM {
18 18
19IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, 19IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
20 Kernel::KProcess* process) 20 Kernel::KProcess* process, WindowSystem& window_system)
21 : ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{ 21 : ServiceFramework{system_, "IApplicationProxy"},
22 std::move(applet)} { 22 m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
23 // clang-format off 23 // clang-format off
24 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
25 {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, 25 {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@@ -70,7 +70,7 @@ Result IApplicationProxy::GetDebugFunctions(
70Result IApplicationProxy::GetWindowController( 70Result IApplicationProxy::GetWindowController(
71 Out<SharedPointer<IWindowController>> out_window_controller) { 71 Out<SharedPointer<IWindowController>> out_window_controller) {
72 LOG_DEBUG(Service_AM, "called"); 72 LOG_DEBUG(Service_AM, "called");
73 *out_window_controller = std::make_shared<IWindowController>(system, m_applet); 73 *out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
74 R_SUCCEED(); 74 R_SUCCEED();
75} 75}
76 76
@@ -91,7 +91,8 @@ Result IApplicationProxy::GetCommonStateGetter(
91Result IApplicationProxy::GetLibraryAppletCreator( 91Result IApplicationProxy::GetLibraryAppletCreator(
92 Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) { 92 Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
93 LOG_DEBUG(Service_AM, "called"); 93 LOG_DEBUG(Service_AM, "called");
94 *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet); 94 *out_library_applet_creator =
95 std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
95 R_SUCCEED(); 96 R_SUCCEED();
96} 97}
97 98
diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h
index 6da350df7..8c62459c4 100755
--- a/src/core/hle/service/am/service/application_proxy.h
+++ b/src/core/hle/service/am/service/application_proxy.h
@@ -18,11 +18,12 @@ class ILibraryAppletCreator;
18class IProcessWindingController; 18class IProcessWindingController;
19class ISelfController; 19class ISelfController;
20class IWindowController; 20class IWindowController;
21class WindowSystem;
21 22
22class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 23class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
23public: 24public:
24 explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, 25 explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
25 Kernel::KProcess* process); 26 Kernel::KProcess* process, WindowSystem& window_system);
26 ~IApplicationProxy(); 27 ~IApplicationProxy();
27 28
28private: 29private:
@@ -40,6 +41,7 @@ private:
40 Out<SharedPointer<IApplicationFunctions>> out_application_functions); 41 Out<SharedPointer<IApplicationFunctions>> out_application_functions);
41 42
42private: 43private:
44 WindowSystem& m_window_system;
43 Kernel::KProcess* const m_process; 45 Kernel::KProcess* const m_process;
44 const std::shared_ptr<Applet> m_applet; 46 const std::shared_ptr<Applet> m_applet;
45}; 47};
diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp
index fd66e77b9..b7d7b3c2d 100755
--- a/src/core/hle/service/am/service/application_proxy_service.cpp
+++ b/src/core/hle/service/am/service/application_proxy_service.cpp
@@ -6,12 +6,14 @@
6#include "core/hle/service/am/applet_manager.h" 6#include "core/hle/service/am/applet_manager.h"
7#include "core/hle/service/am/service/application_proxy.h" 7#include "core/hle/service/am/service/application_proxy.h"
8#include "core/hle/service/am/service/application_proxy_service.h" 8#include "core/hle/service/am/service/application_proxy_service.h"
9#include "core/hle/service/am/window_system.h"
9#include "core/hle/service/cmif_serialization.h" 10#include "core/hle/service/cmif_serialization.h"
10 11
11namespace Service::AM { 12namespace Service::AM {
12 13
13IApplicationProxyService::IApplicationProxyService(Core::System& system_) 14IApplicationProxyService::IApplicationProxyService(Core::System& system_,
14 : ServiceFramework{system_, "appletOE"} { 15 WindowSystem& window_system)
16 : ServiceFramework{system_, "appletOE"}, m_window_system{window_system} {
15 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
16 {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"}, 18 {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
17 }; 19 };
@@ -26,8 +28,8 @@ Result IApplicationProxyService::OpenApplicationProxy(
26 LOG_DEBUG(Service_AM, "called"); 28 LOG_DEBUG(Service_AM, "called");
27 29
28 if (const auto applet = this->GetAppletFromProcessId(pid)) { 30 if (const auto applet = this->GetAppletFromProcessId(pid)) {
29 *out_application_proxy = 31 *out_application_proxy = std::make_shared<IApplicationProxy>(
30 std::make_shared<IApplicationProxy>(system, applet, process_handle.Get()); 32 system, applet, process_handle.Get(), m_window_system);
31 R_SUCCEED(); 33 R_SUCCEED();
32 } else { 34 } else {
33 UNIMPLEMENTED(); 35 UNIMPLEMENTED();
@@ -36,7 +38,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
36} 38}
37 39
38std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) { 40std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
39 return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid); 41 return m_window_system.GetByAppletResourceUserId(process_id.pid);
40} 42}
41 43
42} // namespace Service::AM 44} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_proxy_service.h b/src/core/hle/service/am/service/application_proxy_service.h
index 8efafa31a..e5f4ea345 100755
--- a/src/core/hle/service/am/service/application_proxy_service.h
+++ b/src/core/hle/service/am/service/application_proxy_service.h
@@ -12,10 +12,11 @@ namespace AM {
12 12
13struct Applet; 13struct Applet;
14class IApplicationProxy; 14class IApplicationProxy;
15class WindowSystem;
15 16
16class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> { 17class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
17public: 18public:
18 explicit IApplicationProxyService(Core::System& system_); 19 explicit IApplicationProxyService(Core::System& system_, WindowSystem& window_system);
19 ~IApplicationProxyService() override; 20 ~IApplicationProxyService() override;
20 21
21private: 22private:
@@ -24,6 +25,8 @@ private:
24 25
25private: 26private:
26 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); 27 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
28
29 WindowSystem& m_window_system;
27}; 30};
28 31
29} // namespace AM 32} // namespace AM
diff --git a/src/core/hle/service/am/service/common_state_getter.cpp b/src/core/hle/service/am/service/common_state_getter.cpp
index 548498e83..8ab8e3629 100755
--- a/src/core/hle/service/am/service/common_state_getter.cpp
+++ b/src/core/hle/service/am/service/common_state_getter.cpp
@@ -80,15 +80,14 @@ ICommonStateGetter::~ICommonStateGetter() = default;
80 80
81Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) { 81Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
82 LOG_DEBUG(Service_AM, "called"); 82 LOG_DEBUG(Service_AM, "called");
83 *out_event = &m_applet->message_queue.GetMessageReceiveEvent(); 83 *out_event = m_applet->lifecycle_manager.GetSystemEvent().GetHandle();
84 R_SUCCEED(); 84 R_SUCCEED();
85} 85}
86 86
87Result ICommonStateGetter::ReceiveMessage(Out<AppletMessage> out_applet_message) { 87Result ICommonStateGetter::ReceiveMessage(Out<AppletMessage> out_applet_message) {
88 LOG_DEBUG(Service_AM, "called"); 88 LOG_DEBUG(Service_AM, "called");
89 89
90 *out_applet_message = m_applet->message_queue.PopMessage(); 90 if (!m_applet->lifecycle_manager.PopMessage(out_applet_message)) {
91 if (*out_applet_message == AppletMessage::None) {
92 LOG_ERROR(Service_AM, "Tried to pop message but none was available!"); 91 LOG_ERROR(Service_AM, "Tried to pop message but none was available!");
93 R_THROW(AM::ResultNoMessages); 92 R_THROW(AM::ResultNoMessages);
94 } 93 }
@@ -100,7 +99,7 @@ Result ICommonStateGetter::GetCurrentFocusState(Out<FocusState> out_focus_state)
100 LOG_DEBUG(Service_AM, "called"); 99 LOG_DEBUG(Service_AM, "called");
101 100
102 std::scoped_lock lk{m_applet->lock}; 101 std::scoped_lock lk{m_applet->lock};
103 *out_focus_state = m_applet->focus_state; 102 *out_focus_state = m_applet->lifecycle_manager.GetAndClearFocusState();
104 103
105 R_SUCCEED(); 104 R_SUCCEED();
106} 105}
@@ -137,7 +136,7 @@ Result ICommonStateGetter::GetWriterLockAccessorEx(
137Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent( 136Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(
138 OutCopyHandle<Kernel::KReadableEvent> out_event) { 137 OutCopyHandle<Kernel::KReadableEvent> out_event) {
139 LOG_DEBUG(Service_AM, "called"); 138 LOG_DEBUG(Service_AM, "called");
140 *out_event = &m_applet->message_queue.GetOperationModeChangedEvent(); 139 *out_event = m_applet->lifecycle_manager.GetOperationModeChangedSystemEvent().GetHandle();
141 R_SUCCEED(); 140 R_SUCCEED();
142} 141}
143 142
diff --git a/src/core/hle/service/am/service/home_menu_functions.cpp b/src/core/hle/service/am/service/home_menu_functions.cpp
index 0c4d24b58..25f78beb5 100755
--- a/src/core/hle/service/am/service/home_menu_functions.cpp
+++ b/src/core/hle/service/am/service/home_menu_functions.cpp
@@ -4,13 +4,16 @@
4#include "core/hle/result.h" 4#include "core/hle/result.h"
5#include "core/hle/service/am/applet_manager.h" 5#include "core/hle/service/am/applet_manager.h"
6#include "core/hle/service/am/service/home_menu_functions.h" 6#include "core/hle/service/am/service/home_menu_functions.h"
7#include "core/hle/service/am/window_system.h"
7#include "core/hle/service/cmif_serialization.h" 8#include "core/hle/service/cmif_serialization.h"
8 9
9namespace Service::AM { 10namespace Service::AM {
10 11
11IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet) 12IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
12 : ServiceFramework{system_, "IHomeMenuFunctions"}, m_applet{std::move(applet)}, 13 WindowSystem& window_system)
13 m_context{system, "IHomeMenuFunctions"}, m_pop_from_general_channel_event{m_context} { 14 : ServiceFramework{system_, "IHomeMenuFunctions"}, m_window_system{window_system},
15 m_applet{std::move(applet)}, m_context{system, "IHomeMenuFunctions"},
16 m_pop_from_general_channel_event{m_context} {
14 // clang-format off 17 // clang-format off
15 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
16 {10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"}, 19 {10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"},
@@ -37,17 +40,20 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Ap
37IHomeMenuFunctions::~IHomeMenuFunctions() = default; 40IHomeMenuFunctions::~IHomeMenuFunctions() = default;
38 41
39Result IHomeMenuFunctions::RequestToGetForeground() { 42Result IHomeMenuFunctions::RequestToGetForeground() {
40 LOG_WARNING(Service_AM, "(STUBBED) called"); 43 LOG_INFO(Service_AM, "called");
44 m_window_system.RequestHomeMenuToGetForeground();
41 R_SUCCEED(); 45 R_SUCCEED();
42} 46}
43 47
44Result IHomeMenuFunctions::LockForeground() { 48Result IHomeMenuFunctions::LockForeground() {
45 LOG_WARNING(Service_AM, "(STUBBED) called"); 49 LOG_INFO(Service_AM, "called");
50 m_window_system.RequestLockHomeMenuIntoForeground();
46 R_SUCCEED(); 51 R_SUCCEED();
47} 52}
48 53
49Result IHomeMenuFunctions::UnlockForeground() { 54Result IHomeMenuFunctions::UnlockForeground() {
50 LOG_WARNING(Service_AM, "(STUBBED) called"); 55 LOG_INFO(Service_AM, "called");
56 m_window_system.RequestUnlockHomeMenuIntoForeground();
51 R_SUCCEED(); 57 R_SUCCEED();
52} 58}
53 59
diff --git a/src/core/hle/service/am/service/home_menu_functions.h b/src/core/hle/service/am/service/home_menu_functions.h
index caf6fbaab..f56094aa9 100755
--- a/src/core/hle/service/am/service/home_menu_functions.h
+++ b/src/core/hle/service/am/service/home_menu_functions.h
@@ -11,10 +11,12 @@
11namespace Service::AM { 11namespace Service::AM {
12 12
13struct Applet; 13struct Applet;
14class WindowSystem;
14 15
15class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 16class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
16public: 17public:
17 explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet); 18 explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
19 WindowSystem& window_system);
18 ~IHomeMenuFunctions() override; 20 ~IHomeMenuFunctions() override;
19 21
20private: 22private:
@@ -26,6 +28,7 @@ private:
26 Result IsForceTerminateApplicationDisabledForDebug( 28 Result IsForceTerminateApplicationDisabledForDebug(
27 Out<bool> out_is_force_terminate_application_disabled_for_debug); 29 Out<bool> out_is_force_terminate_application_disabled_for_debug);
28 30
31 WindowSystem& m_window_system;
29 const std::shared_ptr<Applet> m_applet; 32 const std::shared_ptr<Applet> m_applet;
30 KernelHelpers::ServiceContext m_context; 33 KernelHelpers::ServiceContext m_context;
31 Event m_pop_from_general_channel_event; 34 Event m_pop_from_general_channel_event;
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 0c2426d4b..cda8c3eb8 100755
--- a/src/core/hle/service/am/service/library_applet_accessor.cpp
+++ b/src/core/hle/service/am/service/library_applet_accessor.cpp
@@ -47,20 +47,21 @@ ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
47Result ILibraryAppletAccessor::GetAppletStateChangedEvent( 47Result ILibraryAppletAccessor::GetAppletStateChangedEvent(
48 OutCopyHandle<Kernel::KReadableEvent> out_event) { 48 OutCopyHandle<Kernel::KReadableEvent> out_event) {
49 LOG_DEBUG(Service_AM, "called"); 49 LOG_DEBUG(Service_AM, "called");
50 *out_event = m_broker->GetStateChangedEvent().GetHandle(); 50 *out_event = m_applet->state_changed_event.GetHandle();
51 R_SUCCEED(); 51 R_SUCCEED();
52} 52}
53 53
54Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) { 54Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) {
55 LOG_DEBUG(Service_AM, "called"); 55 LOG_DEBUG(Service_AM, "called");
56 *out_is_completed = m_broker->IsCompleted(); 56 std::scoped_lock lk{m_applet->lock};
57 *out_is_completed = m_applet->is_completed;
57 R_SUCCEED(); 58 R_SUCCEED();
58} 59}
59 60
60Result ILibraryAppletAccessor::GetResult(Out<Result> out_result) { 61Result ILibraryAppletAccessor::GetResult() {
61 LOG_DEBUG(Service_AM, "called"); 62 LOG_DEBUG(Service_AM, "called");
62 *out_result = m_applet->terminate_result; 63 std::scoped_lock lk{m_applet->lock};
63 R_SUCCEED(); 64 R_RETURN(m_applet->terminate_result);
64} 65}
65 66
66Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() { 67Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() {
@@ -77,7 +78,10 @@ Result ILibraryAppletAccessor::Start() {
77 78
78Result ILibraryAppletAccessor::RequestExit() { 79Result ILibraryAppletAccessor::RequestExit() {
79 LOG_DEBUG(Service_AM, "called"); 80 LOG_DEBUG(Service_AM, "called");
80 m_applet->message_queue.RequestExit(); 81 {
82 std::scoped_lock lk{m_applet->lock};
83 m_applet->lifecycle_manager.RequestExit();
84 }
81 FrontendRequestExit(); 85 FrontendRequestExit();
82 R_SUCCEED(); 86 R_SUCCEED();
83} 87}
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 97d3b6c8a..36712821a 100755
--- a/src/core/hle/service/am/service/library_applet_accessor.h
+++ b/src/core/hle/service/am/service/library_applet_accessor.h
@@ -21,7 +21,7 @@ public:
21private: 21private:
22 Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); 22 Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
23 Result IsCompleted(Out<bool> out_is_completed); 23 Result IsCompleted(Out<bool> out_is_completed);
24 Result GetResult(Out<Result> out_result); 24 Result GetResult();
25 Result PresetLibraryAppletGpuTimeSliceZero(); 25 Result PresetLibraryAppletGpuTimeSliceZero();
26 Result Start(); 26 Result Start();
27 Result RequestExit(); 27 Result RequestExit();
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 c97358d81..3ffb03bc9 100755
--- a/src/core/hle/service/am/service/library_applet_creator.cpp
+++ b/src/core/hle/service/am/service/library_applet_creator.cpp
@@ -7,9 +7,11 @@
7#include "core/hle/service/am/applet_manager.h" 7#include "core/hle/service/am/applet_manager.h"
8#include "core/hle/service/am/frontend/applets.h" 8#include "core/hle/service/am/frontend/applets.h"
9#include "core/hle/service/am/library_applet_storage.h" 9#include "core/hle/service/am/library_applet_storage.h"
10#include "core/hle/service/am/process_creation.h"
10#include "core/hle/service/am/service/library_applet_accessor.h" 11#include "core/hle/service/am/service/library_applet_accessor.h"
11#include "core/hle/service/am/service/library_applet_creator.h" 12#include "core/hle/service/am/service/library_applet_creator.h"
12#include "core/hle/service/am/service/storage.h" 13#include "core/hle/service/am/service/storage.h"
14#include "core/hle/service/am/window_system.h"
13#include "core/hle/service/cmif_serialization.h" 15#include "core/hle/service/cmif_serialization.h"
14#include "core/hle/service/sm/sm.h" 16#include "core/hle/service/sm/sm.h"
15 17
@@ -93,6 +95,7 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
93} 95}
94 96
95std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system, 97std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
98 WindowSystem& window_system,
96 std::shared_ptr<Applet> caller_applet, 99 std::shared_ptr<Applet> caller_applet,
97 AppletId applet_id, 100 AppletId applet_id,
98 LibraryAppletMode mode) { 101 LibraryAppletMode mode) {
@@ -110,53 +113,38 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
110 Firmware1700 = 17, 113 Firmware1700 = 17,
111 }; 114 };
112 115
113 auto process = std::make_unique<Process>(system); 116 auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700);
114 if (!process->Initialize(program_id, Firmware1400, Firmware1700)) { 117 if (!process) {
115 // Couldn't initialize the guest process 118 // Couldn't initialize the guest process
116 return {}; 119 return {};
117 } 120 }
118 121
119 const auto applet = std::make_shared<Applet>(system, std::move(process)); 122 const auto applet = std::make_shared<Applet>(system, std::move(process), false);
120 applet->program_id = program_id; 123 applet->program_id = program_id;
121 applet->applet_id = applet_id; 124 applet->applet_id = applet_id;
122 applet->type = AppletType::LibraryApplet; 125 applet->type = AppletType::LibraryApplet;
123 applet->library_applet_mode = mode; 126 applet->library_applet_mode = mode;
124 127 applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
125 // Set focus state
126 switch (mode) {
127 case LibraryAppletMode::AllForeground:
128 case LibraryAppletMode::NoUi:
129 case LibraryAppletMode::PartialForeground:
130 case LibraryAppletMode::PartialForegroundIndirectDisplay:
131 applet->hid_registration.EnableAppletToGetInput(true);
132 applet->focus_state = FocusState::InFocus;
133 applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
134 break;
135 case LibraryAppletMode::AllForegroundInitiallyHidden:
136 applet->hid_registration.EnableAppletToGetInput(false);
137 applet->focus_state = FocusState::NotInFocus;
138 applet->display_layer_manager.SetWindowVisibility(false);
139 applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
140 break;
141 }
142 128
143 auto broker = std::make_shared<AppletDataBroker>(system); 129 auto broker = std::make_shared<AppletDataBroker>(system);
144 applet->caller_applet = caller_applet; 130 applet->caller_applet = caller_applet;
145 applet->caller_applet_broker = broker; 131 applet->caller_applet_broker = broker;
132 caller_applet->child_applets.push_back(applet);
146 133
147 system.GetAppletManager().InsertApplet(applet); 134 window_system.TrackApplet(applet, false);
148 135
149 return std::make_shared<ILibraryAppletAccessor>(system, broker, applet); 136 return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
150} 137}
151 138
152std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system, 139std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
140 WindowSystem& window_system,
153 std::shared_ptr<Applet> caller_applet, 141 std::shared_ptr<Applet> caller_applet,
154 AppletId applet_id, 142 AppletId applet_id,
155 LibraryAppletMode mode) { 143 LibraryAppletMode mode) {
156 const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); 144 const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
157 145
158 auto process = std::make_unique<Process>(system); 146 auto process = std::make_unique<Process>(system);
159 auto applet = std::make_shared<Applet>(system, std::move(process)); 147 auto applet = std::make_shared<Applet>(system, std::move(process), false);
160 applet->program_id = program_id; 148 applet->program_id = program_id;
161 applet->applet_id = applet_id; 149 applet->applet_id = applet_id;
162 applet->type = AppletType::LibraryApplet; 150 applet->type = AppletType::LibraryApplet;
@@ -166,14 +154,19 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
166 applet->caller_applet = caller_applet; 154 applet->caller_applet = caller_applet;
167 applet->caller_applet_broker = storage; 155 applet->caller_applet_broker = storage;
168 applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); 156 applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
157 caller_applet->child_applets.push_back(applet);
158
159 window_system.TrackApplet(applet, false);
169 160
170 return std::make_shared<ILibraryAppletAccessor>(system, storage, applet); 161 return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
171} 162}
172 163
173} // namespace 164} // namespace
174 165
175ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet) 166ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
176 : ServiceFramework{system_, "ILibraryAppletCreator"}, m_applet{std::move(applet)} { 167 WindowSystem& window_system)
168 : ServiceFramework{system_, "ILibraryAppletCreator"},
169 m_window_system{window_system}, m_applet{std::move(applet)} {
177 static const FunctionInfo functions[] = { 170 static const FunctionInfo functions[] = {
178 {0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"}, 171 {0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
179 {1, nullptr, "TerminateAllLibraryApplets"}, 172 {1, nullptr, "TerminateAllLibraryApplets"},
@@ -195,10 +188,12 @@ Result ILibraryAppletCreator::CreateLibraryApplet(
195 188
196 std::shared_ptr<ILibraryAppletAccessor> library_applet; 189 std::shared_ptr<ILibraryAppletAccessor> library_applet;
197 if (ShouldCreateGuestApplet(applet_id)) { 190 if (ShouldCreateGuestApplet(applet_id)) {
198 library_applet = CreateGuestApplet(system, m_applet, applet_id, library_applet_mode); 191 library_applet =
192 CreateGuestApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
199 } 193 }
200 if (!library_applet) { 194 if (!library_applet) {
201 library_applet = CreateFrontendApplet(system, m_applet, applet_id, library_applet_mode); 195 library_applet =
196 CreateFrontendApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
202 } 197 }
203 if (!library_applet) { 198 if (!library_applet) {
204 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); 199 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
diff --git a/src/core/hle/service/am/service/library_applet_creator.h b/src/core/hle/service/am/service/library_applet_creator.h
index fe6d40eb3..a10a76982 100755
--- a/src/core/hle/service/am/service/library_applet_creator.h
+++ b/src/core/hle/service/am/service/library_applet_creator.h
@@ -12,10 +12,12 @@ namespace Service::AM {
12struct Applet; 12struct Applet;
13class ILibraryAppletAccessor; 13class ILibraryAppletAccessor;
14class IStorage; 14class IStorage;
15class WindowSystem;
15 16
16class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 17class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
17public: 18public:
18 explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet); 19 explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
20 WindowSystem& window_system);
19 ~ILibraryAppletCreator() override; 21 ~ILibraryAppletCreator() override;
20 22
21private: 23private:
@@ -29,6 +31,7 @@ private:
29 Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size, 31 Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size,
30 InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle); 32 InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
31 33
34 WindowSystem& m_window_system;
32 const std::shared_ptr<Applet> m_applet; 35 const std::shared_ptr<Applet> m_applet;
33}; 36};
34 37
diff --git a/src/core/hle/service/am/service/library_applet_proxy.cpp b/src/core/hle/service/am/service/library_applet_proxy.cpp
index 58e709347..f9cfb82a9 100755
--- a/src/core/hle/service/am/service/library_applet_proxy.cpp
+++ b/src/core/hle/service/am/service/library_applet_proxy.cpp
@@ -19,9 +19,9 @@
19namespace Service::AM { 19namespace Service::AM {
20 20
21ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, 21ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
22 Kernel::KProcess* process) 22 Kernel::KProcess* process, WindowSystem& window_system)
23 : ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{ 23 : ServiceFramework{system_, "ILibraryAppletProxy"},
24 std::move(applet)} { 24 m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
25 // clang-format off 25 // clang-format off
26 static const FunctionInfo functions[] = { 26 static const FunctionInfo functions[] = {
27 {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, 27 {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@@ -75,7 +75,7 @@ Result ILibraryAppletProxy::GetDebugFunctions(
75Result ILibraryAppletProxy::GetWindowController( 75Result ILibraryAppletProxy::GetWindowController(
76 Out<SharedPointer<IWindowController>> out_window_controller) { 76 Out<SharedPointer<IWindowController>> out_window_controller) {
77 LOG_DEBUG(Service_AM, "called"); 77 LOG_DEBUG(Service_AM, "called");
78 *out_window_controller = std::make_shared<IWindowController>(system, m_applet); 78 *out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
79 R_SUCCEED(); 79 R_SUCCEED();
80} 80}
81 81
@@ -96,7 +96,8 @@ Result ILibraryAppletProxy::GetCommonStateGetter(
96Result ILibraryAppletProxy::GetLibraryAppletCreator( 96Result ILibraryAppletProxy::GetLibraryAppletCreator(
97 Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) { 97 Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
98 LOG_DEBUG(Service_AM, "called"); 98 LOG_DEBUG(Service_AM, "called");
99 *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet); 99 *out_library_applet_creator =
100 std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
100 R_SUCCEED(); 101 R_SUCCEED();
101} 102}
102 103
@@ -118,7 +119,8 @@ Result ILibraryAppletProxy::GetAppletCommonFunctions(
118Result ILibraryAppletProxy::GetHomeMenuFunctions( 119Result ILibraryAppletProxy::GetHomeMenuFunctions(
119 Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) { 120 Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
120 LOG_DEBUG(Service_AM, "called"); 121 LOG_DEBUG(Service_AM, "called");
121 *out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet); 122 *out_home_menu_functions =
123 std::make_shared<IHomeMenuFunctions>(system, m_applet, m_window_system);
122 R_SUCCEED(); 124 R_SUCCEED();
123} 125}
124 126
diff --git a/src/core/hle/service/am/service/library_applet_proxy.h b/src/core/hle/service/am/service/library_applet_proxy.h
index 7d0714b85..792d58582 100755
--- a/src/core/hle/service/am/service/library_applet_proxy.h
+++ b/src/core/hle/service/am/service/library_applet_proxy.h
@@ -21,11 +21,12 @@ class ILibraryAppletSelfAccessor;
21class IProcessWindingController; 21class IProcessWindingController;
22class ISelfController; 22class ISelfController;
23class IWindowController; 23class IWindowController;
24class WindowSystem;
24 25
25class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 26class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
26public: 27public:
27 explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, 28 explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
28 Kernel::KProcess* process); 29 Kernel::KProcess* process, WindowSystem& window_system);
29 ~ILibraryAppletProxy(); 30 ~ILibraryAppletProxy();
30 31
31private: 32private:
@@ -47,6 +48,7 @@ private:
47 Result GetGlobalStateController( 48 Result GetGlobalStateController(
48 Out<SharedPointer<IGlobalStateController>> out_global_state_controller); 49 Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
49 50
51 WindowSystem& m_window_system;
50 Kernel::KProcess* const m_process; 52 Kernel::KProcess* const m_process;
51 const std::shared_ptr<Applet> m_applet; 53 const std::shared_ptr<Applet> m_applet;
52}; 54};
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 330eb26f0..3fe36b899 100755
--- a/src/core/hle/service/am/service/library_applet_self_accessor.cpp
+++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp
@@ -176,8 +176,7 @@ Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId
176 176
177Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() { 177Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() {
178 LOG_INFO(Service_AM, "called"); 178 LOG_INFO(Service_AM, "called");
179 system.GetAppletManager().TerminateAndRemoveApplet(m_applet->aruid); 179 m_applet->process->Terminate();
180 m_broker->SignalCompletion();
181 R_SUCCEED(); 180 R_SUCCEED();
182} 181}
183 182
diff --git a/src/core/hle/service/am/service/self_controller.cpp b/src/core/hle/service/am/service/self_controller.cpp
index 06314407c..1db02b88f 100755
--- a/src/core/hle/service/am/service/self_controller.cpp
+++ b/src/core/hle/service/am/service/self_controller.cpp
@@ -86,8 +86,7 @@ ISelfController::~ISelfController() {
86Result ISelfController::Exit() { 86Result ISelfController::Exit() {
87 LOG_DEBUG(Service_AM, "called"); 87 LOG_DEBUG(Service_AM, "called");
88 88
89 // TODO 89 m_applet->process->Terminate();
90 system.Exit();
91 90
92 R_SUCCEED(); 91 R_SUCCEED();
93} 92}
@@ -95,7 +94,16 @@ Result ISelfController::Exit() {
95Result ISelfController::LockExit() { 94Result ISelfController::LockExit() {
96 LOG_DEBUG(Service_AM, "called"); 95 LOG_DEBUG(Service_AM, "called");
97 96
98 system.SetExitLocked(true); 97 std::scoped_lock lk{m_applet->lock};
98
99 if (m_applet->lifecycle_manager.GetExitRequested()) {
100 // With exit already requested, ignore and terminate immediately.
101 m_applet->process->Terminate();
102 } else {
103 // Otherwise, set exit lock state.
104 m_applet->exit_locked = true;
105 system.SetExitLocked(true);
106 }
99 107
100 R_SUCCEED(); 108 R_SUCCEED();
101} 109}
@@ -103,10 +111,13 @@ Result ISelfController::LockExit() {
103Result ISelfController::UnlockExit() { 111Result ISelfController::UnlockExit() {
104 LOG_DEBUG(Service_AM, "called"); 112 LOG_DEBUG(Service_AM, "called");
105 113
114 std::scoped_lock lk{m_applet->lock};
115
116 m_applet->exit_locked = false;
106 system.SetExitLocked(false); 117 system.SetExitLocked(false);
107 118
108 if (system.GetExitRequested()) { 119 if (m_applet->lifecycle_manager.GetExitRequested()) {
109 system.Exit(); 120 m_applet->process->Terminate();
110 } 121 }
111 122
112 R_SUCCEED(); 123 R_SUCCEED();
@@ -155,7 +166,7 @@ Result ISelfController::SetOperationModeChangedNotification(bool enabled) {
155 LOG_INFO(Service_AM, "called, enabled={}", enabled); 166 LOG_INFO(Service_AM, "called, enabled={}", enabled);
156 167
157 std::scoped_lock lk{m_applet->lock}; 168 std::scoped_lock lk{m_applet->lock};
158 m_applet->operation_mode_changed_notification_enabled = enabled; 169 m_applet->lifecycle_manager.SetOperationModeChangedNotificationEnabled(enabled);
159 170
160 R_SUCCEED(); 171 R_SUCCEED();
161} 172}
@@ -164,17 +175,18 @@ Result ISelfController::SetPerformanceModeChangedNotification(bool enabled) {
164 LOG_INFO(Service_AM, "called, enabled={}", enabled); 175 LOG_INFO(Service_AM, "called, enabled={}", enabled);
165 176
166 std::scoped_lock lk{m_applet->lock}; 177 std::scoped_lock lk{m_applet->lock};
167 m_applet->performance_mode_changed_notification_enabled = enabled; 178 m_applet->lifecycle_manager.SetPerformanceModeChangedNotificationEnabled(enabled);
168 179
169 R_SUCCEED(); 180 R_SUCCEED();
170} 181}
171 182
172Result ISelfController::SetFocusHandlingMode(bool notify, bool background, bool suspend) { 183Result ISelfController::SetFocusHandlingMode(bool notify, bool background, bool suspend) {
173 LOG_WARNING(Service_AM, "(STUBBED) called, notify={} background={} suspend={}", notify, 184 LOG_INFO(Service_AM, "called, notify={} background={} suspend={}", notify, background, suspend);
174 background, suspend);
175 185
176 std::scoped_lock lk{m_applet->lock}; 186 std::scoped_lock lk{m_applet->lock};
177 m_applet->focus_handling_mode = {notify, background, suspend}; 187 m_applet->lifecycle_manager.SetFocusStateChangedNotificationEnabled(notify);
188 m_applet->lifecycle_manager.SetFocusHandlingMode(suspend);
189 m_applet->UpdateSuspensionStateLocked(true);
178 190
179 R_SUCCEED(); 191 R_SUCCEED();
180} 192}
@@ -183,7 +195,7 @@ Result ISelfController::SetRestartMessageEnabled(bool enabled) {
183 LOG_INFO(Service_AM, "called, enabled={}", enabled); 195 LOG_INFO(Service_AM, "called, enabled={}", enabled);
184 196
185 std::scoped_lock lk{m_applet->lock}; 197 std::scoped_lock lk{m_applet->lock};
186 m_applet->restart_message_enabled = enabled; 198 m_applet->lifecycle_manager.SetResumeNotificationEnabled(enabled);
187 199
188 R_SUCCEED(); 200 R_SUCCEED();
189} 201}
@@ -202,7 +214,8 @@ Result ISelfController::SetOutOfFocusSuspendingEnabled(bool enabled) {
202 LOG_INFO(Service_AM, "called, enabled={}", enabled); 214 LOG_INFO(Service_AM, "called, enabled={}", enabled);
203 215
204 std::scoped_lock lk{m_applet->lock}; 216 std::scoped_lock lk{m_applet->lock};
205 m_applet->out_of_focus_suspension_enabled = enabled; 217 m_applet->lifecycle_manager.SetOutOfFocusSuspendingEnabled(enabled);
218 m_applet->UpdateSuspensionStateLocked(false);
206 219
207 R_SUCCEED(); 220 R_SUCCEED();
208} 221}
diff --git a/src/core/hle/service/am/service/system_applet_proxy.cpp b/src/core/hle/service/am/service/system_applet_proxy.cpp
index d1871ef9b..c435288a2 100755
--- a/src/core/hle/service/am/service/system_applet_proxy.cpp
+++ b/src/core/hle/service/am/service/system_applet_proxy.cpp
@@ -19,9 +19,9 @@
19namespace Service::AM { 19namespace Service::AM {
20 20
21ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, 21ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
22 Kernel::KProcess* process) 22 Kernel::KProcess* process, WindowSystem& window_system)
23 : ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{ 23 : ServiceFramework{system_, "ISystemAppletProxy"},
24 std::move(applet)} { 24 m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
25 // clang-format off 25 // clang-format off
26 static const FunctionInfo functions[] = { 26 static const FunctionInfo functions[] = {
27 {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, 27 {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@@ -75,7 +75,7 @@ Result ISystemAppletProxy::GetDebugFunctions(
75Result ISystemAppletProxy::GetWindowController( 75Result ISystemAppletProxy::GetWindowController(
76 Out<SharedPointer<IWindowController>> out_window_controller) { 76 Out<SharedPointer<IWindowController>> out_window_controller) {
77 LOG_DEBUG(Service_AM, "called"); 77 LOG_DEBUG(Service_AM, "called");
78 *out_window_controller = std::make_shared<IWindowController>(system, m_applet); 78 *out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
79 R_SUCCEED(); 79 R_SUCCEED();
80} 80}
81 81
@@ -96,14 +96,15 @@ Result ISystemAppletProxy::GetCommonStateGetter(
96Result ISystemAppletProxy::GetLibraryAppletCreator( 96Result ISystemAppletProxy::GetLibraryAppletCreator(
97 Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) { 97 Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
98 LOG_DEBUG(Service_AM, "called"); 98 LOG_DEBUG(Service_AM, "called");
99 *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet); 99 *out_library_applet_creator =
100 std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
100 R_SUCCEED(); 101 R_SUCCEED();
101} 102}
102 103
103Result ISystemAppletProxy::GetApplicationCreator( 104Result ISystemAppletProxy::GetApplicationCreator(
104 Out<SharedPointer<IApplicationCreator>> out_application_creator) { 105 Out<SharedPointer<IApplicationCreator>> out_application_creator) {
105 LOG_DEBUG(Service_AM, "called"); 106 LOG_DEBUG(Service_AM, "called");
106 *out_application_creator = std::make_shared<IApplicationCreator>(system); 107 *out_application_creator = std::make_shared<IApplicationCreator>(system, m_window_system);
107 R_SUCCEED(); 108 R_SUCCEED();
108} 109}
109 110
@@ -117,7 +118,8 @@ Result ISystemAppletProxy::GetAppletCommonFunctions(
117Result ISystemAppletProxy::GetHomeMenuFunctions( 118Result ISystemAppletProxy::GetHomeMenuFunctions(
118 Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) { 119 Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
119 LOG_DEBUG(Service_AM, "called"); 120 LOG_DEBUG(Service_AM, "called");
120 *out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet); 121 *out_home_menu_functions =
122 std::make_shared<IHomeMenuFunctions>(system, m_applet, m_window_system);
121 R_SUCCEED(); 123 R_SUCCEED();
122} 124}
123 125
diff --git a/src/core/hle/service/am/service/system_applet_proxy.h b/src/core/hle/service/am/service/system_applet_proxy.h
index 67cd50e03..217d9dc8c 100755
--- a/src/core/hle/service/am/service/system_applet_proxy.h
+++ b/src/core/hle/service/am/service/system_applet_proxy.h
@@ -21,11 +21,12 @@ class ILibraryAppletCreator;
21class IProcessWindingController; 21class IProcessWindingController;
22class ISelfController; 22class ISelfController;
23class IWindowController; 23class IWindowController;
24class WindowSystem;
24 25
25class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { 26class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
26public: 27public:
27 explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet, 28 explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
28 Kernel::KProcess* process); 29 Kernel::KProcess* process, WindowSystem& window_system);
29 ~ISystemAppletProxy(); 30 ~ISystemAppletProxy();
30 31
31private: 32private:
@@ -46,6 +47,7 @@ private:
46 Result GetGlobalStateController( 47 Result GetGlobalStateController(
47 Out<SharedPointer<IGlobalStateController>> out_global_state_controller); 48 Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
48 49
50 WindowSystem& m_window_system;
49 Kernel::KProcess* const m_process; 51 Kernel::KProcess* const m_process;
50 const std::shared_ptr<Applet> m_applet; 52 const std::shared_ptr<Applet> m_applet;
51}; 53};
diff --git a/src/core/hle/service/am/service/window_controller.cpp b/src/core/hle/service/am/service/window_controller.cpp
index 99a4f50a2..54396affb 100755
--- a/src/core/hle/service/am/service/window_controller.cpp
+++ b/src/core/hle/service/am/service/window_controller.cpp
@@ -4,12 +4,15 @@
4#include "core/hle/service/am/applet.h" 4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/applet_manager.h" 5#include "core/hle/service/am/applet_manager.h"
6#include "core/hle/service/am/service/window_controller.h" 6#include "core/hle/service/am/service/window_controller.h"
7#include "core/hle/service/am/window_system.h"
7#include "core/hle/service/cmif_serialization.h" 8#include "core/hle/service/cmif_serialization.h"
8 9
9namespace Service::AM { 10namespace Service::AM {
10 11
11IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet) 12IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet,
12 : ServiceFramework{system_, "IWindowController"}, m_applet{std::move(applet)} { 13 WindowSystem& window_system)
14 : ServiceFramework{system_, "IWindowController"},
15 m_window_system{window_system}, m_applet{std::move(applet)} {
13 // clang-format off 16 // clang-format off
14 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
15 {0, nullptr, "CreateWindow"}, 18 {0, nullptr, "CreateWindow"},
@@ -63,17 +66,9 @@ Result IWindowController::RejectToChangeIntoBackground() {
63} 66}
64 67
65Result IWindowController::SetAppletWindowVisibility(bool visible) { 68Result IWindowController::SetAppletWindowVisibility(bool visible) {
66 m_applet->display_layer_manager.SetWindowVisibility(visible); 69 LOG_INFO(Service_AM, "called");
67 m_applet->hid_registration.EnableAppletToGetInput(visible);
68
69 if (visible) {
70 m_applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
71 m_applet->focus_state = FocusState::InFocus;
72 } else {
73 m_applet->focus_state = FocusState::NotInFocus;
74 }
75 70
76 m_applet->message_queue.PushMessage(AppletMessage::FocusStateChanged); 71 m_window_system.RequestAppletVisibilityState(*m_applet, visible);
77 72
78 R_SUCCEED(); 73 R_SUCCEED();
79} 74}
diff --git a/src/core/hle/service/am/service/window_controller.h b/src/core/hle/service/am/service/window_controller.h
index bfbad9bcc..a784dd4a4 100755
--- a/src/core/hle/service/am/service/window_controller.h
+++ b/src/core/hle/service/am/service/window_controller.h
@@ -9,10 +9,12 @@
9namespace Service::AM { 9namespace Service::AM {
10 10
11struct Applet; 11struct Applet;
12class WindowSystem;
12 13
13class IWindowController final : public ServiceFramework<IWindowController> { 14class IWindowController final : public ServiceFramework<IWindowController> {
14public: 15public:
15 explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet); 16 explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet,
17 WindowSystem& window_system);
16 ~IWindowController() override; 18 ~IWindowController() override;
17 19
18private: 20private:
@@ -24,6 +26,7 @@ private:
24 Result SetAppletWindowVisibility(bool visible); 26 Result SetAppletWindowVisibility(bool visible);
25 Result SetAppletGpuTimeSlice(s64 time_slice); 27 Result SetAppletGpuTimeSlice(s64 time_slice);
26 28
29 WindowSystem& m_window_system;
27 const std::shared_ptr<Applet> m_applet; 30 const std::shared_ptr<Applet> m_applet;
28}; 31};
29 32
diff --git a/src/core/hle/service/am/window_system.cpp b/src/core/hle/service/am/window_system.cpp
new file mode 100755
index 000000000..5cf24007c
--- /dev/null
+++ b/src/core/hle/service/am/window_system.cpp
@@ -0,0 +1,315 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/applet.h"
7#include "core/hle/service/am/applet_manager.h"
8#include "core/hle/service/am/event_observer.h"
9#include "core/hle/service/am/window_system.h"
10
11namespace Service::AM {
12
13WindowSystem::WindowSystem(Core::System& system) : m_system(system) {}
14
15WindowSystem::~WindowSystem() {
16 m_system.GetAppletManager().SetWindowSystem(nullptr);
17}
18
19void WindowSystem::SetEventObserver(EventObserver* observer) {
20 m_event_observer = observer;
21 m_system.GetAppletManager().SetWindowSystem(this);
22}
23
24void WindowSystem::Update() {
25 std::scoped_lock lk{m_lock};
26
27 // Loop through all applets and remove terminated applets.
28 this->PruneTerminatedAppletsLocked();
29
30 // If the home menu is being locked into the foreground, handle that.
31 if (this->LockHomeMenuIntoForegroundLocked()) {
32 return;
33 }
34
35 // Recursively update each applet root.
36 this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu);
37 this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application);
38}
39
40void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
41 std::scoped_lock lk{m_lock};
42
43 if (applet->applet_id == AppletId::QLaunch) {
44 ASSERT(m_home_menu == nullptr);
45 m_home_menu = applet.get();
46 } else if (is_application) {
47 ASSERT(m_application == nullptr);
48 m_application = applet.get();
49 }
50
51 m_event_observer->TrackAppletProcess(*applet);
52 m_applets.emplace(applet->aruid.pid, std::move(applet));
53}
54
55std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
56 std::scoped_lock lk{m_lock};
57
58 const auto it = m_applets.find(aruid);
59 if (it == m_applets.end()) {
60 return nullptr;
61 }
62
63 return it->second;
64}
65
66std::shared_ptr<Applet> WindowSystem::GetMainApplet() {
67 std::scoped_lock lk{m_lock};
68
69 if (m_application) {
70 return m_applets.at(m_application->aruid.pid);
71 }
72
73 return nullptr;
74}
75
76void WindowSystem::RequestHomeMenuToGetForeground() {
77 {
78 std::scoped_lock lk{m_lock};
79 m_foreground_requested_applet = m_home_menu;
80 }
81
82 m_event_observer->RequestUpdate();
83}
84
85void WindowSystem::RequestApplicationToGetForeground() {
86 {
87 std::scoped_lock lk{m_lock};
88 m_foreground_requested_applet = m_application;
89 }
90
91 m_event_observer->RequestUpdate();
92}
93
94void WindowSystem::RequestLockHomeMenuIntoForeground() {
95 {
96 std::scoped_lock lk{m_lock};
97 m_home_menu_foreground_locked = true;
98 }
99
100 m_event_observer->RequestUpdate();
101}
102
103void WindowSystem::RequestUnlockHomeMenuIntoForeground() {
104 {
105 std::scoped_lock lk{m_lock};
106 m_home_menu_foreground_locked = false;
107 }
108
109 m_event_observer->RequestUpdate();
110}
111
112void WindowSystem::RequestAppletVisibilityState(Applet& applet, bool visible) {
113 {
114 std::scoped_lock lk{applet.lock};
115 applet.window_visible = visible;
116 }
117
118 m_event_observer->RequestUpdate();
119}
120
121void WindowSystem::OnOperationModeChanged() {
122 std::scoped_lock lk{m_lock};
123
124 for (const auto& [aruid, applet] : m_applets) {
125 std::scoped_lock lk2{applet->lock};
126 applet->lifecycle_manager.OnOperationAndPerformanceModeChanged();
127 }
128}
129
130void WindowSystem::OnExitRequested() {
131 std::scoped_lock lk{m_lock};
132
133 for (const auto& [aruid, applet] : m_applets) {
134 std::scoped_lock lk2{applet->lock};
135 applet->lifecycle_manager.RequestExit();
136 }
137}
138
139void WindowSystem::OnHomeButtonPressed(ButtonPressDuration type) {
140 std::scoped_lock lk{m_lock};
141
142 // If we don't have a home menu, nothing to do.
143 if (!m_home_menu) {
144 return;
145 }
146
147 // Lock.
148 std::scoped_lock lk2{m_home_menu->lock};
149
150 // Send home button press event to home menu.
151 if (type == ButtonPressDuration::ShortPressing) {
152 m_home_menu->lifecycle_manager.PushUnorderedMessage(
153 AppletMessage::DetectShortPressingHomeButton);
154 }
155}
156
157void WindowSystem::PruneTerminatedAppletsLocked() {
158 for (auto it = m_applets.begin(); it != m_applets.end(); /* ... */) {
159 const auto& [aruid, applet] = *it;
160
161 std::scoped_lock lk{applet->lock};
162
163 if (!applet->process->IsTerminated()) {
164 // Not terminated.
165 it = std::next(it);
166 continue;
167 }
168
169 // Terminated, so ensure all child applets are terminated.
170 if (!applet->child_applets.empty()) {
171 this->TerminateChildAppletsLocked(applet.get());
172
173 // Not ready to unlink until all child applets are terminated.
174 it = std::next(it);
175 continue;
176 }
177
178 // Erase from caller applet's list of children.
179 if (auto caller_applet = applet->caller_applet.lock(); caller_applet) {
180 std::scoped_lock lk2{caller_applet->lock};
181 std::erase(caller_applet->child_applets, applet);
182 applet->caller_applet.reset();
183
184 // We don't need to update the activity state of the caller applet yet.
185 // It will be recalculated once we fall out of the termination handling path.
186 }
187
188 // If this applet was foreground, it no longer is.
189 if (applet.get() == m_foreground_requested_applet) {
190 m_foreground_requested_applet = nullptr;
191 }
192
193 // If this was the home menu, we should clean up.
194 if (applet.get() == m_home_menu) {
195 m_home_menu = nullptr;
196 m_foreground_requested_applet = m_application;
197 }
198
199 // If this was the application, we should try to switch to the home menu.
200 if (applet.get() == m_application) {
201 m_application = nullptr;
202 m_foreground_requested_applet = m_home_menu;
203
204 // If we have a home menu, send it the application exited message.
205 if (m_home_menu) {
206 m_home_menu->lifecycle_manager.PushUnorderedMessage(
207 AppletMessage::ApplicationExited);
208 }
209 }
210
211 // Finalize applet.
212 applet->OnProcessTerminatedLocked();
213
214 // Request update to ensure quiescence.
215 m_event_observer->RequestUpdate();
216
217 // Unlink and advance.
218 it = m_applets.erase(it);
219 }
220
221 // If the last applet has exited, exit the system.
222 if (m_applets.empty()) {
223 m_system.Exit();
224 }
225}
226
227bool WindowSystem::LockHomeMenuIntoForegroundLocked() {
228 // If the home menu is not locked into foreground, then there's nothing to do.
229 if (m_home_menu == nullptr || !m_home_menu_foreground_locked) {
230 m_home_menu_foreground_locked = false;
231 return false;
232 }
233
234 // Terminate any direct child applets of the home menu.
235 std::scoped_lock lk{m_home_menu->lock};
236
237 this->TerminateChildAppletsLocked(m_home_menu);
238
239 // When there are zero child applets left, we can proceed with the update.
240 if (m_home_menu->child_applets.empty()) {
241 m_home_menu->window_visible = true;
242 m_foreground_requested_applet = m_home_menu;
243 return false;
244 }
245
246 return true;
247}
248
249void WindowSystem::TerminateChildAppletsLocked(Applet* applet) {
250 auto child_applets = applet->child_applets;
251
252 applet->lock.unlock();
253 for (const auto& child_applet : child_applets) {
254 std::scoped_lock lk{child_applet->lock};
255 child_applet->process->Terminate();
256 child_applet->terminate_result = AM::ResultLibraryAppletTerminated;
257 }
258 applet->lock.lock();
259}
260
261void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground) {
262 // With no applet, we don't have anything to do.
263 if (!applet) {
264 return;
265 }
266
267 std::scoped_lock lk{applet->lock};
268
269 const bool inherited_foreground = applet->is_process_running && is_foreground;
270 const auto visible_state =
271 inherited_foreground ? ActivityState::ForegroundVisible : ActivityState::BackgroundVisible;
272 const auto obscured_state = inherited_foreground ? ActivityState::ForegroundObscured
273 : ActivityState::BackgroundObscured;
274
275 const bool has_obscuring_child_applets = [&] {
276 for (const auto& child_applet : applet->child_applets) {
277 std::scoped_lock lk2{child_applet->lock};
278 const auto mode = child_applet->library_applet_mode;
279 if (child_applet->is_process_running && child_applet->window_visible &&
280 (mode == LibraryAppletMode::AllForeground ||
281 mode == LibraryAppletMode::AllForegroundInitiallyHidden)) {
282 return true;
283 }
284 }
285
286 return false;
287 }();
288
289 // Update visibility state.
290 applet->display_layer_manager.SetWindowVisibility(is_foreground && applet->window_visible);
291
292 // Update interactibility state.
293 applet->SetInteractibleLocked(is_foreground && applet->window_visible);
294
295 // Update focus state and suspension.
296 const bool is_obscured = has_obscuring_child_applets || !applet->window_visible;
297 const auto state = applet->lifecycle_manager.GetActivityState();
298
299 if (is_obscured && state != obscured_state) {
300 // Set obscured state.
301 applet->lifecycle_manager.SetActivityState(obscured_state);
302 applet->UpdateSuspensionStateLocked(true);
303 } else if (!is_obscured && state != visible_state) {
304 // Set visible state.
305 applet->lifecycle_manager.SetActivityState(visible_state);
306 applet->UpdateSuspensionStateLocked(true);
307 }
308
309 // Recurse into child applets.
310 for (const auto& child_applet : applet->child_applets) {
311 this->UpdateAppletStateLocked(child_applet.get(), is_foreground);
312 }
313}
314
315} // namespace Service::AM
diff --git a/src/core/hle/service/am/window_system.h b/src/core/hle/service/am/window_system.h
new file mode 100755
index 000000000..69e7a27ba
--- /dev/null
+++ b/src/core/hle/service/am/window_system.h
@@ -0,0 +1,83 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <map>
7#include <memory>
8#include <mutex>
9
10#include "common/common_types.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::AM {
17
18struct Applet;
19class EventObserver;
20
21enum class ButtonPressDuration {
22 ShortPressing,
23 MiddlePressing,
24 LongPressing,
25};
26
27class WindowSystem {
28public:
29 explicit WindowSystem(Core::System& system);
30 ~WindowSystem();
31
32public:
33 void SetEventObserver(EventObserver* event_observer);
34 void Update();
35
36public:
37 void TrackApplet(std::shared_ptr<Applet> applet, bool is_application);
38 std::shared_ptr<Applet> GetByAppletResourceUserId(u64 aruid);
39 std::shared_ptr<Applet> GetMainApplet();
40
41public:
42 void RequestHomeMenuToGetForeground();
43 void RequestApplicationToGetForeground();
44 void RequestLockHomeMenuIntoForeground();
45 void RequestUnlockHomeMenuIntoForeground();
46 void RequestAppletVisibilityState(Applet& applet, bool visible);
47
48public:
49 void OnOperationModeChanged();
50 void OnExitRequested();
51 void OnHomeButtonPressed(ButtonPressDuration type);
52 void OnCaptureButtonPressed(ButtonPressDuration type) {}
53 void OnPowerButtonPressed(ButtonPressDuration type) {}
54
55private:
56 void PruneTerminatedAppletsLocked();
57 bool LockHomeMenuIntoForegroundLocked();
58 void TerminateChildAppletsLocked(Applet* applet);
59 void UpdateAppletStateLocked(Applet* applet, bool is_foreground);
60
61private:
62 // System reference.
63 Core::System& m_system;
64
65 // Event observer.
66 EventObserver* m_event_observer{};
67
68 // Lock.
69 std::mutex m_lock{};
70
71 // Home menu state.
72 bool m_home_menu_foreground_locked{};
73 Applet* m_foreground_requested_applet{};
74
75 // Foreground roots.
76 Applet* m_home_menu{};
77 Applet* m_application{};
78
79 // Applet map by aruid.
80 std::map<u64, std::shared_ptr<Applet>> m_applets{};
81};
82
83} // namespace Service::AM
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp
index 059ac3fc9..cb88486dd 100755
--- a/src/core/hle/service/glue/time/manager.cpp
+++ b/src/core/hle/service/glue/time/manager.cpp
@@ -51,16 +51,17 @@ s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
51} 51}
52 52
53s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) { 53s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) {
54 s32 year{2000};
55 set_sys->GetSettingsItemValueImpl(year, "time", "standard_user_clock_initial_year");
56
54 Service::PSC::Time::CalendarTime calendar{ 57 Service::PSC::Time::CalendarTime calendar{
55 .year = 2000, 58 .year = static_cast<s16>(year),
56 .month = 1, 59 .month = 1,
57 .day = 1, 60 .day = 1,
58 .hour = 0, 61 .hour = 0,
59 .minute = 0, 62 .minute = 0,
60 .second = 0, 63 .second = 0,
61 }; 64 };
62 set_sys->GetSettingsItemValueImpl<s16>(calendar.year, "time",
63 "standard_user_clock_initial_year");
64 return CalendarTimeToEpoch(calendar); 65 return CalendarTimeToEpoch(calendar);
65} 66}
66 67
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 4a2e2c56c..e6a5a0250 100755
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -23,11 +23,7 @@ void LoopProcess(Core::System& system) {
23 std::shared_ptr<ResourceManager> resource_manager = 23 std::shared_ptr<ResourceManager> resource_manager =
24 std::make_shared<ResourceManager>(system, firmware_settings); 24 std::make_shared<ResourceManager>(system, firmware_settings);
25 25
26 // TODO: Remove this hack when am is emulated properly.
27 resource_manager->Initialize(); 26 resource_manager->Initialize();
28 resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(),
29 true);
30 resource_manager->SetAruidValidForVibration(system.ApplicationProcess()->GetProcessId(), true);
31 27
32 server_manager->RegisterNamedService( 28 server_manager->RegisterNamedService(
33 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); 29 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
diff --git a/src/core/hle/service/os/process.cpp b/src/core/hle/service/os/process.cpp
new file mode 100755
index 000000000..0dbadc315
--- /dev/null
+++ b/src/core/hle/service/os/process.cpp
@@ -0,0 +1,152 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/svc_types.h"
8#include "core/hle/service/os/process.h"
9#include "core/loader/loader.h"
10
11namespace Service {
12
13Process::Process(Core::System& system)
14 : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
15 m_process_started() {}
16
17Process::~Process() {
18 this->Finalize();
19}
20
21bool Process::Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result) {
22 // First, ensure we are not holding another process.
23 this->Finalize();
24
25 // Create the process.
26 auto* const process = Kernel::KProcess::Create(m_system.Kernel());
27 Kernel::KProcess::Register(m_system.Kernel(), process);
28
29 // On exit, ensure we free the additional reference to the process.
30 SCOPE_EXIT {
31 process->Close();
32 };
33
34 // Insert process modules into memory.
35 const auto [load_result, load_parameters] = loader.Load(*process, m_system);
36 out_load_result = load_result;
37
38 // Ensure loading was successful.
39 if (load_result != Loader::ResultStatus::Success) {
40 return false;
41 }
42
43 // TODO: remove this, kernel already tracks this
44 m_system.Kernel().AppendNewProcess(process);
45
46 // Note the load parameters from NPDM.
47 m_main_thread_priority = load_parameters->main_thread_priority;
48 m_main_thread_stack_size = load_parameters->main_thread_stack_size;
49
50 // This process has not started yet.
51 m_process_started = false;
52
53 // Take ownership of the process object.
54 m_process = process;
55 m_process->Open();
56
57 // We succeeded.
58 return true;
59}
60
61void Process::Finalize() {
62 // Terminate, if we are currently holding a process.
63 this->Terminate();
64
65 // Close the process.
66 if (m_process) {
67 m_process->Close();
68
69 // TODO: remove this, kernel already tracks this
70 m_system.Kernel().RemoveProcess(m_process);
71 }
72
73 // Clean up.
74 m_process = nullptr;
75 m_main_thread_priority = 0;
76 m_main_thread_stack_size = 0;
77 m_process_started = false;
78}
79
80bool Process::Run() {
81 // If we already started the process, don't start again.
82 if (m_process_started) {
83 return false;
84 }
85
86 // Start.
87 if (m_process) {
88 m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
89 }
90
91 // Mark as started.
92 m_process_started = true;
93
94 // We succeeded.
95 return true;
96}
97
98void Process::Terminate() {
99 if (m_process) {
100 m_process->Terminate();
101 }
102}
103
104void Process::ResetSignal() {
105 if (m_process) {
106 m_process->Reset();
107 }
108}
109
110bool Process::IsRunning() const {
111 if (m_process) {
112 const auto state = m_process->GetState();
113 return state == Kernel::KProcess::State::Running ||
114 state == Kernel::KProcess::State::RunningAttached ||
115 state == Kernel::KProcess::State::DebugBreak;
116 }
117
118 return false;
119}
120
121bool Process::IsTerminated() const {
122 if (m_process) {
123 return m_process->IsTerminated();
124 }
125
126 return false;
127}
128
129u64 Process::GetProcessId() const {
130 if (m_process) {
131 return m_process->GetProcessId();
132 }
133
134 return 0;
135}
136
137u64 Process::GetProgramId() const {
138 if (m_process) {
139 return m_process->GetProgramId();
140 }
141
142 return 0;
143}
144
145void Process::Suspend(bool suspended) {
146 if (m_process) {
147 m_process->SetActivity(suspended ? Kernel::Svc::ProcessActivity::Paused
148 : Kernel::Svc::ProcessActivity::Runnable);
149 }
150}
151
152} // namespace Service
diff --git a/src/core/hle/service/os/process.h b/src/core/hle/service/os/process.h
new file mode 100755
index 000000000..9109b7d0a
--- /dev/null
+++ b/src/core/hle/service/os/process.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Core {
9class System;
10}
11
12namespace Loader {
13class AppLoader;
14enum class ResultStatus : u16;
15} // namespace Loader
16
17namespace Kernel {
18class KProcess;
19}
20
21namespace Service {
22
23class Process {
24public:
25 explicit Process(Core::System& system);
26 ~Process();
27
28 bool Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result);
29 void Finalize();
30
31 bool Run();
32 void Terminate();
33 void Suspend(bool suspended);
34 void ResetSignal();
35
36 bool IsInitialized() const {
37 return m_process != nullptr;
38 }
39
40 bool IsRunning() const;
41 bool IsTerminated() const;
42
43 u64 GetProcessId() const;
44 u64 GetProgramId() const;
45
46 Kernel::KProcess* GetHandle() const {
47 return m_process;
48 }
49
50private:
51 Core::System& m_system;
52 Kernel::KProcess* m_process{};
53 s32 m_main_thread_priority{};
54 u64 m_main_thread_stack_size{};
55 bool m_process_started{};
56};
57
58} // namespace Service
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 6c8540186..70e089902 100755
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1461,7 +1461,6 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1461 OnPauseGame(); 1461 OnPauseGame();
1462 } else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) { 1462 } else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) {
1463 auto_paused = false; 1463 auto_paused = false;
1464 RequestGameResume();
1465 OnStartGame(); 1464 OnStartGame();
1466 } 1465 }
1467 } 1466 }
@@ -1702,7 +1701,6 @@ void GMainWindow::OnPrepareForSleep(bool prepare_sleep) {
1702 } else { 1701 } else {
1703 if (!emu_thread->IsRunning() && auto_paused) { 1702 if (!emu_thread->IsRunning() && auto_paused) {
1704 auto_paused = false; 1703 auto_paused = false;
1705 RequestGameResume();
1706 OnStartGame(); 1704 OnStartGame();
1707 } 1705 }
1708 } 1706 }
@@ -3457,7 +3455,6 @@ void GMainWindow::OnPauseContinueGame() {
3457 if (emu_thread->IsRunning()) { 3455 if (emu_thread->IsRunning()) {
3458 OnPauseGame(); 3456 OnPauseGame();
3459 } else { 3457 } else {
3460 RequestGameResume();
3461 OnStartGame(); 3458 OnStartGame();
3462 } 3459 }
3463 } 3460 }
@@ -5013,10 +5010,6 @@ void GMainWindow::RequestGameExit() {
5013 system->GetAppletManager().RequestExit(); 5010 system->GetAppletManager().RequestExit();
5014} 5011}
5015 5012
5016void GMainWindow::RequestGameResume() {
5017 system->GetAppletManager().RequestResume();
5018}
5019
5020void GMainWindow::filterBarSetChecked(bool state) { 5013void GMainWindow::filterBarSetChecked(bool state) {
5021 ui->action_Show_Filter_Bar->setChecked(state); 5014 ui->action_Show_Filter_Bar->setChecked(state);
5022 emit(OnToggleFilterBar()); 5015 emit(OnToggleFilterBar());
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 697c38e57..1501c99bc 100755
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -310,7 +310,6 @@ private:
310 bool ConfirmChangeGame(); 310 bool ConfirmChangeGame();
311 bool ConfirmForceLockedExit(); 311 bool ConfirmForceLockedExit();
312 void RequestGameExit(); 312 void RequestGameExit();
313 void RequestGameResume();
314 void changeEvent(QEvent* event) override; 313 void changeEvent(QEvent* event) override;
315 void closeEvent(QCloseEvent* event) override; 314 void closeEvent(QCloseEvent* event) override;
316 315