From 815e37484cc89890b07c7f47dd57180c9a778372 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 6 Jul 2023 16:58:14 -0500 Subject: [PATCH 01/12] [Xamarin.Android.Build.Tasks] implement $(AndroidStripIL) Context: https://github.com/dotnet/runtime/pull/86722 This adds an `` step after the `` task. This trims away IL of AOT-compiled methods. This is WIP. Builds work currently, but the app crashes at runtime with: 07-06 16:57:07.413 8865 8865 E companyname.foo: * Assertion at /__w/1/s/src/mono/mono/mini/mini-trampolines.c:1416, condition `invoke' not met --- .../targets/Microsoft.Android.Sdk.Aot.targets | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index db621d58ecf..1f0c9acf3a5 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -123,11 +123,25 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). LLVMPath="$(_LLVMPath)" LdName="$(_LdName)" LdFlags="$(_LdFlags)" + CollectCompiledMethods="$(AndroidStripIL)" + CompiledMethodsOutputDirectory="$(IntermediateOutputPath)tokens" WorkingDirectory="$(MSBuildProjectDirectory)" AotArguments="$(AndroidAotAdditionalArguments)"> + + + + Date: Fri, 11 Aug 2023 12:45:44 -0400 Subject: [PATCH 02/12] Update parameter names --- .../targets/Microsoft.Android.Sdk.Aot.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 1f0c9acf3a5..5833a91ae2f 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -123,8 +123,8 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). LLVMPath="$(_LLVMPath)" LdName="$(_LdName)" LdFlags="$(_LdFlags)" - CollectCompiledMethods="$(AndroidStripIL)" - CompiledMethodsOutputDirectory="$(IntermediateOutputPath)tokens" + CollectTrimmingEligibleMethods="$(AndroidStripIL)" + TrimmingEligibleMethodsOutputDirectory="$(IntermediateOutputPath)tokens" WorkingDirectory="$(MSBuildProjectDirectory)" AotArguments="$(AndroidAotAdditionalArguments)"> From d0db3401a62a6b42826a466bae2f8323c8c4a511 Mon Sep 17 00:00:00 2001 From: Fan Yang Date: Mon, 14 Aug 2023 17:08:13 -0400 Subject: [PATCH 03/12] Disable removing attribute when AndroidStripIL is enanbled. --- src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index b118454ee96..bbccc06e86a 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1973,7 +1973,7 @@ because xbuild doesn't support framework reference assemblies. From 19b2ab986565da98391dd5c7c91853b69f57bdb2 Mon Sep 17 00:00:00 2001 From: Fan Yang Date: Wed, 16 Aug 2023 12:01:45 -0400 Subject: [PATCH 04/12] Add a test --- .../Tests/InstallAndRunTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index fc60f88a1b7..83f84a5ecd0 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1075,5 +1075,24 @@ public void SupportDesugaringStaticInterfaceMethods () ); } + [Test] + public void EnableAndroidStripIL () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + EnableDefaultItems = true, + }; + proj.SetProperty("AndroidStripIL", "true"); + + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + RunProjectAndAssert (proj, builder); + + WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log")); + bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", + Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30); + Assert.IsTrue(didLaunch, "Activity should have started."); + } + } } From 61523203b0f57a9121be826658a5ec72459efcd8 Mon Sep 17 00:00:00 2001 From: Fan Yang Date: Wed, 16 Aug 2023 14:39:27 -0400 Subject: [PATCH 05/12] Set default parameter values --- .../targets/Microsoft.Android.Sdk.DefaultProperties.targets | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index e6719010b43..bd9c9fc9e1b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -93,7 +93,9 @@ <_AndroidXA1029 Condition=" '$(AotAssemblies)' != '' ">true <_AndroidXA1030 Condition=" '$(RunAOTCompilation)' == 'true' and '$(PublishTrimmed)' == 'false' ">true $(RunAOTCompilation) - true + false + true + false diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 83f84a5ecd0..b9216ea4f39 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1076,13 +1076,13 @@ public void SupportDesugaringStaticInterfaceMethods () } [Test] - public void EnableAndroidStripIL () + public void EnableAndroidStripILAfterAOT () { var proj = new XamarinAndroidApplicationProject { IsRelease = true, EnableDefaultItems = true, }; - proj.SetProperty("AndroidStripIL", "true"); + proj.SetProperty("AndroidStripILAfterAOT", "true"); var builder = CreateApkBuilder (); Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); From 647c8b9f06e91f315c6e19a923ac600449fed965 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 18 Aug 2023 11:56:26 -0400 Subject: [PATCH 10/12] Update build-properties.md Rewrite for consistency with the "flow" of other properties. --- .../guides/building-apps/build-properties.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Documentation/guides/building-apps/build-properties.md b/Documentation/guides/building-apps/build-properties.md index 61e57743a88..afe06d94074 100644 --- a/Documentation/guides/building-apps/build-properties.md +++ b/Documentation/guides/building-apps/build-properties.md @@ -1305,10 +1305,15 @@ Support for this property was added in Xamarin.Android 11.3. ## AndroidStripILAfterAOT -When setting it to true, the method body of the AOT compiled methods will be strip away. -By default, `AndroidStripILAfterAOT` is set to false. -To maximize the impact of this feature, when setting it to true, the default value of -`AndroidEnableProfiledAot` becomes false. However, you could overwrite it by setting it to true explicitly. +A bool property that specifies whether or not the *method bodies* of AOT compiled methods will be removed. + +The default value is `false`, and the method bodies of AOT compiled methods will *not* be removed. + +When set to `true`, [`$(AndroidEnableProfiledAot)`](#androidenableprofiledaot) is set to `false` by default. +This means that in Release configuration builds -- in which +[`$(RunAOTCompilation)`](#runaotcompilation) is `true` by default -- AOT is enabled for *everything*. +This can result in increased app sizes. This behavior can be overridden by explicitly setting +`$(AndroidEnableProfiledAot)` to `true` within your project file. Support for this property was added in .NET 8. From e4db7b8c1f1b4273fdf76e13995b5fd014bcea29 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 18 Aug 2023 13:51:13 -0500 Subject: [PATCH 11/12] EnableAndroidStripILAfterAOT asserts IL is stripped `HasBody` was true and `Body.Instructions.Count` was 0 --- .../MSBuildDeviceIntegration.csproj | 3 +++ .../Tests/InstallAndRunTests.cs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj index 8f6b1ecd0b8..70616562284 100644 --- a/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj +++ b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj @@ -37,6 +37,9 @@ + + $(MicrosoftAndroidSdkOutDir)Xamarin.Android.Cecil.dll + diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index b9216ea4f39..f35cc7f212a 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using System.Xml.Linq; using System.Xml.XPath; +using Mono.Cecil; using NUnit.Framework; using Xamarin.ProjectTools; @@ -1079,13 +1080,31 @@ public void SupportDesugaringStaticInterfaceMethods () public void EnableAndroidStripILAfterAOT () { var proj = new XamarinAndroidApplicationProject { + ProjectName = nameof (EnableAndroidStripILAfterAOT), + RootNamespace = nameof (EnableAndroidStripILAfterAOT), IsRelease = true, EnableDefaultItems = true, }; proj.SetProperty("AndroidStripILAfterAOT", "true"); + // So we can use Mono.Cecil to open assemblies directly + proj.SetProperty ("AndroidEnableAssemblyCompression", "false"); var builder = CreateApkBuilder (); Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + + var apk = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk"); + FileAssert.Exists (apk); + var helper = new ArchiveAssemblyHelper (apk); + Assert.IsTrue (helper.Exists ($"assemblies/{proj.ProjectName}.dll"), $"{proj.ProjectName}.dll should exist in apk!"); + using (var stream = helper.ReadEntry ($"assemblies/{proj.ProjectName}.dll")) { + stream.Position = 0; + using var assembly = AssemblyDefinition.ReadAssembly (stream); + var type = assembly.MainModule.GetType ($"{proj.RootNamespace}.MainActivity"); + var method = type.Methods.FirstOrDefault (p => p.Name == "OnCreate"); + Assert.IsNotNull (method, $"{proj.RootNamespace}.MainActivity.OnCreate should exist!"); + Assert.IsTrue (!method.HasBody || method.Body.Instructions.Count == 0, $"{proj.RootNamespace}.MainActivity.OnCreate should have no body!"); + } + RunProjectAndAssert (proj, builder); WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log")); From 40475e26df35c7bf3d9e2ca1a8dfdbec2dfac9da Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 21 Aug 2023 12:27:57 -0500 Subject: [PATCH 12/12] `$(AndroidEnableProfiledAot)` test parameter --- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index f35cc7f212a..1672b36b7cb 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1077,7 +1077,7 @@ public void SupportDesugaringStaticInterfaceMethods () } [Test] - public void EnableAndroidStripILAfterAOT () + public void EnableAndroidStripILAfterAOT ([Values (false, true)] bool profiledAOT) { var proj = new XamarinAndroidApplicationProject { ProjectName = nameof (EnableAndroidStripILAfterAOT), @@ -1086,6 +1086,7 @@ public void EnableAndroidStripILAfterAOT () EnableDefaultItems = true, }; proj.SetProperty("AndroidStripILAfterAOT", "true"); + proj.SetProperty("AndroidEnableProfiledAot", profiledAOT.ToString ()); // So we can use Mono.Cecil to open assemblies directly proj.SetProperty ("AndroidEnableAssemblyCompression", "false");