From 3ebb6ace44e98e4c67a39ff997e17dd5acac8fa0 Mon Sep 17 00:00:00 2001
From: Mary <mary@mary.zone>
Date: Mon, 8 May 2023 15:09:02 +0200
Subject: [PATCH] memory: Add Android support

---
 src/Ryujinx.Memory/MemoryBlock.cs             |  2 +-
 src/Ryujinx.Memory/MemoryManagement.cs        | 24 +++++++++----------
 src/Ryujinx.Memory/MemoryManagementUnix.cs    | 17 +++++++++++++
 src/Ryujinx.Memory/MemoryManagerUnixHelper.cs |  9 ++++---
 4 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/src/Ryujinx.Memory/MemoryBlock.cs b/src/Ryujinx.Memory/MemoryBlock.cs
index 7fe7862a9..a715a9376 100644
--- a/src/Ryujinx.Memory/MemoryBlock.cs
+++ b/src/Ryujinx.Memory/MemoryBlock.cs
@@ -426,7 +426,7 @@ namespace Ryujinx.Memory
                     return OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134);
                 }
 
-                return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS();
+                return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid();
             }
 
             return true;
diff --git a/src/Ryujinx.Memory/MemoryManagement.cs b/src/Ryujinx.Memory/MemoryManagement.cs
index 860d3f368..436a23272 100644
--- a/src/Ryujinx.Memory/MemoryManagement.cs
+++ b/src/Ryujinx.Memory/MemoryManagement.cs
@@ -10,7 +10,7 @@ namespace Ryujinx.Memory
             {
                 return MemoryManagementWindows.Allocate((IntPtr)size);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 return MemoryManagementUnix.Allocate(size, forJit);
             }
@@ -26,7 +26,7 @@ namespace Ryujinx.Memory
             {
                 return MemoryManagementWindows.Reserve((IntPtr)size, viewCompatible);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 return MemoryManagementUnix.Reserve(size, forJit);
             }
@@ -42,7 +42,7 @@ namespace Ryujinx.Memory
             {
                 MemoryManagementWindows.Commit(address, (IntPtr)size);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 MemoryManagementUnix.Commit(address, size, forJit);
             }
@@ -58,7 +58,7 @@ namespace Ryujinx.Memory
             {
                 MemoryManagementWindows.Decommit(address, (IntPtr)size);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 MemoryManagementUnix.Decommit(address, size);
             }
@@ -74,7 +74,7 @@ namespace Ryujinx.Memory
             {
                 MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 MemoryManagementUnix.MapView(sharedMemory, srcOffset, address, size);
             }
@@ -90,7 +90,7 @@ namespace Ryujinx.Memory
             {
                 MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 MemoryManagementUnix.UnmapView(address, size);
             }
@@ -108,7 +108,7 @@ namespace Ryujinx.Memory
             {
                 result = MemoryManagementWindows.Reprotect(address, (IntPtr)size, permission, forView);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 result = MemoryManagementUnix.Reprotect(address, size, permission);
             }
@@ -129,7 +129,7 @@ namespace Ryujinx.Memory
             {
                 return MemoryManagementWindows.Free(address, (IntPtr)size);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 return MemoryManagementUnix.Free(address);
             }
@@ -145,7 +145,7 @@ namespace Ryujinx.Memory
             {
                 return MemoryManagementWindows.CreateSharedMemory((IntPtr)size, reserve);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 return MemoryManagementUnix.CreateSharedMemory(size, reserve);
             }
@@ -161,7 +161,7 @@ namespace Ryujinx.Memory
             {
                 MemoryManagementWindows.DestroySharedMemory(handle);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 MemoryManagementUnix.DestroySharedMemory(handle);
             }
@@ -177,7 +177,7 @@ namespace Ryujinx.Memory
             {
                 return MemoryManagementWindows.MapSharedMemory(handle);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 return MemoryManagementUnix.MapSharedMemory(handle, size);
             }
@@ -193,7 +193,7 @@ namespace Ryujinx.Memory
             {
                 MemoryManagementWindows.UnmapSharedMemory(address);
             }
-            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid())
             {
                 MemoryManagementUnix.UnmapSharedMemory(address, size);
             }
diff --git a/src/Ryujinx.Memory/MemoryManagementUnix.cs b/src/Ryujinx.Memory/MemoryManagementUnix.cs
index e132dbbb8..fc4508c2c 100644
--- a/src/Ryujinx.Memory/MemoryManagementUnix.cs
+++ b/src/Ryujinx.Memory/MemoryManagementUnix.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Memory
 {
     [SupportedOSPlatform("linux")]
     [SupportedOSPlatform("macos")]
+    [SupportedOSPlatform("android")]
     static class MemoryManagementUnix
     {
         private static readonly ConcurrentDictionary<IntPtr, ulong> _allocations = new();
@@ -156,6 +157,22 @@ namespace Ryujinx.Memory
                     }
                 }
             }
+            else if (OperatingSystem.IsAndroid())
+            {
+                byte[] memName = Encoding.ASCII.GetBytes("Ryujinx-XXXXXX");
+
+                fixed (byte* pMemName = memName)
+                {
+                    fd = ASharedMemory_create((IntPtr)pMemName, (nuint)size);
+                    if (fd <= 0)
+                    {
+                        throw new OutOfMemoryException();
+                    }
+                }
+
+                // ASharedMemory_create handle ftruncate for us.
+                return (IntPtr)fd;
+            }
             else
             {
                 byte[] fileName = "/dev/shm/Ryujinx-XXXXXX"u8.ToArray();
diff --git a/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs b/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs
index 43888c85b..f9b4f6c4c 100644
--- a/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs
+++ b/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs
@@ -89,6 +89,9 @@ namespace Ryujinx.Memory
         [LibraryImport("libc", SetLastError = true)]
         public static partial int shm_unlink(IntPtr name);
 
+        [DllImport("android")]
+        internal static extern int ASharedMemory_create(IntPtr name, nuint size);
+
         private static int MmapFlagsToSystemFlags(MmapFlags flags)
         {
             int result = 0;
@@ -110,7 +113,7 @@ namespace Ryujinx.Memory
 
             if (flags.HasFlag(MmapFlags.MAP_ANONYMOUS))
             {
-                if (OperatingSystem.IsLinux())
+                if (OperatingSystem.IsLinux() || OperatingSystem.IsAndroid())
                 {
                     result |= MAP_ANONYMOUS_LINUX_GENERIC;
                 }
@@ -126,7 +129,7 @@ namespace Ryujinx.Memory
 
             if (flags.HasFlag(MmapFlags.MAP_NORESERVE))
             {
-                if (OperatingSystem.IsLinux())
+                if (OperatingSystem.IsLinux() || OperatingSystem.IsAndroid())
                 {
                     result |= MAP_NORESERVE_LINUX_GENERIC;
                 }
@@ -142,7 +145,7 @@ namespace Ryujinx.Memory
 
             if (flags.HasFlag(MmapFlags.MAP_UNLOCKED))
             {
-                if (OperatingSystem.IsLinux())
+                if (OperatingSystem.IsLinux() || OperatingSystem.IsAndroid())
                 {
                     result |= MAP_UNLOCKED_LINUX_GENERIC;
                 }