forked from flutter/flutter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Windows] Ensure window is shown (flutter#127046)
## Background The Windows runner has a race at startup: 1. **Platform thread**: creates a hidden window 2. **Platform thread**: launches the Flutter engine 3. **UI/Raster threads**: renders the first frame 4. **Platform thread**: Registers a callback to show the window once the next frame has been rendered. Steps 3 and 4 happen in parallel and it is possible for step 3 to complete before step 4 starts. In this scenario, the next frame callback is never called and the window is never shown. As a result the `windows_startup_test`'s test, which [verifies that the "show window" callback is called](https://github.com/flutter/flutter/blob/1f09a8662dad3bb1959b24e9124e05e2b9dbff1d/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp#L60-L64), can flake if the first frame is rendered before the show window callback has been registered. ## Solution This change makes the runner schedule a frame after it registers the next frame callback. If step 3 hasn't completed yet, this no-ops as a frame is already scheduled. If step 3 has already completed, a new frame will be rendered, which will call the next frame callback and show the window. Part of flutter#119415 See this thread for alternatives that were considered: flutter/engine#42061 (comment)
- Loading branch information
1 parent
41e4c58
commit ce61eda
Showing
15 changed files
with
348 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
packages/flutter_tools/lib/src/windows/migrations/show_window_migration.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright 2014 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import '../../base/file_system.dart'; | ||
import '../../base/project_migrator.dart'; | ||
import '../../cmake_project.dart'; | ||
import 'utils.dart'; | ||
|
||
const String _before = r''' | ||
flutter_controller_->engine()->SetNextFrameCallback([&]() { | ||
this->Show(); | ||
}); | ||
return true; | ||
'''; | ||
const String _after = r''' | ||
flutter_controller_->engine()->SetNextFrameCallback([&]() { | ||
this->Show(); | ||
}); | ||
// Flutter can complete the first frame before the "show window" callback is | ||
// registered. Ensure a frame is pending to ensure the window is shown. | ||
// This no-ops if the first frame hasn't completed yet. | ||
flutter_controller_->ForceRedraw(); | ||
return true; | ||
'''; | ||
|
||
/// Migrates Windows apps to ensure the window is shown. | ||
/// | ||
/// This prevents a race condition between Flutter rendering the first frame | ||
/// and the app registering the callback to show the window on the first frame. | ||
/// See https://github.com/flutter/flutter/issues/119415. | ||
class ShowWindowMigration extends ProjectMigrator { | ||
ShowWindowMigration(WindowsProject project, super.logger) | ||
: _file = project.runnerFlutterWindowFile; | ||
|
||
final File _file; | ||
|
||
@override | ||
void migrate() { | ||
// Skip this migration if the affected file does not exist. This indicates | ||
// the app has done non-trivial changes to its runner and this migration | ||
// might not work as expected if applied. | ||
if (!_file.existsSync()) { | ||
logger.printTrace(''' | ||
windows/runner/flutter_window.cpp file not found, skipping show window migration. | ||
This indicates non-trivial changes have been made to the Windows runner in the | ||
"windows" folder. If needed, you can reset the Windows runner by deleting the | ||
"windows" folder and then using the "flutter create --platforms=windows ." command. | ||
'''); | ||
return; | ||
} | ||
|
||
// Migrate the windows/runner/flutter_window.cpp file. | ||
final String originalContents = _file.readAsStringSync(); | ||
final String newContents = replaceFirst( | ||
originalContents, | ||
_before, | ||
_after, | ||
); | ||
if (originalContents != newContents) { | ||
logger.printStatus( | ||
'windows/runner/flutter_window.cpp does not ensure the show window ' | ||
'callback is called, updating.' | ||
); | ||
_file.writeAsStringSync(newContents); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
packages/flutter_tools/lib/src/windows/migrations/utils.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2014 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
/// Creates a new string with the first occurrence of [before] replaced by | ||
/// [after]. | ||
/// | ||
/// If the [originalContents] uses CRLF line endings, the [before] and [after] | ||
/// will be converted to CRLF line endings before the replacement is made. | ||
/// This is necessary for users that have git autocrlf enabled. | ||
/// | ||
/// Example: | ||
/// ```dart | ||
/// 'a\n'.replaceFirst('a\n', 'b\n'); // 'b\n' | ||
/// 'a\r\n'.replaceFirst('a\n', 'b\n'); // 'b\r\n' | ||
/// ``` | ||
String replaceFirst(String originalContents, String before, String after) { | ||
final String result = originalContents.replaceFirst(before, after); | ||
if (result != originalContents) { | ||
return result; | ||
} | ||
|
||
final String beforeCrlf = before.replaceAll('\n', '\r\n'); | ||
final String afterCrlf = after.replaceAll('\n', '\r\n'); | ||
|
||
return originalContents.replaceFirst(beforeCrlf, afterCrlf); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.