ApplicationServiceServer.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Cpu;
  4. using Ryujinx.HLE.HOS.Kernel.Threading;
  5. using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
  6. using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
  7. using System.Collections.Generic;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace Ryujinx.HLE.HOS.Services.Account.Acc
  11. {
  12. class ApplicationServiceServer
  13. {
  14. readonly AccountServiceFlag _serviceFlag;
  15. public ApplicationServiceServer(AccountServiceFlag serviceFlag)
  16. {
  17. _serviceFlag = serviceFlag;
  18. }
  19. public ResultCode GetUserCountImpl(ServiceCtx context)
  20. {
  21. context.ResponseData.Write(context.Device.System.AccountManager.GetUserCount());
  22. return ResultCode.Success;
  23. }
  24. public ResultCode GetUserExistenceImpl(ServiceCtx context)
  25. {
  26. ResultCode resultCode = CheckUserId(context, out UserId userId);
  27. if (resultCode != ResultCode.Success)
  28. {
  29. return resultCode;
  30. }
  31. context.ResponseData.Write(context.Device.System.AccountManager.TryGetUser(userId, out _));
  32. return ResultCode.Success;
  33. }
  34. public ResultCode ListAllUsers(ServiceCtx context)
  35. {
  36. return WriteUserList(context, context.Device.System.AccountManager.GetAllUsers());
  37. }
  38. public ResultCode ListOpenUsers(ServiceCtx context)
  39. {
  40. return WriteUserList(context, context.Device.System.AccountManager.GetOpenedUsers());
  41. }
  42. private ResultCode WriteUserList(ServiceCtx context, IEnumerable<UserProfile> profiles)
  43. {
  44. if (context.Request.RecvListBuff.Count == 0)
  45. {
  46. return ResultCode.InvalidBuffer;
  47. }
  48. ulong outputPosition = context.Request.RecvListBuff[0].Position;
  49. ulong outputSize = context.Request.RecvListBuff[0].Size;
  50. MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
  51. ulong offset = 0;
  52. foreach (UserProfile userProfile in profiles)
  53. {
  54. if (offset + 0x10 > outputSize)
  55. {
  56. break;
  57. }
  58. context.Memory.Write(outputPosition + offset, userProfile.UserId.High);
  59. context.Memory.Write(outputPosition + offset + 8, userProfile.UserId.Low);
  60. offset += 0x10;
  61. }
  62. return ResultCode.Success;
  63. }
  64. public ResultCode GetLastOpenedUser(ServiceCtx context)
  65. {
  66. context.Device.System.AccountManager.LastOpenedUser.UserId.Write(context.ResponseData);
  67. return ResultCode.Success;
  68. }
  69. public ResultCode GetProfile(ServiceCtx context, out IProfile profile)
  70. {
  71. profile = default;
  72. ResultCode resultCode = CheckUserId(context, out UserId userId);
  73. if (resultCode != ResultCode.Success)
  74. {
  75. return resultCode;
  76. }
  77. if (!context.Device.System.AccountManager.TryGetUser(userId, out UserProfile userProfile))
  78. {
  79. Logger.Warning?.Print(LogClass.ServiceAcc, $"User 0x{userId} not found!");
  80. return ResultCode.UserNotFound;
  81. }
  82. profile = new IProfile(userProfile);
  83. // Doesn't occur in our case.
  84. // return ResultCode.NullObject;
  85. return ResultCode.Success;
  86. }
  87. public ResultCode IsUserRegistrationRequestPermitted(ServiceCtx context)
  88. {
  89. context.ResponseData.Write(_serviceFlag != AccountServiceFlag.Application);
  90. return ResultCode.Success;
  91. }
  92. public ResultCode TrySelectUserWithoutInteraction(ServiceCtx context)
  93. {
  94. if (context.Device.System.AccountManager.GetUserCount() < 1)
  95. {
  96. // Invalid UserId.
  97. UserId.Null.Write(context.ResponseData);
  98. return ResultCode.UserNotFound;
  99. }
  100. bool isNetworkServiceAccountRequired = context.RequestData.ReadBoolean();
  101. if (isNetworkServiceAccountRequired)
  102. {
  103. // NOTE: This checks something related to baas (online), and then return an invalid UserId if the check in baas returns an error code.
  104. // In our case, we can just log it for now.
  105. Logger.Stub?.PrintStub(LogClass.ServiceAcc, new { isNetworkServiceAccountRequired });
  106. }
  107. // NOTE: As we returned an invalid UserId if there is more than one user earlier, now we can return only the first one.
  108. context.Device.System.AccountManager.GetFirst().UserId.Write(context.ResponseData);
  109. return ResultCode.Success;
  110. }
  111. public ResultCode CheckNetworkServiceAvailabilityAsync(ServiceCtx context, out IAsyncContext asyncContext)
  112. {
  113. KEvent asyncEvent = new(context.Device.System.KernelContext);
  114. AsyncExecution asyncExecution = new(asyncEvent);
  115. asyncExecution.Initialize(1000, CheckNetworkServiceAvailabilityAsyncImpl);
  116. asyncContext = new IAsyncContext(asyncExecution);
  117. // return ResultCode.NullObject if the IAsyncContext pointer is null. Doesn't occur in our case.
  118. return ResultCode.Success;
  119. }
  120. private async Task CheckNetworkServiceAvailabilityAsyncImpl(CancellationToken token)
  121. {
  122. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  123. // TODO: Use a real function instead, with the CancellationToken.
  124. await Task.CompletedTask;
  125. }
  126. public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
  127. {
  128. ResultCode resultCode = CheckUserId(context, out UserId _);
  129. if (resultCode != ResultCode.Success)
  130. {
  131. return resultCode;
  132. }
  133. if (context.Request.SendBuff.Count == 0)
  134. {
  135. return ResultCode.InvalidBuffer;
  136. }
  137. ulong inputPosition = context.Request.SendBuff[0].Position;
  138. ulong inputSize = context.Request.SendBuff[0].Size;
  139. if (inputSize != 0x24000)
  140. {
  141. return ResultCode.InvalidBufferSize;
  142. }
  143. byte[] thumbnailBuffer = new byte[inputSize];
  144. context.Memory.Read(inputPosition, thumbnailBuffer);
  145. // NOTE: Account service call nn::fs::WriteSaveDataThumbnailFile().
  146. // TODO: Store thumbnailBuffer somewhere, in save data 0x8000000000000010 ?
  147. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  148. return ResultCode.Success;
  149. }
  150. public ResultCode ClearSaveDataThumbnail(ServiceCtx context)
  151. {
  152. ResultCode resultCode = CheckUserId(context, out UserId _);
  153. if (resultCode != ResultCode.Success)
  154. {
  155. return resultCode;
  156. }
  157. /*
  158. // NOTE: Doesn't occur in our case.
  159. if (userId == null)
  160. {
  161. return ResultCode.InvalidArgument;
  162. }
  163. */
  164. // NOTE: Account service call nn::fs::WriteSaveDataThumbnailFileHeader();
  165. // TODO: Clear the Thumbnail somewhere, in save data 0x8000000000000010 ?
  166. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  167. return ResultCode.Success;
  168. }
  169. public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
  170. {
  171. return WriteUserList(context, context.Device.System.AccountManager.GetStoredOpenedUsers());
  172. }
  173. public ResultCode ListQualifiedUsers(ServiceCtx context)
  174. {
  175. // TODO: Determine how users are "qualified". We assume all users are "qualified" for now.
  176. return WriteUserList(context, context.Device.System.AccountManager.GetAllUsers());
  177. }
  178. public ResultCode CheckUserId(ServiceCtx context, out UserId userId)
  179. {
  180. userId = context.RequestData.ReadStruct<UserId>();
  181. if (userId.IsNull)
  182. {
  183. return ResultCode.NullArgument;
  184. }
  185. return ResultCode.Success;
  186. }
  187. }
  188. }