[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps - #11480

Closed
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable
Closed

[TrimmableTypeMap] Remove ManagedPeer from trimmable type map apps#11480
simonrozsival wants to merge 12 commits into
mainfrom
dev/simonrozsival/managedpeer-trimmable

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 25, 2026

Copy link
Copy Markdown
Member

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.ManagedPeer class from java_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 maui Release CoreCLR+trimmable app on Samsung A16, the change improved am start -W TotalTime by 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:false
  • MSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter "Name=TrimmableTypeMap_RuntimeArtifacts_ArePackagedInSdk|Name=Build_WithExportAndExportField_GeneratesJcwAndTypeMap" -v:minimal
  • Rebuilt/installed/launched Release CoreCLR+trimmable MAUI app on Samsung R58Y30HZ65V; launch succeeded with no fatal/crash logcat rows.
  • Confirmed final trimmable runtime jar/dex and APK dex strings do not contain Lnet/dot/jni/ManagedPeer;.

References #10795

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>
CopilotAI review requested due to automatic review settings May 25, 2026 09:24

CopilotAI 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.

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 ManagedPeer native registration for trimmable typemap builds.
  • Exclude net/dot/jni/ManagedPeer from java_runtime_trimmable.jar generation.
  • Extend trimmable typemap build tests to assert the jar/dex/apk outputs contain no ManagedPeer class/descriptor references.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.csAdds 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.targetsWrites a runtimeconfig host option disabling ManagedPeer native registration for trimmable typemap builds.
src/java-runtime/java-runtime.targetsRemoves ManagedPeer.java from the trimmable runtime jar source set.

simonrozsivaland others added 7 commits May 25, 2026 12:08
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>
@simonrozsivalsimonrozsival changed the title Remove ManagedPeer from trimmable type map apps[TrimmableTypeMap] Remove ManagedPeer from trimmable type map appsMay 25, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 25, 2026
@simonrozsival
simonrozsival marked this pull request as draft May 25, 2026 14:38
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented May 28, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Conflicts are resolved in commit 51229e7c4 (merged origin/main into this branch, resolved TrimmableTypeMapBuildTests.cs, and updated external/Java.Interop to the merged commit).

@simonrozsival
simonrozsival marked this pull request as ready for review May 28, 2026 07:17
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot 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.

✅ 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:

SeverityCount
⚠️ Warning1
💡 Suggestion1

Positive callouts:

  • Good binary-level verification (ContainsAscii on dex files) — catches cases where the type descriptor could survive even if the .class is removed.
  • The AssertApkDexDoesNotContain helper is well-factored and reusable.
  • Removing the break from the JCW loop to assert all files don't reference ManagedPeer is 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.");

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.

🤖 ⚠️Code organization — This line is a duplicate of line 550 — same assertion message and expression. Looks like an accidental copy-paste. Remove one of the two.

Rule: Remove unused code (Postmortem #58)

Comment on lines +358 to +360
foreach (var f in allJavaFiles) {
var text = File.ReadAllText (f);
if (text.Contains ("EchoString") && text.Contains ("InitialFoo")) {
StringAssert.DoesNotContain ("net.dot.jni.ManagedPeer", text,

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.

🤖 💡 TestingStringAssert.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

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request. Also address Copilot reviews.

Done in d49389c: conflicts are resolved on the branch, and I addressed the remaining Copilot review items in TrimmableTypeMapBuildTests.cs (removed the duplicate assertion and improved Java file checks to report all offending files in one assertion).

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/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
MemberAuthor

@copilot resolve the merge conflicts in this pull request

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflict in TrimmableTypeMapBuildTests.cs in commit 88787117a.

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
simonrozsival marked this pull request as draft June 15, 2026 15:34
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

This should be revisited once #11652 is merged

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival