Skip to content

[android] Enable android-arm CoreCLR with softfp ABI handling#127578

Open
simonrozsival wants to merge 23 commits intodotnet:mainfrom
simonrozsival:dev/simonrozsival/android-arm-ci-setup
Open

[android] Enable android-arm CoreCLR with softfp ABI handling#127578
simonrozsival wants to merge 23 commits intodotnet:mainfrom
simonrozsival:dev/simonrozsival/android-arm-ci-setup

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival commented Apr 29, 2026

Note

This PR description was updated with GitHub Copilot.

Fixes #127500.

Description

This re-enables the android-arm CoreCLR runtime pack and CI coverage, and fixes the Android ARM softfp ABI handling needed for native code, ReadyToRun/Crossgen2-generated code, and NativeAOT target handling.

Android arm maps to the armeabi-v7a ABI. That ABI can use VFP instructions internally, but floating-point arguments and return values cross function-call boundaries through core registers/stack rather than VFP argument registers. In .NET target terminology, the matching AOT/JIT ABI is armel.

The original enablement exposed runtime crashes caused by parts of the build and code-generation pipeline disagreeing on that ABI. Native/CoreCLR builds needed ARM_SOFTFP, and AOT compiler target handling needed to treat Android ARM as Linux/Bionic with the softfp ABI.

Changes

  • Re-enable android-arm as a supported CoreCLR runtime pack target.

  • Re-enable Android ARM CoreCLR legs in the runtime and extra-platform CI pipelines.

  • Add Android ARM Helix queue selection.

  • Set ARM_SOFTFP for Android ARM native/CoreCLR builds.

  • Treat Android ARM compile definitions as softfp when setting CoreCLR target definitions.

  • Keep Android as an accepted AOT command-line target OS without extending the internal TargetOS enum.

  • Centralize Android command-line normalization in both Crossgen2 and NativeAOT ILCompiler:

    --targetos:android -> TargetOS.Linux
    --targetos:android --targetarch:arm -> NativeAotArmel / softfp ABI
    --targetos:android --targetarch:arm64 -> NativeAot
    
  • Update Crossgen2 call sites to pass the real Android target identity instead of duplicating Android-to-Linux remaps in MSBuild.

  • Update NativeAOT build integration to pass --targetos:android through to ILCompiler while preserving the existing bionic ARM armel target-architecture handling.

Validation

Built Android ARM locally:

./build.sh clr+libs+host+packs -os android -arch arm -c Release

Result:

Build succeeded.
0 Warning(s)
0 Error(s)

Validated on a physical Android device with armeabi-v7a support.

The following Android ARM test runs completed with zero failures with both TestReadyToRun=true and TestReadyToRun=false:

  • System.Runtime.Tests
  • System.Runtime.Numerics.Tests
  • System.Numerics.Vectors.Tests
  • System.Numerics.Tensors.Tests
  • Microsoft.Bcl.Numerics.Tests

Additional validation for the centralized AOT target handling:

./build.sh clr+libs+host /p:RestoreDisableParallel=true
./dotnet.sh build src/coreclr/tools/aot/crossgen2/crossgen2.csproj /p:RestoreDisableParallel=true
./dotnet.sh build src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj /p:RestoreDisableParallel=true
./dotnet.sh build src/tasks/Crossgen2Tasks/Crossgen2Tasks.csproj /p:RestoreDisableParallel=true
./build.sh tasks /p:RestoreDisableParallel=true
./dotnet.sh build src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILCompiler.TypeSystem.Tests.csproj /t:Test --no-restore
./dotnet.sh build src/coreclr/tools/aot/ILCompiler.Compiler.Tests/ILCompiler.Compiler.Tests.csproj /t:Test --no-restore

Also smoke-tested that both Crossgen2 and ILCompiler accept Android target arguments, including --targetos:android --targetarch:arm and --targetos:android --targetarch:arm64, and that the existing --targetos:linux --targetarch:armel normalization still works.

simonrozsival and others added 2 commits April 29, 2026 19:36
Enable the softfp ABI for Android ARM native/CoreCLR builds.

Teach Crossgen2 to accept android as a target OS and choose the armel ABI for android-arm before normalizing the target OS to Linux for existing object and runtime behavior.

Update the CoreLib, library test, SDK, and in-tree Android R2R callers to pass android/arm directly so linux-bionic RIDs keep their existing behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the android-arm CoreCLR runtime pack and CI enablement from dotnet#127225 now that the ABI handling is fixed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 29, 2026 18:40
@github-actions github-actions Bot added the area-crossgen2-coreclr only use for closed issues label Apr 29, 2026
Copy link
Copy Markdown
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 re-enables android-arm (armeabi-v7a) CoreCLR runtime pack production and CI by ensuring Crossgen2/JIT agree on Android ARM32’s required softfp call-boundary ABI (modeled as armel in the type system), while keeping the rest of Crossgen2’s behavior on existing Linux/Bionic paths.

Changes:

  • Teach Crossgen2 to accept --targetos:android, and for android-arm select the softfp (armel) ABI then normalize the OS to Linux for the remaining pipeline.
  • Update Android build/plumbing to pass the real $(TargetOS) to Crossgen2 (instead of remapping Android to Linux at the caller).
  • Re-enable android_arm CoreCLR runtime pack support and restore CI/Helix coverage, including Android ARM queue mapping.

Reviewed changes

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

Show a summary per file
File Description
src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs Allows the Crossgen2 task logic to resolve android as a target OS from RID graph matching.
src/mono/msbuild/android/build/AndroidBuild.InTree.targets Passes $(TargetOS) through to Crossgen2 for Android in-tree builds.
src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj Stops remapping Android to Linux for Crossgen2 invocation; passes $(TargetOS) directly.
src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs Adds TargetOS.Android to represent Android explicitly in target selection.
src/coreclr/tools/Common/CommandLineHelpers.cs Enables parsing --targetos:android into TargetOS.Android.
src/coreclr/tools/aot/crossgen2/Program.cs Implements Android normalization: select softfp (NativeAotArmel) for Android ARM32, then treat as Linux for the remaining Crossgen2 logic.
src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs Updates extended help to include android as a valid --targetos value.
src/coreclr/crossgen-corelib.proj Always passes --targetos:$(TargetOS) (removes Android→Linux remap at the caller).
src/coreclr/clrdefinitions.cmake Defines ARM_SOFTFP for Android ARM32 targets so native/JIT compilation agrees on softfp.
eng/testing/tests.readytorun.targets Passes $(TargetOS) to Crossgen2 for test R2R flows (removes Android→Linux remap).
eng/Subsets.props Re-enables CoreCLR support gating for Android ARM32 (still excludes Android x86).
eng/pipelines/runtime.yml Re-adds android_arm CoreCLR functional test coverage in the main pipeline matrix.
eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml Adds android_arm CoreCLR coverage in the extra-platforms Android pipeline.
eng/pipelines/coreclr/templates/helix-queues-setup.yml Adds Helix queue mapping for the android_arm platform.
eng/native/configureplatform.cmake Sets ARM_SOFTFP for Android ARM32 at CMake configuration time.

@simonrozsival
Copy link
Copy Markdown
Member Author

/azp run runtime-extra-platforms

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

TargetOS targetOS = Get(_command.TargetOS);
TargetAbi targetAbi = Crossgen2RootCommand.IsArmel ? TargetAbi.NativeAotArmel : TargetAbi.NativeAot;

if (targetOS == TargetOS.Android)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Android is handled in the target files for nativeaot currently:

<!-- linux-bionic on ARM uses armel (softfp) ABI -->
<_targetArchitectureWithAbi>$(_targetArchitecture)</_targetArchitectureWithAbi>
<_targetArchitectureWithAbi Condition="'$(_linuxLibcFlavor)' == 'bionic' and '$(_targetArchitecture)' == 'arm'">armel</_targetArchitectureWithAbi>
. If we are going to promote it to a first class OS for crossgen2, we should do the same for NativeAOT too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It seems the special casing of armel needs to duplicated in number of files. I think it would be fine to add Android to TargetOS enum if it made things easier.

My point was that both crossgen2 and nativeaot should do it the same way.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm for making things easier via an enum. The pushback has always been if there's nothing special about Android in naot/r2r, handle it in the targets. I still think that's true.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Centralizing the normalization of android -> linux and android-arm -> linux-armel makes the most sense to me. At the same time, I want to avoid making more changes than necessary in this PR. I wonder if we should do the refactoring later if needed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Note

This reply was generated with GitHub Copilot.

I went back to the centralized approach. TargetOS.Android is now recognized by the shared AOT command-line handling, and both Crossgen2 and NativeAOT ILCompiler normalize it internally: Android is treated as Linux for the effective target OS, and Android ARM selects the NativeAotArmel / softfp ABI.

I also updated the Crossgen2 call sites to pass the real Android target identity instead of duplicating the Android-to-Linux remap in MSBuild. NativeAOT now passes --targetos:android through to ILCompiler as well; its existing bionic ARM armel architecture mapping remains, and both compilers accept --targetos:android --targetarch:armel.

This was referenced Apr 30, 2026
@simonrozsival
Copy link
Copy Markdown
Member Author

Note

This CI analysis comment was drafted with Copilot.

I compared the current CI on #127578 with the original Android ARM runtime-pack enablement PR, #127225, and the first softfp follow-up, #127527. My read is that the original Android ARM ABI mismatch is not manifesting in the current run: the exact smoke job that exposed it before now passes.

PR / build Android ARM signal Verdict
#127225, build 1398504 android-arm Release AllSubsets_CoreCLR_Smoke failed across smoke work items Original ABI mismatch manifested; tracked by #127500 as SIGSEGV during runner init at System.DateTime.get_Now()
#127527, build 1400569 Same android-arm CoreCLR_Smoke job still failed Partial fix only; follow-up local investigation found remaining R2R ABI corruption symptoms like Hashtable(... Single loadFactor), Decimal.op_Explicit / VarDecFromR8, and NFloat
#127578, build 1402505 android-arm Release AllSubsets_CoreCLR_Smoke passed Strong evidence the old smoke-level ABI issue is fixed
#127578, build 1402544 Full Android legs still have failures Different failure set; not the old ARM ABI signature

Current Android pass/fail breakdown:

Job Result Failed work items / notes
android-arm CoreCLR_Smoke Pass No failed work items
android-arm64 CoreCLR_Smoke Pass No failed work items
android-x64 CoreCLR_Smoke Pass No failed work items
android-arm64 Mono_Smoke Pass No failed work items
android-x64 MonoAOTOffsets Pass No failed work items
android-x64 AllSubsets_Mono Pass No failed work items
android-x64 Mono RuntimeTests_Interp Pass No failed work items
android-x64 NativeAOT_RuntimeTests Pass No failed work items
android-arm AllSubsets_CoreCLR Fail System.IO.Compression.Tests, System.Net.NameResolution.Functional.Tests, System.Net.NameResolution.Pal.Tests, System.Net.Sockets.Tests
android-arm64 AllSubsets_CoreCLR Fail System.IO.Compression.Tests, System.Net.NameResolution.Functional.Tests, System.Net.Sockets.Tests
android-x64 AllSubsets_CoreCLR Fail System.IO.Compression.Tests, System.Net.Sockets.Tests
android-x64 NativeAOT Fail System.IO.Compression.Tests, System.Linq.Expressions.Tests, System.Net.Sockets.Tests

Failure classification:

  • System.IO.Compression.Tests: the failing tests are the three RoundTrip_AllWindowLogs cases, all returning DestinationTooSmall. I reproduced these locally on android-arm CoreCLR both with and without R2R, so this is not R2R-specific. This matches the broader mobile compression issue tracked by #127563.
  • System.Net.NameResolution.*: matches the existing Android/mobile networking/configuration failure class tracked by #126456.
  • System.Net.Sockets.Tests: matches the existing Android socket/IPv6 failure class tracked by #127565.
  • android-x64 NativeAOT / System.Linq.Expressions.Tests: still looks unclassified from this pass and should be investigated or tracked separately.

I also searched the current downloaded Android AzDO/Helix logs for the old ABI signatures: System.DateTime.get_Now, SIGSEGV / SIGABRT, managed Hashtable..ctor(... Single loadFactor), loadFactor, Decimal.op_Explicit, VarDecFromR8, NFloat, and arithmetic-overflow R2R corruption. None of those signatures appear in the current Android logs; the only Hashtable hit is a native source filename (jithashtable.cpp) in build output.

So I would not treat the current red CI as evidence that the original Android ARM ABI mismatch is still present. The important ABI validation signal passed; the remaining Android failures are later library/test-suite issues, mostly already represented by known mobile issues, with the NativeAOT System.Linq.Expressions failure as the remaining item to classify.

simonrozsival and others added 2 commits April 30, 2026 12:15
Keep Android as Linux for Crossgen2 and pass armel from in-tree MSBuild callers so the compiler selects the softfp ABI without making Android a first-class Crossgen2 OS.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Align the Android ARM Crossgen2 remap with the existing _CrossGenTargetOS naming pattern and use _CrossGenTargetArch for the architecture remap. Keep the Android in-tree target simpler by hardcoding Crossgen2 TargetOS metadata to linux.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/coreclr/tools/Common/CommandLineHelpers.cs
Comment thread eng/native/configureplatform.cmake Outdated
Comment thread src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs Outdated
Comment thread src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs
Copy link
Copy Markdown
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Thanks!

Copilot AI review requested due to automatic review settings May 7, 2026 06:04
Copy link
Copy Markdown
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

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

if (TARGETDETAILS_ARCH STREQUAL "armel")
if (TARGETDETAILS_ARCH STREQUAL "armel" OR
(TARGETDETAILS_ARCH STREQUAL "arm" AND CLR_CMAKE_TARGET_ANDROID))
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE ARM_SOFTFP)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This ARM_SOFTFP define looks redundant. Delete it?

eng\native\gen-buildsys.sh(85):cmake_extra_defines="$cmake_extra_defines -DARM_SOFTFP=1"

Comment thread src/coreclr/tools/aot/ILCompiler/Program.cs Outdated
Copilot AI review requested due to automatic review settings May 8, 2026 03:34
Copy link
Copy Markdown
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

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/tools/Common/CommandLineHelpers.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 8, 2026 03:56
Comment thread src/coreclr/tools/Common/CommandLineHelpers.cs Outdated
Copy link
Copy Markdown
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

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@simonrozsival
Copy link
Copy Markdown
Member Author

simonrozsival commented May 8, 2026

Note

This comment was AI/Copilot-generated based on the local investigation.

@vitekkaras FYI, the CI failure is happening before tests run because Android library Helix submissions enable XHarness (IncludeXHarnessCli=true in sendtohelixhelp.proj), and the Helix SDK's XHarness targets default to XHarnessTargetFramework=net8.0 and DotNetCliVersion=8.0.100 when not overridden (XHarnessRunner.targets). The new Android arm queue name includes Arm32 (Windows.11.Amd64.Android.Arm32.Open in helix-queues-setup.yml), and Helix SDK infers the dotnet CLI runtime from queue-name substrings, mapping Windows+Arm32 to win-arm (DotNetCli.props). That inference is wrong for this queue because Arm32 is the Android device ABI, while the Helix host is still Windows Amd64; the libraries SendToHelix path therefore needs to override these defaults to use runtime's SDK from global.json and the host CLI runtime (win-x64).

runtime (Build android-arm Release AllSubsets_CoreCLR_Smoke):

/__w/1/s/.packages/microsoft.dotnet.helix.sdk/11.0.0-beta.26211.102/tools/dotnet-cli/DotNetCli.targets(7,5): error : Unable to find dotnet cli sdk version 8.0.100 from any of the specified feeds. [/__w/1/s/src/libraries/sendtohelixhelp.proj]

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

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[android] Got a SIGSEGV while executing native code. at System.DateTime.get_Now()

7 participants