diff --git a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart index 491e2e59307..ddb72829b33 100644 --- a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart +++ b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart @@ -155,11 +155,11 @@ class FuchsiaReloadCommand extends FlutterCommand { // A cache of VMService connections. final HashMap _vmServiceCache = new HashMap(); - VMService _getVMService(int port) { + Future _getVMService(int port) async { if (!_vmServiceCache.containsKey(port)) { final String addr = 'http://$ipv4Loopback:$port'; final Uri uri = Uri.parse(addr); - final VMService vmService = VMService.connect(uri); + final VMService vmService = await VMService.connect(uri); _vmServiceCache[port] = vmService; } return _vmServiceCache[port]; @@ -183,7 +183,7 @@ class FuchsiaReloadCommand extends FlutterCommand { for (int port in ports) { if (!await _checkPort(port)) continue; - final VMService vmService = _getVMService(port); + final VMService vmService = await _getVMService(port); await vmService.getVM(); await vmService.waitForViews(); views.addAll(vmService.vm.views); @@ -283,7 +283,7 @@ class FuchsiaReloadCommand extends FlutterCommand { Future _listVMs(List ports) async { for (int port in ports) { - final VMService vmService = _getVMService(port); + final VMService vmService = await _getVMService(port); await vmService.getVM(); await vmService.waitForViews(); printStatus(_vmServiceToString(vmService)); diff --git a/packages/flutter_tools/lib/src/commands/screenshot.dart b/packages/flutter_tools/lib/src/commands/screenshot.dart index 1f7085a2e35..59e56f9ded6 100644 --- a/packages/flutter_tools/lib/src/commands/screenshot.dart +++ b/packages/flutter_tools/lib/src/commands/screenshot.dart @@ -80,7 +80,7 @@ class ScreenshotCommand extends FlutterCommand { Future runSkia(File outputFile) async { final Uri observatoryUri = new Uri(scheme: 'http', host: '127.0.0.1', port: int.parse(argResults[_kSkia])); - final VMService vmService = VMService.connect(observatoryUri); + final VMService vmService = await VMService.connect(observatoryUri); final Map skp = await vmService.vm.invokeRpcRaw('_flutter.screenshotSkp'); outputFile ??= getUniqueFile(fs.currentDirectory, 'flutter', 'skp'); diff --git a/packages/flutter_tools/lib/src/commands/trace.dart b/packages/flutter_tools/lib/src/commands/trace.dart index 4674d67d574..33e88ed9c29 100644 --- a/packages/flutter_tools/lib/src/commands/trace.dart +++ b/packages/flutter_tools/lib/src/commands/trace.dart @@ -55,7 +55,7 @@ class TraceCommand extends FlutterCommand { Tracing tracing; try { - tracing = Tracing.connect(observatoryUri); + tracing = await Tracing.connect(observatoryUri); } catch (error) { throwToolExit('Error connecting to observatory: $error'); } @@ -97,8 +97,8 @@ class TraceCommand extends FlutterCommand { class Tracing { Tracing(this.vmService); - static Tracing connect(Uri uri) { - final VMService observatory = VMService.connect(uri); + static Future connect(Uri uri) async { + final VMService observatory = await VMService.connect(uri); return new Tracing(observatory); } diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 119f3bf4543..1c7008e48b9 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -53,12 +53,12 @@ class FlutterDevice { /// code of the running application (a.k.a. HotReload). /// This ensures that the reload process follows the normal orchestration of /// the Flutter Tools and not just the VM internal service. - void connect({ReloadSources reloadSources}) { + Future _connect({ReloadSources reloadSources}) async { if (vmServices != null) return; vmServices = new List(observatoryUris.length); for (int i = 0; i < observatoryUris.length; i++) { - vmServices[i] = VMService.connect(observatoryUris[i], + vmServices[i] = await VMService.connect(observatoryUris[i], reloadSources: reloadSources); printTrace('Connected to service protocol: ${observatoryUris[i]}'); } @@ -599,7 +599,7 @@ abstract class ResidentRunner { bool viewFound = false; for (FlutterDevice device in flutterDevices) { device.viewFilter = viewFilter; - device.connect(reloadSources: reloadSources); + await device._connect(reloadSources: reloadSources); await device.getVMs(); await device.waitForViews(); if (device.views == null) diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 7cfab0131c7..3227cc454f7 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -140,15 +140,19 @@ class VMService { /// protocol itself. /// /// See: https://github.com/dart-lang/sdk/commit/df8bf384eb815cf38450cb50a0f4b62230fba217 - static VMService connect( + static Future connect( Uri httpUri, { Duration requestTimeout: kDefaultRequestTimeout, ReloadSources reloadSources, - }) { + }) async { final Uri wsUri = httpUri.replace(scheme: 'ws', path: fs.path.join(httpUri.path, 'ws')); final StreamChannel channel = _openChannel(wsUri); final rpc.Peer peer = new rpc.Peer.withoutJson(jsonDocument.bind(channel)); - return new VMService._(peer, httpUri, wsUri, requestTimeout, reloadSources); + final VMService service = new VMService._(peer, httpUri, wsUri, requestTimeout, reloadSources); + // This call is to ensure we are able to establish a connection instead of + // keeping on trucking and failing farther down the process. + await service._sendRequest('getVersion', const {}); + return service; } final Uri httpAddress; diff --git a/packages/flutter_tools/test/vmservice_test.dart b/packages/flutter_tools/test/vmservice_test.dart new file mode 100644 index 00000000000..6cb07146306 --- /dev/null +++ b/packages/flutter_tools/test/vmservice_test.dart @@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium 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 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:test/test.dart'; + +import 'package:flutter_tools/src/base/port_scanner.dart'; +import 'package:flutter_tools/src/vmservice.dart'; + +void main() { + group('VMService', () { + test('fails connection eagerly in the connect() method', () async { + final int port = await const HostPortScanner().findAvailablePort(); + expect( + VMService.connect(Uri.parse('http://localhost:$port')), + throwsA(const isInstanceOf()), + ); + }); + }); +}