Skip to content

[Xamarin.Android.Build.Tasks] Remove R8 assembly rewriter - #12846

Merged
simonrozsival merged 2 commits into
mainfrom
simonrozsival-remove-r8-assembly-rewriter
Sep 21, 2026
Merged

simonrozsival merged 2 commits into
mainfrom
simonrozsival-remove-r8-assembly-rewriter

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Summary

Remove the experimental build-time managed-assembly rewriting approach for R8 so any future assembly-rewriting design can start from a clean foundation.

This cleanup is related to #12535 and the original prototype in #12575.

What this PR undoes

This removes the managed rewriting implementation developed across the R8 obfuscation stack:

Concretely, this PR removes the rewrite task, rewrite-only metadata/IL utilities, dedicated tests and fixtures, and the XA4325/XA4326 resources and documentation. The intent is to abandon this implementation rather than preserve an unused rewriting stack that a future design would need to work around.

What remains in place

We may revisit managed assembly rewriting in .NET 12 based on customer feedback and performance data, but with a fresh design rather than this implementation.

Validation

  • Built Xamarin.Android.Build.Tasks
  • Ran Microsoft.Android.Build.Tasks.Tests
  • Ran Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests
  • Built MSBuildDeviceIntegration
  • Ran focused R8MappingTests

Copilot AI lite review requested due to automatic review settings September 21, 2026 13:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The test project has an unresolved compile issue after the project reference removal; localization artifacts also need synchronization.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity · 1 Low severity

Open (2)
What changed in this PR

Removes the experimental R8 managed-assembly rewriter while retaining ordinary R8 processing and R8Mapping.

Changes:

  • Deletes rewriter implementation, tasks, fixtures, and tests.
  • Removes XA4325/XA4326 resources and documentation.
  • Retains and updates R8Mapping tests.
File Change
tests/​Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/​JniAssemblyRewriterTests.cs Removes rewriter integration tests.
tests/​Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/​GeneratedTypeMapRewriterTests.cs Removes typemap rewriter tests.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​NativeResourceSectionCopier.cs Removes resource rewrite helper.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​MetadataRawColumns.cs Removes metadata helper.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​MetadataEncoding.cs Removes encoding helper.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​LdstrRewriter.cs Removes string rewriter.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​JniRewritePlanner.cs Removes rewrite planning logic.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​JniRewritePlan.cs Removes rewrite plan and IL scanner.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​JniRewriteException.cs Removes rewrite exception.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​JniDescriptorText.cs Removes descriptor helper.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​JniAssemblyRewriter.cs Removes rewriter entry point.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​IlOpcodeTable.cs Removes opcode metadata.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​FieldRvaTable.cs Removes FieldRVA support.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​CustomAttributeStringRewriter.cs Removes attribute rewriting helper.
src/​Xamarin.Android.Build.Tasks/​Utilities/​JniRemapping/​AssemblyRebuilder.cs Removes PE reconstruction implementation.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​JniRemapping/​R8MappingTests.cs Retains parser coverage and removes deleted helper usage.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​JniRemapping/​NativeResourceSectionCopierTests.cs Removes helper tests.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​JniRemapping/​LdstrRewriterTests.cs Removes string-rewriter tests.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​JniRemapping/​JniFixtureBuilder.cs Removes rewrite fixtures.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​JniRemapping/​JniDescriptorTextTests.cs Removes descriptor-helper tests.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​JniRemapping/​AssemblyRebuilderTests.cs Removes rebuilder tests.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Tasks/​RewriteJniNamesForR8Tests.cs Removes task tests.
src/​Xamarin.Android.Build.Tasks/​Tasks/​RewriteJniNamesForR8.cs Removes the experimental rewrite task.
src/​Xamarin.Android.Build.Tasks/​Properties/​Resources.resx Removes XA4325/XA4326 resources.
src/​Xamarin.Android.Build.Tasks/​Properties/​Resources.Designer.cs Removes generated resource accessors.
src/​Microsoft.Android.Build.Tasks/​Tests/​Microsoft.Android.Build.Tasks.Tests/​Microsoft.Android.Build.Tasks.Tests.csproj Removes the rewriter-only project reference.
src/​Microsoft.Android.Build.Tasks/​Tests/​Microsoft.Android.Build.Tasks.Tests/​JniAssemblyRewriterTypeMapTests.cs Removes rewriter type-map tests.
Documentation/​docs-mobile/​TOC.yml Removes diagnostic navigation entries.
Documentation/​docs-mobile/​messages/​xa4326.md Removes XA4326 documentation.
Documentation/​docs-mobile/​messages/​xa4325.md Removes XA4325 documentation.
Documentation/​docs-mobile/​messages/​index.md Removes diagnostic index entries.
Files not reviewed (1)
  • src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs: Generated file

Comment thread src/Xamarin.Android.Build.Tasks/Properties/Resources.resx
@simonrozsival
simonrozsival added this pull request to stack #12850 September 21, 2026 14:15
@simonrozsival simonrozsival added ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). r8-runtime-rewriting labels Sep 21, 2026
@simonrozsival
simonrozsival merged commit 3c669fd into main Sep 21, 2026
44 checks passed
@simonrozsival
simonrozsival deleted the simonrozsival-remove-r8-assembly-rewriter branch September 21, 2026 20:49
simonrozsival added a commit that referenced this pull request Oct 1, 2026
Depends on #12846.

This is the consolidated runtime foundation for the R8 runtime-remapping stack. It supersedes the earlier split runtime implementation in #12796 and #12817 without abandoning that workstream.

It adds the generic JNI remapping support shared by Java.Interop, Mono.Android, MonoVM, CoreCLR, and NativeAOT, including forward/reverse type remapping, descriptor-aware method and constructor remapping, field remapping, Java hiding/fallback behavior, and focused tests.

The generated application object contains read-only remapping tables and a single `jni_remapping_data` descriptor. Native startup passes that descriptor to managed initialization; type, reverse-type, method, and field lookup algorithms remain in `JniRemappingLookup.cs`. No C++ remapping lookup implementation or lookup P/Invokes are introduced.

This PR intentionally contains no R8 build orchestration and no managed assembly rewriting. Producer-side R8 mapping ingestion and generated-table wiring are in the next stack layer, #12848; public mode and build orchestration follow in #12692, with the modern task-assembly boundary in #12844.

## APK size and disabled-remapping footprint

The measured Simple/CoreCLR baselines were refreshed from the complete test attachments in [CI build 1618183](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1618183):

| Configuration | Previous APK bytes | Current APK bytes | Change |
|---|---:|---:|---:|
| Without R8 | 6,526,395 | 6,530,491 | +4,096 (0.063%) |
| With R8 | 6,526,395 | 6,526,395 | 0 |

The test failure was the **per-file** threshold on `libxamarin-app.so`, not a large APK regression: that library grew from 11,744 to 12,368 bytes (+624, 5.05%). Isolated re-links using the archived CI object files attribute this exactly:

- **400 bytes** for the expanded empty remapping ABI: the 48-byte descriptor, reverse-type and field placeholders, and their ELF symbol/hash/string/relocation bookkeeping.
- **224 bytes** for the two runtime configuration entries that explicitly disable remapping. Removing only these entries produces 12,144 bytes; replacing only the remapping object with the previous two-table layout produces 11,968 bytes. Removing both reproduces the previous 11,744-byte library. The `.text` section remains **36 bytes** in all four variants; this is fixed data/configuration overhead, not added remapping executable code.

For this no-remapping application, all four table counts are zero and both remapping switches are configured `false`. Inspection of the actual linked **`Mono.Android.Runtime.dll`** confirms that `JniRemappingLookup` is absent. The earlier approximately 100 KiB cost from retaining the managed remapping implementation has not returned.

The full baseline comparison also crosses the **.NET 11 RC2 to .NET 12 alpha update inherited from `main` in #12939**, so its other changes must not be attributed wholesale to this PR. The APK's CoreCLR, JIT, globalization, and System.Native binaries are byte-identical to the new runtime pack; the cached previous runtime pack matches the old reference sizes. For example, `libcoreclr.so` shrank 103,792 uncompressed bytes, while `libclrjit.so` grew 15,896 bytes. The assembly store grew 23,880 bytes and `libmonodroid.so` shrank 2,896 bytes. Summed across all entries, **uncompressed contents actually shrank 65,868 bytes**.

APK size measures the **compressed and signed archive**, not the sum of those uncompressed sizes. The current APK uses DEFLATE for its native libraries, an 8 KiB signing block, and 4 KiB signing alignment. The nearest retained pre-upgrade comparison, [CI build 1617831](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1617831), shows the larger assembly store (+23,216 compressed bytes) and JIT (+6,970) almost offset by the smaller CoreCLR (-28,694) and other entries: compressed payload grows just **1,034 bytes**, while ZIP/signing/alignment overhead grows **3,062 bytes**, producing the observed **4 KiB APK step**. `libxamarin-app.so` itself adds only **107 compressed bytes** in that comparison.

**Comparison limitation:** the exact reference APK was generated locally before the runtime update and was not retained. Build 1617831 has slightly different dex/store/monodroid entries, although its total APK size matches the reference. The compressed/padding breakdown is therefore an explicitly identified historical CI comparison, not an exact reconstruction of the local reference or a same-toolchain `main`-versus-PR A/B test. The isolated 400/224-byte native attribution and removal of the managed lookup are independently confirmed.
simonrozsival added a commit that referenced this pull request Oct 9, 2026
Context: #12535

This is the product policy and build-orchestration layer for opt-in R8 runtime JNI remapping. It is stacked on:

- #12846 — removes the abandoned managed-assembly rewriting implementation
- #12847 — adds generic runtime JNI remapping support
- #12848 — parses the final R8 mapping and generates native runtime lookup tables

A final dependent PR, #12844, moves the .NET-only R8 mapping task into `Microsoft.Android.Build.Tasks`.

This PR does not rewrite managed assemblies. Managed bindings retain their original JNI names; the lower layers generate native tables that translate lookups to the names and descriptors emitted by R8.

## Opt-in

For a trimmed CoreCLR or NativeAOT application:

```xml
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
  <AndroidLinkTool>r8</AndroidLinkTool>
  <AndroidTypeMapImplementation>trimmable</AndroidTypeMapImplementation>
  <PublishTrimmed>true</PublishTrimmed>
  <AndroidR8ObfuscationMode>runtime-remapping</AndroidR8ObfuscationMode>
</PropertyGroup>
```

`runtime-remapping` is the sole opt-in; there is no separate enable property. It does not apply to library projects. The existing `private-members` and `disabled` behavior remains unchanged. Unknown mode values report XA1050, while incompatible runtime-remapping configurations report XA4329.

## Build orchestration

- Runs R8 once, after ILLink or all per-RID NativeAOT ILC compilations.
- Converts that final mapping into runtime remapping tables before native linking.
- Defers NativeAOT linking until the shared R8 pass completes, then relinks each RID without rerunning ILC.
- Applies the runtime-remapping-specific bootstrap, native-callback, manifest, resource, and JNI safety keep rules.
- Preserves existing MAM remapping precedence and asset handling.
- Tracks mapping inputs, generated XML, native table sources, task assemblies, native-link inputs, configuration changes, missing-output recovery, and opt-out for incremental builds.
- Preserves generated ProGuard rule timestamps when their contents are unchanged so managed-only rebuilds do not rerun R8 unnecessarily.

## Coverage in this layer

Host tests cover mode defaults, configuration validation, keep-rule policy, NativeAOT ProGuard configuration, packaging metadata, and incremental behavior. Build/device integration tests cover renamed types and members, constructors, overloads, inherited lookups, peer activation, single-pass ordering, multi-RID builds, missing-output recovery, and opt-out for CoreCLR and NativeAOT.

The generic lookup semantics and mapping/table-generation tests live in #12847 and #12848 respectively.

## Experimental limitations

NativeAOT literal matching is conservative and can retain extra entries. Arbitrarily computed JNI names may require explicit remaps or keep rules. Conservative public/nested-class, interface, bootstrap, and native-callback keeps limit obfuscation. Existing Intune/R8 conflict handling is not full remapping-chain composition, and ambiguous reverse mappings for merged classes are omitted. This remains an experimental opt-in, not a production-readiness claim.

----

- [x] Useful description of why the change is necessary.
- [x] Links to related issues and dependent layers.
- [x] Unit and integration coverage.

Fixes: #12535
simonrozsival added a commit that referenced this pull request Oct 10, 2026
…mbly (#12844)

## Summary

This PR is stacked on and depends on #12692. That parent is built on the focused lower chain #12846, #12847, and #12848.

This final layer is only a task-assembly boundary change for the runtime-R8 remapping producer. It moves `GenerateR8JniRemapping` and the .NET-only helpers it directly requires into `Microsoft.Android.Build.Tasks`:

- `JniRemappingAssemblyScanner`
- `R8Mapping`
- `JniDescriptorText`
- `NativeAotJniRetention`

The generic runtime table producer remains in `Xamarin.Android.Build.Tasks`: `GenerateJniRemappingNativeCode` and `JniRemappingNativeCodeGenerator` are unchanged and continue to serve both MAM and R8 remapping.

The relocation also:

- loads only `GenerateR8JniRemapping` from the modern assembly using the existing Full/Core `UsingTask` pattern
- tracks both modern and legacy task assemblies in mixed incremental targets
- links only the metadata helpers required by the read-only scanner
- packages `ELFSharp.dll` beside the modern task assembly under `tools/net`
- keeps net10 `MSBuildDeviceIntegration` compatible by linking `R8Mapping.cs` instead of referencing the net11 task project
- preserves a test-only aliased legacy task reference to validate generated XML through `MergeRemapXml` and `GenerateJniRemappingNativeCode`

This PR does not restore or relocate the removed managed assembly rewriter, rewrite planners/rebuilders, rewrite-only tests, or `XA4325`/`XA4326` behavior.

## Validation

- `Microsoft.Android.Build.Tasks` build
- `Xamarin.Android.Build.Tasks` build
- 86 focused modern R8 remapping tests
- 41 trimmable typemap integration tests
- `MSBuildDeviceIntegration` project build
- verified packaged `tools/net/ELFSharp.dll`
- final read-only review found no blocking issues
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r8-runtime-rewriting ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants