Fix a race in EmbedderTest.CanSpecifyCustomUITaskRunner#182649
Fix a race in EmbedderTest.CanSpecifyCustomUITaskRunner#182649auto-submit[bot] merged 5 commits intoflutter:masterfrom
Conversation
The UI task runner will be destroyed during the call to FlutterEngineShutdown. It should continue forwarding tasks to the engine until the destruction callback is invoked. After that, it should stop using the engine. The test had been using a mutex to guard the engine, but that does not work in this case because both the platform and UI threads must be able to run tasks during engine shutdown. If the test's platform thread holds the mutex during the call to engine.reset(), then the UI task runner can not acquire it to run its tasks. The test previously avoided that by calling engine.reset() without holding the mutex. That creates a race between engine shutdown and the UI task runner's check of engine.is_valid().
There was a problem hiding this comment.
Code Review
This pull request addresses a race condition in the CanSpecifyCustomUITaskRunner test. The fix involves using a destruction callback on the custom UI task runner to set a flag, preventing tasks from being run on a shutdown engine. This replaces a mutex-based approach that could lead to deadlocks. The EmbedderTestTaskRunner has been updated to use std::function for its destruction callback, improving its flexibility. Additionally, a static variable in another test was made non-static to improve test isolation.
engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_util.h
Outdated
Show resolved
Hide resolved
…tests_util.h Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
gaaclarke
left a comment
There was a problem hiding this comment.
Nice catch.
Test exempt: this is a test
| auto ui_thread = std::make_unique<fml::Thread>("test_ui_thread"); | ||
| auto ui_task_runner = ui_thread->GetTaskRunner(); | ||
| std::mutex ui_task_runner_mutex; | ||
| bool ui_task_runner_destroyed = false; |
There was a problem hiding this comment.
Please add the IPLR_GUARDED_BY macro to this variable.
There was a problem hiding this comment.
The IPLR_ macros are defined in Impeller, but this test is in the engine tree outside Impeller. The engine/shell subsystems are not using the threading annotations.
There was a problem hiding this comment.
It's a couple of lines you can inline in this file. It's basically a preprocessor check for clang and an attribute on the variable.
| }); | ||
| test_task_runner.SetDestructionCallback( | ||
| [](void* user_data) { destruction_callback_called = true; }); | ||
| [&]() { destruction_callback_called = true; }); |
There was a problem hiding this comment.
The convention at google is to use explicit load() and store() functions with std::atomics.
| task_runner_description_.destruction_callback = [](void* user_data) { | ||
| auto thiz = reinterpret_cast<EmbedderTestTaskRunner*>(user_data); | ||
| if (thiz->destruction_callback_) { | ||
| thiz->destruction_callback_(); |
There was a problem hiding this comment.
Is this executing on a different thread than SetDestructionCallback? If so there is a race condition and we'll need a mutex.
There was a problem hiding this comment.
Changed this callback to be immutable after construction
gaaclarke
left a comment
There was a problem hiding this comment.
LGTM modulo a nit about clang's guarded_by attribute. Thanks jason.
| auto ui_thread = std::make_unique<fml::Thread>("test_ui_thread"); | ||
| auto ui_task_runner = ui_thread->GetTaskRunner(); | ||
| std::mutex ui_task_runner_mutex; | ||
| bool ui_task_runner_destroyed = false; |
There was a problem hiding this comment.
It's a couple of lines you can inline in this file. It's basically a preprocessor check for clang and an attribute on the variable.
|
I'm going to try to merge master to kick the bots. CI seems... unhappy. |
Roll Flutter from dad6f9d4107a to b31548feb941 (39 revisions) flutter/flutter@dad6f9d...b31548f 2026-02-25 [email protected] [web] Fix failure on Firefox 148 (flutter/flutter#182855) 2026-02-25 [email protected] Roll Fuchsia Linux SDK from KfPgw04T0OEADLJA5... to XI0Ax7fbtYE4XKYAQ... (flutter/flutter#182887) 2026-02-25 [email protected] Use AnimationStyle curve and reverseCurve in ModalBottomSheet animation (flutter/flutter#181403) 2026-02-25 [email protected] Roll Dart SDK from fd3dce5b6a4e to 5c57e75f1102 (9 revisions) (flutter/flutter#182801) 2026-02-25 98614782+auto-submit[bot]@users.noreply.github.com Reverts "refactor: remove material in context_menu_controller_test, icon_test, list_wheel_scroll_view_test, media_query_test, platform_menu_bar_test (#182697)" (flutter/flutter#182879) 2026-02-25 [email protected] Make sure that an AnimatedSlide doesn't crash in 0x0 environment (flutter/flutter#181535) 2026-02-24 [email protected] Reland Standardize on Test* widgets in *_tester.dart files (flutter/flutter#182632) 2026-02-24 [email protected] docs(Path): clarify that zero-length contours are excluded from computeMetrics (flutter/flutter#180165) 2026-02-24 [email protected] Fix typo in assert message (flutter/flutter#182843) 2026-02-24 [email protected] [win32] Fix overflow in TaskRunnerWindow. (flutter/flutter#182822) 2026-02-24 [email protected] feat: Add --no-uninstall flag to flutter test for integration tests (flutter/flutter#182714) 2026-02-24 [email protected] Rename noFrequencyBasedMinification to useFrequencyBasedMinification (flutter/flutter#182684) 2026-02-24 [email protected] [Impeller] Fix fail to render pixel buffer texture on Linux (flutter/flutter#181656) 2026-02-24 [email protected] Remove FlutterFramework app migration (flutter/flutter#182100) 2026-02-24 [email protected] Roll Packages from 12b43a1 to 062c8d4 (5 revisions) (flutter/flutter#182839) 2026-02-24 [email protected] [web] Run webparagraph tests in CI (flutter/flutter#182092) 2026-02-24 [email protected] Fix a race in EmbedderTest.CanSpecifyCustomUITaskRunner (flutter/flutter#182649) 2026-02-24 [email protected] flutter_tools: Use a super-parameter in several missed cases (flutter/flutter#182581) 2026-02-24 [email protected] Replace more references to `flutter/engine` with `flutter/flutter` (flutter/flutter#182654) 2026-02-24 [email protected] Carousel: Migration from Scrollable+Viewport to CustomScrollView (flutter/flutter#182475) 2026-02-24 [email protected] Refactor impellerc_main to better organize some of its logic (flutter/flutter#182783) 2026-02-24 [email protected] Remove unused `getPluginList ` (flutter/flutter#182660) 2026-02-24 [email protected] Refactor: Remove material from ticker provider test (flutter/flutter#181697) 2026-02-24 [email protected] Roll Skia from 26eebffe12bd to f44d7db68805 (3 revisions) (flutter/flutter#182821) 2026-02-24 [email protected] refactor: remove material in context_menu_controller_test, icon_test, list_wheel_scroll_view_test, media_query_test, platform_menu_bar_test (flutter/flutter#182697) 2026-02-24 [email protected] Roll Skia from 7dad66aae75a to 26eebffe12bd (5 revisions) (flutter/flutter#182810) 2026-02-24 [email protected] Update roadmap for 2026 (flutter/flutter#182798) 2026-02-24 [email protected] Marks Windows tool_tests_commands_1_2 to be unflaky (flutter/flutter#179670) 2026-02-23 [email protected] [web] scroll iOS iframe text input into view (flutter/flutter#179759) 2026-02-23 [email protected] Fix textscaler clamp assertion error (flutter/flutter#181716) 2026-02-23 [email protected] Roll Skia from 9a5a3c92c336 to 7dad66aae75a (4 revisions) (flutter/flutter#182779) 2026-02-23 [email protected] Move more getters from userMessages class to the appropriate places (flutter/flutter#182656) 2026-02-23 [email protected] Manual roll Dart SDK from f8fac50475b8 to fd3dce5b6a4e (6 revisions) (flutter/flutter#182768) 2026-02-23 [email protected] Copy Flutter framework to Add to App FlutterPluginRgistrant (flutter/flutter#182523) 2026-02-23 [email protected] Add progress indicator to artifact downloads (flutter/flutter#181808) 2026-02-23 [email protected] Clarify batch release mode requirements (flutter/flutter#182228) 2026-02-23 [email protected] [web] Remove --disable-gpu from flutter chrome tests (flutter/flutter#182618) 2026-02-23 [email protected] running-apps: update running-apps to use Duration.ago() (flutter/flutter#182172) 2026-02-23 [email protected] Refactor bin/ shell scripts for better performance and safety (flutter/flutter#182674) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. ...
The UI task runner will be destroyed during the call to FlutterEngineShutdown. It should continue forwarding tasks to the engine until the destruction callback is invoked. After that, it should stop using the engine. The test had been using a mutex to guard the engine, but that does not work in this case because both the platform and UI threads must be able to run tasks during engine shutdown. If the test's platform thread holds the mutex during the call to engine.reset(), then the UI task runner can not acquire it to run its tasks. The test previously avoided that by calling engine.reset() without holding the mutex. That creates a race between engine shutdown and the UI task runner's check of engine.is_valid(). --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: gaaclarke <[email protected]>
The UI task runner will be destroyed during the call to FlutterEngineShutdown. It should continue forwarding tasks to the engine until the destruction callback is invoked. After that, it should stop using the engine.
The test had been using a mutex to guard the engine, but that does not work in this case because both the platform and UI threads must be able to run tasks during engine shutdown. If the test's platform thread holds the mutex during the call to engine.reset(), then the UI task runner can not acquire it to run its tasks. The test previously avoided that by calling engine.reset() without holding the mutex. That creates a race between engine shutdown and the UI task runner's check of engine.is_valid().