Android framework version
net11.0-android (Preview)
Affected platform version
.NET 11
Description
Summary
Extract all typemap-related targets from Xamarin.Android.Common.targets and Microsoft.Android.Sdk.ILLink.targets into a dedicated Xamarin.Android.TypeMap.Legacy.targets file, imported conditionally based on _AndroidTypeMapImplementation. This is a pure refactoring — no new code, no new tasks, no trimmable typemap logic. The only new files are .targets files that reorganize existing MSBuild XML.
After this change, adding a new typemap implementation becomes a matter of creating a new .targets file that is imported when _AndroidTypeMapImplementation == 'trimmable', without touching any of the legacy targets.
Motivation
Today, Xamarin.Android.Common.targets contains all typemap logic inline in _GenerateJavaStubs — JCW generation, ACW map, type mappings, marshal methods, manifest generation, and additional provider sources. This monolithic structure makes it extremely difficult to add a new typemap implementation without accidentally mixing artifacts.
When the trimmable typemap is added, it will generate completely different outputs (a managed TypeMap assembly + JCW Java sources) compared to the legacy path (LLVM IR → .o objects + mono.android.jar copy). If both sets of artifacts are present, the app will fail with duplicate class errors (D8/R8) or native linker errors. The separation must be airtight.
Similarly, Microsoft.Android.Sdk.ILLink.targets contains both shared linking infrastructure (_LinkAssemblies) and legacy-specific ILLink custom steps (_PrepareLinking, trimmer step configuration). The trimmable typemap on CoreCLR still uses ILLink for standard trimming but must NOT get the legacy custom steps (e.g., TypeMappingStep, PreserveRegistrations). On NativeAOT, ILLink is disabled entirely — ILC handles trimming.
Current state — Build pipeline for type mapping
The existing build pipeline has two typemap "implementations" controlled by _AndroidTypeMapImplementation:
llvm-ir (default for MonoVM and CoreCLR) — native binary lookup tables compiled from LLVM IR into the app's .so
managed (default for NativeAOT) — ILLink-substituted hash-based arrays in ManagedTypeMapping, with pre-generated marshal method lookup via ManagedMarshalMethodsLookupTable
Key properties
| Property |
Default |
Purpose |
_AndroidTypeMapImplementation |
llvm-ir (non-NativeAOT), managed (NativeAOT) |
Selects typemap strategy |
_TypeMapKind |
mvid (Release), strings-asm (Debug) |
Sub-variant of the llvm-ir implementation |
_AndroidUseMarshalMethods |
false (Debug), $(AndroidEnableMarshalMethods) (Release) |
Enables pre-generated marshal method stubs |
Where typemap logic currently lives
In Xamarin.Android.Common.targets — _GenerateJavaStubs target:
GenerateJavaCallableWrappers — generates .java JCW source files
GenerateACWMap — generates acw-map.txt
GenerateJavaStubs — scans for marshal methods, builds NativeCodeGenState
RewriteMarshalMethods — rewrites assemblies with marshal method stubs (Release only)
GenerateTypeMappings — generates LLVM IR (.ll) typemap lookup tables
GenerateMainAndroidManifest — generates AndroidManifest.xml (depends on NativeCodeGenState)
GenerateAdditionalProviderSources — generates runtime provider .java files
In Xamarin.Android.Common.targets — other targets:
_GetMonoPlatformJarPath — locates prebuilt mono.android.jar
_PrepareNativeAssemblySources — prepares per-ABI native source items from _TypeMapAssemblySource
_AddStaticResources — copies mono.android.jar, generates TypeManager.java
_RemoveRegisterAttribute — strips [Register] from assemblies after linking
In Microsoft.Android.Sdk.ILLink.targets:
_PrepareLinking — configures ILLink custom steps, preserve lists, trimmer data
_FixRootAssembly — adjusts root assembly mode
_TouchAndroidLinkFlag — writes link flag for _RemoveRegisterAttribute
_LinkAssemblies — shared linking dependency chain (needed by ALL paths)
Prebuilt SDK artifacts that are typemap-specific
| Artifact |
Where it lives |
Typemap coupling |
mono.android.jar |
$(_XATargetFrameworkDirectories) |
Contains prebuilt JCWs for Mono.Android.dll types. Trimmable typemap generates its own JCWs — both present → duplicate class errors. |
java_runtime_*.jar |
MSBuild targets directory |
Contains ManagedPeer, TypeManager — runtime infrastructure. Shared by both paths. |
TypeManager.java |
Generated by CreateTypeManagerJava |
Only needed when marshal methods enabled in legacy mode. |
Native .o typemap objects |
Compiled from LLVM IR .ll files |
Linked into libxamarin-app.so. Only produced by legacy path. |
What this issue changes
Naming: "Legacy" for existing implementations
The file covering both llvm-ir and managed implementations should be named Xamarin.Android.TypeMap.Legacy.targets. Both implementations share the same JCW generation → stub generation → type mapping pipeline (just with different flags). "Legacy" clearly communicates "everything that isn't the new trimmable system" without being misleading about the managed NativeAOT path.
File structure
| File |
Purpose |
Xamarin.Android.TypeMap.Legacy.targets |
All existing typemap logic (llvm-ir + managed) |
Xamarin.Android.TypeMap.Trimmable.targets |
Shared config + runtime dispatcher + validation |
Xamarin.Android.TypeMap.Trimmable.CoreCLR.targets |
CoreCLR-specific stubs (empty for now) |
Xamarin.Android.TypeMap.Trimmable.NativeAOT.targets |
NativeAOT-specific stubs (empty for now) |
The trimmable path needs CoreCLR/NativeAOT-specific files because their build pipelines are fundamentally different:
- CoreCLR: TypeMap assembly will be generated after
_GenerateJavaStubs, before ILLink. ILLink trims it.
- NativeAOT: ILLink is disabled. TypeMap assembly will be generated before ILC from post-linked assemblies. Must be added to
IlcReference, UnmanagedEntryPointsAssembly, and TrimmerRootAssembly.
A single trimmable targets file would need Condition attributes on nearly every target. Two small runtime-specific files are cleaner.
Step 1: Create Xamarin.Android.TypeMap.Legacy.targets
Move all legacy-specific targets, their UsingTask declarations, and related properties.
UsingTask declarations to move from Common.targets:
CollectTypeMapFilesForArchive
CreateTypeManagerJava
GenerateTypeMappings
GetMonoPlatformJar
RemoveRegisterAttribute
Properties to define:
_RemoveRegisterFlag — flag file for incremental _RemoveRegisterAttribute
_BeforeGenerateAndroidManifestTasks = _GenerateLegacyJavaCallableWrappers — hooks legacy JCW generation into _GenerateJavaStubs dependency chain (see Step 3)
Targets to define:
| Target |
Source |
Hook mechanism |
_GenerateLegacyJavaCallableWrappers |
Tasks currently inline in _GenerateJavaStubs body (GenerateJavaCallableWrappers, GenerateACWMap, GenerateJavaStubs, RewriteMarshalMethods) |
Runs as dependency of _GenerateJavaStubs via _BeforeGenerateAndroidManifestTasks property |
_GenerateLegacyAndroidManifest |
GenerateMainAndroidManifest + GenerateAdditionalProviderSources tasks from _GenerateJavaStubs body |
AfterTargets="_GenerateJavaStubs" |
_SetLegacyTypemapProperties |
_TypeMapKind property assignment from _CreatePropertiesCache area |
BeforeTargets="_CreatePropertiesCache" |
_GetMonoPlatformJarPath |
Existing target in Common.targets |
Overrides empty stub defined in Common.targets before imports |
_PrepareNativeAssemblySources |
Existing target in Common.targets |
Overrides empty stub defined in Common.targets before imports |
_AddLegacyTypeManagerResources |
CreateTypeManagerJava + mono.android.jar copy from _AddStaticResources |
AfterTargets="_AddStaticResources" |
_GenerateLegacyTypeMappings |
GenerateTypeMappings call from _GenerateJavaStubs body (can also be kept inside _GenerateLegacyJavaCallableWrappers if ordering allows) |
AfterTargets="_GenerateJavaStubs" or inside _GenerateLegacyJavaCallableWrappers |
_PrepareLinking |
Currently in ILLink.targets |
AfterTargets="ComputeResolvedFilesToPublishList" |
_FixRootAssembly |
Currently in ILLink.targets |
AfterTargets="PrepareForILLink" |
_TouchAndroidLinkFlag |
Currently in ILLink.targets |
AfterTargets="ILLink" |
_RemoveRegisterAttribute |
Existing target in Common.targets (full version with RemoveRegisterAttribute task) |
Overrides simplified version in Common.targets |
_CollectLegacyTypeMapFiles |
CollectTypeMapFilesForArchive invocation |
BeforeTargets="_BuildApk" |
Step 2: Create trimmable target stubs
Xamarin.Android.TypeMap.Trimmable.targets (shared dispatcher):
- Define
_TypeMapAssemblyName property (used by the trimmable typemap implementation)
- Conditionally import CoreCLR or NativeAOT sub-targets based on
$(_AndroidRuntime)
- Validation target: error if runtime is not CoreCLR or NativeAOT
Xamarin.Android.TypeMap.Trimmable.CoreCLR.targets (stub):
- Override
_PrepareNativeAssemblySources as empty (no native typemap sources)
- TODO comments marking where the trimmable typemap will add manifest generation + TypeMap assembly generation
Xamarin.Android.TypeMap.Trimmable.NativeAOT.targets (stub):
- TODO comments marking where the trimmable typemap will add ILC integration
- Note: Do NOT set
RunILLink=false / PublishTrimmed=false in stubs — this would break NativeAOT builds. Only add these when the replacement typemap generation is implemented.
Step 3: Modify Common.targets
-
Add empty stub targets BEFORE the conditional imports:
<!-- Empty stubs for targets overridden by Legacy/Trimmable .targets files.
These MUST be defined BEFORE the imports so that the imported overrides win
("last definition wins" in MSBuild). -->
<Target Name="_GetMonoPlatformJarPath" />
<Target Name="_PrepareNativeAssemblySources" />
<Import Project="Xamarin.Android.TypeMap.Trimmable.targets"
Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' " />
<Import Project="Xamarin.Android.TypeMap.Legacy.targets"
Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' " />
-
Add _BeforeGenerateAndroidManifestTasks to _GenerateJavaStubs DependsOnTargets:
<Target Name="_GenerateJavaStubs"
DependsOnTargets="$(_GenerateJavaStubsDependsOnTargets);$(BeforeGenerateAndroidManifest);$(_BeforeGenerateAndroidManifestTasks)"
...>
This property is set by Legacy.targets to _GenerateLegacyJavaCallableWrappers. When trimmable, it's unset and _GenerateJavaStubs runs without legacy JCW generation.
-
Strip _GenerateJavaStubs body — remove all task invocations. Keep only:
_MergedManifestDocuments item setup
- Stamp file output (
<Touch>)
<FileWrites> for $(_ManifestOutput)
-
Simplify _RemoveRegisterAttribute — remove RemoveRegisterAttribute task call, _AndroidLinkFlag inputs, _RemoveRegisterFlag outputs. Keep only the assembly copy logic. Legacy.targets overrides this with the full version.
-
Remove _TypeMapKind and TypeMapKind=$(_TypeMapKind) from property cache — moved to _SetLegacyTypemapProperties in Legacy.targets.
-
Remove legacy items from _AddStaticResources — CreateTypeManagerJava call, mono.android.jar copy/touch, related <FileWrites>.
-
Move legacy UsingTask declarations to Legacy.targets.
Step 4: Simplify Microsoft.Android.Sdk.ILLink.targets
Remove _PrepareLinking, _FixRootAssembly, _TouchAndroidLinkFlag (all moved to Legacy.targets). Keep only _LinkAssemblies.
Step 5: Add notes to Microsoft.Android.Sdk.NativeAOT.targets
Add comments indicating where the trimmable typemap will hook in. No functional changes needed.
Things to watch out for
Target ordering with AfterTargets
Multiple targets using AfterTargets="_GenerateJavaStubs" run in undefined order. If ordering between them matters (e.g., manifest generation depends on typemap generation), use explicit DependsOnTargets between them.
_RemoveRegisterAttribute incremental build
The legacy version has Inputs="$(_AndroidLinkFlag)" / Outputs="$(_RemoveRegisterFlag)" for incremental builds. The simplified version in Common.targets (trimmable path) doesn't need these because it doesn't produce the flag file. Verify incremental build correctness for both paths.
ILLink custom steps must NOT reach the trimmable path
The trimmable CoreCLR path still uses ILLink (for standard trimming) but must NOT get legacy custom steps like TypeMappingStep or PreserveRegistrations. Verify that _PrepareLinking only runs from Legacy.targets.
NativeAOT stubs must not break current NativeAOT builds
Stubs for trimmable NativeAOT must be truly empty. Do NOT set RunILLink=false or disable any NativeAOT build infrastructure — that comes when the replacement typemap generation is implemented.
_CollectRuntimeJarFilenames — shared, not legacy
The runtime jar selection (java_runtime_clr.jar / java_runtime_net6.jar) is shared by both paths. Don't move it into Legacy.targets. Both paths need runtime jars — the difference is in mono.android.jar (legacy-only) and TypeManager.java (legacy-only).
Test coverage
The test "build with _AndroidTypeMapImplementation=trimmable succeeds" will produce an app that crashes at runtime (no typemap, no trimmable manifest). The test should verify build completion only — not device deployment. More useful artifact verification tests:
trimmable build does NOT contain typemap.*.o files
trimmable build does NOT copy mono.android.jar
trimmable build does NOT invoke RemoveRegisterAttribute
Definition of Done
Android framework version
net11.0-android (Preview)
Affected platform version
.NET 11
Description
Summary
Extract all typemap-related targets from
Xamarin.Android.Common.targetsandMicrosoft.Android.Sdk.ILLink.targetsinto a dedicatedXamarin.Android.TypeMap.Legacy.targetsfile, imported conditionally based on_AndroidTypeMapImplementation. This is a pure refactoring — no new code, no new tasks, no trimmable typemap logic. The only new files are.targetsfiles that reorganize existing MSBuild XML.After this change, adding a new typemap implementation becomes a matter of creating a new
.targetsfile that is imported when_AndroidTypeMapImplementation == 'trimmable', without touching any of the legacy targets.Motivation
Today,
Xamarin.Android.Common.targetscontains all typemap logic inline in_GenerateJavaStubs— JCW generation, ACW map, type mappings, marshal methods, manifest generation, and additional provider sources. This monolithic structure makes it extremely difficult to add a new typemap implementation without accidentally mixing artifacts.When the trimmable typemap is added, it will generate completely different outputs (a managed TypeMap assembly + JCW Java sources) compared to the legacy path (LLVM IR →
.oobjects +mono.android.jarcopy). If both sets of artifacts are present, the app will fail with duplicate class errors (D8/R8) or native linker errors. The separation must be airtight.Similarly,
Microsoft.Android.Sdk.ILLink.targetscontains both shared linking infrastructure (_LinkAssemblies) and legacy-specific ILLink custom steps (_PrepareLinking, trimmer step configuration). The trimmable typemap on CoreCLR still uses ILLink for standard trimming but must NOT get the legacy custom steps (e.g.,TypeMappingStep,PreserveRegistrations). On NativeAOT, ILLink is disabled entirely — ILC handles trimming.Current state — Build pipeline for type mapping
The existing build pipeline has two typemap "implementations" controlled by
_AndroidTypeMapImplementation:llvm-ir(default for MonoVM and CoreCLR) — native binary lookup tables compiled from LLVM IR into the app's.somanaged(default for NativeAOT) — ILLink-substituted hash-based arrays inManagedTypeMapping, with pre-generated marshal method lookup viaManagedMarshalMethodsLookupTableKey properties
_AndroidTypeMapImplementationllvm-ir(non-NativeAOT),managed(NativeAOT)_TypeMapKindmvid(Release),strings-asm(Debug)llvm-irimplementation_AndroidUseMarshalMethodsfalse(Debug),$(AndroidEnableMarshalMethods)(Release)Where typemap logic currently lives
In
Xamarin.Android.Common.targets—_GenerateJavaStubstarget:GenerateJavaCallableWrappers— generates.javaJCW source filesGenerateACWMap— generatesacw-map.txtGenerateJavaStubs— scans for marshal methods, buildsNativeCodeGenStateRewriteMarshalMethods— rewrites assemblies with marshal method stubs (Release only)GenerateTypeMappings— generates LLVM IR (.ll) typemap lookup tablesGenerateMainAndroidManifest— generatesAndroidManifest.xml(depends onNativeCodeGenState)GenerateAdditionalProviderSources— generates runtime provider.javafilesIn
Xamarin.Android.Common.targets— other targets:_GetMonoPlatformJarPath— locates prebuiltmono.android.jar_PrepareNativeAssemblySources— prepares per-ABI native source items from_TypeMapAssemblySource_AddStaticResources— copiesmono.android.jar, generatesTypeManager.java_RemoveRegisterAttribute— strips[Register]from assemblies after linkingIn
Microsoft.Android.Sdk.ILLink.targets:_PrepareLinking— configures ILLink custom steps, preserve lists, trimmer data_FixRootAssembly— adjusts root assembly mode_TouchAndroidLinkFlag— writes link flag for_RemoveRegisterAttribute_LinkAssemblies— shared linking dependency chain (needed by ALL paths)Prebuilt SDK artifacts that are typemap-specific
mono.android.jar$(_XATargetFrameworkDirectories)Mono.Android.dlltypes. Trimmable typemap generates its own JCWs — both present → duplicate class errors.java_runtime_*.jarManagedPeer,TypeManager— runtime infrastructure. Shared by both paths.TypeManager.javaCreateTypeManagerJava.otypemap objects.llfileslibxamarin-app.so. Only produced by legacy path.What this issue changes
Naming: "Legacy" for existing implementations
The file covering both
llvm-irandmanagedimplementations should be namedXamarin.Android.TypeMap.Legacy.targets. Both implementations share the same JCW generation → stub generation → type mapping pipeline (just with different flags). "Legacy" clearly communicates "everything that isn't the new trimmable system" without being misleading about themanagedNativeAOT path.File structure
Xamarin.Android.TypeMap.Legacy.targetsXamarin.Android.TypeMap.Trimmable.targetsXamarin.Android.TypeMap.Trimmable.CoreCLR.targetsXamarin.Android.TypeMap.Trimmable.NativeAOT.targetsThe trimmable path needs CoreCLR/NativeAOT-specific files because their build pipelines are fundamentally different:
_GenerateJavaStubs, before ILLink. ILLink trims it.IlcReference,UnmanagedEntryPointsAssembly, andTrimmerRootAssembly.A single trimmable targets file would need
Conditionattributes on nearly every target. Two small runtime-specific files are cleaner.Step 1: Create
Xamarin.Android.TypeMap.Legacy.targetsMove all legacy-specific targets, their UsingTask declarations, and related properties.
UsingTask declarations to move from
Common.targets:CollectTypeMapFilesForArchiveCreateTypeManagerJavaGenerateTypeMappingsGetMonoPlatformJarRemoveRegisterAttributeProperties to define:
_RemoveRegisterFlag— flag file for incremental_RemoveRegisterAttribute_BeforeGenerateAndroidManifestTasks=_GenerateLegacyJavaCallableWrappers— hooks legacy JCW generation into_GenerateJavaStubsdependency chain (see Step 3)Targets to define:
_GenerateLegacyJavaCallableWrappers_GenerateJavaStubsbody (GenerateJavaCallableWrappers,GenerateACWMap,GenerateJavaStubs,RewriteMarshalMethods)_GenerateJavaStubsvia_BeforeGenerateAndroidManifestTasksproperty_GenerateLegacyAndroidManifestGenerateMainAndroidManifest+GenerateAdditionalProviderSourcestasks from_GenerateJavaStubsbodyAfterTargets="_GenerateJavaStubs"_SetLegacyTypemapProperties_TypeMapKindproperty assignment from_CreatePropertiesCacheareaBeforeTargets="_CreatePropertiesCache"_GetMonoPlatformJarPathCommon.targetsCommon.targetsbefore imports_PrepareNativeAssemblySourcesCommon.targetsCommon.targetsbefore imports_AddLegacyTypeManagerResourcesCreateTypeManagerJava+mono.android.jarcopy from_AddStaticResourcesAfterTargets="_AddStaticResources"_GenerateLegacyTypeMappingsGenerateTypeMappingscall from_GenerateJavaStubsbody (can also be kept inside_GenerateLegacyJavaCallableWrappersif ordering allows)AfterTargets="_GenerateJavaStubs"or inside_GenerateLegacyJavaCallableWrappers_PrepareLinkingILLink.targetsAfterTargets="ComputeResolvedFilesToPublishList"_FixRootAssemblyILLink.targetsAfterTargets="PrepareForILLink"_TouchAndroidLinkFlagILLink.targetsAfterTargets="ILLink"_RemoveRegisterAttributeCommon.targets(full version withRemoveRegisterAttributetask)Common.targets_CollectLegacyTypeMapFilesCollectTypeMapFilesForArchiveinvocationBeforeTargets="_BuildApk"Step 2: Create trimmable target stubs
Xamarin.Android.TypeMap.Trimmable.targets(shared dispatcher):_TypeMapAssemblyNameproperty (used by the trimmable typemap implementation)$(_AndroidRuntime)Xamarin.Android.TypeMap.Trimmable.CoreCLR.targets(stub):_PrepareNativeAssemblySourcesas empty (no native typemap sources)Xamarin.Android.TypeMap.Trimmable.NativeAOT.targets(stub):RunILLink=false/PublishTrimmed=falsein stubs — this would break NativeAOT builds. Only add these when the replacement typemap generation is implemented.Step 3: Modify
Common.targetsAdd empty stub targets BEFORE the conditional imports:
Add
_BeforeGenerateAndroidManifestTasksto_GenerateJavaStubsDependsOnTargets:This property is set by Legacy.targets to
_GenerateLegacyJavaCallableWrappers. When trimmable, it's unset and_GenerateJavaStubsruns without legacy JCW generation.Strip
_GenerateJavaStubsbody — remove all task invocations. Keep only:_MergedManifestDocumentsitem setup<Touch>)<FileWrites>for$(_ManifestOutput)Simplify
_RemoveRegisterAttribute— removeRemoveRegisterAttributetask call,_AndroidLinkFlaginputs,_RemoveRegisterFlagoutputs. Keep only the assembly copy logic. Legacy.targets overrides this with the full version.Remove
_TypeMapKindandTypeMapKind=$(_TypeMapKind)from property cache — moved to_SetLegacyTypemapPropertiesin Legacy.targets.Remove legacy items from
_AddStaticResources—CreateTypeManagerJavacall,mono.android.jarcopy/touch, related<FileWrites>.Move legacy UsingTask declarations to Legacy.targets.
Step 4: Simplify
Microsoft.Android.Sdk.ILLink.targetsRemove
_PrepareLinking,_FixRootAssembly,_TouchAndroidLinkFlag(all moved to Legacy.targets). Keep only_LinkAssemblies.Step 5: Add notes to
Microsoft.Android.Sdk.NativeAOT.targetsAdd comments indicating where the trimmable typemap will hook in. No functional changes needed.
Things to watch out for
Target ordering with
AfterTargetsMultiple targets using
AfterTargets="_GenerateJavaStubs"run in undefined order. If ordering between them matters (e.g., manifest generation depends on typemap generation), use explicitDependsOnTargetsbetween them._RemoveRegisterAttributeincremental buildThe legacy version has
Inputs="$(_AndroidLinkFlag)"/Outputs="$(_RemoveRegisterFlag)"for incremental builds. The simplified version in Common.targets (trimmable path) doesn't need these because it doesn't produce the flag file. Verify incremental build correctness for both paths.ILLink custom steps must NOT reach the trimmable path
The trimmable CoreCLR path still uses ILLink (for standard trimming) but must NOT get legacy custom steps like
TypeMappingSteporPreserveRegistrations. Verify that_PrepareLinkingonly runs from Legacy.targets.NativeAOT stubs must not break current NativeAOT builds
Stubs for trimmable NativeAOT must be truly empty. Do NOT set
RunILLink=falseor disable any NativeAOT build infrastructure — that comes when the replacement typemap generation is implemented._CollectRuntimeJarFilenames— shared, not legacyThe runtime jar selection (
java_runtime_clr.jar/java_runtime_net6.jar) is shared by both paths. Don't move it into Legacy.targets. Both paths need runtime jars — the difference is inmono.android.jar(legacy-only) andTypeManager.java(legacy-only).Test coverage
The test "build with
_AndroidTypeMapImplementation=trimmablesucceeds" will produce an app that crashes at runtime (no typemap, no trimmable manifest). The test should verify build completion only — not device deployment. More useful artifact verification tests:trimmablebuild does NOT containtypemap.*.ofilestrimmablebuild does NOT copymono.android.jartrimmablebuild does NOT invokeRemoveRegisterAttributeDefinition of Done
Xamarin.Android.Build.Testsfull suite passes (all existing tests use legacy path by default)Xamarin.Android.TypeMap.Legacy.targetswith all legacy typemap targetsXamarin.Android.TypeMap.Trimmable.targets(dispatcher with validation)Xamarin.Android.TypeMap.Trimmable.CoreCLR.targets(empty stubs)Xamarin.Android.TypeMap.Trimmable.NativeAOT.targets(empty stubs)Common.targetshas zero legacy typemap task invocations — only shared setup + conditional importsILLink.targetsreduced to_LinkAssembliesonly_AndroidTypeMapImplementation=trimmablesucceeds (stubs are no-ops)trimmablebuild does NOT produce native typemap.oobjectstrimmablebuild does NOT copymono.android.jartrimmablebuild does NOT invokeRemoveRegisterAttribute