[android] Enable android-arm CoreCLR with softfp ABI handling#127578
[android] Enable android-arm CoreCLR with softfp ABI handling#127578simonrozsival wants to merge 4 commits intodotnet:mainfrom
Conversation
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>
There was a problem hiding this comment.
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 forandroid-armselect 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_armCoreCLR 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. |
|
/azp run runtime-extra-platforms |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Tagging subscribers to 'arch-android': @vitek-karas, @simonrozsival, @steveisok, @akoeplinger |
| TargetOS targetOS = Get(_command.TargetOS); | ||
| TargetAbi targetAbi = Crossgen2RootCommand.IsArmel ? TargetAbi.NativeAotArmel : TargetAbi.NativeAot; | ||
|
|
||
| if (targetOS == TargetOS.Android) |
There was a problem hiding this comment.
Android is handled in the target files for nativeaot currently:
. If we are going to promote it to a first class OS for crossgen2, we should do the same for NativeAOT too.There was a problem hiding this comment.
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.
|
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.
Current Android pass/fail breakdown:
Failure classification:
I also searched the current downloaded Android AzDO/Helix logs for the old ABI signatures: 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 |
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>
There was a problem hiding this comment.
Pull request overview
Re-enables CoreCLR support and CI coverage for android-arm by aligning Android ARM32 builds with the required softfp calling convention and updating Crossgen2 invocation plumbing to avoid ABI mismatches that can corrupt floating-point arguments/returns.
Changes:
- Enable softfp behavior for Android ARM32 in native/CoreCLR build configuration (ARM_SOFTFP).
- Adjust Crossgen2 target OS/arch arguments for Android ARM32 so R2R payloads use the softfp (
armel) ABI. - Re-enable
android_armCoreCLR runtime pack gating and add CI/Helix coverage forandroid_arm.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tests/readytorun/multifolder/multifolder.csproj | Remaps Crossgen2 target OS/arch for Android ARM32 when generating the response file. |
| src/tests/Common/CLRTest.CrossGen.targets | Normalizes Crossgen2 --targetos/--targetarch for Android ARM32 in common test script generation. |
| src/mono/msbuild/android/build/AndroidBuild.InTree.targets | Forces Crossgen2 target arch to armel for ARM32 R2R compilation in Android in-tree builds. |
| src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj | Adjusts runtime-pack Crossgen2 tool item to use normalized target OS/arch (incl. armel for Android ARM32). |
| src/coreclr/crossgen-corelib.proj | Normalizes Crossgen2 target OS/arch for CoreLib crossgen on Android ARM32. |
| src/coreclr/clrdefinitions.cmake | Defines ARM_SOFTFP for Android+ARM in CoreCLR target definitions. |
| eng/testing/tests.readytorun.targets | Ensures Crossgen2 uses armel when running R2R tests for Android ARM32. |
| eng/Subsets.props | Unblocks CoreCLR support for Android ARM32 (still blocks Android x86). |
| eng/pipelines/runtime.yml | Adds android_arm to the main CoreCLR Android CI matrix. |
| eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml | Adds android_arm to extra-platforms CoreCLR Android jobs. |
| 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 native builds. |
| <_CrossGenTargetOS Condition="'$(TargetOS)' != 'android'">$(TargetOS)</_CrossGenTargetOS> | ||
| <_CrossGenTargetOS Condition="'$(TargetOS)' == 'android'">linux</_CrossGenTargetOS> | ||
| <_CrossGenTargetArch>$(TargetArchitecture)</_CrossGenTargetArch> | ||
| <_CrossGenTargetArch Condition="'$(TargetOS)' == 'android' and '$(TargetArchitecture)' == 'arm'">armel</_CrossGenTargetArch> |
| <_CrossGenTargetArch>$(TargetArchitecture)</_CrossGenTargetArch> | ||
| <_CrossGenTargetArch Condition="'$(TargetArchitecture)' == 'arm'">armel</_CrossGenTargetArch> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <Crossgen2Tool Include="$(Crossgen2Path)" | ||
| TargetArch="$(TargetArchitecture)" | ||
| TargetArch="$(_CrossGenTargetArch)" | ||
| TargetOS="linux" | ||
| PerfmapFormatVersion="$(PublishReadyToRunPerfmapFormatVersion)"/> |
| <_CrossGenTargetOS Condition="'$(TargetOS)' != 'android'">$(TargetOS)</_CrossGenTargetOS> | ||
| <_CrossGenTargetOS Condition="'$(TargetOS)' == 'android'">linux</_CrossGenTargetOS> | ||
| <_CrossGenTargetArch>$(TargetArchitecture)</_CrossGenTargetArch> | ||
| <_CrossGenTargetArch Condition="'$(TargetOS)' == 'android' and '$(TargetArchitecture)' == 'arm'">armel</_CrossGenTargetArch> |
Note
This PR description was drafted with GitHub Copilot.
Fixes #127500.
Description
This re-enables the
android-armCoreCLR runtime pack and CI coverage with the missing softfp ABI handling for Android ARM.In .NET's Android build plumbing,
android-armmaps to Android'sarmeabi-v7aABI. This is the Android ARM32 ABI used by the NDK path we build with; Crossgen2 does not need to distinguish it from the older, obsoletearmeabiABI.armeabi-v7acan use VFP floating-point instructions internally, but function-call boundaries use the softfp calling convention. In practice, that means floating-point arguments and return values are passed through core registers/stack rather than VFP argument registers. In Crossgen2/JIT target terminology, this is represented by selecting thearmelABI.The first enablement attempt in #127225 exposed runtime crashes because not every .NET code generation path agreed on that ABI. #127527 fixed part of the native build configuration, but local investigation showed ReadyToRun code produced by Crossgen2 could still be generated with the wrong ARM ABI.
Investigation
The failures consistently pointed to a floating-point calling convention mismatch:
DateTime.Nowcrash involved a native floating-point helper call.Hashtable(int, float)failure showed a constant0.72fload factor arriving corrupted at the callee.double/decimalconversions in test infrastructure paths.After enabling softfp for the native/CoreCLR build, the minimal JIT repros passed, but R2R payloads still failed. That narrowed the remaining issue to Crossgen2 target ABI selection rather than managed library logic.
The final shape is:
Android callers pass the real target identity to Crossgen2:
Crossgen2 recognizes that
android-armrequires softfp call boundaries, selects thearmelABI, and then normalizes the target OS to Linux.This keeps the Android-specific behavior limited to ABI selection. The rest of Crossgen2 continues to use the existing Linux/Bionic paths.
Changes
ARM_SOFTFPfor Android ARM native/CoreCLR target builds.--targetos:android.armelABI forandroid-armin Crossgen2, then normalize the target OS to Linux.$(TargetOS)instead of remapping Android to Linux at the caller.android-armCoreCLR runtime pack and CI coverage from [android] Enable CoreCLR runtime pack production for android-arm #127225.Validation
Built Android ARM locally:
Result:
Validated on physical Android device with
armeabi-v7asupport (Samsung A16).The following Android ARM test runs completed with zero failures with both
TestReadyToRun=trueandTestReadyToRun=false:System.Runtime.TestsSystem.Runtime.Numerics.TestsSystem.Numerics.Vectors.TestsSystem.Numerics.Tensors.TestsMicrosoft.Bcl.Numerics.Tests