[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480simonrozsival wants to merge 10 commits into
Conversation
Disable Java.Interop ManagedPeer native registration for trimmable type map builds and remove the Java ManagedPeer class from the trimmable runtime jar. The trimmable path registers native methods through generated JCW static initializers, so ManagedPeer is dead weight there. Add coverage to ensure trimmable runtime artifacts, generated Java, and built APK dex files do not reference ManagedPeer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR removes the legacy Java.Interop ManagedPeer native-registration path from trimmable type map builds, where native methods are registered via generated JCW static initializers, reducing unnecessary startup work for CoreCLR+trimmable apps.
Changes:
- Add runtimeconfig host option to disable
ManagedPeernative registration for trimmable typemap builds. - Exclude
net/dot/jni/ManagedPeerfromjava_runtime_trimmable.jargeneration. - Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no
ManagedPeerclass/descriptor references.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.cs | Adds assertions ensuring trimmable runtime artifacts and generated outputs don’t reference ManagedPeer (jar entry, dex string, generated Java, APK dex). |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets | Writes a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds. |
| src/java-runtime/java-runtime.targets | Removes ManagedPeer.java from the trimmable runtime jar source set. |
Remove the Java.Interop runtimeconfig switch from the trimmable typemap targets. Android now disables the legacy ManagedPeer native registration path through JniRuntime.CreationOptions when the existing trimmable typemap runtime feature is enabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use Span.IndexOf for the test dex byte search and update the Java.Interop submodule with the ManagedPeer runtime-option review fixes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bring in the Java.Interop regression test that documents ManagedPeer is intentionally absent from the built-in simple-reference map. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Set Java.Interop.RuntimeFeature.ManagedPeerNativeRegistration=false for the trimmable typemap path and update the Java.Interop submodule to keep legacy ManagedPeer behavior enabled by default elsewhere. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bring in the Java.Interop coverage that verifies Java.Interop.RuntimeFeature.ManagedPeerNativeRegistration=false skips ManagedPeer.Init(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the Java.Interop dependency to remove test-only ManagedPeer production instrumentation while keeping the ManagedPeer runtime switch coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@copilot resolve the merge conflicts in this pull request |
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Conflicts are resolved in commit |
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
✅ LGTM — Clean, focused change
Summary: Disables ManagedPeer native registration for trimmable type map builds via the Java.Interop.RuntimeFeature.ManagedPeerNativeRegistration runtime host config option, and excludes ManagedPeer.java from java_runtime_trimmable.jar/.dex. Test coverage is thorough — SDK artifact verification, generated JCW source checks, and APK dex binary scanning.
Issues found:
| Severity | Count |
|---|---|
| 1 | |
| 💡 Suggestion | 1 |
Positive callouts:
- Good binary-level verification (
ContainsAsciion dex files) — catches cases where the type descriptor could survive even if the.classis removed. - The
AssertApkDexDoesNotContainhelper is well-factored and reusable. - Removing the
breakfrom the JCW loop to assert all files don't referenceManagedPeeris the right call. - The 18ms startup improvement with benchmark data in the PR description is appreciated.
Note: This PR depends on dotnet/java-interop#1434 and #11503. Mergeability is blocked on those dependencies.
Generated by Android PR Reviewer for issue #11480 · ● 6.9M
|
|
||
| var javaFiles = Directory.GetFiles (javaDir, "*.java", SearchOption.AllDirectories); | ||
| Assert.IsNotEmpty (javaFiles, "At least one trimmable JCW Java source file should be generated."); | ||
| Assert.IsNotEmpty (javaFiles, "At least one trimmable JCW Java source file should be generated."); |
There was a problem hiding this comment.
🤖
Rule: Remove unused code (Postmortem #58)
| foreach (var f in allJavaFiles) { | ||
| var text = File.ReadAllText (f); | ||
| if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) { | ||
| StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text, |
There was a problem hiding this comment.
🤖 💡 Testing — StringAssert.DoesNotContain will fail and abort the loop on the first file that contains the string, so you won't see failures from subsequent files. If the goal is to check all generated Java files (which seems to be why the break was removed), consider collecting violations first and asserting once at the end, e.g. with Assert.Multiple or by accumulating failures into a list. Current behavior is fine for catching the issue but may make debugging harder if multiple files are affected.
Rule: Test assertions must be specific
Depends on dotnet/java-interop#1434
Depends on #11503
Disables Java.Interop ManagedPeer native registration for trimmable type map builds and removes the Java
net.dot.jni.ManagedPeerclass fromjava_runtime_trimmable.jar. Trimmable type map apps register native methods through generated JCW static initializers, so the legacy ManagedPeer registration path is dead weight there.This removes the ManagedPeer startup cost for CoreCLR+trimmable apps. In a
dotnet new mauiRelease CoreCLR+trimmable app on Samsung A16, the change improvedam start -W TotalTimeby about 18 ms median / 17 ms average across 20 cold starts versus a temporary baseline, with all starts successful.Validation:
./dotnet-local.sh build src/java-runtime/java-runtime.csproj -v:minimal -nr:false./dotnet-local.sh build src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj -v:minimal -nr:falseMSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimalLnet/dot/jni/ManagedPeer;.References #10795