ApplicationServiceServer.cs 7.2 KB

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