From 94d073aef3b416a1120a087bc9335de2f1689459 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 22 Jan 2021 10:26:52 -0600 Subject: [PATCH 1/2] [One .NET] AOT support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/xamarin/xamarin-android/issues/6052 Helpful reading: * https://github.com/dotnet/runtime/blob/15dec9a2aa5a4236d6ba70de2e9c146867b9d2e0/src/tasks/AotCompilerTask/MonoAOTCompiler.cs * https://github.com/dotnet/runtime/blob/15dec9a2aa5a4236d6ba70de2e9c146867b9d2e0/src/mono/netcore/nuget/Microsoft.NET.Runtime.MonoAOTCompiler.Task/README.md To make this work, I moved the existing `` MSBuild task calls to a new `_AndroidAot` MSBuild target in `Xamarin.Android.Legacy.targets`. In the .NET 6 targets, there is a *different* `_AndroidAot` MSBuild target that runs the new `` MSBuild task. The `_AndroidAot` target runs per `$(RuntimeIdentifier)` after the linker completes. Native libraries are added to the `@(ResolvedFileToPublish)` item group to be included in the final `.apk`. To follow convention with Blazor WASM: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#blazor-webassembly-ahead-of-time-aot-compilation The `$(RunAOTCompilation)` MSBuild property enables AOT. To help with backwards compatibility with "legacy" Xamarin.Android, I kept the `$(AotAssemblies)` MSBuild property intact. Unfortunately, we have to manually import things to support `$(AotAssemblies)`: Since, the default Mono workload does not support `$(AotAssemblies)`: https://github.com/dotnet/runtime/blob/69711860262e44458bbe276393ea3eb9f7a2192a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in#L20-L25 I think this is reasonable for now. ~~ Limitations ~~ * Profiled AOT is not implemented yet: https://github.com/xamarin/xamarin-android/issues/6053 * `$(EnableLLVM)` fails when locating `opt`: https://github.com/dotnet/runtime/issues/56386 * `AndroidClientHandler` usage causes runtime crash: https://github.com/dotnet/runtime/issues/56315 * Use of folder names like `Build AndÜmläüts` fails: https://github.com/dotnet/runtime/issues/56163 ~~ Results ~~ All tests were running on a Pixel 5. Using the HelloAndroid app: https://github.com/dotnet/maui-samples/tree/main/HelloAndroid Defaults to two architectures: arm64 and x86 Average of 10 runs with `-c Release` and no AOT: Activity: Displayed 00:00:00.308 Apk size: 8367969 Average of 10 runs with `-c Release -p:RunAOTCompilation=true`: Activity: Displayed 00:00:00.209 Apk size: 12082123 Using the HelloMaui app: https://github.com/dotnet/maui-samples/tree/main/HelloMaui Defaults to two architectures: arm64 and x86 Average of 10 runs with `-c Release` and no AOT: Activity: Displayed 00:00:01.117 Apk size: 16272964 Average of 10 runs with `-c Release -p:RunAOTCompilation=true`: Activity: Displayed 00:00:00.568 Apk size: 42869016 --- Documentation/guides/OneDotNet.md | 12 + .../GenerateSupportedPlatforms.cs | 4 + build-tools/automation/azure-pipelines.yaml | 14 +- .../Microsoft.Android.Sdk.After.targets | 1 + .../targets/Microsoft.Android.Sdk.Aot.targets | 87 ++++++ ...oft.Android.Sdk.AssemblyResolution.targets | 2 +- ...soft.Android.Sdk.DefaultProperties.targets | 3 + src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs | 194 +------------ .../Tasks/BuildApk.cs | 6 +- .../Tasks/CilStrip.cs | 4 +- .../Tasks/GetAotArguments.cs | 272 ++++++++++++++++++ .../Xamarin.Android.Build.Tests/AotTests.cs | 22 +- .../IncrementalBuildTest.cs | 2 + .../Utilities/BaseTest.cs | 15 + .../Xamarin.Android.Build.Tests/XASdkTests.cs | 28 +- .../Xamarin.Android.Common.targets | 62 ---- .../Xamarin.Android.Legacy.targets | 71 +++++ .../Tests/AotProfileTests.cs | 2 +- 18 files changed, 539 insertions(+), 262 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs diff --git a/Documentation/guides/OneDotNet.md b/Documentation/guides/OneDotNet.md index c3619205f5b..09b2cf4cbdc 100644 --- a/Documentation/guides/OneDotNet.md +++ b/Documentation/guides/OneDotNet.md @@ -164,6 +164,18 @@ It is recommended to migrate to the new linker settings, as [linker]: https://docs.microsoft.com/dotnet/core/deploying/trimming-options [linker-full]: https://docs.microsoft.com/dotnet/core/deploying/trimming-options#trimmed-assemblies +## AOT + +`$(RunAOTCompilation)` will be the new MSBuild property for enabling +AOT. This is the same property used for [Blazor WASM][blazor]. +`$(AotAssemblies)` will also enable AOT, in order to help with +migration from "legacy" Xamarin.Android to .NET 6. + +It is recommended to migrate to the new `$(RunAOTCompilation)` +property, as `$(AotAssemblies)` will eventually be deprecated. + +[blazor]: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#blazor-webassembly-ahead-of-time-aot-compilation + ## dotnet cli There are currently a few "verbs" we are aiming to get working in diff --git a/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/GenerateSupportedPlatforms.cs b/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/GenerateSupportedPlatforms.cs index fb491f744dc..57205c01fda 100644 --- a/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/GenerateSupportedPlatforms.cs +++ b/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/GenerateSupportedPlatforms.cs @@ -64,6 +64,10 @@ public override bool Execute () writer.WriteAttributeString ("Condition", " '$(TargetPlatformVersion)' == '' "); writer.WriteString (versions.MaxStableVersion.ApiLevel.ToString ("0.0", CultureInfo.InvariantCulture)); writer.WriteEndElement (); // + writer.WriteStartElement ("AndroidMinimumSupportedApiLevel"); + writer.WriteAttributeString ("Condition", " '$(AndroidMinimumSupportedApiLevel)' == '' "); + writer.WriteString (MinimumApiLevel.ToString ()); + writer.WriteEndElement (); // writer.WriteEndElement (); // writer.WriteStartElement ("ItemGroup"); diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index aa8585666cb..3df4deb4a93 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -49,7 +49,7 @@ variables: # - This is a non-fork branch with name containing "mono-" (for Mono bumps) IsMonoBranch: $[and(ne(variables['System.PullRequest.IsFork'], 'True'), or(contains(variables['Build.SourceBranchName'], 'mono-'), contains(variables['System.PullRequest.SourceBranch'], 'mono-')))] RunAllTests: $[or(eq(variables['XA.RunAllTests'], true), eq(variables['IsMonoBranch'], true))] - DotNetNUnitCategories: '& TestCategory != DotNetIgnore & TestCategory != AOT & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication' + DotNetNUnitCategories: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != ProfiledAOT & TestCategory != LLVM & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication' NUnit.NumberOfTestWorkers: 4 GitHub.Token: $(github--pat--vs-mobiletools-engineering-service2) CONVERT_JAVADOC_TO_XMLDOC: $[ne(variables['Build.DefinitionName'], 'Xamarin.Android-PR')] @@ -798,6 +798,18 @@ stages: artifactFolder: net6-Interpreter useDotNet: true + - template: yaml-templates/apk-instrumentation.yaml + parameters: + configuration: $(XA.Build.Configuration) + testName: Mono.Android.NET_Tests-Aot + project: tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj + testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)-Aot.xml + # InetAccess excluded due to: https://github.com/dotnet/runtime/issues/56315 + extraBuildArgs: /p:RunAOTCompilation=true /p:ExcludeCategories=InetAccess + artifactSource: bin/Test$(XA.Build.Configuration)/net6.0-android/Mono.Android.NET_Tests-Signed.apk + artifactFolder: net6-aot + useDotNet: true + - task: MSBuild@1 displayName: shut down emulator inputs: diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets index 1e2b90a1f16..15f83d483ef 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets @@ -18,6 +18,7 @@ This file is imported *after* the Microsoft.NET.Sdk/Sdk.targets. + 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 new file mode 100644 index 00000000000..705affcc8b0 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + <_AndroidAotInputs Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> + + + + + + + + + + <_MonoAOTAssemblies Include="@(_AndroidAotInputs->'%(FullPath)')" AotArguments="$(_AotArguments)" /> + + + + + + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index ad39e5f3823..de356268f77 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets @@ -31,7 +31,7 @@ _ResolveAssemblies MSBuild target. Properties\AndroidManifest.xml AndroidManifest.xml true + true + false + $(RunAOTCompilation) - - - - - - - <_UpdateAndroidResourcesDependsOn> $(CoreResolveReferencesDependsOn); @@ -658,4 +659,74 @@ projects. .NET 5 projects will not import this file. + + + + <_StartupAotProfile Condition="'%(ResolvedAssemblies.Filename)' == 'Xamarin.Forms.Platform.Android'">startup-xf.aotprofile + <_StartupAotProfile Condition="'$(_StartupAotProfile)' == ''">startup.aotprofile + + + + + + + + + <_AotProfiles Include="@(AndroidAotProfile)" /> + + + + + + + <_CilStripAssemblies Include="@(_ShrunkAssemblies)" Condition=" '%(FileName)' != 'Mono.Android' " /> + + + + + + + + + + + + + diff --git a/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs b/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs index 93dcd07bba5..8885879417c 100644 --- a/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs @@ -5,7 +5,7 @@ namespace Xamarin.Android.Build.Tests { - [Category ("UsesDevice"), Category ("AOT")] + [Category ("UsesDevice"), Category ("AOT"), Category ("ProfiledAOT")] public class AotProfileTests : DeviceTest { From 04bacb87cf917cd236e329f698f2012919849687 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 27 Jul 2021 16:47:06 -0500 Subject: [PATCH 2/2] Fix AOT tests in Mono.Android.NET-Tests.csproj * had the wrong file path for `TestResults-*.xml` * `$(ExcludeCategories)` should include `DotNetIgnore` and `InetAccess` --- build-tools/automation/azure-pipelines.yaml | 5 ++--- .../Mono.Android.NET-Tests.csproj | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 3df4deb4a93..bdafebf3e70 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -803,9 +803,8 @@ stages: configuration: $(XA.Build.Configuration) testName: Mono.Android.NET_Tests-Aot project: tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj - testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)-Aot.xml - # InetAccess excluded due to: https://github.com/dotnet/runtime/issues/56315 - extraBuildArgs: /p:RunAOTCompilation=true /p:ExcludeCategories=InetAccess + testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)Aot.xml + extraBuildArgs: /p:TestsFlavor=Aot /p:RunAOTCompilation=true artifactSource: bin/Test$(XA.Build.Configuration)/net6.0-android/Mono.Android.NET_Tests-Signed.apk artifactFolder: net6-aot useDotNet: true diff --git a/tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj b/tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj index 296d426a057..9cb12a9b4ca 100644 --- a/tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj +++ b/tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj @@ -19,8 +19,12 @@ false <_MonoAndroidTestPackage>Mono.Android.NET_Tests -$(TestsFlavor)NET6 - + DotNetIgnore + $(ExcludeCategories):InetAccess