Skip to content

[r8-obfuscation] Enable R8 JNI name obfuscation for NativeAOT - #12634

Closed
simonrozsival wants to merge 4 commits into
simonrozsival-coreclr-r8-jni-integrationfrom
simonrozsival-nativeaot-r8-jni-integration
Closed

simonrozsival wants to merge 4 commits into
simonrozsival-coreclr-r8-jni-integrationfrom
simonrozsival-nativeaot-r8-jni-integration

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Sep 1, 2026 •

Copy link
Copy Markdown
Member

Related to #12535

Depends on #12632

Layer 6 of 6 and the top of the replacement stack for draft PR #12575. Extends the shared two-pass R8 JNI name-obfuscation pipeline to NativeAOT, including incremental pre-ILC assembly rewriting, conservative JNI class/member reachability, seed-compatible final keep rules, and prebuilt runtime JNI startup keeps.

Testing:

  • Modified target XML parses successfully.
  • Xamarin.Android.Build.Tasks.csproj builds successfully.
  • Complete Xamarin.Android.Build.Tests.csproj builds successfully.
  • NativeAOT and direct-manifest generator tests: 28/28 passed.
  • Cumulative focused R8/JNI unit suites: 165/165 passed.
  • TypeMapAssemblyGeneratorTests: 121/121 passed, including owner-specific JNI method-name FieldRVA coverage.
  • Independent Opus 5 correctness review found no remaining high-confidence issues and separately confirmed skipped incremental targets still evaluate item redirection.
  • All three NativeAOT R8/JNI integration variants were attempted, but the local SDK stops before project code with NETSDK1147: To build this project, the following workloads must be installed: android; no unrelated workload was installed.

@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from f51fbae to f88d2f4 Compare September 1, 2026 22:33
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch 7 times, most recently from a7bff4c to a8fff0b Compare September 2, 2026 06:31
@simonrozsival

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@simonrozsival

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@simonrozsival

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@simonrozsival

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from 1cee050 to 65740e9 Compare September 2, 2026 09:05
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch 2 times, most recently from 4c591ed to 80dbc97 Compare September 2, 2026 10:21
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from 2f3c599 to 5e41251 Compare September 2, 2026 11:23
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from 80dbc97 to 2099dc9 Compare September 2, 2026 11:23
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from 5e41251 to cbc7457 Compare September 2, 2026 11:59
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from 2099dc9 to 07eaa87 Compare September 2, 2026 12:02
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from cbc7457 to 61d0a23 Compare September 2, 2026 12:23
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from 07eaa87 to 7c2485f Compare September 2, 2026 13:21
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from cbb6df2 to f547135 Compare September 2, 2026 15:05
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from 61d0a23 to ed2522d Compare September 2, 2026 15:23
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from f547135 to ec9422a Compare September 2, 2026 15:29
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from ec9422a to c544a34 Compare September 2, 2026 17:55
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from 60b031c to 15c4b79 Compare September 2, 2026 21:34
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from c544a34 to 1912f90 Compare September 2, 2026 21:42
@MichalStrehovsky

Copy link
Copy Markdown
Member

Why is this rewriting necessary? Can't we tell R8 not to rename things we need? There must be an escape hatch for reflection. What we're doing is reflection.

Bugs in rewritten assemblies pretty much always land on runtime team's plate to troubleshoot. dotnet/maui#37782 (comment) was the most recent one and that one was extra annoying because people who knew about the rewriting (they edited the rewriter files in the past) were on the thread and did not say there was a rewrite. I'm not a big fan of these approaches.

simonrozsival and others added 4 commits September 3, 2026 07:00
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
NativeAOT correctly removes an unreferenced managed peer from the final R8 reachability set. Keep the test peer live through MainActivity and assert its exact reachability provenance before checking the final mapping.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The generated ACW keep file is intentionally excluded from final R8, so NativeAOT correctly removed the unreferenced library peer. Reference it from the app and assert its reachability provenance before validating the public mapping.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-r8-jni-integration branch from 15c4b79 to 6a05a22 Compare September 3, 2026 05:00
@simonrozsival
simonrozsival force-pushed the simonrozsival-nativeaot-r8-jni-integration branch from 1912f90 to 4226ed9 Compare September 3, 2026 05:00
@simonrozsival

Copy link
Copy Markdown
Member Author

@MichalStrehovsky we are looking into ways to support Google's new requirements on app optimizations (https://android-developers.googleblog.com/2026/08/app-quality-memory-optimization-secure-onboarding.html). We're currently using a -dontobfuscate flag, but it appears that that won't soon be acceptable by Play Store policy.

@jkotas

jkotas commented Sep 3, 2026 •

Copy link
Copy Markdown
Member

@simonrozsival Michal's question was whether you can meet the requirement by generating fine-grained -keep directives in proguard-rules.pro file instead of IL rewriting. Have you evaluated that option? I agree that IL rewriting is always a factory for problems.

@jonathanpeppers

Copy link
Copy Markdown
Member

I'm trying this out as an alternative, but we will have to submit an app to Google Play to test the full end-to-end:

@simonrozsival

Copy link
Copy Markdown
Member Author

I see. We'll explore other other options which won't require assembly rewriting. We can revisit the idea of changing the Java type name and signature constants directly in the string constants only if we can't maintain reasonable performance. Thanks for the feedback.

@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12634

@github-actions github-actions Bot 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.

⚠️ Needs Changes

Found 1 error: the new NativeAOT configuration task unconditionally rewrites outputs, breaking timestamp preservation and causing avoidable R8/downstream packaging work on incremental builds. The two-pass NativeAOT/R8 wiring and accompanying coverage otherwise align with the stated design.

CI is currently red: 42/44 checks passed, with dotnet-android (Package Tests macOS > Tests > APKs 2) and the aggregate dotnet-android check failing. Azure build details could not be retrieved from this environment, so the package-test failure remains unclassified.

Generated by Android PR Reviewer for #12634 · gpt56 · 506.1 AIC · ⌖ 9.11 AIC · ⊞ 25.7K
Comment /review to run again

} else {
GenerateProguardConfiguration.WriteMappedRules (writer, reachableR8Entries);
}
File.WriteAllText (OutputFile, writer.ToString ());

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.

🤖 ❌ MSBuild tasks — This replaces the content-preserving Files.CopyIfStringChanged() with an unconditional write. When this target reruns but produces unchanged rules, it touches _ProguardProjectConfiguration; line 151 similarly touches the reachability manifest. Both are _CompileToDalvik inputs, so this unnecessarily reruns R8 and downstream packaging. Please preserve timestamps for both outputs and cover a same-content producer rerun.

Rule: Use Files.CopyIfStringChanged() (Postmortem #53)

@simonrozsival
simonrozsival removed this pull request from stack #12635 September 17, 2026 14:32
simonrozsival added a commit that referenced this pull request Sep 21, 2026
## 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:

- #12629 added the PE metadata rebuild substrate.
- #12630 added managed JNI metadata rewriting from R8 mappings.
- #12631 added rewriting for generated trimmable type-map assemblies.
- #12632 and #12634 integrated and tested that rewriting approach for CoreCLR and NativeAOT.

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

- The generic `R8Mapping` parser introduced in #12628 remains, along with its tests and the `MSBuildDeviceIntegration` consumer. It is independently useful for reading R8 mapping files.
- The ordinary R8 configuration and `private-members` obfuscation/optimization policy from #12668 remain unchanged. This PR does **not** disable R8 or remove private-member obfuscation.
- Existing D8/R8 packaging, ProGuard rule handling, and non-rewriting build behavior remain unchanged.
- Runtime remapping remains active as the stacked follow-up work in #12847, #12848, #12692, and #12844. Those PRs implement the alternative opt-in strategy without managed assembly rewriting and are not part of this cleanup diff.

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`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants