From 1d472e6f4c9514d1cbecf61e2622aa2ae4670f50 Mon Sep 17 00:00:00 2001
From: Jonathan Peppers <jonathan.peppers@microsoft.com>
Date: Wed, 14 Jun 2023 11:34:24 -0500
Subject: [PATCH] [Xamarin.Android.Build.Tasks] <GenerateJavaStubs/> should
 open readonly in some cases

I was investigating a failure building Android projects in `Release`
mode inside VS Mac:

    Task "GenerateJavaStubs"
        Failed to read '/usr/local/share/dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm/8.0.0-preview.5.23280.8/runtimes/android-arm/lib/net8.0/Microsoft.CSharp.dll' with debugging symbols. Retrying to load it without it. Error details are logged below.
        System.UnauthorizedAccessException: Access to the path '/usr/local/share/dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm/8.0.0-preview.5.23280.8/runtimes/android-arm/lib/net8.0/Microsoft.CSharp.dll' is denied.
        ---> System.IO.IOException: Permission denied
        --- End of inner exception stack trace ---
        at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
        at Interop.CheckIo(Error error, String path, Boolean isDirError)
        at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Func`4 createOpenException)
        at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
        at Mono.Cecil.ModuleDefinition.ReadModule(String fileName, ReaderParameters parameters) in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/cecil/Mono.Cecil/ModuleDefinition.cs:line 1103
        at Java.Interop.Tools.Cecil.DirectoryAssemblyResolver.LoadFromMemoryMappedFile(String file, ReaderParameters options) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs:line 184
        at Java.Interop.Tools.Cecil.DirectoryAssemblyResolver.ReadAssembly(String file) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs:line 169
        /usr/local/share/dotnet/packs/Microsoft.Android.Sdk.Darwin/34.0.0-preview.5.312/tools/Xamarin.Android.Common.targets(1513,3): error XA0009: Error while loading assembly: '/usr/local/share/dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm/8.0.0-preview.5.23280.8/runtimes/android-arm/lib/net8.0/Microsoft.CSharp.dll'.
    Done executing task "GenerateJavaStubs" -- FAILED.

I noticed `DirectoryAssemblyResolver.LoadFromMemoryMappedFile()` was
not opening the file in read-only mode for `Debug` builds.

In 8bc7a3e8, we added "marshal methods" support that unconditionally
enables `ReaderParameters.ReadWrite`.

We should be able to toggle these settings only when "marshal methods"
is enabled:

    var readerParams = new ReaderParameters();
    if (useMarshalMethods) {
        readerParams.ReadWrite = true;
        readerParams.InMemory = true;
    }

This should improve performance for `Debug` builds, and avoid opening
files in read/write mode.
---
 .../Tasks/GenerateJavaStubs.cs                   | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
index 69584ae7893..04286ff5d77 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
@@ -100,10 +100,11 @@ public class GenerateJavaStubs : AndroidTask
 		public override bool RunTask ()
 		{
 			try {
+				bool useMarshalMethods = !Debug && EnableMarshalMethods;
 				// We're going to do 3 steps here instead of separate tasks so
 				// we can share the list of JLO TypeDefinitions between them
-				using (DirectoryAssemblyResolver res = MakeResolver ()) {
-					Run (res, useMarshalMethods: !Debug && EnableMarshalMethods);
+				using (DirectoryAssemblyResolver res = MakeResolver (useMarshalMethods)) {
+					Run (res, useMarshalMethods);
 				}
 			} catch (XamarinAndroidException e) {
 				Log.LogCodedError (string.Format ("XA{0:0000}", e.Code), e.MessageWithoutCode);
@@ -121,12 +122,13 @@ public override bool RunTask ()
 			return !Log.HasLoggedErrors;
 		}
 
-		DirectoryAssemblyResolver MakeResolver ()
+		DirectoryAssemblyResolver MakeResolver (bool useMarshalMethods)
 		{
-			var readerParams = new ReaderParameters {
-				ReadWrite = true,
-				InMemory = true,
-			};
+			var readerParams = new ReaderParameters();
+			if (useMarshalMethods) {
+				readerParams.ReadWrite = true;
+				readerParams.InMemory = true;
+			}
 
 			var res = new DirectoryAssemblyResolver (this.CreateTaskLogger (), loadDebugSymbols: true, loadReaderParameters: readerParams);
 			foreach (var dir in FrameworkDirectories) {
