Skip to content

Conversation

@sbomer
Copy link
Member

@sbomer sbomer commented Oct 30, 2025

  • Enables building native AOT smoke tests for android with one APK per test project
  • Adds marker files to set expected exit code when running through helix
  • Adds a runtime-androidemulator job for native AOT smoke tests
  • Expands libraries test coverage to include non-smoke tests
  • Sets up appcontext base directory in test host
  • Calls managed main through a pinvoke when running Exe project

Fixes #120715

sbomer added 30 commits October 13, 2025 17:21
- Expand native AOT smoke tests to all libraries tests - Add job for
runtime smoke tests using native AOT on emulator
Move NDK compiler logic to a shared props file and import it in test and
build projects to unify Android NativeAOT and Mono builds.
- Set ASSETS_DIR for crypto tests
  (using same pattern as existing crypto test)
- Set AppContext.BaseDirectory

We should probably change crypto tests to use
just AppContext.BaseDirectory.
- Use ReferenceXUnitWrapperGenerator != false to define SINGLE_FILE_TEST_RUNNER (android & singlefile targets) instead of IsFunctionalTest
- Condition SingleFileTestRunner compile and TrimmerRootAssembly (TestUtilities) on wrapper/generator and SkipTestUtilitiesReference
- Add Android NativeAOT publish/trim settings and set NativeLib/CustomNativeMain for android nativeaot
- Make DisableImplicitFrameworkReferences respect preexisting value and add explicit DisableImplicitFrameworkReferences=false in nativeaot tests dir
- Import testing\tests.targets when TargetsAndroid is true
- Update many NativeAOT smoke tests Main signatures to public static int Main(string[] args) to match runner invocation
- Ensure they have Main entry point
- Tighten MSBuild conditions:
  - Only set NativeLib/CustomNativeMain for Android when OutputType == Exe
  - Only import testing/tests.targets for Android when using MicrosoftNETSdk and building executables
  - Make TestNativeAOT/UseNativeAOTRuntime defaults apply when TestBuildMode == nativeaot and only include monodroid-nativeaot.cs for executable/XUnit-wrapper cases
- Avoid importing logic for SharedLibrary
- Fix library filename
- Set HasMergedInTests to ensure projects build
This import is now covered by the IsMergedTestRunnerAssembly property.
Fixes a warning about a double import.
Fixes issue where mono runtime tests are getting incorrect assembly name
due to this undesired import.
class Program
{
[Method]
static int Main()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look sustainable. src\tests\nativeaot is not different from the rest of src\tests. We would have to do these changes to all of src\tests to ship Android.

I assume this is needed because monodroid-nativeaot.cs needs to call main?

Can we make this work with the CustomMain approach? See the src\tests\nativeaot\CustomMain test - in that test we start in native code in CustomMainWithStubExeNative.cpp and call a magic __managed__Main symbol to reach the managed main.

If we let the compiler generate __managed__Main for these, monodroid-nativeaot.cs could just do:

[DllImport("*" /* Magic name that hard-binds the symbol at linker time*/, EntryPoint="__managed__Main")]
static extern int ManagedMain(int argc, void** argv);

And then p/invoke that (yep, it's weird, we're in managed code, we do a p/invoke transition, and the first thing managed_main will do is to transition back to managed; should be fine; the important part is that this gives us a very stable symbol name and signature).

This should match what iOS testing is doing: #87260, the only difference is that iOS testing calls managed__Main from native code and we would call it from managed code.

The trick at the project level should be:

  • OutputType = Exe
  • NativeLib = Shared (or Static would work too, but I think this is using Shared right now)
  • CustomNativeMain= true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use this approach for the runtime tests, thanks!

I already had to set CustomNativeMain to get around an error when using OutputType=Exe with NativeLib=Shared, and had it on my list to check if that would cause an unnecessary export. Now I know!

I was wondering how dotnet/android avoids the error - apparently they override OutputType so that it's always Library.

@sbomer sbomer force-pushed the sbomer/naot-android-coverage branch from 20fbe86 to d08f20b Compare October 31, 2025 22:51
internal static class TestFiles
{
internal const string TestDataFolder = "TestData";
internal static readonly string? TestDataRoot = Environment.GetEnvironmentVariable("ASSETS_DIR") ?? AppContext.BaseDirectory;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need an adjustment with this in place?

var filesDir = env->GetStringUTFChars(j_files_dir) ?? string.Empty;
AppContext.SetData("APP_CONTEXT_BASE_DIRECTORY", filesDir);
Environment.CurrentDirectory = filesDir;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, cleaned this up. I'm planning to clean up other uses of the TEST_ASSETS env var in a separate PR.

@dotnet dotnet deleted a comment from azure-pipelines bot Nov 3, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Nov 3, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Nov 3, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Nov 3, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Nov 3, 2025
Copilot AI review requested due to automatic review settings November 3, 2025 18:43
- Clean up whitespace diffs
- Clean up TEST_ASSETS reference
- ifdef out test logic that fails on Android
- Work around failure by not using libc++
@sbomer
Copy link
Member Author

sbomer commented Nov 3, 2025

/azp run runtime-android

@sbomer
Copy link
Member Author

sbomer commented Nov 3, 2025

/azp run runtime-androidemulator

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

1 similar comment
@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@dotnet dotnet deleted a comment from azure-pipelines bot Nov 3, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for running NativeAOT tests on Android by implementing the necessary infrastructure changes. The changes enable Android NativeAOT tests to build, package as APKs, and run on Android devices/emulators through Helix.

Key Changes

  • Adds Android-specific build configuration for NativeAOT tests
  • Implements custom entry point handling for NativeAOT on Android via monodroid-nativeaot.cs template
  • Configures CI/CD pipelines to build and run NativeAOT tests on Android
  • Excludes several tests that are incompatible with Android NativeAOT

Reviewed Changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/tests/nativeaot/Directory.Build.props Adds Android-specific build properties including library import generator settings and test runner configuration
src/tests/Directory.Build.props Enables aggressive trimming for Android NativeAOT, similar to iOS/tvOS
src/tests/Directory.Build.targets Adds logic to skip OutputType inference and handle DisableImplicitFrameworkReferences for Android NativeAOT
src/tests/build.proj Imports Android NDK compiler properties and adds RuntimeFlavor resolution for Android builds
src/tests/Common/mergedrunner*.targets Adds ExpectedExitCode file generation and conditions for mobile targets
src/tests/Common/helixpublishwitharcade.proj Reads ExpectedExitCode from file for Android test payloads
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Implements entry point execution via __managed__Main for Android NativeAOT tests
eng/testing/Android/AndroidNdkCompiler.props New file that centralizes Android NDK compiler/linker path configuration
src/mono/msbuild/android/build/AndroidBuild.props Imports centralized AndroidNdkCompiler.props instead of defining CppCompilerAndLinker locally
eng/testing/tests.*.targets Updates conditions to use ReferenceXUnitWrapperGenerator and adds NativeAOT-specific properties for Android
eng/pipelines/extra-platforms/*.yml Adds new Android NativeAOT CI jobs and removes /p:RunSmokeTestsOnly=true
eng/pipelines/common/platform-matrix.yml Parameterizes runtimeFlavor for Android platforms
src/tests/nativeaot/SmokeTests/*/?.csproj Marks several smoke tests as unsupported on Android with explanatory comments
src/tests/issues.targets Excludes nativeaot/SmokeTests/UnitTests from Android NativeAOT
src/libraries/tests.proj Excludes multiple library test projects that fail on Android NativeAOT
src/libraries//tests/.cs Adds ActiveIssue attributes for tests that fail on Android NativeAOT
src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs Removes trailing whitespace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NAOT][android] Microsoft.Extensions.Hosting.Unit.Tests failure

4 participants