dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.93k stars 532 forks source link

[Xamarin.Android.Build.Tasks] close `XAAssemblyResolvers` #9531

Closed jonathanpeppers closed 12 hours ago

jonathanpeppers commented 2 days ago

Context: https://discord.com/channels/732297728826277939/732297916680765551/1308554103206580244 Fixes: https://github.com/dotnet/android/issues/9133 Context: 86260ed3

Various customers have been reporting UnauthorizedAccessExceptions in incremental builds, which seems to be a new problem in .NET 9. We were not able to reproduce the issue locally, but with the number of reports it seems to be a real issue.

One customer shared a MSBuild.dmp file (while the file was locked), where I could observe the objects in memory:

MemoryMappedViewStream  132
    Mono.Cecil.PE.Image 100
        Mono.Cecil.ModuleDefinition 100
            Mono.Cecil.TypeDefinition   100
                Mono.Cecil.TypeDefinition[] 100
                    List<Mono.Cecil.TypeDefinition> 1
                        Xamarin.Android.Tasks.NativeCodeGenState [Static variable Xamarin.Android.Tasks.NativeCodeGenState.<Template>k__BackingField]   1

Then realized the problem was:

We were also storing some static state (NativeCodeGenState) to be shared across multiple MSBuild tasks:

public static NativeCodeGenState? Template { get; set; }

NativeCodeGenState also holds a XAAssemblyResolver in a Resolver property. This means this XAAssemblyResolver instance would also be kept alive.

It appears we only use the static Template property for a bool flag, so I changed the property to a bool instead.

After this change, we can safely dispose Resolver instances. I looped over the NativeCodeGenState instances disposing of each Resolver at the end of the <GenerateJavaStubs/> MSBuild task.

jonathanpeppers commented 1 day ago

Actually, there might be a test failure:

Mono.Android.NET_Tests, Java.InteropTests.InvokeVirtualFromConstructorTests.ActivationConstructor
Java.Lang.UnsatisfiedLinkError : No implementation found for void net.dot.jni.test.CallVirtualFromConstructorDerived.calledFromConstructor(int) (tried Java_net_dot_jni_test_CallVirtualFromConstructorDerived_calledFromConstructor and Java_net_dot_jni_test_CallVirtualFromConstructorDerived_calledFromConstructor__I)
jonathanpeppers commented 1 day ago

I still see the UnsatisfiedLinkError, which I'm confused how my changes cause it. It even happens in the Debug build.