Parcel.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Memory;
  3. using Ryujinx.Common.Utilities;
  4. using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
  5. using System;
  6. using System.Diagnostics;
  7. using System.Runtime.CompilerServices;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
  11. {
  12. sealed class Parcel : IDisposable
  13. {
  14. private readonly MemoryOwner<byte> _rawDataOwner;
  15. private Span<byte> Raw => _rawDataOwner.Span;
  16. private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0];
  17. private Span<byte> Payload => Raw.Slice((int)Header.PayloadOffset, (int)Header.PayloadSize);
  18. private Span<byte> Objects => Raw.Slice((int)Header.ObjectOffset, (int)Header.ObjectsSize);
  19. private int _payloadPosition;
  20. private int _objectPosition;
  21. private bool _isDisposed;
  22. public Parcel(ReadOnlySpan<byte> data)
  23. {
  24. _rawDataOwner = MemoryOwner<byte>.RentCopy(data);
  25. _payloadPosition = 0;
  26. _objectPosition = 0;
  27. }
  28. public Parcel(uint payloadSize, uint objectsSize)
  29. {
  30. uint headerSize = (uint)Unsafe.SizeOf<ParcelHeader>();
  31. _rawDataOwner = MemoryOwner<byte>.RentCleared(checked((int)BitUtils.AlignUp<uint>(headerSize + payloadSize + objectsSize, 4)));
  32. Header.PayloadSize = payloadSize;
  33. Header.ObjectsSize = objectsSize;
  34. Header.PayloadOffset = headerSize;
  35. Header.ObjectOffset = Header.PayloadOffset + Header.ObjectsSize;
  36. }
  37. public string ReadInterfaceToken()
  38. {
  39. // Ignore the policy flags
  40. #pragma warning disable IDE0059 // Remove unnecessary value assignment
  41. int strictPolicy = ReadInt32();
  42. #pragma warning restore IDE0059
  43. return ReadString16();
  44. }
  45. public string ReadString16()
  46. {
  47. int size = ReadInt32();
  48. if (size < 0)
  49. {
  50. return "";
  51. }
  52. ReadOnlySpan<byte> data = ReadInPlace((size + 1) * 2);
  53. // Return the unicode string without the last character (null terminator)
  54. return Encoding.Unicode.GetString(data[..(size * 2)]);
  55. }
  56. public int ReadInt32() => ReadUnmanagedType<int>();
  57. public uint ReadUInt32() => ReadUnmanagedType<uint>();
  58. public bool ReadBoolean() => ReadUnmanagedType<uint>() != 0;
  59. public long ReadInt64() => ReadUnmanagedType<long>();
  60. public ulong ReadUInt64() => ReadUnmanagedType<ulong>();
  61. public T ReadFlattenable<T>() where T : unmanaged, IFlattenable
  62. {
  63. long flattenableSize = ReadInt64();
  64. T result = new();
  65. Debug.Assert(flattenableSize == result.GetFlattenedSize());
  66. result.Unflatten(this);
  67. return result;
  68. }
  69. public T ReadUnmanagedType<T>() where T : unmanaged
  70. {
  71. ReadOnlySpan<byte> data = ReadInPlace(Unsafe.SizeOf<T>());
  72. return MemoryMarshal.Cast<byte, T>(data)[0];
  73. }
  74. public ReadOnlySpan<byte> ReadInPlace(int size)
  75. {
  76. ReadOnlySpan<byte> result = Payload.Slice(_payloadPosition, size);
  77. _payloadPosition += BitUtils.AlignUp(size, 4);
  78. return result;
  79. }
  80. [StructLayout(LayoutKind.Sequential, Size = 0x28)]
  81. private struct FlatBinderObject
  82. {
  83. public int Type;
  84. public int Flags;
  85. public long BinderId;
  86. public long Cookie;
  87. private byte _serviceNameStart;
  88. public Span<byte> ServiceName => MemoryMarshal.CreateSpan(ref _serviceNameStart, 0x8);
  89. }
  90. public void WriteObject<T>(T obj, string serviceName) where T : IBinder
  91. {
  92. FlatBinderObject flatBinderObject = new()
  93. {
  94. Type = 2,
  95. Flags = 0,
  96. BinderId = HOSBinderDriverServer.GetBinderId(obj),
  97. };
  98. Encoding.ASCII.GetBytes(serviceName).CopyTo(flatBinderObject.ServiceName);
  99. WriteUnmanagedType(ref flatBinderObject);
  100. // TODO: figure out what this value is
  101. Span<byte> fourBytes = stackalloc byte[4];
  102. WriteInplaceObject(fourBytes);
  103. }
  104. public AndroidStrongPointer<T> ReadStrongPointer<T>() where T : unmanaged, IFlattenable
  105. {
  106. bool hasObject = ReadBoolean();
  107. if (hasObject)
  108. {
  109. T obj = ReadFlattenable<T>();
  110. return new AndroidStrongPointer<T>(obj);
  111. }
  112. else
  113. {
  114. return new AndroidStrongPointer<T>();
  115. }
  116. }
  117. public void WriteStrongPointer<T>(ref AndroidStrongPointer<T> value) where T : unmanaged, IFlattenable
  118. {
  119. WriteBoolean(!value.IsNull);
  120. if (!value.IsNull)
  121. {
  122. WriteFlattenable<T>(ref value.Object);
  123. }
  124. }
  125. public void WriteFlattenable<T>(ref T value) where T : unmanaged, IFlattenable
  126. {
  127. WriteInt64(value.GetFlattenedSize());
  128. value.Flatten(this);
  129. }
  130. public void WriteStatus(Status status) => WriteUnmanagedType(ref status);
  131. public void WriteBoolean(bool value) => WriteUnmanagedType(ref value);
  132. public void WriteInt32(int value) => WriteUnmanagedType(ref value);
  133. public void WriteUInt32(uint value) => WriteUnmanagedType(ref value);
  134. public void WriteInt64(long value) => WriteUnmanagedType(ref value);
  135. public void WriteUInt64(ulong value) => WriteUnmanagedType(ref value);
  136. public void WriteUnmanagedSpan<T>(ReadOnlySpan<T> value) where T : unmanaged
  137. {
  138. WriteInplace(MemoryMarshal.Cast<T, byte>(value));
  139. }
  140. public void WriteUnmanagedType<T>(ref T value) where T : unmanaged
  141. {
  142. WriteInplace(SpanHelpers.AsByteSpan(ref value));
  143. }
  144. public void WriteInplace(ReadOnlySpan<byte> data)
  145. {
  146. Span<byte> result = Payload.Slice(_payloadPosition, data.Length);
  147. data.CopyTo(result);
  148. _payloadPosition += BitUtils.AlignUp(data.Length, 4);
  149. }
  150. public void WriteInplaceObject(ReadOnlySpan<byte> data)
  151. {
  152. Span<byte> result = Objects.Slice(_objectPosition, data.Length);
  153. data.CopyTo(result);
  154. _objectPosition += BitUtils.AlignUp(data.Length, 4);
  155. }
  156. private void UpdateHeader()
  157. {
  158. uint headerSize = (uint)Unsafe.SizeOf<ParcelHeader>();
  159. Header.PayloadSize = (uint)_payloadPosition;
  160. Header.ObjectsSize = (uint)_objectPosition;
  161. Header.PayloadOffset = headerSize;
  162. Header.ObjectOffset = Header.PayloadOffset + Header.PayloadSize;
  163. }
  164. public ReadOnlySpan<byte> Finish()
  165. {
  166. UpdateHeader();
  167. return Raw[..(int)(Header.PayloadSize + Header.ObjectsSize + Unsafe.SizeOf<ParcelHeader>())];
  168. }
  169. public void Dispose()
  170. {
  171. if (!_isDisposed)
  172. {
  173. _isDisposed = true;
  174. _rawDataOwner.Dispose();
  175. }
  176. }
  177. }
  178. }