Skip to content

[NativeAOT] Stop linking Android NDK libunwind into applications #12146

Description

@simonrozsival

Summary

Stop linking or extracting the Android NDK's libunwind.a into NativeAOT application links.

This is the parent goal for #12139. Removing libc++/libc++abi is a prerequisite because libc++abi is currently the primary built-in _Unwind_* consumer that causes the NDK archive to be extracted.

NativeAOT's private LLVM-libunwind implementation must remain. It is required for managed stack walking, exception handling, GC, stack traces, profiling, and related runtime services.

Motivation

Android NativeAOT currently has two unwind implementations in the final link closure:

  1. NativeAOT's private implementation in libRuntime.WorkstationGC.a;
  2. the Android NDK implementation in libunwind.a.

With .NET 10.0.9 and NDK 29.0.14206865, both archives export the same global symbols. Two independent dotnet/android PR builds reproduce the resulting linker failure:

Both fail:

DotNetInstallAndRunMinorAPILevels(True, "net10.0-android36.1", NativeAOT)

ld.lld reports duplicate definitions including:

  • __unw_init_local
  • __unw_get_reg
  • __unw_step
  • __unw_resume
  • unw_local_addr_space

The .NET 11 fix in dotnet/runtime#128927 privatizes NativeAOT's symbols and remains valuable defense-in-depth. It does not make the second unwind implementation useful, however. Avoiding the NDK archive entirely removes duplicate code from the link closure and prevents this class of collision for runtime versions without privatization.

Dependency and sequence

  • Complete [NativeAOT] Remove libc++ from libNativeAOT.so #12139 to remove libc++_static.a and libc++abi.a from NativeAOT application links.
  • Capture the complete final link response for every supported ABI after libc++ removal.
  • Identify every remaining _Unwind_* consumer, including compiler runtime objects and supported third-party native libraries.
  • Prove whether the NDK libunwind.a input is unused without relying only on linker garbage collection.
  • Remove the NDK libunwind.a input from both the workload NativeLinker path and the legacy NDK/clang path.
  • Stop packaging any NDK libunwind payload that is no longer required specifically by NativeAOT.
  • Add regression coverage that rejects an NDK libunwind.a entry in NativeAOT link responses.
  • Measure the resulting native-library and APK size reduction.

Likely implementation surfaces include:

  • src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
  • src/Xamarin.Android.Build.Tasks/Utilities/NativeRuntimeComponents.cs
  • src/androidsdk/androidsdk.targets
  • build-tools/create-packs/Microsoft.Android.Runtime.proj

Validation

For arm64, arm32, x64, and x86 where supported, in Debug and Release:

  • final link response does not contain the Android NDK's libunwind.a;
  • final libNativeAOT.so has no unresolved _Unwind_* requirements;
  • NativeAOT's private unwind implementation remains present and usable;
  • managed exceptions and native-to-managed exception transitions work;
  • GC stack walking and repeated GC bridge processing work;
  • managed stack traces, profiling, and crash reporting work;
  • workload NativeLinker and legacy linker paths both succeed;
  • supported third-party native-library scenarios continue to link.

Non-goals

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: App+Library BuildIssues when building Library projects or Application projects.Area: NativeAOTIssues that only occur when using NativeAOT.drop-libcppWork to remove the libc++ dependency from Android NativeAOTneeds-triageIssues that need to be assigned.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions