Repository navigation
[xabt] Skip legacy scans for trimmable typemaps - #12976
Merged
Merged
Conversation
Debug trimmable builds still ran the legacy Cecil Java scans. The new runtime tests export an IList, which the trimmable generator supports but the legacy scanner cannot import, causing XALNS7003. Pass $(AndroidTypeMapImplementation) into <LinkAssembliesNoShrink/> and skip both legacy scans for trimmable typemaps. Compare the implementation name case-insensitively in C# while preserving assembly saving and optional compatibility fixups. Add pipeline coverage and Debug/Release collection-export builds. The failure was reproduced locally with legacy scans enabled, and all nine focused regression tests pass. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The fix is targeted, preserves legacy behavior, and includes appropriate regression coverage.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Skips incompatible legacy Cecil scans when using trimmable typemaps while preserving assembly fixups and saving.
Changes:
- Passes the typemap implementation into
LinkAssembliesNoShrink. - Conditionally omits legacy scan steps.
- Adds pipeline and Debug/Release regression coverage.
| File | Description |
|---|---|
Xamarin.Android.Common.targets |
Passes typemap configuration to the task. |
TrimmableTypeMapBuildTests.cs |
Tests collection exports in Debug and Release. |
LinkerTests.cs |
Verifies pipeline-step selection and casing. |
AssemblyModifierPipeline.cs |
Skips legacy scans for trimmable typemaps. |
Skipping the legacy trimmable scans leaves two existing tests with stale expectations. They fail on both macOS and Windows in build 1619664. Check the multi-TFM receiver's ACW mapping and compiled DEX class instead of the obsolete .jlo.xml output. Require explicit export constructors to build successfully and retain their JNI signatures instead of expecting the legacy scanner's XALNS7003 exception. All 12 focused tests pass locally, including the original collection export regressions and both CoreCLR and NativeAOT constructors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival
approved these changes
Oct 1, 2026
Member
Author
simonrozsival
added a commit
that referenced
this pull request
Oct 1, 2026
Include the merged #12976 trimmable typemap scan fix while preserving the runtime foundation and measured APK baselines. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival
added a commit
that referenced
this pull request
Oct 1, 2026
Integrate main through c35205f, including PR #12976's collection-export and explicit-constructor JNI regressions. Resolve conflicts by retaining the deleted legacy scanners and unconditional assembly copying; preserve both managed typemap and JCW/Dex multi-TFM assertions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival
added a commit
that referenced
this pull request
Oct 1, 2026
Include #12976 and retain the upstream migration from standalone generator tests to on-device and focused host coverage. Preserve SDK typemap pre-generation and app integration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival
added a commit
that referenced
this pull request
Oct 1, 2026
Include the upstream trimmable typemap legacy-scan fix from #12976 while preserving AAPT2 damaged-cache recovery and incremental keep-rule registration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival
added a commit
that referenced
this pull request
Oct 1, 2026
Bring in the merged Debug trimmable collection-export scanner fix (#12976) and current main changes without changing the standalone assembly-state scope. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival
added a commit
that referenced
this pull request
Oct 1, 2026
Include the merged trimmable legacy-scan fix from #12976, along with current main's SDK filtering and CI coverage updates. Preserve the independent NativeAOT bootstrap change and existing PR metadata. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
3 tasks done
simonrozsival
added a commit
that referenced
this pull request
Oct 3, 2026
… managed code (#12962) Part of #12940. Assembly stores need valid, ABI-specific ELF libraries so Android can package them under `lib/<abi>/libassembly-store.so` and Google Play can split an AAB by ABI. Today, producing these data-only libraries invokes `.S -> llvm-mc -> .o -> ld`. Write them directly in managed code instead, avoiding those external processes for store wrapping without changing the raw store format or packaging contract. ### Implementation - Add the framework-only `Microsoft.Android.Tasks.AssemblyStoreElfWriter` and a uniquely named `<WrapAssemblyStoresAsSharedLibraries/>` task in the modern .NET build-task assembly. Neither the writer nor its focused test project adds a managed ELF-parser dependency. - Produce little-endian ELF32/ELF64 `ET_DYN` images with one read-only load segment, read-only dynamic metadata, a non-executable stack, and a single default-visible global object symbol, `_assembly_store`. Preserve ARM EABI5/base-softfp flags and 16 KiB alignment for 64-bit ABIs / 4 KiB for 32-bit ABIs. - Stream-copy store bytes unchanged. Keep section names and section headers after the payload, outside `PT_LOAD`, so stripping can rebuild non-allocated metadata safely. - Dispatch stores unconditionally to the modern task using the existing store setting, with no LLVM fallback or new feature switch. Preserve the existing incremental packaging gate, file tracking, cleanup, and the legacy discrete assembly/PDB/config wrapper path. ### Trusted native store contract Current main already resolves only `_assembly_store` and calls `configure_from_payload(pointer, path)`. This PR preserves that API and **all existing runtime behavior and checks**; the native source delta is only a comment clarifying the contract. The XABA v3 payload is intentionally trusted build-generated data. There is no `_assembly_store_end`, external payload length, replacement size field, or runtime ELF-header walk. The standard ELF symbol size describes the payload for inspection only; the native loader does not consume it. This is not an untrusted-input parsing boundary. ### Standalone scope Updated by a normal merge of main at `c35205f1db840afb260678efaf83ef034afec51e`, including the upstream Debug-scanner fix in #12976. #12895 is **not a prerequisite**. Other application-specific LLVM generation and bundled tool usage remain intact; this does **not** eliminate all CoreCLR LLVM/binutils requirements. The writer diff has no bootstrap/environment/runtime-property changes, runtime-owned decompression/state changes, DSO-cache or JNI-remapping changes, typemap/marshal removal, `libxamarin-app.so` removal, NDK/linker-policy changes, or tool-distribution pruning. ### NDK-based inspection tests Use the official Android NDK's `llvm-readobj`, `llvm-nm`, `llvm-strip`, and `llvm-objcopy`, without adding ELFSharp to the modern test project. A small test-only helper is shared with the APK/AAB regression tests; no native tools are invoked by the managed writer. Existing ELFSharp consumers elsewhere in the repository are unchanged. `llvm-readobj` supplies ELF header/section/symbol/program-header metadata, and `llvm-objcopy` extracts payload, dynamic-table, string-table, and hash bytes. The independent symbol-and-segment extraction checks remain, including before/after stripping. Extraction uses a disposable output copy so the original library is not rewritten. **Resolve the toolchain on the executing test host**, in this order: `TEST_ANDROID_NDK_PATH`, `ANDROID_NDK_LATEST_HOME`, that user's `android-toolchain/ndk` installation, then a build-time `AndroidNdkDirectory` only if it still exists. This follows the existing test discovery convention and supports DLLs built on macOS and transferred to Windows/Linux. The four packaging-test failures in build [1620483](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1620483) selected the embedded macOS builder path, `/Users/cloudtest/android-toolchain/ndk`. The failing Linux and Windows agents had already successfully installed NDK r28c in the existing setup step before testing. The fix uses those installations; it does **not** add a CI download/install step or weaken inspection assertions. Native inspection cases remain tagged `RequiresAndroidNdk`. An absent or explicitly invalid toolchain still fails with a diagnostic; the stream/input-validation cases need no native tools. Five new discovery regressions cover runtime override, executing-host precedence over even an existing builder path, stale builder paths, explicit invalid configuration, and a valid local build fallback. ### Bounded process capture The .NET 11 native-tool test runner uses [`Process.RunAndCaptureText`](https://devblogs.microsoft.com/dotnet/process-api-improvements-in-dotnet-11/) to drain stdout and stderr together, with one 30-second timeout covering output capture and process exit. Timeout exceptions and canceled exit status are failures, not successful partial results. There are no unbounded manual exit waits. The helper is also linked into the existing net10.0 packaging tests, where the new API is unavailable. That build uses cancellation-aware concurrent reads and a cancellation-bounded combined wait, with the same whole-operation deadline. No target frameworks or product dependencies change. Five shared process regressions exercise output exceeding pipe capacity on both streams, nonzero exit diagnostics, a process that never closes output, a process that closes both streams but does not exit, and an exited parent whose child retains inherited pipes. The two POSIX-specific pipe-lifecycle cases are excluded on Windows. The identical regression sources are compiled into both test assemblies. ### Review follow-up Preserve already-written wrappers and cleanup directories when a later item lacks `Abi`: break the wrapping loop, finalize outputs, and return failure through the logged XA4234. A three-item regression checks the earlier output remains tracked and later stores are not written. Add `NativeLibraryLoadTests.AssemblyStoreDlopenResolvesOriginalPayload` to the existing device-integration suite. It builds and installs a Release CoreCLR app through production assembly-store packaging, then uses bionic `dlopen("libassembly-store.so", RTLD_NOW | RTLD_LOCAL)` and `dlsym("_assembly_store")`. The complete resolved payload's SHA-256 must equal the original raw build-generated store. The test verifies process bitness and the manifest mode and covers both extracted filesystem libraries and APK-embedded libraries. The regression has 32-bit and 64-bit cases, selecting a supported CoreCLR ABI from the target. Locally, both loading modes passed on exclusive session-owned ARM64 emulators running API 29 and API 35. Both installed system images expose only `arm64-v8a`; their two 32-bit cases were explicitly skipped. The 32-bit cases run where `armeabi-v7a` is available and are not claimed as locally validated. The temporary emulators were stopped and deleted afterward; no shared emulator or physical device was used. ### Validation | Coverage | Result | | --- | --- | | Combined modern writer + process + discovery tests | **89 passed, 0 failed/skipped**, compiled with the exact stale CI builder path and run with an execution-host NDK override | | Combined net10.0 raw-store/packaging + process + discovery tests | **14 passed, 0 failed/skipped**, including actual arm/arm64/x64 APK/AAB builds and incremental checks; compiled with the same stale CI path | | NDK environment fallback | **24 native round-trip cases passed** using only `ANDROID_NDK_LATEST_HOME`, without `TEST_ANDROID_NDK_PATH` | | Executing user's standard installation | **14 host cases passed** with both NDK environment variables unset, including actual three-ABI APK/AAB builds | | ELF layout and writer task coverage | All four encodable ABIs, layout/hash/dynamic metadata, stream and size/error handling, ABI archive/cleanup metadata, and partial-output failure handling retained | | Independent official NDK inspection | All 24 symbol-based payload cases passed across arm/arm64/x64, four sizes, before/after stripping, plus section extraction | | Actual bionic loader, API 29 and API 35 ARM64 | 2 passed per system image, 0 failed; 2 unsupported 32-bit cases skipped per image. Both extracted and embedded modes match the complete original payload | | Modern test dependency graph | No ELFSharp entry in resolved NuGet assets or the output `.deps.json` | | Upstream #12976 regression coverage after the main merge | 15 focused host cases previously passed; original Debug and JNI-reference-leak test-app builds succeed | Exact current-head local commands, with both test assemblies deliberately built using `-p:AndroidNdkDirectory=/Users/cloudtest/android-toolchain/ndk` and runtime `TEST_ANDROID_NDK_PATH` pointing at the installed private NDK: - `./dotnet-local.sh test src/Microsoft.Android.Build.Tasks/Tests/Microsoft.Android.Build.Tasks.Tests/Microsoft.Android.Build.Tasks.Tests.csproj --disable-build-servers -nr:false -p:UseSharedCompilation=false -p:AndroidNdkDirectory=/Users/cloudtest/android-toolchain/ndk -v minimal --filter "FullyQualifiedName~NativeToolTestHelperTests|FullyQualifiedName~AssemblyStoreElfWriterTests|FullyQualifiedName~DlopenAssemblyStoreGeneratorTests|FullyQualifiedName~WrapAssemblyStoresAsSharedLibrariesTests"` — **89 passed, 0 skipped**. - `./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll -v minimal --filter "FullyQualifiedName~NativeToolTestHelperTests|FullyQualifiedName~PackagingTest.ManagedAssemblyStoreElfWrappers|FullyQualifiedName~Tasks.CreateAssemblyStoreTests"` — **14 passed, 0 skipped**, repeated successfully with both NDK environment variables unset. - `./dotnet-local.sh test bin/TestDebug/net11.0/Microsoft.Android.Build.Tasks.Tests.dll -v minimal --filter "FullyQualifiedName~DlopenAssemblyStoreGeneratorTests.NativeToolsCanExtractPayloadBySymbol"` — **24 passed, 0 skipped** with only `ANDROID_NDK_LATEST_HOME` set. - `./dotnet-local.sh test bin/TestDebug/MSBuildDeviceIntegration/net10.0/MSBuildDeviceIntegration.dll -v minimal --filter "FullyQualifiedName~NativeLibraryLoadTests.AssemblyStoreDlopenResolvesOriginalPayload"` — **2 passed, 2 unsupported-ABI skips on each of API 29 and API 35**, with `ADB_TARGET` and `ANDROID_SERIAL` explicitly selecting the session-owned emulator. Earlier validation also built CoreCLR and NativeAOT native hosts for arm/arm64/x64 in Debug and Release, configured the local workload with `make prepare` / `make leeroy`, verified nine real bundletool ABI/config split APKs preserve their matching store libraries, and verified all six real APK/AAB store payloads survive native strip/objcopy round trips. Validation uses this worktree's main-pinned SDK (`12.0.100-alpha.1.26477.101`) and existing installed Android SDK/NDK/JDK tooling, not PoC task/native outputs. No product/framework/runtime pins are overridden. The stale NDK metadata is a test-artifact relocation simulation, not a product build pin override. ---- Pull Request [title](https://github.com/dotnet/android/blob/main/Documentation/workflow/commit-messages.md#commit-summary) and [description](https://github.com/dotnet/android/blob/main/Documentation/workflow/commit-messages.md#commit-body) should follow the [`commit-messages.md` workflow documentation](https://github.com/dotnet/android/blob/main/Documentation/workflow/commit-messages.md), and in particular should include: - [x] Useful description of *why the change is necessary*. - [x] Links to issues fixed - [x] Unit tests
3 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Fix the Debug build failure in Azure DevOps build 1618733.
<LinkAssembliesNoShrink/>still ran the legacy Cecil Java callable-wrapper and typemap scans for trimmable builds. The new runtime tests export anIList, which the trimmable generator supports but the legacy scanner cannot import, causingXALNS7003before tests run.Pass
$(AndroidTypeMapImplementation)into the task and skip both legacy scans for trimmable typemaps, using an ordinal case-insensitive comparison in C#. Preserve assembly saving, optional compatibility fixups, and legacy scanning when the task parameter is omitted.Validation: reproduce the same exception locally with legacy scans enabled, then confirm 9/9 focused regression tests pass with the fix. Coverage includes the compatibility-fixup matrix, one uppercase typemap case, and Debug/Release collection-export builds.