Skip to content

[TrimmableTypeMap] fix JavaPeerableProxy activation gref leak#11116

Closed
simonrozsival wants to merge 8 commits intomainfrom
dev/simonrozsival/11101-trimmable-typemap-followup
Closed

[TrimmableTypeMap] fix JavaPeerableProxy activation gref leak#11116
simonrozsival wants to merge 8 commits intomainfrom
dev/simonrozsival/11101-trimmable-typemap-followup

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival commented Apr 15, 2026

Follow-up to #11112.

This PR keeps the trimmable typemap side of the remaining activation leak fix, scoped to generated proxy activation:

  • add JavaPeerProxy.CreateActivatedPeer(Type, IntPtr) as the shared helper for inherited Java activation paths
  • update inherited-constructor proxy generation to use the shared helper instead of repeating the activation sequence at each call site
  • keep the trimming contract explicit by passing an annotated Type instead of relying on a trim suppression
  • add and update TypeMapAssemblyGeneratorTests coverage

Copilot AI review requested due to automatic review settings April 15, 2026 09:00
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/11101-trimmable-typemap-followup branch from 007428d to ab6d8da Compare April 15, 2026 09:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 addresses a remaining JNI global reference leak in the NativeAOT / trimmable typemap activation path by ensuring activated peers are constructed (and marked) before invoking inherited activation constructors, and adds regression coverage for both runtime and generator behavior.

Changes:

  • Add JavaPeerProxy.ConstructActivatedPeer() helper for typemap-generated proxy activation.
  • Update typemap proxy IL emission to pre-construct activated peers before calling inherited activation constructors/UCO constructors.
  • Add regression tests: device-side gref leak test during inflation, and generator-side metadata coverage for the new helper reference.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/Mono.Android-Tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.cs Adds a device regression test to detect global-ref growth across repeated inflations.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs Extends generator tests to ensure the new helper is referenced in generated assemblies.
src/Mono.Android/Java.Interop/TypeManager.cs Updates Activate() to construct the peer via ValueManager.ConstructPeer() using the shared uninitialized-object helper.
src/Mono.Android/Java.Interop/JavaPeerProxy.cs Introduces ConstructActivatedPeer() to centralize “pre-construct activated peer” logic for proxies.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs Emits calls to ConstructActivatedPeer() for inherited activation ctor/UCO paths to prevent duplicate gref creation.

@simonrozsival simonrozsival changed the title [TrimmableTypeMap] fix NativeAOT inherited activation leak [TrimmableTypeMap] fix JavaPeerableProxy activation leak Apr 15, 2026
@simonrozsival simonrozsival changed the title [TrimmableTypeMap] fix JavaPeerableProxy activation leak [TrimmableTypeMap] fix JavaPeerableProxy activation gref leak Apr 15, 2026
@simonrozsival simonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels Apr 15, 2026
@simonrozsival simonrozsival changed the base branch from dev/peppers/fix-activate-gref-leak to main April 15, 2026 12:32
jonathanpeppers and others added 5 commits April 15, 2026 14:34
Fixes: #11101
Fixes: #10989

Context: 5c23bcda8 (PR #9640)

The Java.Interop Unification (5c23bcd) changed `Object` to extend
`JavaObject`, introducing an additional `ConstructPeer` call in the
constructor chain. `TypeManager.Activate` was updated to use
`SetPeerReference` but never set the `Activatable` state flag.
Without it, each `ConstructPeer` call in the constructor chain
(`JavaObject()` and `Object.SetHandle()`) creates a new JNI global
ref, overwriting the previous one without deleting it — leaking 3
global refs per `LayoutInflater.Inflate` call.

Before the fix, the new test fails with:

    Global reference leak detected: 30 extra global refs after
    inflating/GC'ing 10 custom views. Before=207, After=237

This went unnoticed because the `Activate` path is only triggered
when Java creates .NET objects (not the other way around). The two
main scenarios are Activity recreation and custom C# views in Android
XML layouts. Most developers use .NET MAUI, which has a single
Activity and does not use custom C# views in Android layout XML files,
so neither scenario was commonly hit.

Changes:

  - Promote `GetUninitializedObject` from a local function in
    `CreateProxy` to a shared static method. It sets
    `Activatable | Replaceable`, which tells `ConstructPeer` to
    return early and not create duplicate global refs.

  - Have `Activate` call `GetUninitializedObject` then
    `ConstructPeer` to create one global ref while `jobject` is
    still a valid JNI local ref. The `Activatable` flag then prevents
    duplicates during the constructor chain.

  - Add regression test that inflates custom views and asserts JNI
    global reference count does not grow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/11101-trimmable-typemap-followup branch from 125e014 to 19c0bc7 Compare April 15, 2026 12:35
simonrozsival and others added 3 commits April 15, 2026 14:39
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants