Skip to content

[Android]Fix deadlock on modal navigation#32920

Closed
pictos wants to merge 3 commits intodotnet:mainfrom
pictos:fix-deadlock-on-modal-navigation
Closed

[Android]Fix deadlock on modal navigation#32920
pictos wants to merge 3 commits intodotnet:mainfrom
pictos:fix-deadlock-on-modal-navigation

Conversation

@pictos
Copy link
Copy Markdown
Contributor

@pictos pictos commented Nov 29, 2025

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

This PR adds the Navigated event inside DialogFragment. The issue happens because the Push/PopModal navigation returns too early and causes the hanging since it gets lost.

Also added TaskCreationOptions.RunContinuationsAsynchronously to both TaskCompletionSource in Pop and Push modal navigations. This will make the continuations run in the expected order.

I kept the AnimationEnded event because they fire in different moments, so I believe it's better to keep it for animated navigations.

Issues Fixed

This is a follow up of: #32853

Fixes #32310

Copilot AI review requested due to automatic review settings November 29, 2025 22:44
@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Nov 29, 2025
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 fixes an Android-specific deadlock issue where calling PopModalAsync immediately after PushModalAsync with only a Task.Yield() in between would cause the app to hang. The solution introduces a Navigated event in the ModalFragment that fires in OnResume() to ensure non-animated modal navigation completes properly, and applies TaskCreationOptions.RunContinuationsAsynchronously to both TaskCompletionSource instances to ensure continuations run in the expected order.

Key changes:

  • Added Navigated event to ModalFragment class that fires in OnResume() lifecycle method
  • Applied TaskCreationOptions.RunContinuationsAsynchronously to both modal Push and Pop TaskCompletionSource instances
  • Added comprehensive UI test to verify the fix prevents the deadlock

Reviewed changes

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

File Description
src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.Android.cs Core fix: Added Navigated event, OnResume() override, and TaskCreationOptions.RunContinuationsAsynchronously to prevent deadlock in modal navigation
src/Controls/tests/TestCases.HostApp/Issues/Issue32310.cs Test reproduction page that demonstrates the deadlock scenario with PushModalAsync + Task.Yield() + PopModalAsync
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32310.cs UI test that verifies modal navigation completes without hanging
Comments suppressed due to low confidence (1)

src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.Android.cs:207

  • Consider using TrySetResult instead of SetResult for consistency with the Pop modal path (line 123, 137) and for better error handling. If OnResume() is called multiple times or if there's any other race condition, SetResult will throw an InvalidOperationException, while TrySetResult would gracefully handle the case where the result is already set.
void OnNavigated(object? sender, EventArgs e)
{
    dialogFragment.Navigated -= OnNavigated;
    animationCompletionSource.TrySetResult(true);
}

void OnAnimationEnded(object? sender, EventArgs e)
{
    dialogFragment!.AnimationEnded -= OnAnimationEnded;
    animationCompletionSource.TrySetResult(true);
}
			void OnNavigated(object? sender, EventArgs e)
			{
				dialogFragment.Navigated -= OnNavigated;
				animationCompletionSource.SetResult(true);
			}

			void OnAnimationEnded(object? sender, EventArgs e)
			{
				dialogFragment!.AnimationEnded -= OnAnimationEnded;
				animationCompletionSource.SetResult(true);

Updated `ModalNavigationManager.Android.cs` to improve modal navigation handling:
- Removed unused `AndroidX.Core.View` namespace.
- Added `_pendingNavigation` field to track pending navigation operations.
- Modified `OnResume` to check `_pendingNavigation` and prevent redundant `Navigated` event invocations.
- Ensured `_pendingNavigation` is reset after navigation completes.
@PureWeen
Copy link
Copy Markdown
Member

@pictos

What about this one?

#32479

@pictos
Copy link
Copy Markdown
Contributor Author

pictos commented Nov 30, 2025

@PureWeen didn't see that one, by bad. I added some comments on that PR and will close this one

@pictos pictos closed this Nov 30, 2025
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 30, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community ✨ Community Contribution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App hangs if PopModalAsync is called after PushModalAsync with single await Task.Yield()

3 participants