Skip to content

chore: Update to .NET 10 Preview 7#21256

Merged
jeromelaban merged 12 commits intomasterfrom
dev/jonpryor/jonp-build-with-net10-p7
Aug 27, 2025
Merged

chore: Update to .NET 10 Preview 7#21256
jeromelaban merged 12 commits intomasterfrom
dev/jonpryor/jonp-build-with-net10-p7

Conversation

@jonpryor
Copy link
Contributor

Context: #19934
Context: #21140
Context: dotnet/sdk#48949

#19934 was the first attempt to build unoplatform/uno with .NET 10. It built (mostly), but it had lots of unit test failures (over 3700) that were not understood at the time.

#21140 was an attempt to cleanup & simplify #19934. It partially succeeded, but required additional reconsideration for a cleaner and more understandable merge.

(Later, PR #21183 helped explain many of the unit test failures that PR #19934 observed: Xamarin.UITest doesn't work reliably under .NET 9! See microsoft/appcenter#2646 and microsoft/appcenter#327!)

Some of the contents of #19934 and #21140 have been split out into separately merged PRs such as #21230 (CS0246 fixes) and #21199 (remove [Export] in some scenarios).

Squash existing "known good" and related changes:

  • doc updates

  • Bumping target framework versions,

  • Use uno.check 1.32.0-dev.45, which knows about .NET 10 Preview 7.

  • $(TreatWarningsAsErrors)=true + NuGet warnings. For example:

    error NU1510: Warning As Error:
    PackageReference System.Private.Uri will not be pruned.
    Consider removing this package from your dependencies, as it is likely unnecessary.
    
  • $(TreatWarningsAsErrors)=true + CS8604 warnings due to nullability changes, particularly in iOS.

  • $(TreatWarningsAsErrors)=true + IL2* warnings, some of which @jonpryor was able to fix in a reasonable timeframe, and some of which was thrown into $(NoWarn) to deal with later.

  • Remove hardcoded $(TargetFramework)=net8.0 from Uno.UI.RemoteControl.TestProcessor.csproj, so that it builds, and remove other uses of net8.0 from everywhere other than src/SolutionTemplate.

  • Provide %(PackageReference.Version) for packages that were producing NU1015 errors, specifically Uno.Fonts.OpenSans.

  • Remove @(PackageReference) values which produced NU1510 warnings such as:

    warning NU1510: PackageReference Microsoft.Win32.Registry will not be pruned. Consider removing this package from your dependencies, as it is likely unnecessary.
    
  • Improve dotnet-install.yml use, as some CI environments don't have a unoplatform/uno checkout, and thus cannot copy files such as build/ci/net10/global.json.

  • Improve local-android-uitest-run.sh for local macOS use: Export and use $ANDROID_AVD_HOME, so that we have a "known" location for whare Emulator images are created. (Not sure what's wrong with my environment, but they are not reliably created or loaded from $HOME/.android/avd.)

    Also update so that it doesn't require running the script from the build/test-scripts directory. You can now run it from topdir:

    UITEST_IS_LOCAL=true \
      build/test-scripts/local-android-uitest-run.sh
    
  • Provision OpenJDK-17, as .NET 9 now requires it.

  • Use Xcode 16.4, as .NET 10 iOS now requires it.

TODO, for future commits to this PR:

  • Xamarin.AndroidX package version bumps from chore: bump Xamarin.AndroidX Package Versions #21205. We felt that these shouldn't be separately merged, as some of version bumps are quite significant and should instead only be used with .NET 10.

  • A new understanding of src/SolutionTemplate: the intent, as @jonpryor currently understands it, is that tests within src/SolutionTemplate are "frozen in time"; $(TargetFrameworks) should not be updated, etc.

    Which means that when we drop support for an older version of .NET, we should in turn remove the old tests.

GitHub Issue: closes #

PR Type:

What is the current behavior? 🤔

What is the new behavior? 🚀

PR Checklist ✅

Please check if your PR fulfills the following requirements:

Other information ℹ️

@github-actions github-actions bot added platform/wasm 🌐 Categorizes an issue or PR as relevant to the WebAssembly platform platform/android 🤖 Categorizes an issue or PR as relevant to the Android platform platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform area/skia ✏️ Categorizes an issue or PR as relevant to Skia area/code-generation Categorizes an issue or PR as relevant to code generation area/build Categorizes an issue or PR as relevant to build infrastructure area/automation Categorizes an issue or PR as relevant to project automation platform/wpf 🪟 Categorizes an issue or PR as relevant to WPF kind/documentation area/sdk Categorizes an issue or PR as relevant to the Uno.Sdk labels Aug 13, 2025
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-build-with-net10-p7 branch from 9bc2a4b to 1d48b65 Compare August 13, 2025 22:11
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-build-with-net10-p7 branch from 1d48b65 to 6d7cf90 Compare August 14, 2025 11:54
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

@jeromelaban
Copy link
Member

Hi @Youssef1313! We're having some trouble with

https://dev.azure.com/uno-platform/Uno%20Platform/_build/results?buildId=173628&view=logs&j=6bdf2dae-f9ad-5d98-5eec-7947c0cfa97e&t=230c33c2-787a-5e7a-373a-3b919dbd215a&l=181

Unhandled exception. System.MissingMethodException: Method not found: 'Boolean Microsoft.Testing.Platform.Helpers.IFileSystem.Exists(System.String)'.
   at Microsoft.Testing.Extensions.VSTestBridge.Configurations.RunSettingsConfigurationProvider.BuildAsync(CommandLineParseResult commandLineParseResult)
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at Microsoft.Testing.Extensions.VSTestBridge.Configurations.RunSettingsConfigurationProvider.BuildAsync(CommandLineParseResult commandLineParseResult)
   at Microsoft.Testing.Platform.Configurations.ConfigurationManager.BuildAsync(IFileLoggerProvider syncFileLoggerProvider, CommandLineParseResult commandLineParseResult) in /_/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationManager.cs:line 37
   at Microsoft.Testing.Platform.Hosts.TestHostBuilder.BuildAsync(ApplicationLoggingState loggingState, TestApplicationOptions testApplicationOptions, IUnhandledExceptionsHandler unhandledExceptionsHandler, DateTimeOffset createBuilderStart) in /_/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs:line 131
   at Microsoft.Testing.Platform.Builder.TestApplicationBuilder.BuildAsync() in /_/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs:line 112
   at TestingPlatformEntryPoint.Main(String[] args) in /__w/1/s/src/SamplesApp/SamplesApp.UITests/obj/Release/net9.0/TestPlatformEntryPoint.cs:line 14
   at TestingPlatformEntryPoint.<Main>(String[] args)

Which seems to be in a generated portion of the test framework. Would you have an idea of what could cause this mismatch? Thanks!!

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-build-with-net10-p7 branch from 6d7cf90 to f775fa1 Compare August 14, 2025 15:02
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-build-with-net10-p7 branch 2 times, most recently from 2cda356 to 4c01f28 Compare August 14, 2025 18:11
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

1 similar comment
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

@unodevops
Copy link
Contributor

⚠️⚠️ The build 173702 has failed on Uno.UI - CI.

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-build-with-net10-p7 branch 2 times, most recently from 6b63cb1 to f03304d Compare August 15, 2025 12:55
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-build-with-net10-p7 branch from f03304d to d7c9645 Compare August 15, 2025 13:34
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-21256/wasm-skia-net9/index.html

jonpryor added a commit that referenced this pull request Aug 28, 2025
…droid

Context: #21256

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within a NativeAOT environment.

Initially, though, this PR *won't* build for NativeAOT.  This is to
ensure that the various build artifacts are built in the expected
locations.  Once the non-NativeAOT build works, we'll enable it.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

TODO:

  * Figure out why the older and untouched
    `.azure-devops-tests-android-skia.yml` stage is now failing (?!).

  * Import various `src` changes needed to allow apps to start
    within a NativeAOT environment.

  * Enable NativeAOT builds by uncommenting the `$(SkiaPublishAot)`
    MSBuild property within `SamplesApp.Skia.netcoremobile.csproj`.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
jonpryor added a commit that referenced this pull request Aug 29, 2025
…droid

Context: #21256

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within a NativeAOT environment.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `DeviceTargetHelper.cs`: the current Android+NativeAOT support
is built atop Linux support, to the extent that
`OperatingSystem.IsLinux()` is true!  Extend the platform detection
logic so that the app can startup, avoiding an assertion:

	I NativeAotFromAndroid: App failed to initialize: Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.IsTrue failed. /data/user/0/uno.platform.samplesapp.skia/files does not contain Uno Platform
	I NativeAotFromAndroid:    at Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowAssertFailed(String, String) + 0x6e
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertContainsIdProps|32_2(StorageFolder, App.<>c__DisplayClass32_0&) + 0x16a
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xb4
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Finally, enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the `$(PublishAot)`
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL linker errors.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

Note: Do *not* make Release-config apps [Debuggable][1] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][2].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://developer.android.com/guide/topics/manifest/application-element#debug
[2]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Aug 29, 2025
…droid

Context: #21256

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within a NativeAOT environment.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `DeviceTargetHelper.cs`: the current Android+NativeAOT support
is built atop Linux support, to the extent that
`OperatingSystem.IsLinux()` is true!  Extend the platform detection
logic so that the app can startup, avoiding an assertion:

	I NativeAotFromAndroid: App failed to initialize: Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.IsTrue failed. /data/user/0/uno.platform.samplesapp.skia/files does not contain Uno Platform
	I NativeAotFromAndroid:    at Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowAssertFailed(String, String) + 0x6e
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertContainsIdProps|32_2(StorageFolder, App.<>c__DisplayClass32_0&) + 0x16a
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xb4
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Finally, enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the `$(PublishAot)`
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

Note: Do *not* make Release-config apps [Debuggable][1] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][2].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://developer.android.com/guide/topics/manifest/application-element#debug
[2]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 2, 2025
…droid

Context: #21256

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within a NativeAOT environment.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `DeviceTargetHelper.cs`: the current Android+NativeAOT support
is built atop Linux support, to the extent that
`OperatingSystem.IsLinux()` is true!  Extend the platform detection
logic so that the app can startup, avoiding an assertion:

	I NativeAotFromAndroid: App failed to initialize: Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.IsTrue failed. /data/user/0/uno.platform.samplesapp.skia/files does not contain Uno Platform
	I NativeAotFromAndroid:    at Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowAssertFailed(String, String) + 0x6e
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertContainsIdProps|32_2(StorageFolder, App.<>c__DisplayClass32_0&) + 0x16a
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xb4
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Finally, enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the `$(PublishAot)`
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

Note: Do *not* make Release-config apps [Debuggable][1] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][2].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://developer.android.com/guide/topics/manifest/application-element#debug
[2]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 3, 2025
…droid

Context: #21256

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within a NativeAOT environment.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `DeviceTargetHelper.cs`: the current Android+NativeAOT support
is built atop Linux support, to the extent that
`OperatingSystem.IsLinux()` is true!  Extend the platform detection
logic so that the app can startup, avoiding an assertion:

	I NativeAotFromAndroid: App failed to initialize: Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.IsTrue failed. /data/user/0/uno.platform.samplesapp.skia/files does not contain Uno Platform
	I NativeAotFromAndroid:    at Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowAssertFailed(String, String) + 0x6e
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertContainsIdProps|32_2(StorageFolder, App.<>c__DisplayClass32_0&) + 0x16a
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xb4
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Finally, enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the `$(PublishAot)`
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

Note: Do *not* make Release-config apps [Debuggable][1] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][2].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://developer.android.com/guide/topics/manifest/application-element#debug
[2]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 11, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within an Android+NativeAOT
environment.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 11, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 12, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 15, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 25, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 25, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 25, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Sep 30, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 2, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 3, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Update `UnitTestsControl.cs` to provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

The problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist* (it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`).
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to the above two
    mentioned exceptions.

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 3, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Update `UnitTestsControl.cs` to provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

The problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist* (it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`).
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to the above two
    mentioned exceptions.

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 3, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Update `UnitTestsControl.cs` to provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

The problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist* (it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`).
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to the above two
    mentioned exceptions.

    These are ignored via:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 3, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Update `UnitTestsControl.cs` to provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

The problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist* (it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`).
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to the above two
    mentioned exceptions.

    These are ignored via:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 4, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Update `UnitTestsControl.cs` to provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

The problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist* (it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`).
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to the above two
    mentioned exceptions.

    These are ignored via:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 6, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
	described below.

    These are ignored via:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

Update `UnitTestsControl.cs` to try to work around NativeAOT
"weirdness" and provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Additionally, if a `TargetInvocationException` is thrown when the
the method arguments count and parameters count match, throw an
`AssertInconclusiveException`.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 6, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into two
major categories:

 1. Failures that don't make sense, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
	described below.

    These are ignored via:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

Update `UnitTestsControl.cs` to try to work around NativeAOT
"weirdness" and provide better error messages when
tests fail in certain scenarios.  Previously, many (many!) tests
would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Additionally, if a `TargetInvocationException` is thrown when the
the method arguments count and parameters count match, throw an
`AssertInconclusiveException`.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 6, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 7, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 10, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`, which fails:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

or:

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 10, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`, which fails:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

or:

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 10, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`, which fails:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

or:

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 10, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`, which fails:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

or:

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit that referenced this pull request Oct 13, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463
Context: AwesomeAssertions/AwesomeAssertions#290

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`, which fails:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

.NET Crypto support isn't propertly initialized in Android+NativeAOT
apps in .NET 10 RC1; see dotnet/android#10463.  This may be fixed in
dotnet/android#10461, but in the meantime we can manually call
`AndroidCryptoNative_InitLibraryOnLoad()` so that methods such as
`SHA1.Create()` won't throw.

Exclude tests which don't pass under NativeAOT.  These fall into
three major categories:

 1. Failures that don't make sense, likely due to unknown bugs within
    the NativeAOT toolchain itself, failing due to
    `TargetParameterCountException` or `InvalidOperationException`
    described below.  Some of these are worked around (see below),
    while others are ignored via e.g.:

        [Ignore("DataRowAttribute.GetData() wraps data in an extra array under NativeAOT; not yet understood why.")]

 2. Failures which are due to `AwesomeAssertions` using
    `MethodInfo.MakeGenericMethod()`; see
    AwesomeAssertions/AwesomeAssertions#290:

        Unhandled exception. System.NotSupportedException: 'AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.HandleImpl[System.Int32](AwesomeAssertions.Equivalency.Steps.EnumerableEquivalencyValidator,System.Object[],System.Collections.Generic.IEnumerable`1[System.Int32])' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
           at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2a
           at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x3f
           at AwesomeAssertions.Equivalency.Steps.GenericEnumerableEquivalencyStep.Handle(Comparands, IEquivalencyValidationContext, IValidateChildNodeEquivalency) + 0x21a
           at AwesomeAssertions.Equivalency.EquivalencyValidator.TryToProveNodesAreEquivalent(Comparands, IEquivalencyValidationContext) + 0x129
           at AwesomeAssertions.Equivalency.EquivalencyValidator.AssertEquality(Comparands, EquivalencyValidationContext) + 0x43
           at AwesomeAssertions.Collections.GenericCollectionAssertions`3.BeEquivalentTo[TExpectation](IEnumerable`1, Func`2, String, Object[]) + 0x1f9

    Basically, the `.BeBeEquivalentTo()` extension method cannot
    currently work in NativeAOT environments.

    These are ignored via:

        [Ignore(".BeEquivalentTo() unsupported under NativeAOT; see: AwesomeAssertions/AwesomeAssertions#290")]

 3. Other limitations within the NativeAOT environment.  For example,
    Android+NativeAOT does not yet have a GC bridge, meaning every
    `Java.Lang.Object` subclass instance is *never* collected by the
    GC unless explicitly `.Dispose()`d

Update `UnitTestsControl.cs` to try to work around some NativeAOT
"weirdness" and provide better error messages when tests fail in
certain scenarios.  Previously, many tests would fail with one of:

	System.Reflection.TargetParameterCountException: Arg_ParmCnt
	    at System.Reflection.DynamicInvokeInfo.ThrowForArgCountMismatch() + 0x83
	    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x136
	    at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x4f
	    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x4b9

or:

	System.InvalidOperationException: Missing parameter does not have default value
	    at Uno.UI.Samples.Tests.UnitTestsControl.ExpandArgumentsWithDefaultValues(Object[] methodArguments, ParameterInfo[] methodParameters) + 0x138
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_4.<<ExecuteTestsForInstance>b__12>d.MoveNext() + 0x92
	--- End of stack trace from previous location ---
	    at Uno.UI.Samples.Tests.UnitTestsControl.<>c__DisplayClass67_2.<<ExecuteTestsForInstance>g__InvokeTestMethod|5>d.MoveNext() + 0x549

A problem is that the reported test that was failing would be
reported as e.g. `When_Add_Remove(System.Object[])`, which is a test
method which *does not exist*; it's actually
`When_Add_Remove(object, int, LeakTestStyles, RuntimeTestPlatforms)`.
Additionally, which parameter doesn't have a default value?
Or how does the parameter count not match? Or…

An intermediate form of this commit would wrap the
`TargetParameterCountException` in an `InvalidOperationException`,
resulting in messages such as:

	System.InvalidOperationException: Exception thrown while invoking Uno.UI.Tests.Windows_Globalization.Given_NumeralSystemTranslator.When_NumeralSystemIsMtei(System.String, System.String) with arguments { System.Object[]{ 1 as System.String, ꯱ as System.String } }.
	---> System.Reflection.TargetParameterCountException: Parameter count mismatch.

Note that `When_NumeralSystemIsMtei(System.String, System.String)`
takes two arguments, but it's given *one* argument with value
`{{ System.Object[]{ 1 as System.String, ꯱ as System.String } }}`,
i.e. *the values are there*, just "wrapped" in an extra array.

Update `UnitTestsControl.InvokeTestMethod()` to always call
`ExpandArgumentsWithDefaultValues()` as part of test method
invocation, so that we have a centralized place to look for such
"extra array wrapping".  Update `ExpandArgumentsWithDefaultValues()`
so that if it encounters an array for a parameter type which isn't
an array, the array is expanded as additional arguments.

Log various "weird" scenarios via `Console.WriteLine()` to make it
easier to get a "complete" listing of such failing methods by using
`adb logcat` output.

TODO? the migration to AwesomeAssertions in 80c0705 results in some
"bizarre" failure messages, e.g.

	Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Expected value to be less than or equal to 81 because
	TextBox/SingleTextBox;Microsoft.UI.Xaml.VisualStateManager;Microsoft.UI.Xaml.Controls.Grid;…;ElementStub/HorizontalScrollBar;…

which is *truncated* at *4000* characters.  *Something* is wonky there.

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/automation Categorizes an issue or PR as relevant to project automation area/build Categorizes an issue or PR as relevant to build infrastructure area/code-generation Categorizes an issue or PR as relevant to code generation area/sdk Categorizes an issue or PR as relevant to the Uno.Sdk area/skia ✏️ Categorizes an issue or PR as relevant to Skia area/solution-templates Categorizes an issue or PR as relevant to the solution template kind/documentation platform/android 🤖 Categorizes an issue or PR as relevant to the Android platform platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform platform/wasm 🌐 Categorizes an issue or PR as relevant to the WebAssembly platform platform/wpf 🪟 Categorizes an issue or PR as relevant to WPF

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants