Parcel.cs 6.7 KB

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