Summary
CheckAaptErrorNotRaisedForInvalidFileNameWithValidLogicalName(NativeAOT) fails during _RemoveRegisterAttribute (it is not an aapt error despite the test name):
Xamarin.Android.Common.targets(2014,3): error XACIC7028: System.IO.FileNotFoundException:
Could not find file '.../microsoft.netcore.app.runtime.nativeaot.android-arm64/11.0.0-preview.6.26322.111/runtimes/android-arm64/lib/net11.0/shrunk/System.Net.HttpListener.dll'.
at Microsoft.Android.Build.Tasks.Files.CopyIfChanged(String source, String destination)
at Xamarin.Android.Tasks.CopyIfChanged.RunTask()
Diagnosis
_RemoveRegisterAttribute (Common.targets ~2011, runs in Release / AndroidLinkMode != None) does:
<CopyIfChanged SourceFiles="@(_ResolvedAssemblies)" DestinationFiles="@(_ShrunkAssemblies)" />
For the trimmable NativeAOT path, @(_ResolvedAssemblies) contains System.Net.HttpListener.dll pointing at a .../shrunk/ path that does not exist — the framework assembly was trimmed away by ILC, but the _ResolvedAssemblies/_ShrunkAssemblies lists (computed before/around ILC) still reference it at its expected post-shrink location. CopyIfChanged then throws on the missing source.
The LlvmIr/legacy path overrides _RemoveRegisterAttribute (Microsoft.Android.Sdk.TypeMap.LlvmIr.targets ~372). The trimmable path uses the Common default and only patches in the generated TypeMap DLLs (_PrepareTrimmableTypeMapAssemblies, Trimmable.targets ~248-275) to keep source/destination counts in sync — but does not account for framework assemblies that ILC removes.
This only reproduces when the app references framework assemblies that get trimmed (e.g. System.Net.HttpListener via the default project); a minimal app that doesn't pull them in builds fine. The test became a failure once the trimmable NativeAOT build flow advanced far enough to reach _RemoveRegisterAttribute (it was not observed in earlier, more-broken builds).
Fix direction (needs design)
- Filter
@(_ResolvedAssemblies) / @(_ShrunkAssemblies) for the trimmable NativeAOT path to only assemblies that survive ILC (exist on disk), keeping source/destination aligned; or
- Make
_RemoveRegisterAttribute tolerate missing sources; or
- Override
_RemoveRegisterAttribute for the trimmable NativeAOT path (as LlvmIr does) so it doesn't depend on the illink "shrunk" assembly layout.
Acceptance criteria
References
- Repro test:
CheckAaptErrorNotRaisedForInvalidFileNameWithValidLogicalName (src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs).
- Code:
Xamarin.Android.Common.targets (_RemoveRegisterAttribute ~2011), Microsoft.Android.Sdk.TypeMap.Trimmable.targets (_PrepareTrimmableTypeMapAssemblies ~248), Microsoft.Android.Sdk.TypeMap.LlvmIr.targets (_RemoveRegisterAttribute override ~372).
Summary
CheckAaptErrorNotRaisedForInvalidFileNameWithValidLogicalName(NativeAOT)fails during_RemoveRegisterAttribute(it is not an aapt error despite the test name):Diagnosis
_RemoveRegisterAttribute(Common.targets ~2011, runs in Release /AndroidLinkMode != None) does:For the trimmable NativeAOT path,
@(_ResolvedAssemblies)containsSystem.Net.HttpListener.dllpointing at a.../shrunk/path that does not exist — the framework assembly was trimmed away by ILC, but the_ResolvedAssemblies/_ShrunkAssemblieslists (computed before/around ILC) still reference it at its expected post-shrink location.CopyIfChangedthen throws on the missing source.The LlvmIr/legacy path overrides
_RemoveRegisterAttribute(Microsoft.Android.Sdk.TypeMap.LlvmIr.targets ~372). The trimmable path uses the Common default and only patches in the generated TypeMap DLLs (_PrepareTrimmableTypeMapAssemblies, Trimmable.targets ~248-275) to keep source/destination counts in sync — but does not account for framework assemblies that ILC removes.This only reproduces when the app references framework assemblies that get trimmed (e.g.
System.Net.HttpListenervia the default project); a minimal app that doesn't pull them in builds fine. The test became a failure once the trimmable NativeAOT build flow advanced far enough to reach_RemoveRegisterAttribute(it was not observed in earlier, more-broken builds).Fix direction (needs design)
@(_ResolvedAssemblies)/@(_ShrunkAssemblies)for the trimmable NativeAOT path to only assemblies that survive ILC (exist on disk), keeping source/destination aligned; or_RemoveRegisterAttributetolerate missing sources; or_RemoveRegisterAttributefor the trimmable NativeAOT path (as LlvmIr does) so it doesn't depend on the illink "shrunk" assembly layout.Acceptance criteria
CheckAaptErrorNotRaisedForInvalidFileNameWithValidLogicalName(NativeAOT)passes.System.Net.HttpListener, etc.) build under NativeAOT._RemoveRegisterAttributecounts remain consistent.References
CheckAaptErrorNotRaisedForInvalidFileNameWithValidLogicalName(src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs).Xamarin.Android.Common.targets(_RemoveRegisterAttribute~2011),Microsoft.Android.Sdk.TypeMap.Trimmable.targets(_PrepareTrimmableTypeMapAssemblies~248),Microsoft.Android.Sdk.TypeMap.LlvmIr.targets(_RemoveRegisterAttributeoverride ~372).