HLE: Refactoring of ApplicationLoader (#4480)

* HLE: Refactoring of ApplicationLoader

* Fix SDL2 Headless

* Addresses gdkchan feedback

* Fixes LoadUnpackedNca RomFS loading

* remove useless casting

* Cleanup and fixe empty application name

* Remove ProcessInfo

* Fixes typo

* ActiveProcess to ActiveApplication

* Update check

* Clean using.

* Use the correct filepath when loading Homebrew.npdm

* Fix NRE in ProcessResult if MetaLoader is null

* Add more checks for valid processId & return success

* Add missing logging statement for npdm error

* Return result for LoadKip()

* Move error logging out of PFS load extension method

This avoids logging "Could not find Main NCA"
followed by "Loading main..." when trying to start hbl.

* Fix GUIs not checking load results

* Fix style and formatting issues

* Fix formatting and wording

* gtk: Refactor LoadApplication()

---------

Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
This commit is contained in:
Ac_K 2023-03-31 21:16:46 +02:00 committed by GitHub
parent 8198b99935
commit 4c2d9ff3ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1567 additions and 1322 deletions

View file

@ -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.Application.ControlData.Value.UserAccountSwitchLock);
context.ResponseData.Write((byte)context.Device.Processes.ActiveApplication.ApplicationControlProperties.UserAccountSwitchLock);
Logger.Stub?.PrintStub(LogClass.ServiceAcc);

View file

@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
public ILibraryAppletSelfAccessor(ServiceCtx context)
{
if (context.Device.Application.TitleId == 0x0100000000001009)
if (context.Device.Processes.ActiveApplication.ProgramId == 0x0100000000001009)
{
// Create MiiEdit data.
_appletStandalone = new AppletStandalone()
@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
}
else
{
throw new NotImplementedException($"{context.Device.Application.TitleId} applet is not implemented.");
throw new NotImplementedException($"{context.Device.Processes.ActiveApplication.ProgramId} applet is not implemented.");
}
}

View file

@ -115,28 +115,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid();
// Mask out the low nibble of the program ID to get the application ID
ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul);
ApplicationId applicationId = new ApplicationId(context.Device.Processes.ActiveApplication.ProgramId & ~0xFul);
BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
ref ApplicationControlProperty control = ref controlHolder.Value;
if (LibHac.Common.Utilities.IsZeros(controlHolder.ByteSpan))
{
// If the current application doesn't have a loaded control property, create a dummy one
// and set the savedata sizes so a user savedata will be created.
control = ref new BlitStruct<ApplicationControlProperty>(1).Value;
// The set sizes don't actually matter as long as they're non-zero because we use directory savedata.
control.UserAccountSaveDataSize = 0x4000;
control.UserAccountSaveDataJournalSize = 0x4000;
Logger.Warning?.Print(LogClass.ServiceAm,
"No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
}
ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
LibHac.HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in nacp, in userId);
context.ResponseData.Write(requiredSize);
@ -153,7 +137,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.Application.ControlData.Value.SupportedLanguageFlag;
int supportedLanguages = (int)context.Device.Processes.ActiveApplication.ApplicationControlProperties.SupportedLanguageFlag;
int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages);
if (firstSupported > (int)TitleLanguage.BrazilianPortuguese)
@ -196,7 +180,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.Application.ControlData.Value.DisplayVersion);
context.ResponseData.Write(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion);
return ResultCode.Success;
}
@ -251,13 +235,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
long journalSize = context.RequestData.ReadInt64();
// Mask out the low nibble of the program ID to get the application ID
ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul);
ApplicationId applicationId = new ApplicationId(context.Device.Processes.ActiveApplication.ProgramId & ~0xFul);
BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
LibHac.Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
out CacheStorageTargetMedia storageTarget, applicationId, in controlHolder.Value, index, saveSize,
journalSize);
out CacheStorageTargetMedia storageTarget, applicationId, in nacp, index, saveSize, journalSize);
if (result.IsFailure()) return (ResultCode)result.Value;
@ -677,7 +660,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
throw new InvalidSystemResourceException($"JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx#requirements for more information)");
}
context.Device.Application.LoadServiceNca(filePath);
context.Device.LoadNca(filePath);
// FIXME: Most likely not how this should be done?
while (!context.Device.System.SmRegistry.IsServiceRegistered("jit:u"))

View file

@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
return new ApplicationLaunchProperty
{
TitleId = context.Device.Application.TitleId,
TitleId = context.Device.Processes.ActiveApplication.ProgramId,
Version = 0x00,
BaseGameStorageId = (byte)StorageId.BuiltInSystem,
UpdateGameStorageId = (byte)StorageId.None

View file

@ -31,7 +31,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.Application.TitleId, out ApplicationAlbumEntry applicationAlbumEntry);
ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
context.ResponseData.WriteStruct(applicationAlbumEntry);
@ -60,7 +60,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.Application.TitleId, out ApplicationAlbumEntry applicationAlbumEntry);
ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
context.ResponseData.WriteStruct(applicationAlbumEntry);
@ -88,7 +88,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.Application.TitleId, out ApplicationAlbumEntry applicationAlbumEntry);
ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
context.ResponseData.WriteStruct(applicationAlbumEntry);

View file

@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Services.Fatal
errorReport.AppendLine();
errorReport.AppendLine("ErrorReport log:");
errorReport.AppendLine($"\tTitleId: {context.Device.Application.TitleId:x16}");
errorReport.AppendLine($"\tTitleId: {context.Device.Processes.ActiveApplication.ProgramIdText}");
errorReport.AppendLine($"\tPid: {pid}");
errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}");
errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}");
@ -64,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Fatal
{
errorReport.AppendLine("CPU Context:");
if (context.Device.Application.TitleIs64Bit)
if (context.Device.Processes.ActiveApplication.Is64Bit)
{
CpuContext64 cpuContext64 = MemoryMarshal.Cast<byte, CpuContext64>(cpuContext)[0];

View file

@ -334,7 +334,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
}
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented.
ApplicationControlProperty controlProperty = context.Device.Application.ControlData.Value;
ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
/*

View file

@ -808,7 +808,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{
byte programIndex = context.RequestData.ReadByte();
if ((context.Device.Application.TitleId & 0xf) != programIndex)
if ((context.Device.Processes.ActiveApplication.ProgramId & 0xf) != programIndex)
{
throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex}).");
}

View file

@ -48,7 +48,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.Application.TitleId);
return CountAddOnContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(3)]
@ -59,7 +59,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.Application.TitleId);
return ListAddContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(4)] // 1.0.0-6.2.0
@ -79,7 +79,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.Application.TitleId);
return GetAddOnContentBaseIdImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(6)] // 1.0.0-6.2.0
@ -99,7 +99,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.Application.TitleId);
return PrepareAddOnContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(8)] // 4.0.0+
@ -128,7 +128,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.Application.TitleId);
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.ActiveApplication.ProgramId);
if (resultCode != ResultCode.Success)
{
@ -294,7 +294,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.Application.ControlData.Value.AddOnContentBaseId;
_addOnContentBaseId = context.Device.Processes.ActiveApplication.ApplicationControlProperties.AddOnContentBaseId;
if (_addOnContentBaseId == 0)
{
@ -308,7 +308,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
{
uint index = context.RequestData.ReadUInt32();
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.ActiveApplication.ProgramId);
if (resultCode != ResultCode.Success)
{

View file

@ -1,4 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Ns
using LibHac.Ns;
using Ryujinx.Common.Utilities;
using System;
namespace Ryujinx.HLE.HOS.Services.Ns
{
[Service("ns:am")]
class IApplicationManagerInterface : IpcService
@ -14,9 +18,9 @@
ulong position = context.Request.ReceiveBuff[0].Position;
byte[] nacpData = context.Device.Application.ControlData.ByteSpan.ToArray();
ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
context.Memory.Write(position, nacpData);
context.Memory.Write(position, SpanHelpers.AsByteSpan(ref nacp).ToArray());
return ResultCode.Success;
}

View file

@ -1,4 +1,7 @@
namespace Ryujinx.HLE.HOS.Services.Ns
using LibHac.Common;
using LibHac.Ns;
namespace Ryujinx.HLE.HOS.Services.Ns
{
class IReadOnlyApplicationControlDataInterface : IpcService
{
@ -13,9 +16,9 @@
ulong position = context.Request.ReceiveBuff[0].Position;
byte[] nacpData = context.Device.Application.ControlData.ByteSpan.ToArray();
ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
context.Memory.Write(position, nacpData);
context.Memory.Write(position, SpanHelpers.AsByteSpan(ref nacp).ToArray());
return ResultCode.Success;
}

View file

@ -56,8 +56,8 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
_titleId = titleId;
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields.
_ratingAge = Array.ConvertAll(context.Device.Application.ControlData.Value.RatingAge.ItemsRo.ToArray(), Convert.ToInt32);
_parentalControlFlag = context.Device.Application.ControlData.Value.ParentalControlFlag;
_ratingAge = Array.ConvertAll(context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge.ItemsRo.ToArray(), Convert.ToInt32);
_parentalControlFlag = context.Device.Processes.ActiveApplication.ApplicationControlProperties.ParentalControlFlag;
}
}

View file

@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
{
@ -16,8 +15,6 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
{
ref readonly var controlProperty = ref context.Device.Application.ControlData.Value;
ulong inputPosition = context.Request.SendBuff[0].Position;
ulong inputSize = context.Request.SendBuff[0].Size;
@ -34,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
}
}
PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)controlProperty.PlayLogQueryCapability;
PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryCapability;
List<ulong> titleIds = new List<ulong>();
@ -48,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
// Check if input title ids are in the whitelist.
foreach (ulong titleId in titleIds)
{
if (!controlProperty.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId))
if (!context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId))
{
return (ResultCode)Am.ResultCode.ObjectInvalid;
}