Skip to content

Commit 9a782d7

Browse files
[One .NET] new "greenfield" projects are trimmed by default (#8805)
Context: 5205a5f Context: 8a5b2a0 Context: #8724 Context: #8797 As we have solved all trimming warnings (5205a5f. 8a5b2a0) in the Android workload, we can now go "all in" on trimming. Early in .NET 6 (maybe even 5?) we "hid" many trimming warnings as we did not yet plan to solve them: <SuppressTrimAnalysisWarnings Condition=" '$(SuppressTrimAnalysisWarnings)' == '' ">true</SuppressTrimAnalysisWarnings> These warnings were not *actionable* at the time for customers, as many warnings were in `Mono.Android.dll`, `Java.Interop.dll`, etc. Going forward, let's stop suppressing these warnings for `$(TrimMode)`=full. We can also enable trimming for new projects: * `dotnet new android` * `dotnet new android-wear` New projects will have the [`$(TrimMode)`][0] property set to `Full` by default: <!-- Enable full trimming in Release mode. To learn more, see: https://learn.microsoft.com/dotnet/core/deploying/trimming/trimming-options#trimming-granularity --> <PropertyGroup Condition="'$(Configuration)' == 'Release'"> <TrimMode>full</TrimMode> </PropertyGroup> We wouldn't want to do this for existing projects *yet*, as they might have existing code, NuGet packages, etc. where trimming warnings might be present. We can also improve the templates for Android class libraries: * `dotnet new androidlib` * `dotnet new android-bindinglib` New class library projects will have the [`$(IsTrimmable)`][1] property set to `true` by default: <!-- Enable trim analyzers for Android class libraries. To learn more, see: https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming --> <IsTrimmable>true</IsTrimmable> This way, new class libraries will be "trimmable" by default and be able to react to trimming warnings. We can also use `$(TrimMode)=full` in many of our existing tests: * MSBuild tests that assert 0 warnings can use `$(TrimMode)=full`. * On-device tests can use `$(TrimMode)=full`. ~~ General trimming warnings ~~ This was discovered through `Mono.Android-NET-Tests.csproj`, but there were a few trimmer warnings in the "layout bindings" feature: …\dotnet\packs\Microsoft.Android.Sdk.Windows\…\tools\LayoutBinding.cs(79,56): warning IL2091: Xamarin.Android.Design.LayoutBinding.<>c__DisplayClass8_0<T>.<FindFragment>b__0(Activity): 'T' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' in 'Android.App.FragmentManager.FindFragmentById<T>(Int32)'. The generic parameter 'T' of 'Xamarin.Android.Design.LayoutBinding.<>c__DisplayClass8_0<T>' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. …\dotnet\packs\Microsoft.Android.Sdk.Windows\…\tools\LayoutBinding.cs(35,5): warning IL2091: Xamarin.Android.Design.LayoutBinding.FindView<T>(Int32, T&): 'T' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' in 'Android.App.Activity.FindViewById<T>(Int32)'. The generic parameter 'T' of 'Xamarin.Android.Design.LayoutBinding.FindView<T>(Int32, T&)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. …\dotnet\packs\Microsoft.Android.Sdk.Windows\…\tools\LayoutBinding.cs(37,5): warning IL2091: Xamarin.Android.Design.LayoutBinding.FindView<T>(Int32, T&): 'T' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' in 'Android.Views.View.FindViewById<T>(Int32)'. The generic parameter 'T' of 'Xamarin.Android.Design.LayoutBinding.FindView<T>(Int32, T&)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. We can `[DynamicallyAccessedMembers(Constructors)]` to fix these. ~~ Trimming warnings in tests ~~ Several tests that verify "trimming unsafe features" just specify: [RequiresUnreferencedCode ("Tests trimming unsafe features")] If the test might have an issue under NativeAOT, I used: // FIXME: #8724 #pragma warning disable IL3050 Places that use `Assembly.GetType()` can use `Type.GetType()` instead: -var JavaProxyThrowable_type = typeof (Java.Lang.Object) - .Assembly - .GetType ("Android.Runtime.JavaProxyThrowable"); +var JavaProxyThrowable_type = Type.GetType ("Android.Runtime.JavaProxyThrowable, Mono.Android"); `SystemTests.AppDomainTest` was just ignored (and had warnings). Update to just verify `PlatformNotSupportedException` is thrown. ~~ Test failures ~~ `JsonSerializerTest` requires setting [`$(JsonSerializerIsReflectionEnabledByDefault)`][2]=true: <JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault> Otherwise, an exception is thrown: System.InvalidOperationException : JsonSerializerIsReflectionDisabled `Java.Interop-Tests` were initially not loaded at all, with the log message: W NUnit : Failed to load tests from assembly 'Java.Interop-Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065 If we make `Java.Interop-Tests.dll` a `@(TrimmerRootAssembly)`: <TrimmerRootAssembly Include="Java.Interop-Tests" RootMode="All" /> Then all the tests cases are preserved and can be run, in the same way the "main app assembly" is preserved. `Android.GraphicsTests.NinePatchTests` failed with: The drawable created from resource tile should be a NinePatchDrawable. Expected: not null But was: null The only usage of `NinePatchDrawable` was: Assert.IsNotNull (d as NinePatchDrawable); `NinePatchDrawable` likely needs its interfaces and constructors preserved for this test to pass. I added an attribute for just `All` members for the test to pass: [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (NinePatchDrawable))] `Xamarin.Android.RuntimeTests.CustomWidgetTests` failed with: (Binary XML file line #1 in Mono.Android.NET_Tests:layout/uppercase_custom: Binary XML file line #1 in Mono.Android.NET_Tests:layout/uppercase_custom: Error inflating class Mono.Android_Test.Library.CustomTextView) at Java.Interop.JniEnvironment.InstanceMethods.CallObjectMethod(JniObjectReference , JniMethodInfo , JniArgumentValue* ) at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualObjectMethod(String , IJavaPeerable , JniArgumentValue* ) at Android.Views.LayoutInflater.Inflate(Int32 , ViewGroup ) at Xamarin.Android.RuntimeTests.CustomWidgetTests.<>c.<UpperCaseCustomWidget_ShouldNotThrowInflateException>b__0_0() at NUnit.Framework.Constraints.VoidInvocationDescriptor.Invoke() at NUnit.Framework.Constraints.ExceptionInterceptor.Intercept(Object ) --- End of managed Java.Lang.RuntimeException stack trace --- android.view.InflateException: Binary XML file line #1 in Mono.Android.NET_Tests:layout/uppercase_custom: Binary XML file line #1 in Mono.Android.NET_Tests:layout/uppercase_custom: Error inflating class Mono.Android_Test.Library.CustomTextView Caused by: android.view.InflateException: Binary XML file line #1 in Mono.Android.NET_Tests:layout/uppercase_custom: Error inflating class Mono.Android_Test.Library.CustomTextView Caused by: java.lang.ClassNotFoundException: Mono.Android_Test.Library.CustomTextView at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:454) at android.view.LayoutInflater.createView(LayoutInflater.java:815) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961) at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084) at android.view.LayoutInflater.inflate(LayoutInflater.java:682) at android.view.LayoutInflater.inflate(LayoutInflater.java:534) at android.view.LayoutInflater.inflate(LayoutInflater.java:481) at crc643df67da7b13bb6b1.TestInstrumentation_1.n_onStart(Native Method) at crc643df67da7b13bb6b1.TestInstrumentation_1.onStart(TestInstrumentation_1.java:32) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189) Caused by: java.lang.ClassNotFoundException: Didn't find class "Mono.Android_Test.Library.CustomTextView" on path In this case, `Mono.Android_Test.Library.CustomTextView` was used from an Android layout, but not used anywhere in managed code. To fix, I added: [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (Mono.Android_Test.Library.CustomTextView))] I could have also made `Mono.Android_Test.Library` a `@(TrimmerRootAssembly)`. TODO: `View` subclasses used within Android Layout `.axml` files should be automatically preserved; see #8797. [0]: https://learn.microsoft.com/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0#trimming-granularity [1]: https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming?pivots=dotnet-8-0#enable-project-specific-trimming [2]: https://learn.microsoft.com/dotnet/core/compatibility/serialization/8.0/publishtrimmed
1 parent ed2739b commit 9a782d7

File tree

22 files changed

+129
-47
lines changed

22 files changed

+129
-47
lines changed

src/Microsoft.Android.Templates/android-bindinglib/AndroidBinding1.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">AndroidBinding1</RootNamespace>
66
<Nullable>enable</Nullable>
77
<ImplicitUsings>enable</ImplicitUsings>
8+
<!--
9+
Enable trim analyzers for Android class libraries.
10+
To learn more, see: https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming
11+
-->
12+
<IsTrimmable>true</IsTrimmable>
813
<!--
914
NOTE: you can simply add .aar or .jar files in this directory to be included in the project.
1015
To learn more, see: https://learn.microsoft.com/dotnet/maui/migration/android-binding-projects

src/Microsoft.Android.Templates/android-wear/AndroidApp1.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
1212
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);XA4218</MSBuildWarningsAsMessages>
1313
</PropertyGroup>
14+
<!--
15+
Enable full trimming in Release mode.
16+
To learn more, see: https://learn.microsoft.com/dotnet/core/deploying/trimming/trimming-options#trimming-granularity
17+
-->
18+
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
19+
<TrimMode>full</TrimMode>
20+
</PropertyGroup>
1421
<ItemGroup>
1522
<PackageReference Include="Xamarin.AndroidX.Wear" Version="1.2.0.5" />
1623
</ItemGroup>

src/Microsoft.Android.Templates/android/AndroidApp1.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,11 @@
1010
<ApplicationVersion>1</ApplicationVersion>
1111
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
1212
</PropertyGroup>
13+
<!--
14+
Enable full trimming in Release mode.
15+
To learn more, see: https://learn.microsoft.com/dotnet/core/deploying/trimming/trimming-options#trimming-granularity
16+
-->
17+
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
18+
<TrimMode>full</TrimMode>
19+
</PropertyGroup>
1320
</Project>

src/Microsoft.Android.Templates/androidlib/AndroidLib1.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">AndroidLib1</RootNamespace>
66
<Nullable>enable</Nullable>
77
<ImplicitUsings>enable</ImplicitUsings>
8+
<!--
9+
Enable trim analyzers for Android class libraries.
10+
To learn more, see: https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming
11+
-->
12+
<IsTrimmable>true</IsTrimmable>
813
</PropertyGroup>
914
</Project>

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@
7474
<AndroidLinkMode Condition=" '$(AndroidLinkMode)' == '' and '$(PublishTrimmed)' == 'true' ">SdkOnly</AndroidLinkMode>
7575
<AndroidLinkMode Condition=" '$(AndroidLinkMode)' == '' ">None</AndroidLinkMode>
7676
<!-- For compat with user code not marked trimmable, only trim opt-in by default. -->
77-
<TrimMode Condition=" '$(TrimMode)' == '' and '$(AndroidLinkMode)' == 'Full' ">link</TrimMode>
77+
<TrimMode Condition=" '$(TrimMode)' == '' and '$(AndroidLinkMode)' == 'Full' ">full</TrimMode>
7878
<TrimMode Condition="'$(TrimMode)' == ''">partial</TrimMode>
79+
<SuppressTrimAnalysisWarnings Condition=" '$(SuppressTrimAnalysisWarnings)' == '' and '$(TrimMode)' == 'full' ">false</SuppressTrimAnalysisWarnings>
7980
<SuppressTrimAnalysisWarnings Condition=" '$(SuppressTrimAnalysisWarnings)' == '' ">true</SuppressTrimAnalysisWarnings>
8081
<!-- Prefer $(RuntimeIdentifiers) plural -->
8182
<RuntimeIdentifiers Condition=" '$(RuntimeIdentifier)' == '' And '$(RuntimeIdentifiers)' == '' ">android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>

src/Xamarin.Android.Build.Tasks/Resources/LayoutBinding.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
2+
using System.Diagnostics.CodeAnalysis;
33
using Android.App;
44
using Android.Views;
55

@@ -9,6 +9,8 @@ namespace Xamarin.Android.Design
99

1010
abstract class LayoutBinding
1111
{
12+
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
13+
1214
Activity boundActivity;
1315
View boundView;
1416
OnLayoutItemNotFoundHandler onLayoutItemNotFound;
@@ -25,7 +27,13 @@ protected LayoutBinding (View view, OnLayoutItemNotFoundHandler onLayoutItemNotF
2527
this.onLayoutItemNotFound = onLayoutItemNotFound;
2628
}
2729

28-
protected T FindView <T> (int resourceId, ref T cachedField) where T: View
30+
protected T FindView <
31+
[DynamicallyAccessedMembers (Constructors)]
32+
T
33+
> (
34+
int resourceId,
35+
ref T cachedField)
36+
where T: View
2937
{
3038
if (cachedField != null)
3139
return cachedField;
@@ -58,7 +66,14 @@ Activity EnsureActivity ()
5866
throw new InvalidOperationException ("Finding fragments is supported only for Activity instances");
5967
}
6068

61-
T __FindFragment<T> (int resourceId, Func<Activity, T> finder, ref T cachedField) where T: Java.Lang.Object
69+
T __FindFragment<
70+
[DynamicallyAccessedMembers (Constructors)]
71+
T
72+
> (
73+
int resourceId,
74+
Func<Activity, T> finder,
75+
ref T cachedField)
76+
where T: Java.Lang.Object
6277
{
6378
if (cachedField != null)
6479
return cachedField;
@@ -74,7 +89,15 @@ T __FindFragment<T> (int resourceId, Func<Activity, T> finder, ref T cachedField
7489
return ret;
7590
}
7691
#if __ANDROID_11__
77-
protected T FindFragment<T> (int resourceId, global::Android.App.Fragment __ignoreMe, ref T cachedField) where T: global::Android.App.Fragment
92+
protected T FindFragment<
93+
[DynamicallyAccessedMembers (Constructors)]
94+
T
95+
> (
96+
int resourceId,
97+
global::Android.App.Fragment __ignoreMe,
98+
ref T cachedField
99+
)
100+
where T: global::Android.App.Fragment
78101
{
79102
return __FindFragment<T> (resourceId, (activity) => activity.FragmentManager.FindFragmentById<T> (resourceId), ref cachedField);
80103
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ public void BuildHasNoWarnings (bool isRelease, bool xamarinForms, bool multidex
240240
new XamarinFormsAndroidApplicationProject () :
241241
new XamarinAndroidApplicationProject ();
242242
proj.IsRelease = isRelease;
243+
// Enable full trimming
244+
if (!xamarinForms && isRelease) {
245+
proj.TrimModeRelease = TrimMode.Full;
246+
}
243247
if (multidex) {
244248
proj.SetProperty ("AndroidEnableMultiDex", "True");
245249
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/AndroidLinkMode.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@ public enum AndroidLinkMode
99
SdkOnly,
1010
Full,
1111
}
12+
13+
public enum TrimMode
14+
{
15+
Partial,
16+
Full,
17+
}
1218
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22

33
namespace Xamarin.ProjectTools
44
{
@@ -18,6 +18,7 @@ public static class KnownProperties
1818
public const string RuntimeIdentifiers = "RuntimeIdentifiers";
1919
public const string RunAOTCompilation = "RunAOTCompilation";
2020
public const string PublishTrimmed = "PublishTrimmed";
21+
public const string TrimMode = "TrimMode";
2122
public const string SupportedOSPlatformVersion = "SupportedOSPlatformVersion";
2223

2324
public const string Deterministic = "Deterministic";

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ public AndroidLinkMode AndroidLinkModeRelease {
155155
set { SetProperty (ReleaseProperties, KnownProperties.AndroidLinkMode, value.ToString ()); }
156156
}
157157

158+
public TrimMode TrimModeRelease {
159+
get => Enum.TryParse (GetProperty (ReleaseProperties, KnownProperties.TrimMode), out TrimMode trimMode) ? trimMode : TrimMode.Partial;
160+
set => SetProperty (ReleaseProperties, KnownProperties.TrimMode, value.ToString ().ToLowerInvariant ());
161+
}
162+
158163
public bool EnableMarshalMethods {
159164
get { return string.Equals (GetProperty (KnownProperties.AndroidEnableMarshalMethods), "True", StringComparison.OrdinalIgnoreCase); }
160165
set { SetProperty (KnownProperties.AndroidEnableMarshalMethods, value.ToString ()); }

0 commit comments

Comments
 (0)