Skip to content

Commit 78f8863

Browse files
[Xamarin.Android.Build.Tasks] close XAAssemblyResolvers (#9531)
Fixes: #9133 Context: https://discord.com/channels/732297728826277939/732297916680765551/1308554103206580244 Context: 86260ed 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`][0] 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 opened some `.dll` files with `Mono.Cecil`. * They were never closed. * Future incremental build attempts would fail on various operations of the same `.dll` files. We were also storing some static state (`NativeCodeGenState`) to be shared across multiple MSBuild tasks: partial class NativeCodeGenState { 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: partial class NativeCodeGenState { public static bool TemplateJniAddNativeMethodRegistrationAttributePresent { get; set; } } 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/>` and `<GeneratePackageManagerJava/>` MSBuild tasks. [0]: https://drive.google.com/file/d/12dOkO6ZdbK67sNeY_PVS4d0mgnLyOwUA/view?pli=1
1 parent 22f23dd commit 78f8863

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

Diff for: src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs

+15-3
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,6 @@ void Run (bool useMarshalMethods)
222222
}
223223
JCWGenerator.EnsureAllArchitecturesAreIdentical (Log, nativeCodeGenStates);
224224

225-
NativeCodeGenState.Template = templateCodeGenState;
226-
BuildEngine4.RegisterTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (NativeCodeGenStateRegisterTaskKey), nativeCodeGenStates, RegisteredTaskObjectLifetime.Build);
227-
228225
if (useMarshalMethods) {
229226
// We need to parse the environment files supplied by the user to see if they want to use broken exception transitions. This information is needed
230227
// in order to properly generate wrapper methods in the marshal methods assembly rewriter.
@@ -262,6 +259,9 @@ void Run (bool useMarshalMethods)
262259
WriteTypeMappings (state);
263260
}
264261

262+
// Set for use by <GeneratePackageManagerJava/> task later
263+
NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState.JniAddNativeMethodRegistrationAttributePresent;
264+
265265
var acwMapGen = new ACWMapGenerator (Log);
266266
if (!acwMapGen.Generate (templateCodeGenState, AcwMapFile)) {
267267
Log.LogDebugMessage ("ACW map generation failed");
@@ -270,6 +270,18 @@ void Run (bool useMarshalMethods)
270270
IList<string> additionalProviders = MergeManifest (templateCodeGenState, MaybeGetArchAssemblies (userAssembliesPerArch, templateCodeGenState.TargetArch));
271271
GenerateAdditionalProviderSources (templateCodeGenState, additionalProviders);
272272

273+
if (useMarshalMethods) {
274+
// Save NativeCodeGenState for <GeneratePackageManagerJava/> task later
275+
Log.LogDebugMessage ($"Saving {nameof (NativeCodeGenState)} to {nameof (NativeCodeGenStateRegisterTaskKey)}");
276+
BuildEngine4.RegisterTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (NativeCodeGenStateRegisterTaskKey), nativeCodeGenStates, RegisteredTaskObjectLifetime.Build);
277+
} else {
278+
// Otherwise, dispose all XAAssemblyResolvers
279+
Log.LogDebugMessage ($"Disposing all {nameof (NativeCodeGenState)}.{nameof (NativeCodeGenState.Resolver)}");
280+
foreach (var state in nativeCodeGenStates.Values) {
281+
state.Resolver.Dispose ();
282+
}
283+
}
284+
273285
Dictionary<string, ITaskItem> MaybeGetArchAssemblies (Dictionary<AndroidTargetArch, Dictionary<string, ITaskItem>> dict, AndroidTargetArch arch)
274286
{
275287
if (!dict.TryGetValue (arch, out Dictionary<string, ITaskItem> archDict)) {

Diff for: src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ void AddEnvironment ()
331331
BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions,
332332
PackageNamingPolicy = pnp,
333333
BoundExceptionType = boundExceptionType,
334-
JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.Template != null ? NativeCodeGenState.Template.JniAddNativeMethodRegistrationAttributePresent : false,
334+
JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent,
335335
HaveRuntimeConfigBlob = haveRuntimeConfigBlob,
336336
NumberOfAssembliesInApk = assemblyCount,
337337
BundledAssemblyNameWidth = assemblyNameWidth,
@@ -395,6 +395,14 @@ void AddEnvironment ()
395395
}
396396
}
397397

398+
if (nativeCodeGenStates is not null) {
399+
// Dispose all XAAssemblyResolvers
400+
Log.LogDebugMessage ($"Disposing all {nameof (NativeCodeGenState)}.{nameof (NativeCodeGenState.Resolver)}");
401+
foreach (var state in nativeCodeGenStates.Values) {
402+
state.Resolver.Dispose ();
403+
}
404+
}
405+
398406
NativeCodeGenState EnsureCodeGenState (AndroidTargetArch targetArch)
399407
{
400408
if (nativeCodeGenStates == null || !nativeCodeGenStates.TryGetValue (targetArch, out NativeCodeGenState? state)) {

Diff for: src/Xamarin.Android.Build.Tasks/Utilities/NativeCodeGenState.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Xamarin.Android.Tasks;
1212
/// </summary>
1313
class NativeCodeGenState
1414
{
15-
public static NativeCodeGenState? Template { get; set; }
15+
public static bool TemplateJniAddNativeMethodRegistrationAttributePresent { get; set; }
1616

1717
/// <summary>
1818
/// Target architecture for which this instance was created.

0 commit comments

Comments
 (0)