Skip to content

Commit

Permalink
Remove the timeout when launching DevTools (flutter#74859)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hixie authored Feb 2, 2021
1 parent 43d604e commit 8acac06
Show file tree
Hide file tree
Showing 16 changed files with 353 additions and 216 deletions.
7 changes: 5 additions & 2 deletions packages/flutter_tools/lib/src/commands/attach.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class AttachCommand extends FlutterCommand {
);
usesTrackWidgetCreation(verboseHelp: verboseHelp);
addDdsOptions(verboseHelp: verboseHelp);
addDevToolsOptions();
addDevToolsOptions(verboseHelp: verboseHelp);
usesDeviceTimeoutOption();
hotRunnerFactory ??= HotRunnerFactory();
}
Expand Down Expand Up @@ -207,7 +207,8 @@ known, it can be explicitly provided to attach via the command-line, e.g.
body: () => _attachToDevice(device),
overrides: <Type, Generator>{
Artifacts: () => overrideArtifacts,
});
},
);

return FlutterCommandResult.success();
}
Expand Down Expand Up @@ -327,6 +328,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
connectionInfoCompleter: connectionInfoCompleter,
appStartedCompleter: appStartedCompleter,
allowExistingDdsInstance: true,
enableDevTools: boolArg(FlutterCommand.kEnableDevTools),
);
},
device,
Expand Down Expand Up @@ -365,6 +367,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
result = await runner.attach(
appStartedCompleter: onAppStart,
allowExistingDdsInstance: true,
enableDevTools: boolArg(FlutterCommand.kEnableDevTools),
);
if (result != 0) {
throwToolExit(null, exitCode: result);
Expand Down
1 change: 1 addition & 0 deletions packages/flutter_tools/lib/src/commands/daemon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ class AppDomain extends Domain {
return runner.run(
connectionInfoCompleter: connectionInfoCompleter,
appStartedCompleter: appStartedCompleter,
enableDevTools: true,
route: route,
);
},
Expand Down
3 changes: 2 additions & 1 deletion packages/flutter_tools/lib/src/commands/run.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
usesDeviceUserOption();
usesDeviceTimeoutOption();
addDdsOptions(verboseHelp: verboseHelp);
addDevToolsOptions();
addDevToolsOptions(verboseHelp: verboseHelp);
addAndroidSpecificBuildOptions(hide: !verboseHelp);
}

Expand Down Expand Up @@ -621,6 +621,7 @@ class RunCommand extends RunCommandBase {

final int result = await runner.run(
appStartedCompleter: appStartedTimeRecorder,
enableDevTools: stayResident && boolArg(FlutterCommand.kEnableDevTools),
route: route,
);
if (result != 0) {
Expand Down
10 changes: 3 additions & 7 deletions packages/flutter_tools/lib/src/devtools_launcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
@override
Future<void> launch(Uri vmServiceUri) async {
// Place this entire method in a try/catch that swallows exceptions because
// we do not want to block Flutter run/attach operations on a DevTools
// failure.
// this method is guaranteed not to return a Future that throws.
try {
bool offline = false;
try {
Expand Down Expand Up @@ -109,8 +108,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(_logger.printError);
devToolsUri = await completer.future
.timeout(const Duration(seconds: 10));
devToolsUrl = await completer.future;
} on Exception catch (e, st) {
_logger.printError('Failed to launch DevTools: $e', stackTrace: st);
}
Expand All @@ -124,7 +122,6 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
'global',
'list',
]);

if (_pubGlobalListProcess.stdout.toString().contains('devtools ')) {
return true;
}
Expand All @@ -144,7 +141,6 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
if (!shouldActivate) {
return false;
}

final Status status = _logger.startProgress(
'Activating Dart DevTools...',
);
Expand Down Expand Up @@ -182,7 +178,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {

@override
Future<void> close() async {
devToolsUri = null;
devToolsUrl = null;
if (_devToolsProcess != null) {
_devToolsProcess.kill();
await _devToolsProcess.exitCode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class WebDriverService extends DriverService {
final Completer<void> appStartedCompleter = Completer<void>.sync();
final int result = await _residentRunner.run(
appStartedCompleter: appStartedCompleter,
enableDevTools: false,
route: route,
);
_webUri = _residentRunner.uri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
bool enableDevTools = false, // ignored, we don't yet support devtools for web
String route,
}) async {
firstBuildTime = DateTime.now();
Expand Down Expand Up @@ -531,6 +532,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
return attach(
connectionInfoCompleter: connectionInfoCompleter,
appStartedCompleter: appStartedCompleter,
enableDevTools: enableDevTools,
);
});
} on WebSocketException {
Expand Down Expand Up @@ -745,6 +747,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
bool allowExistingDdsInstance = false,
bool enableDevTools = false, // ignored, we don't yet support devtools for web
}) async {
if (_chromiumLauncher != null) {
final Chromium chrome = await _chromiumLauncher.connectedInstance;
Expand Down
95 changes: 83 additions & 12 deletions packages/flutter_tools/lib/src/resident_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,8 @@ abstract class ResidentRunner {
final CommandHelp commandHelp;
final bool machine;

@visibleForTesting
DevtoolsLauncher get devToolsLauncher => _devToolsLauncher;
DevtoolsLauncher _devToolsLauncher;

bool _exited = false;
Expand Down Expand Up @@ -878,13 +880,15 @@ abstract class ResidentRunner {
Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
bool enableDevTools = false,
String route,
});

Future<int> attach({
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
bool allowExistingDdsInstance = false,
bool enableDevTools = false,
});

bool get supportsRestart => false;
Expand Down Expand Up @@ -1275,19 +1279,26 @@ abstract class ResidentRunner {
return _devToolsLauncher.activeDevToolsServer;
}

Future<void> serveDevToolsGracefully({
Uri devToolsServerAddress
// This must be guaranteed not to return a Future that fails.
Future<void> serveAndAnnounceDevTools({
Uri devToolsServerAddress,
}) async {
if (!supportsServiceProtocol) {
return;
}

_devToolsLauncher ??= DevtoolsLauncher.instance;
if (devToolsServerAddress != null) {
_devToolsLauncher.devToolsUri = devToolsServerAddress;
_devToolsLauncher.devToolsUrl = devToolsServerAddress;
} else {
await _devToolsLauncher.serve();
unawaited(_devToolsLauncher.serve());
}
await _devToolsLauncher.ready;
if (_reportedDebuggers) {
// Since the DevTools only just became available, we haven't had a chance to
// report their URLs yet. Do so now.
printDebuggerList(includeObservatory: false);
}
await maybeCallDevToolsUriServiceExtension();
}

Future<void> maybeCallDevToolsUriServiceExtension() async {
Expand Down Expand Up @@ -1417,6 +1428,39 @@ abstract class ResidentRunner {
appFinished();
}

bool _reportedDebuggers = false;

void printDebuggerList({ bool includeObservatory = true, bool includeDevtools = true }) {
final DevToolsServerAddress devToolsServerAddress = activeDevToolsServer();
if (devToolsServerAddress == null) {
includeDevtools = false;
}
for (final FlutterDevice device in flutterDevices) {
if (device.vmService == null) {
continue;
}
if (includeObservatory) {
// Caution: This log line is parsed by device lab tests.
globals.printStatus(
'An Observatory debugger and profiler on ${device.device.name} is available at: '
'${device.vmService.httpAddress}',
);
}
if (includeDevtools) {
final Uri uri = devToolsServerAddress.uri?.replace(
queryParameters: <String, dynamic>{'uri': '${device.vmService.httpAddress}'},
);
if (uri != null) {
globals.printStatus(
'The Flutter DevTools debugger and profiler '
'on ${device.device.name} is available at: $uri',
);
}
}
}
_reportedDebuggers = true;
}

/// Called to print help to the terminal.
void printHelp({ @required bool details });

Expand Down Expand Up @@ -1763,24 +1807,51 @@ String nextPlatform(String currentPlatform, FeatureFlags featureFlags) {

/// A launcher for the devtools debugger and analysis tool.
abstract class DevtoolsLauncher {
Uri devToolsUri;
static DevtoolsLauncher get instance => context.get<DevtoolsLauncher>();

/// Serve Dart DevTools and return the host and port they are available on.
///
/// This method must return a future that is guaranteed not to fail, because it
/// will be used in unawaited contexts. It may, however, return null.
Future<DevToolsServerAddress> serve();

/// Launch a Dart DevTools process, optionally targeting a specific VM Service
/// URI if [vmServiceUri] is non-null.
///
/// This method must return a future that is guaranteed not to fail, because it
/// will be used in unawaited contexts.
@visibleForTesting
Future<void> launch(Uri vmServiceUri);

/// Serve Dart DevTools and return the host and port they are available on.
Future<DevToolsServerAddress> serve();

Future<void> close();

static DevtoolsLauncher get instance => context.get<DevtoolsLauncher>();
/// Returns a future that completes when the DevTools server is ready.
///
/// Completes when [devToolsUrl] is set. That can be set either directly, or
/// by calling [serve].
Future<void> get ready => _readyCompleter.future;
Completer<void> _readyCompleter = Completer<void>();

Uri get devToolsUrl => _devToolsUrl;
Uri _devToolsUrl;
set devToolsUrl(Uri value) {
assert((_devToolsUrl == null) != (value == null));
_devToolsUrl = value;
if (_devToolsUrl != null) {
_readyCompleter.complete();
} else {
_readyCompleter = Completer<void>();
}
}

/// The URL of the current DevTools server.
///
/// Returns null if [ready] is not complete.
DevToolsServerAddress get activeDevToolsServer {
if (devToolsUri == null) {
if (_devToolsUrl == null) {
return null;
}
return DevToolsServerAddress(devToolsUri.host, devToolsUri.port);
return DevToolsServerAddress(devToolsUrl.host, devToolsUrl.port);
}
}

Expand Down
Loading

0 comments on commit 8acac06

Please sign in to comment.