From 636b398d8ed8f2de6a192e5256c069c4baea70cb Mon Sep 17 00:00:00 2001 From: Babib3l Date: Fri, 15 May 2026 15:46:26 +0200 Subject: [PATCH] hle: add process identity metadata for application services Introduce explicit process identity metadata for loaded programs and expose PID-based lookup helpers from the process loader. This lets HLE services resolve title metadata from the calling process instead of relying on the global active application. Also log disk cache initialization with PID, title ID, display version, selector, and enabled state so cache ownership is visible. --- .../HOS/ArmProcessContextFactory.cs | 8 ++++- .../Acc/IAccountServiceForApplication.cs | 2 +- .../ILibraryAppletSelfAccessor.cs | 6 ++-- .../ApplicationProxy/IApplicationFunctions.cs | 14 ++++---- .../Services/Arp/ApplicationLaunchProperty.cs | 2 +- .../Caps/IScreenShotApplicationService.cs | 6 ++-- .../HOS/Services/Fatal/IService.cs | 5 +-- .../HOS/Services/Fs/IFileSystemProxy.cs | 2 +- .../IUserLocalCommunicationService.cs | 10 +++--- .../Services/Ns/Aoc/IAddOnContentManager.cs | 14 ++++---- .../Ns/IApplicationManagerInterface.cs | 2 +- ...ReadOnlyApplicationControlDataInterface.cs | 2 +- .../IParentalControlService.cs | 7 ++-- .../QueryPlayStatisticsManager.cs | 5 +-- .../Loaders/Processes/ProcessIdentity.cs | 34 +++++++++++++++++++ .../Loaders/Processes/ProcessKind.cs | 12 +++++++ .../Loaders/Processes/ProcessLoader.cs | 17 ++++++++++ .../Loaders/Processes/ProcessLoaderHelper.cs | 1 + 18 files changed, 113 insertions(+), 36 deletions(-) create mode 100644 src/Ryujinx.HLE/Loaders/Processes/ProcessIdentity.cs create mode 100644 src/Ryujinx.HLE/Loaders/Processes/ProcessKind.cs diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index 28f7ef25f..49d4587ae 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -118,7 +118,13 @@ namespace Ryujinx.HLE.HOS } } - DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize, _diskCacheSelector ?? "default"); + string cacheSelector = _diskCacheSelector ?? "default"; + + Logger.Info?.Print( + LogClass.Ptc, + $"Initializing disk cache for pid {pid}, title {_titleIdText}, version '{_displayVersion}', selector '{cacheSelector}', enabled={_diskCacheEnabled}."); + + DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize, cacheSelector); return processContext; } diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs index 98af10694..05d7384e7 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs @@ -190,7 +190,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc // TODO: Account actually calls nn::arp::detail::IReader::GetApplicationControlProperty() with the current Pid and store the result (NACP file) internally. // But since we use LibHac and we load one Application at a time, it's not necessary. - context.ResponseData.Write((byte)context.Device.Processes.ActiveApplication.ApplicationControlProperties.UserAccountSwitchLock); + context.ResponseData.Write((byte)context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties.UserAccountSwitchLock); Logger.Stub?.PrintStub(LogClass.ServiceAcc); diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs index fa986de93..4216d2d12 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs @@ -10,7 +10,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib public ILibraryAppletSelfAccessor(ServiceCtx context) { - if (context.Device.Processes.ActiveApplication.ProgramId == 0x0100000000001009) + ulong programId = context.Device.Processes.GetProcess(context.Process.Pid).ProgramId; + + if (programId == 0x0100000000001009) { // Create MiiEdit data. _appletStandalone = new AppletStandalone() @@ -26,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib } else { - throw new NotImplementedException($"{context.Device.Processes.ActiveApplication.ProgramId} applet is not implemented."); + throw new NotImplementedException($"{programId} applet is not implemented."); } } diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 9986bf824..2bc064a33 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -115,11 +115,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati public ResultCode EnsureSaveData(ServiceCtx context) { Uid userId = context.RequestData.ReadStruct().ToLibHacUid(); + var process = context.Device.Processes.GetProcess(context.Process.Pid); // Mask out the low nibble of the program ID to get the application ID - ApplicationId applicationId = new(context.Device.Processes.ActiveApplication.ProgramId & ~0xFul); + ApplicationId applicationId = new(process.Identity.ApplicationId); - ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty nacp = process.ApplicationControlProperties; LibHac.HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient; LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in nacp, in userId); @@ -139,7 +140,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati // TODO: When above calls are implemented, switch to using ns:am long desiredLanguageCode = context.Device.System.State.DesiredLanguageCode; - int supportedLanguages = (int)context.Device.Processes.ActiveApplication.ApplicationControlProperties.SupportedLanguageFlag; + int supportedLanguages = (int)context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties.SupportedLanguageFlag; int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages); if (firstSupported > (int)TitleLanguage.BrazilianPortuguese) @@ -182,7 +183,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati public ResultCode GetDisplayVersion(ServiceCtx context) { // If an NACP isn't found, the buffer will be all '\0' which seems to be the correct implementation. - context.ResponseData.Write(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion); + context.ResponseData.Write(context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties.DisplayVersion); return ResultCode.Success; } @@ -235,11 +236,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati ushort index = (ushort)context.RequestData.ReadUInt64(); long saveSize = context.RequestData.ReadInt64(); long journalSize = context.RequestData.ReadInt64(); + var process = context.Device.Processes.GetProcess(context.Process.Pid); // Mask out the low nibble of the program ID to get the application ID - ApplicationId applicationId = new(context.Device.Processes.ActiveApplication.ProgramId & ~0xFul); + ApplicationId applicationId = new(process.Identity.ApplicationId); - ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty nacp = process.ApplicationControlProperties; LibHac.Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize, out CacheStorageTargetMedia storageTarget, applicationId, in nacp, index, saveSize, journalSize); diff --git a/src/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs b/src/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs index 26089bddb..ac91b2959 100644 --- a/src/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs +++ b/src/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs @@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp return new ApplicationLaunchProperty { - TitleId = context.Device.Processes.ActiveApplication.ProgramId, + TitleId = context.Device.Processes.GetProcess(context.Process.Pid).ProgramId, Version = 0x00, BaseGameStorageId = (byte)StorageId.BuiltInSystem, UpdateGameStorageId = (byte)StorageId.None, diff --git a/src/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs b/src/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs index 2ccb7c598..f12cf0ea4 100644 --- a/src/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs @@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray(); - ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry); + ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.GetProcess(context.Process.Pid).ProgramId, out ApplicationAlbumEntry applicationAlbumEntry); context.ResponseData.WriteStruct(applicationAlbumEntry); @@ -98,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray(); - ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry); + ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.GetProcess(context.Process.Pid).ProgramId, out ApplicationAlbumEntry applicationAlbumEntry); context.ResponseData.WriteStruct(applicationAlbumEntry); @@ -143,7 +143,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray(); - ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry); + ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.GetProcess(context.Process.Pid).ProgramId, out ApplicationAlbumEntry applicationAlbumEntry); context.ResponseData.WriteStruct(applicationAlbumEntry); diff --git a/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs b/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs index c3ed92ed0..3c5526db4 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fatal/IService.cs @@ -50,12 +50,13 @@ namespace Ryujinx.HLE.HOS.Services.Fatal private ResultCode ThrowFatalWithCpuContextImpl(ServiceCtx context, ResultCode resultCode, ulong pid, FatalPolicy fatalPolicy, ReadOnlySpan cpuContext) { + var process = context.Device.Processes.GetProcess(pid); StringBuilder errorReport = new(); errorReport.AppendLine(); errorReport.AppendLine("ErrorReport log:"); - errorReport.AppendLine($"\tTitleId: {context.Device.Processes.ActiveApplication.ProgramIdText}"); + errorReport.AppendLine($"\tTitleId: {process.ProgramIdText}"); errorReport.AppendLine($"\tPid: {pid}"); errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}"); errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}"); @@ -64,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Fatal { errorReport.AppendLine("CPU Context:"); - if (context.Device.Processes.ActiveApplication.Is64Bit) + if (process.Is64Bit) { CpuContext64 cpuContext64 = MemoryMarshal.Cast(cpuContext)[0]; diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs index 08ede2b5b..40042af69 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -885,7 +885,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs { byte programIndex = context.RequestData.ReadByte(); - if ((context.Device.Processes.ActiveApplication.ProgramId & 0xf) != programIndex) + if (context.Device.Processes.GetProcess(context.Process.Pid).Identity.ProgramIndex != programIndex) { throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex})."); } diff --git a/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs b/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs index 2f764e99f..699fe1f66 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs @@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator private bool CheckLocalCommunicationIdPermission(ServiceCtx context, ulong localCommunicationIdChecked) { // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty controlProperty = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties; foreach (ulong localCommunicationId in controlProperty.LocalCommunicationId) { @@ -438,7 +438,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator if (scanFilter.NetworkId.IntentId.LocalCommunicationId == -1 && NetworkClient.NeedsRealId) { // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty controlProperty = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties; scanFilter.NetworkId.IntentId.LocalCommunicationId = (long)controlProperty.LocalCommunicationId[0]; } @@ -613,7 +613,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator if (networkConfig.IntentId.LocalCommunicationId == -1 && NetworkClient.NeedsRealId) { // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty controlProperty = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties; networkConfig.IntentId.LocalCommunicationId = (long)controlProperty.LocalCommunicationId[0]; } @@ -948,7 +948,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator if (networkInfo.NetworkId.IntentId.LocalCommunicationId == -1 && NetworkClient.NeedsRealId) { // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty controlProperty = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties; networkInfo.NetworkId.IntentId.LocalCommunicationId = (long)controlProperty.LocalCommunicationId[0]; } @@ -1208,7 +1208,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator } // TODO: Call nn::arp::GetApplicationLaunchProperty here when implemented. - NetworkClient.SetGameVersion(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion); + NetworkClient.SetGameVersion(context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties.DisplayVersion); resultCode = ResultCode.Success; _nifmResultCode = resultCode; diff --git a/src/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs b/src/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs index c77358803..4801c7150 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs @@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc // NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId. - return CountAddOnContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId); + return CountAddOnContentImpl(context, context.Device.Processes.GetProcess(pid).ProgramId); } [CommandCmif(3)] @@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc // NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId. - return ListAddContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId); + return ListAddContentImpl(context, context.Device.Processes.GetProcess(pid).ProgramId); } [CommandCmif(4)] // 1.0.0-6.2.0 @@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc // NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId. - return GetAddOnContentBaseIdImpl(context, context.Device.Processes.ActiveApplication.ProgramId); + return GetAddOnContentBaseIdImpl(context, context.Device.Processes.GetProcess(pid).ProgramId); } [CommandCmif(6)] // 1.0.0-6.2.0 @@ -107,7 +107,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc // NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId. - return PrepareAddOnContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId); + return PrepareAddOnContentImpl(context, context.Device.Processes.GetProcess(pid).ProgramId); } [CommandCmif(8)] // 4.0.0+ @@ -138,7 +138,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc // NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId. // TODO: Found where stored value is used. - ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.ActiveApplication.ProgramId); + ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.GetProcess(pid).ProgramId); if (resultCode != ResultCode.Success) { @@ -310,7 +310,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc // NOTE: Service calls arp:r GetApplicationControlProperty to get AddOnContentBaseId using TitleId, // If the call fails, it returns ResultCode.InvalidPid. - _addOnContentBaseId = context.Device.Processes.ActiveApplication.ApplicationControlProperties.AddOnContentBaseId; + _addOnContentBaseId = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties.AddOnContentBaseId; if (_addOnContentBaseId == 0) { @@ -324,7 +324,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc { uint index = context.RequestData.ReadUInt32(); - ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.ActiveApplication.ProgramId); + ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, titleId); if (resultCode != ResultCode.Success) { diff --git a/src/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs b/src/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs index f510da594..83dcb86af 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs @@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns ulong position = context.Request.ReceiveBuff[0].Position; - ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty nacp = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties; context.Memory.Write(position, SpanHelpers.AsByteSpan(ref nacp).ToArray()); diff --git a/src/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs b/src/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs index ca7d42b48..1714d4729 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns ulong position = context.Request.ReceiveBuff[0].Position; - ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties; + ApplicationControlProperty nacp = context.Device.Processes.GetProcess(context.Process.Pid).ApplicationControlProperties; context.Memory.Write(position, SpanHelpers.AsByteSpan(ref nacp).ToArray()); diff --git a/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs b/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs index c36482e41..392225812 100644 --- a/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs @@ -53,16 +53,17 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory if (titleId != 0) { _titleId = titleId; + var process = context.Device.Processes.GetProcess(_pid); // TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields. - _ratingAge = new int[context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge.Length]; + _ratingAge = new int[process.ApplicationControlProperties.RatingAge.Length]; for (int i = 0; i < _ratingAge.Length; i++) { - _ratingAge[i] = Convert.ToInt32(context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge[i]); + _ratingAge[i] = Convert.ToInt32(process.ApplicationControlProperties.RatingAge[i]); } - _parentalControlFlag = context.Device.Processes.ActiveApplication.ApplicationControlProperties.ParentalControlFlag; + _parentalControlFlag = process.ApplicationControlProperties.ParentalControlFlag; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs b/src/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs index b34ff0476..0b05810fa 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs @@ -31,7 +31,8 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService } } - PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryCapability; + var process = context.Device.Processes.GetProcess(context.Process.Pid); + PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)process.ApplicationControlProperties.PlayLogQueryCapability; List titleIds = []; @@ -45,7 +46,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService // Check if input title ids are in the whitelist. foreach (ulong titleId in titleIds) { - if (!context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryableApplicationId.AsReadOnlySpan().Contains(titleId)) + if (!process.ApplicationControlProperties.PlayLogQueryableApplicationId.AsReadOnlySpan().Contains(titleId)) { return (ResultCode)Am.ResultCode.ObjectInvalid; } diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessIdentity.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessIdentity.cs new file mode 100644 index 000000000..051e9a18f --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessIdentity.cs @@ -0,0 +1,34 @@ +namespace Ryujinx.HLE.Loaders.Processes +{ + public readonly struct ProcessIdentity + { + public ulong ProcessId { get; } + public ulong ProgramId { get; } + public ulong ApplicationId { get; } + public byte ProgramIndex { get; } + public string ProgramIdText { get; } + public string DisplayVersion { get; } + public ProcessKind Kind { get; } + + public ProcessIdentity( + ulong processId, + ulong programId, + byte programIndex, + string displayVersion, + ProcessKind kind) + { + ProcessId = processId; + ProgramId = programId; + ProgramIndex = programIndex; + ApplicationId = programId & ~0xFul; + ProgramIdText = $"{programId:x16}"; + DisplayVersion = displayVersion ?? string.Empty; + Kind = kind; + } + + public override string ToString() + { + return $"{Kind} pid={ProcessId} program={ProgramIdText} application={ApplicationId:x16} index={ProgramIndex} version={DisplayVersion}"; + } + } +} diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessKind.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessKind.cs new file mode 100644 index 000000000..eda7c9e86 --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessKind.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.Loaders.Processes +{ + public enum ProcessKind + { + Unknown, + Application, + SystemApplication, + SystemApplet, + LibraryApplet, + Homebrew, + } +} diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index f217ecd0b..f32dc651d 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -93,6 +93,23 @@ namespace Ryujinx.HLE.Loaders.Processes _processesByPid = new ConcurrentDictionary(); } + public bool TryGetProcess(ulong pid, out ProcessResult process) + { + return _processesByPid.TryGetValue(pid, out process); + } + + public ProcessResult GetProcess(ulong pid) + { + if (_processesByPid.TryGetValue(pid, out ProcessResult process)) + { + return process; + } + + Logger.Warning?.Print(LogClass.Loader, $"Process metadata for pid {pid} was not found. Falling back to active application metadata."); + + return ActiveApplication; + } + public bool LoadXci(string path, ulong applicationId) { FileStream stream = new(path, FileMode.Open, FileAccess.Read); diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs index afd8ebffc..f22dfd1dd 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs @@ -436,6 +436,7 @@ namespace Ryujinx.HLE.Loaders.Processes allowCodeMemoryForJit, processContextFactory.DiskCacheLoadState, process.Pid, + programIndex, meta.MainThreadPriority, meta.MainThreadStackSize, device.System.State.DesiredTitleLanguage);