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
-
Check out the repro branch:
git clone https://github.com/AdamEssenmacher/maui.git
cd maui
git checkout repro/android-webview-file-chooser-callback-leak
-
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
-
Launch the app:
adb -s emulator-5554 shell monkey -p com.microsoft.maui.repros.androidwebviewfilechoosercallbackleak 1
-
In the app, tap Open tracked chooser.
-
Cancel the Android file picker.
-
Tap Force GC.
-
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
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
Check out the repro branch:
git clone https://github.com/AdamEssenmacher/maui.git cd maui git checkout repro/android-webview-file-chooser-callback-leakBuild and install the repro app on Android:
Launch the app:
In the app, tap
Open tracked chooser.Cancel the Android file picker.
Tap
Force GC.Repeat steps 4-6 a few times.
Actual result
Registry callbacks,Tracked live, andWeak refs alivecontinue 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