Skip to content

Prevent Flutter daemon getEmulators/getSupportedPlatforms before device.enable has completed#5948

Merged
DanTup merged 1 commit intomasterfrom
add-daemon-startup-delay
Mar 2, 2026
Merged

Prevent Flutter daemon getEmulators/getSupportedPlatforms before device.enable has completed#5948
DanTup merged 1 commit intomasterfrom
add-daemon-startup-delay

Conversation

@DanTup
Copy link
Member

@DanTup DanTup commented Mar 2, 2026

I noticed in the logs that we can call functions before device.enable completes. It's a long shot, but I wonder if it might be what leads to the timeouts in #5793. We've had issues in the past where sending requests too early would cause issues, which lead to the daemonStarted promise, however it only awaited for any output message and not for device.enable to complete.

This adds a new completer for device.enable completing, and then an additional 2s delay. If the timeouts reduce with this change, it might help narrow down the ultimate cause in the flutter tool.

@DanTup DanTup added this to the v3.130.0 milestone Mar 2, 2026
@DanTup DanTup added is enhancement An enhancement or improvement that should be listed in release notes but is not a bug fix. in flutter Relates to running Flutter apps labels Mar 2, 2026
@codecov
Copy link

codecov bot commented Mar 2, 2026

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 67.36%. Comparing base (6a95a9c) to head (8ff7ab4).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
src/extension/flutter/flutter_daemon.ts 90.90% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5948      +/-   ##
==========================================
+ Coverage   67.35%   67.36%   +0.01%     
==========================================
  Files         169      169              
  Lines       13014    13018       +4     
  Branches     2577     2577              
==========================================
+ Hits         8765     8769       +4     
- Misses       3787     3788       +1     
+ Partials      462      461       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@DanTup DanTup force-pushed the add-daemon-startup-delay branch from ab4ab82 to f787521 Compare March 2, 2026 11:31
…ce.enable has completed

I noticed in the logs that we can call functions before `device.enable` completes. It's a long shot, but I wonder if it might be what leads to the timeouts in #5793. We've had issues in the past where sending requests too early would cause issues, which lead to the `daemonStarted` promise, however it only awaited for _any_ output message and not for `device.enable` to complete.

This adds a new completer for `device.enable` completing, and then an additional 2s delay. If the timeouts reduce with this change, it might help narrow down the ultimate cause in the `flutter` tool.
@DanTup DanTup force-pushed the add-daemon-startup-delay branch from f787521 to 8ff7ab4 Compare March 2, 2026 11:41
@DanTup DanTup merged commit 4f6d5d3 into master Mar 2, 2026
23 checks passed
@DanTup DanTup deleted the add-daemon-startup-delay branch March 2, 2026 12:31
@DanTup DanTup requested a review from Copilot March 2, 2026 14:27
@DanTup
Copy link
Member Author

DanTup commented Mar 2, 2026

@codex review

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request aims to prevent race conditions by ensuring getEmulators and getSupportedPlatforms are not called before device.enable has completed. It achieves this by introducing a new daemonInitialized state that completes after device.enable and an additional delay. The changes are logical and well-structured. My review includes a suggestion to simplify the new delay logic for better clarity and to clean up some related test code.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f6d5d366d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

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 aims to reduce Flutter daemon timeout/hang scenarios by preventing early getEmulators/getSupportedPlatforms requests from being sent before device.enable has completed (plus an additional 2s delay), to help diagnose/mitigate timeouts like those tracked in #5793.

Changes:

  • Remove the public daemonStarted promise from IFlutterDaemon and stop awaiting it in FlutterDeviceManager.
  • Add internal gating in FlutterDaemon so getEmulators() / getSupportedPlatforms() wait until after device.enable completes and a fixed 2s delay elapses.
  • Update the device manager tests’ fake daemon to reflect the interface change.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/extension/flutter/flutter_daemon.ts Introduces daemon “responsive” vs “initialized” gating; delays emulator/platform requests until after device.enable + 2s.
src/shared/vscode/device_manager.ts Removes explicit waiting for daemon “started” before calling daemon APIs.
src/shared/interfaces.ts Removes daemonStarted from IFlutterDaemon.
src/test/flutter/device_manager.test.ts Updates test fake daemon to align with the daemon interface change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


public getEmulators(): Thenable<f.FlutterEmulator[]> {
public async getEmulators(): Promise<f.FlutterEmulator[]> {
await this.daemonInitialized;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getEmulators() awaits this.daemonInitialized with no fallback/timeout. If daemon.connected never arrives or device.enable never settles (or the daemon exits early), this promise never resolves and callers (eg. FlutterDeviceManager constructor) can hang indefinitely. Consider racing initialization with a timeout or process-exit/dispose signal (resolving/rejecting the completer) so emulator requests can fail fast and still be covered by existing timeout/error reporting.

Suggested change
await this.daemonInitialized;
await withTimeout(
this.daemonInitialized,
"Flutter daemon did not initialize in time to retrieve emulators",
twentySecondsInMs,
);

Copilot uses AI. Check for mistakes.
Comment on lines +321 to 324
public async getSupportedPlatforms(projectRoot: string): Promise<f.SupportedPlatformsResponse> {
await this.daemonInitialized;
return this.withRecordedTimeout("daemon.getSupportedPlatforms", this.sendRequest("daemon.getSupportedPlatforms", { projectRoot }));
}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSupportedPlatforms() also blocks on this.daemonInitialized before entering withRecordedTimeout(...), so if initialization never completes these calls will never time out/log (and any upstream withTimeout(...) only times out the caller, not the underlying work). Consider ensuring daemonInitialized is always completed (resolve/reject) on daemon exit/error and/or wrapping the initialization wait in a bounded timeout.

Copilot uses AI. Check for mistakes.
Comment on lines +47 to +55
// Delay marking as initialized for a few seconds to see whether it helps prevent
// the first emulator requests from hanging.
// https://github.com/Dart-Code/Dart-Code/issues/5793
const completer = this.daemonInitializedCompleter;
async function markInitializedAfterDelay() {
setTimeout(() => completer.resolve(), 2000);
}

void this.deviceEnable().then(markInitializedAfterDelay, markInitializedAfterDelay);
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

daemonInitializedCompleter is only resolved after deviceEnable() settles, then an additional setTimeout delay. If device.enable hangs (or the daemon fails before sending daemon.connected), daemonInitialized will never complete and can permanently block emulator/platform requests. Consider adding a maximum wait (timeout) and completing the completer on daemon exit/dispose, and using the existing delay(...) helper instead of an async function that schedules a raw setTimeout for clarity.

Copilot uses AI. Check for mistakes.
public supportedPlatforms: f.PlatformType[] | undefined;
public supportedPlatformsDelaySeconds: number | undefined;
public daemonStarted = Promise.resolve();
public daemonInitialized = Promise.resolve();
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

daemonInitialized on FakeFlutterDaemon is not referenced anywhere in this test file and is no longer required to satisfy IFlutterDaemon (since daemonStarted was removed). Consider removing it to avoid confusion about how initialization is supposed to work in tests.

Suggested change
public daemonInitialized = Promise.resolve();

Copilot uses AI. Check for mistakes.
DanTup added a commit that referenced this pull request Mar 2, 2026
Some tweaks from review on #5948 from after it merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in flutter Relates to running Flutter apps is enhancement An enhancement or improvement that should be listed in release notes but is not a bug fix.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants