Skip to content

Commit 8df9772

Browse files
sbomerCopilot
andauthored
[illink] Move FixLegacyResourceDesignerStep to post-trim pipeline (#11059)
Migrate `FixLegacyResourceDesignerStep` out of the ILLink trimmer process and into PostTrimmingPipeline, continuing the work in #10842 to remove custom ILLink steps. The step now runs after ILLink via a thin wrapper (PostTrimmingFixLegacyResourceDesignerStep) that calls ProcessAssemblyDesigner() directly, matching the former ILLink behavior. - Remove all #if ILLINK conditionals from FixLegacyResourceDesignerStep, LinkDesignerBase, and BaseStep - Remove FixLegacyResourceDesignerStep and LinkDesignerBase from the ILLink project (no longer compiled as a trimmer step) - Add UseDesignerAssembly property to PostTrimmingPipeline task - Wire AndroidUseDesignerAssembly through targets to PostTrimmingPipeline - Remove _TrimmerCustomSteps entry for FixLegacyResourceDesignerStep ### [targets] Fix NativeAOT designer assembly trimming In NativeAOT builds, _AddResourceDesignerToPublishFiles ran after _ComputeManagedAssemblyToLink, so the designer assembly was not in ManagedAssemblyToLink. ILLink skipped the designer assembly entirely and did not rewrite its netstandard references. Fix by adding _AddResourceDesignerToPublishFiles to _PrepareLinking's DependsOnTargets, so the designer is passed to ILLink. ### Fix merge conflict: remove FixAbstractMethodsStep from ILLink csproj FixAbstractMethodsStep was moved from ILLink to the post-trim pipeline on main (7ae24aa). The merge conflict resolution incorrectly kept the Compile include, but the file now uses types not available in the ILLink project (IAssemblyModifierPipelineStep, StepContext, Properties.Resources). ### Root designer assembly to prevent ILLink from trimming resource properties FixLegacyResourceDesignerStep now runs in PostTrimmingPipeline (after ILLink) instead of as an ILLink custom step. Previously, the step ran before MarkStep and rewrote library assemblies to reference designer properties, which caused MarkStep to preserve them. Now that the rewriting happens after ILLink, we must root the designer assembly so all resource properties survive trimming. Add TrimmerRootAssembly for the designer in _AddResourceDesignerToPublishFiles. This keeps IsTrimmable=true (action=link) so ILLink still rewrites the netstandard assembly reference, but roots all types so nothing is trimmed. An alternative approach would be to run FixLegacyResourceDesignerStep before ILLink instead of after. That would allow ILLink to trim unused resource properties from the designer (since the rewritten references would already be in place for MarkStep), but it would also process resource references in assemblies that ILLink may later remove entirely. ### Use TrimmerRootDescriptor instead of TrimmerRootAssembly for designer assembly TrimmerRootAssembly (-a flag) makes the designer an entry point, which causes ILLink to retain netstandard.dll as a dependency, leaking it into the APK (+19KB). TrimmerRootDescriptor (-x flag) preserves all designer types/members without making it an entry point, avoiding the regression. ### Update SkiaSharp test to expect XA8000 instead of IL8000 for release builds FixLegacyResourceDesignerStep now runs in PostTrimmingPipeline (MSBuild task) instead of inside ILLink, so the error code is always XA8000 regardless of build configuration. ### Fix incremental build: use WriteOnlyWhenDifferent for linker descriptor WriteLinesToFile was regenerating the TrimmerRootDescriptor XML on every build, changing its timestamp and causing ILLink to re-run on incremental builds. Adding WriteOnlyWhenDifferent preserves the timestamp when the content hasn't changed. - Add TODO to simplify TrimmerRootDescriptor once dotnet/runtime#126518 is fixed ### Update APK size reference baselines FixLegacyResourceDesignerStep now runs post-ILLink with preserve=all, keeping all designer properties instead of only those referenced by libraries. This increases the designer assembly from ~19KB to ~135KB in the XForms MonoVM test app (1% of total APK size). Other baselines updated for SDK changes from the main branch merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7bc5a9e commit 8df9772

15 files changed

+154
-141
lines changed

src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
<Compile Include="..\Xamarin.Android.Build.Tasks\Linker\External\Linker\BaseMarkHandler.cs" Link="External\BaseMarkHandler.cs" />
1717
<Compile Include="..\Xamarin.Android.Build.Tasks\Linker\MonoDroid.Tuner\AndroidLinkConfiguration.cs" Link="MonoDroid.Tuner\AndroidLinkConfiguration.cs" />
1818
<Compile Include="..\Xamarin.Android.Build.Tasks\Linker\MonoDroid.Tuner\Extensions.cs" Link="MonoDroid.Tuner\Extensions.cs" />
19-
<Compile Include="..\Xamarin.Android.Build.Tasks\Linker\MonoDroid.Tuner\FixLegacyResourceDesignerStep.cs" Link="MonoDroid.Tuner\FixLegacyResourceDesignerStep.cs" />
20-
<Compile Include="..\Xamarin.Android.Build.Tasks\Linker\MonoDroid.Tuner\LinkDesignerBase.cs" Link="MonoDroid.Tuner\LinkDesignerBase.cs" />
2119

2220
<!--Other .NET for Android / Java.Interop files-->
2321
<Compile Include="..\..\external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil\CustomAttributeProviderRocks.cs" Link="Java.Interop\CustomAttributeProviderRocks.cs" />

src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,7 @@ public virtual void LogMessage (string message)
8989

9090
public virtual void LogError (int code, string message)
9191
{
92-
#if ILLINK
93-
Context.LogMessage (MessageContainer.CreateCustomErrorMessage (message, code, origin: new MessageOrigin ()));
94-
#else // !ILLINK
9592
Context.LogError ($"XA{code}", message);
96-
#endif // !ILLINK
9793
}
9894
}
9995
}

src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,11 @@
1414
using Mono.Linker.Steps;
1515

1616
using Mono.Tuner;
17-
#if ILLINK
18-
using Resources = Microsoft.Android.Sdk.ILLink.Properties.Resources;
19-
#else // !ILLINK
2017
using Resources = Xamarin.Android.Tasks.Properties.Resources;
21-
#endif // ILLINK
2218

2319
namespace MonoDroid.Tuner
2420
{
25-
public class FixLegacyResourceDesignerStep : LinkDesignerBase
26-
#if !ILLINK
27-
, Xamarin.Android.Tasks.IAssemblyModifierPipelineStep
28-
#endif // !ILLINK
21+
public class FixLegacyResourceDesignerStep : LinkDesignerBase, Xamarin.Android.Tasks.IAssemblyModifierPipelineStep
2922
{
3023
internal const string DesignerAssemblyName = "_Microsoft.Android.Resource.Designer";
3124
internal const string DesignerAssemblyNamespace = "_Microsoft.Android.Resource.Designer";
@@ -36,14 +29,6 @@ public class FixLegacyResourceDesignerStep : LinkDesignerBase
3629
Dictionary<string, MethodDefinition> lookup;
3730
Dictionary<string, MethodDefinition> lookupCaseInsensitive;
3831

39-
protected override void EndProcess ()
40-
{
41-
if (designerAssembly != null) {
42-
LogMessage ($" Setting Action on {designerAssembly.Name} to Link.");
43-
Annotations.SetAction (designerAssembly, AssemblyAction.Link);
44-
}
45-
}
46-
4732
protected override void LoadDesigner ()
4833
{
4934
if (designerLoaded)
@@ -72,7 +57,6 @@ protected override void LoadDesigner ()
7257
}
7358
}
7459

75-
#if !ILLINK
7660
public void ProcessAssembly (AssemblyDefinition assembly, Xamarin.Android.Tasks.StepContext context)
7761
{
7862
// Only run this step on non-main user Android assemblies
@@ -81,7 +65,6 @@ public void ProcessAssembly (AssemblyDefinition assembly, Xamarin.Android.Tasks.
8165

8266
context.IsAssemblyModified |= ProcessAssemblyDesigner (assembly);
8367
}
84-
#endif // !ILLINK
8568

8669
internal override bool ProcessAssemblyDesigner (AssemblyDefinition assembly)
8770
{

src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,27 @@
44
using Mono.Linker;
55
using Mono.Linker.Steps;
66
using System;
7-
using System.Linq;
87
using Xamarin.Android.Tasks;
98
using System.Collections.Generic;
109
using System.Globalization;
1110
using Mono.Cecil.Cil;
1211
using System.Text.RegularExpressions;
1312
using Mono.Collections.Generic;
14-
#if ILLINK
15-
using Microsoft.Android.Sdk.ILLink;
16-
#endif
1713

1814

1915
namespace MonoDroid.Tuner {
2016
public abstract class LinkDesignerBase : BaseStep
2117
{
2218
protected IMetadataResolver Cache => Context;
2319

24-
public
25-
#if !ILLINK
26-
override
27-
#endif
28-
void LogMessage (string message)
20+
public override void LogMessage (string message)
2921
{
3022
Context.LogMessage (message);
3123
}
3224

33-
public
34-
#if !ILLINK
35-
override
36-
#endif
37-
void LogError (int code, string error)
25+
public override void LogError (int code, string error)
3826
{
39-
#if ILLINK
40-
Context.LogMessage (MessageContainer.CreateCustomErrorMessage (error, code, origin: new MessageOrigin ()));
41-
#else // !ILLINK
4227
Context.LogError ($"XA{code}", error);
43-
#endif // !ILLINK
4428
}
4529

4630
public virtual AssemblyDefinition Resolve (AssemblyNameReference name)

src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,18 +226,43 @@ Copyright (C) 2016 Xamarin. All rights reserved.
226226
In additon we MUST set the `PostprocessAssembly` metadata to `true` so that the file
227227
is processed by the ILLink step. If we do not do this then the reference to
228228
`netstandard.dll` is not replaced with `System.Private.CoreLib` and the app crashes.
229+
230+
We use a TrimmerRootDescriptor (not TrimmerRootAssembly) to prevent ILLink from
231+
trimming the designer's resource properties. FixLegacyResourceDesignerStep runs
232+
after ILLink and needs all properties present when rewriting library assemblies.
233+
A descriptor (-x) preserves types without making the assembly an entry point,
234+
which avoids pulling netstandard.dll into the output.
235+
See https://github.com/dotnet/runtime/issues/126518
236+
237+
TODO: Once dotnet/runtime#126518 is fixed and flows to dotnet/android,
238+
simplify this to use TrimmerRootAssembly instead of the XML descriptor.
229239
-->
230240
<Target Name="_AddResourceDesignerToPublishFiles"
231241
Condition=" '$(AndroidUseDesignerAssembly)' == 'True' "
232242
AfterTargets="ComputeResolvedFilesToPublishList"
233243
DependsOnTargets="_SetupDesignerProperties">
244+
<PropertyGroup>
245+
<_DesignerLinkerDescriptor>$(IntermediateOutputPath)_Microsoft.Android.Resource.Designer.xml</_DesignerLinkerDescriptor>
246+
</PropertyGroup>
247+
<WriteLinesToFile
248+
File="$(_DesignerLinkerDescriptor)"
249+
Overwrite="true"
250+
WriteOnlyWhenDifferent="true"
251+
Lines="&lt;linker&gt;&lt;assembly fullname=&quot;$(_DesignerAssemblyName)&quot;&gt;&lt;type fullname=&quot;*&quot; preserve=&quot;all&quot; /&gt;&lt;/assembly&gt;&lt;/linker&gt;"
252+
/>
234253
<ItemGroup>
235254
<ResolvedFileToPublish Include="$(_GenerateResourceDesignerAssemblyOutput)">
236255
<RelativePath>$(_DesignerAssemblyName).dll</RelativePath>
237256
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
238257
<PostprocessAssembly>true</PostprocessAssembly>
239258
<IsTrimmable>true</IsTrimmable>
240259
</ResolvedFileToPublish>
260+
<!-- Preserve all designer types/members via descriptor so ILLink keeps resource
261+
properties. Using a descriptor (not TrimmerRootAssembly) avoids making the
262+
assembly an entry point, which would pull netstandard.dll into the output.
263+
See https://github.com/dotnet/runtime/issues/126518 -->
264+
<TrimmerRootDescriptor Include="$(_DesignerLinkerDescriptor)" />
265+
<FileWrites Include="$(_DesignerLinkerDescriptor)" />
241266
</ItemGroup>
242267
</Target>
243268

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
<Target Name="_PrepareLinking"
168168
Condition=" '$(PublishTrimmed)' == 'true' "
169169
AfterTargets="ComputeResolvedFilesToPublishList"
170-
DependsOnTargets="GetReferenceAssemblyPaths;_CreatePropertiesCache">
170+
DependsOnTargets="GetReferenceAssemblyPaths;_CreatePropertiesCache;_AddResourceDesignerToPublishFiles">
171171
<PropertyGroup>
172172
<TrimmerRemoveSymbols Condition=" '$(AndroidIncludeDebugSymbols)' != 'true' ">true</TrimmerRemoveSymbols>
173173
<_ExtraTrimmerArgs Condition=" '$(_EnableSerializationDiscovery)' != 'false' ">--enable-serialization-discovery $(_ExtraTrimmerArgs)</_ExtraTrimmerArgs>
@@ -204,12 +204,6 @@
204204
<_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="Microsoft.Android.Sdk.ILLink.PreserveJavaInterfaces" />
205205
<!-- Custom steps that run after MarkStep -->
206206
<!-- Custom steps that run after CleanStep -->
207-
<_TrimmerCustomSteps
208-
Condition=" '$(AndroidUseDesignerAssembly)' == 'true' "
209-
Include="$(_AndroidLinkerCustomStepAssembly)"
210-
BeforeStep="MarkStep"
211-
Type="MonoDroid.Tuner.FixLegacyResourceDesignerStep"
212-
/>
213207
<_TrimmerCustomSteps
214208
Condition=" '$(_AndroidTypeMapImplementation)' == 'managed' "
215209
Include="$(_AndroidLinkerCustomStepAssembly)"
@@ -254,7 +248,8 @@
254248
Assemblies="@(_PostTrimmingAssembly)"
255249
AddKeepAlives="$(AndroidAddKeepAlives)"
256250
AndroidLinkResources="$(AndroidLinkResources)"
257-
Deterministic="$(Deterministic)" />
251+
Deterministic="$(Deterministic)"
252+
UseDesignerAssembly="$(AndroidUseDesignerAssembly)" />
258253
</Target>
259254

260255
<!-- Inject _TypeMapKind into the property cache -->

src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Android.Build.Tasks;
77
using Microsoft.Build.Framework;
88
using Mono.Cecil;
9+
using Mono.Linker;
910
using MonoDroid.Tuner;
1011

1112
namespace Xamarin.Android.Tasks;
@@ -16,7 +17,7 @@ namespace Xamarin.Android.Tasks;
1617
/// This opens each assembly once (via DirectoryAssemblyResolver with ReadWrite) and
1718
/// runs all registered steps on it, then writes modified assemblies in-place. Currently
1819
/// runs CheckForObsoletePreserveAttributeStep, StripEmbeddedLibrariesStep and
19-
/// (optionally) AddKeepAlivesStep.
20+
/// (optionally) AddKeepAlivesStep and FixLegacyResourceDesignerStep.
2021
///
2122
/// Runs in the inner build after ILLink but before ReadyToRun/crossgen2 compilation,
2223
/// so that R2R images are generated from the already-modified assemblies.
@@ -34,6 +35,8 @@ public class PostTrimmingPipeline : AndroidTask
3435

3536
public bool Deterministic { get; set; }
3637

38+
public bool UseDesignerAssembly { get; set; }
39+
3740
public override bool RunTask ()
3841
{
3942
using var resolver = new DirectoryAssemblyResolver (
@@ -100,6 +103,15 @@ public override bool RunTask ()
100103
},
101104
(msg) => Log.LogDebugMessage (msg)));
102105
}
106+
if (UseDesignerAssembly) {
107+
// Create an MSBuildLinkContext so FixLegacyResourceDesignerStep can resolve assemblies
108+
// and log messages. The resolver is owned by the outer 'using' block, so we intentionally
109+
// do not dispose this context (LinkContext.Dispose would double-dispose the resolver).
110+
var linkContext = new MSBuildLinkContext (resolver, Log);
111+
var fixLegacyStep = new FixLegacyResourceDesignerStep ();
112+
fixLegacyStep.Initialize (linkContext);
113+
steps.Add (new PostTrimmingFixLegacyResourceDesignerStep (fixLegacyStep));
114+
}
103115

104116
foreach (var (item, assembly) in loadedAssemblies) {
105117
var context = new StepContext (item, item);
@@ -118,3 +130,24 @@ public override bool RunTask ()
118130
return !Log.HasLoggedErrors;
119131
}
120132
}
133+
134+
/// <summary>
135+
/// Thin wrapper around <see cref="FixLegacyResourceDesignerStep"/> for the post-trimming pipeline.
136+
/// Calls <see cref="FixLegacyResourceDesignerStep.ProcessAssemblyDesigner"/> directly, matching the
137+
/// behavior of the former ILLink path which processed all assemblies without StepContext flag filtering.
138+
/// Assemblies without a resource designer are skipped internally by ProcessAssemblyDesigner.
139+
/// </summary>
140+
class PostTrimmingFixLegacyResourceDesignerStep : IAssemblyModifierPipelineStep
141+
{
142+
readonly FixLegacyResourceDesignerStep _inner;
143+
144+
public PostTrimmingFixLegacyResourceDesignerStep (FixLegacyResourceDesignerStep inner)
145+
{
146+
_inner = inner;
147+
}
148+
149+
public void ProcessAssembly (AssemblyDefinition assembly, StepContext context)
150+
{
151+
context.IsAssemblyModified |= _inner.ProcessAssemblyDesigner (assembly);
152+
}
153+
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@
55
"Size": 3036
66
},
77
"classes.dex": {
8-
"Size": 397520
8+
"Size": 400044
99
},
1010
"lib/arm64-v8a/libassembly-store.so": {
11-
"Size": 3091928
11+
"Size": 3115312
1212
},
1313
"lib/arm64-v8a/libclrjit.so": {
14-
"Size": 3141224
14+
"Size": 3202072
1515
},
1616
"lib/arm64-v8a/libcoreclr.so": {
17-
"Size": 5736320
17+
"Size": 5766640
1818
},
1919
"lib/arm64-v8a/libmonodroid.so": {
20-
"Size": 1375784
20+
"Size": 1365104
2121
},
2222
"lib/arm64-v8a/libmscordaccore.so": {
23-
"Size": 2442416
23+
"Size": 2493552
2424
},
2525
"lib/arm64-v8a/libmscordbi.so": {
26-
"Size": 1894280
26+
"Size": 1902744
2727
},
2828
"lib/arm64-v8a/libSystem.Globalization.Native.so": {
2929
"Size": 71936
@@ -32,13 +32,13 @@
3232
"Size": 1281696
3333
},
3434
"lib/arm64-v8a/libSystem.Native.so": {
35-
"Size": 105664
35+
"Size": 107904
3636
},
3737
"lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": {
3838
"Size": 165536
3939
},
4040
"lib/arm64-v8a/libxamarin-app.so": {
41-
"Size": 20128
41+
"Size": 20520
4242
},
4343
"META-INF/BNDLTOOL.RSA": {
4444
"Size": 1221
@@ -74,5 +74,5 @@
7474
"Size": 1904
7575
}
7676
},
77-
"PackageSize": 9176858
77+
"PackageSize": 9258778
7878
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
"Size": 22388
99
},
1010
"lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": {
11-
"Size": 18288
11+
"Size": 18696
1212
},
1313
"lib/arm64-v8a/lib_Java.Interop.dll.so": {
14-
"Size": 88040
14+
"Size": 88048
1515
},
1616
"lib/arm64-v8a/lib_Mono.Android.dll.so": {
17-
"Size": 118024
17+
"Size": 117928
1818
},
1919
"lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": {
20-
"Size": 26544
20+
"Size": 26464
2121
},
2222
"lib/arm64-v8a/lib_System.Console.dll.so": {
2323
"Size": 24432
@@ -35,7 +35,7 @@
3535
"Size": 21632
3636
},
3737
"lib/arm64-v8a/lib_UnnamedProject.dll.so": {
38-
"Size": 20032
38+
"Size": 20144
3939
},
4040
"lib/arm64-v8a/libarc.bin.so": {
4141
"Size": 19176
@@ -44,7 +44,7 @@
4444
"Size": 36616
4545
},
4646
"lib/arm64-v8a/libmonodroid.so": {
47-
"Size": 1386512
47+
"Size": 1386072
4848
},
4949
"lib/arm64-v8a/libmonosgen-2.0.so": {
5050
"Size": 3124368
@@ -62,7 +62,7 @@
6262
"Size": 165536
6363
},
6464
"lib/arm64-v8a/libxamarin-app.so": {
65-
"Size": 19840
65+
"Size": 19792
6666
},
6767
"META-INF/BNDLTOOL.RSA": {
6868
"Size": 1221

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
"Size": 3124
66
},
77
"classes.dex": {
8-
"Size": 24224
8+
"Size": 25400
99
},
1010
"lib/arm64-v8a/libUnnamedProject.so": {
11-
"Size": 4968680
11+
"Size": 5056848
1212
},
1313
"META-INF/BNDLTOOL.RSA": {
14-
"Size": 1211
14+
"Size": 1221
1515
},
1616
"META-INF/BNDLTOOL.SF": {
1717
"Size": 1211
@@ -44,5 +44,5 @@
4444
"Size": 1904
4545
}
4646
},
47-
"PackageSize": 2094050
47+
"PackageSize": 2122722
4848
}

0 commit comments

Comments
 (0)