Skip to content

Android WebView file chooser callbacks leak via ActivityResultCallbackRegistry #35405

Description

@AdamEssenmacher

Description

On Android, MauiWebChromeClient registers a static callback in ActivityResultCallbackRegistry for each WebView file chooser request. When the Android picker completes or is cancelled, ActivityResultCallbackRegistry.InvokeCallback invokes the callback but does not remove it from the static callback dictionary.

As a result, each completed WebView file chooser request can remain rooted for the lifetime of the app. The retained callback closure holds the IValueCallback, preventing it from being garbage collected.

Steps to Reproduce

Repro project:
https://github.com/AdamEssenmacher/maui/tree/repro/android-webview-file-chooser-callback-leak/src/Controls/samples/AndroidWebViewFileChooserCallbackLeakRepro

  1. Check out the repro branch:

    git clone https://github.com/AdamEssenmacher/maui.git
    cd maui
    git checkout repro/android-webview-file-chooser-callback-leak
  2. Build and install the repro app on Android:

    dotnet build src/Controls/samples/AndroidWebViewFileChooserCallbackLeakRepro/Maui.Controls.AndroidWebViewFileChooserCallbackLeakRepro.csproj -f net10.0-android -t:Install -p:AndroidDeviceSerial=emulator-5554
  3. Launch the app:

    adb -s emulator-5554 shell monkey -p com.microsoft.maui.repros.androidwebviewfilechoosercallbackleak 1
  4. In the app, tap Open tracked chooser.

  5. Cancel the Android file picker.

  6. Tap Force GC.

  7. Repeat steps 4-6 a few times.

Actual result

Registry callbacks, Tracked live, and Weak refs alive continue to grow or remain above zero after completed/cancelled chooser requests. The app reports:

Completed tracked callbacks are still alive.

This shows completed file chooser callbacks remain rooted by ActivityResultCallbackRegistry.

Expected result

After the Android activity result is delivered, the registered callback should be removed from ActivityResultCallbackRegistry. After forced GC, completed tracked callbacks should be finalized and the registry callback count should return to baseline.

Link to public reproduction project repository

https://github.com/AdamEssenmacher/maui/tree/repro/android-webview-file-chooser-callback-leak/src/Controls/samples/AndroidWebViewFileChooserCallbackLeakRepro

Version with bug

10.0.60

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

No response

Did you find any workaround?

No response

Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions