Handle new observatory url (#7061) * reapply handle new Observatory URL changes Fixes https://github.com/flutter/flutter/issues/6843 * allow non numeric IPv4 addresses Fixes https://github.com/flutter/flutter/issues/7051
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index bf86f76..01de477 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -8,6 +8,7 @@ import '../android/android_sdk.dart'; import '../application_package.dart'; +import '../base/common.dart'; import '../base/os.dart'; import '../base/logger.dart'; import '../base/process.dart'; @@ -260,16 +261,15 @@ return true; } - Future<int> _forwardPort(String service, int devicePort, int port) async { + Future<int> _forwardPort(int hostPort, int devicePort) async { try { - // Set up port forwarding for observatory. - port = await portForwarder.forward(devicePort, hostPort: port); - printTrace('$service listening on http://127.0.0.1:$port'); - return port; + hostPort = await portForwarder.forward(devicePort, hostPort: hostPort); + printTrace('Forwarded host port $hostPort to device port $devicePort'); + return hostPort; } catch (e) { - printError('Unable to forward port $port: $e'); + throw new ToolExit( + 'Unable to forward host port $hostPort to device port $devicePort: $e'); } - return null; } @override @@ -355,36 +355,40 @@ // device has printed "Observatory is listening on...". printTrace('Waiting for observatory port to be available...'); + // TODO(danrubel): The iOS device class does something similar to this code below. + // The various Device subclasses should be refactored and common code moved into the superclass. try { - int observatoryDevicePort, diagnosticDevicePort; + Uri observatoryDeviceUri, diagnosticDeviceUri; if (debuggingOptions.buildMode == BuildMode.debug) { - Future<List<int>> scrapeServicePorts = Future.wait( - <Future<int>>[observatoryDiscovery.nextPort(), diagnosticDiscovery.nextPort()] + Future<List<Uri>> scrapeServiceUris = Future.wait( + <Future<Uri>>[observatoryDiscovery.nextUri(), diagnosticDiscovery.nextUri()] ); - List<int> devicePorts = await scrapeServicePorts.timeout(new Duration(seconds: 20)); - observatoryDevicePort = devicePorts[0]; - diagnosticDevicePort = devicePorts[1]; - } else { - observatoryDevicePort = await observatoryDiscovery.nextPort().timeout(new Duration(seconds: 20)); + List<Uri> deviceUris = await scrapeServiceUris.timeout(new Duration(seconds: 20)); + observatoryDeviceUri = deviceUris[0]; + diagnosticDeviceUri = deviceUris[1]; + } else if (debuggingOptions.buildMode == BuildMode.profile) { + observatoryDeviceUri = await observatoryDiscovery.nextUri().timeout(new Duration(seconds: 20)); } - printTrace('observatory port on device: $observatoryDevicePort'); + printTrace('Observatory Uri on device: $observatoryDeviceUri'); int observatoryLocalPort = await debuggingOptions.findBestObservatoryPort(); // TODO(devoncarew): Remember the forwarding information (so we can later remove the // port forwarding). - observatoryLocalPort = await _forwardPort(ProtocolDiscovery.kObservatoryService, observatoryDevicePort, observatoryLocalPort); + observatoryLocalPort = await _forwardPort(observatoryLocalPort, observatoryDeviceUri.port); + Uri observatoryLocalUri = observatoryDeviceUri.replace(port: observatoryLocalPort); - int diagnosticLocalPort; - if (diagnosticDevicePort != null) { - printTrace('diagnostic port on device: $diagnosticDevicePort'); - diagnosticLocalPort = await debuggingOptions.findBestDiagnosticPort(); - diagnosticLocalPort = await _forwardPort(ProtocolDiscovery.kDiagnosticService, diagnosticDevicePort, diagnosticLocalPort); + Uri diagnosticLocalUri; + if (diagnosticDeviceUri != null) { + printTrace('Diagnostic Server Uri on device: $diagnosticDeviceUri'); + int diagnosticLocalPort = await debuggingOptions.findBestDiagnosticPort(); + diagnosticLocalPort = await _forwardPort(diagnosticLocalPort, diagnosticDeviceUri.port); + diagnosticLocalUri = diagnosticDeviceUri.replace(port: diagnosticLocalPort); } return new LaunchResult.succeeded( - observatoryPort: observatoryLocalPort, - diagnosticPort: diagnosticLocalPort + observatoryUri: observatoryLocalUri, + diagnosticUri: diagnosticLocalUri, ); } catch (error) { if (error is TimeoutException)
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index a1a868c..1fbffeb 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -359,8 +359,8 @@ connectionInfoCompleter = new Completer<DebugConnectionInfo>(); connectionInfoCompleter.future.then((DebugConnectionInfo info) { Map<String, dynamic> params = <String, dynamic>{ - 'port': info.port, - 'wsUri': info.wsUri + 'port': info.httpUri.port, + 'wsUri': info.wsUri.toString(), }; if (info.baseUri != null) params['baseUri'] = info.baseUri;
diff --git a/packages/flutter_tools/lib/src/commands/trace.dart b/packages/flutter_tools/lib/src/commands/trace.dart index 7464020..1bbaf6f 100644 --- a/packages/flutter_tools/lib/src/commands/trace.dart +++ b/packages/flutter_tools/lib/src/commands/trace.dart
@@ -55,10 +55,14 @@ Future<Null> runCommand() async { int observatoryPort = int.parse(argResults['debug-port']); + // TODO(danrubel): this will break if we move to the new observatory URL + // See https://github.com/flutter/flutter/issues/7038 + Uri observatoryUri = Uri.parse('http://127.0.0.1:$observatoryPort'); + Tracing tracing; try { - tracing = await Tracing.connect(observatoryPort); + tracing = await Tracing.connect(observatoryUri); } catch (error) { throwToolExit('Error connecting to observatory: $error'); } @@ -100,8 +104,8 @@ class Tracing { Tracing(this.vmService); - static Future<Tracing> connect(int port) { - return VMService.connect(port).then((VMService observatory) => new Tracing(observatory)); + static Future<Tracing> connect(Uri uri) { + return VMService.connect(uri).then((VMService observatory) => new Tracing(observatory)); } final VMService vmService;
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 67354df..1769c2f 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart
@@ -299,22 +299,22 @@ } class LaunchResult { - LaunchResult.succeeded({ this.observatoryPort, this.diagnosticPort }) : started = true; - LaunchResult.failed() : started = false, observatoryPort = null, diagnosticPort = null; + LaunchResult.succeeded({ this.observatoryUri, this.diagnosticUri }) : started = true; + LaunchResult.failed() : started = false, observatoryUri = null, diagnosticUri = null; - bool get hasObservatory => observatoryPort != null; + bool get hasObservatory => observatoryUri != null; final bool started; - final int observatoryPort; - final int diagnosticPort; + final Uri observatoryUri; + final Uri diagnosticUri; @override String toString() { StringBuffer buf = new StringBuffer('started=$started'); - if (observatoryPort != null) - buf.write(', observatory=$observatoryPort'); - if (diagnosticPort != null) - buf.write(', diagnostic=$diagnosticPort'); + if (observatoryUri != null) + buf.write(', observatory=$observatoryUri'); + if (diagnosticUri != null) + buf.write(', diagnostic=$diagnosticUri'); return buf.toString(); } }
diff --git a/packages/flutter_tools/lib/src/hot.dart b/packages/flutter_tools/lib/src/hot.dart index ec4f3ef..c490b97 100644 --- a/packages/flutter_tools/lib/src/hot.dart +++ b/packages/flutter_tools/lib/src/hot.dart
@@ -109,7 +109,7 @@ final String applicationBinary; bool get prebuiltMode => applicationBinary != null; Set<String> _dartDependencies; - int _observatoryPort; + Uri _observatoryUri; AssetBundle _bundle; AssetBundle get bundle => _bundle; final bool benchmarkMode; @@ -217,9 +217,9 @@ return 2; } - _observatoryPort = result.observatoryPort; + _observatoryUri = result.observatoryUri; try { - await connectToServiceProtocol(_observatoryPort); + await connectToServiceProtocol(_observatoryUri); } catch (error) { printError('Error connecting to the service protocol: $error'); return 2; @@ -231,8 +231,8 @@ if (connectionInfoCompleter != null) { connectionInfoCompleter.complete( new DebugConnectionInfo( - port: _observatoryPort, - wsUri: 'ws://localhost:$_observatoryPort/ws', + httpUri: _observatoryUri, + wsUri: vmService.wsAddress, baseUri: baseUri.toString() ) ); @@ -534,7 +534,7 @@ ansiAlternative: '$red$fire$bold To hot reload your app on the fly, ' 'press "r" or F5. To restart the app entirely, press "R".$reset' ); - printStatus('The Observatory debugger and profiler is available at: http://127.0.0.1:$_observatoryPort/'); + printStatus('The Observatory debugger and profiler is available at: $_observatoryUri'); if (details) { printHelpDetails(); printStatus('To repeat this help message, press "h" or F1. To quit, press "q", F10, or Ctrl-C.');
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 9e05e19..cb77af7 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -246,8 +246,8 @@ } int installationResult = -1; - int localObsPort; - int localDiagPort; + Uri localObsUri; + Uri localDiagUri; if (!debuggingOptions.debuggingEnabled) { // If debugging is not enabled, just launch the application and continue. @@ -258,30 +258,36 @@ // ports post launch. printTrace("Debugging is enabled, connecting to observatory and the diagnostic server"); - Future<int> forwardObsPort = _acquireAndForwardPort(app, - ProtocolDiscovery.kObservatoryService, - debuggingOptions.observatoryPort); - Future<int> forwardDiagPort; + // TODO(danrubel): The Android device class does something similar to this code below. + // The various Device subclasses should be refactored and common code moved into the superclass. + Future<Uri> forwardObsUri = _acquireServiceUri( + app, + ProtocolDiscovery.kObservatoryService, + debuggingOptions.observatoryPort, + ); + Future<Uri> forwardDiagUri; if (debuggingOptions.buildMode == BuildMode.debug) { - forwardDiagPort = _acquireAndForwardPort(app, - ProtocolDiscovery.kDiagnosticService, - debuggingOptions.diagnosticPort); + forwardDiagUri = _acquireServiceUri( + app, + ProtocolDiscovery.kDiagnosticService, + debuggingOptions.diagnosticPort, + ); } else { - forwardDiagPort = new Future<int>.value(null); + forwardDiagUri = new Future<Uri>.value(null); } Future<int> launch = runCommandAndStreamOutput(launchCommand, trace: true); - List<int> ports = await launch.then((int result) async { + List<Uri> uris = await launch.then((int result) async { installationResult = result; if (result != 0) { printTrace("Failed to launch the application on device."); - return <int>[null, null]; + return <Uri>[null, null]; } printTrace("Application launched on the device. Attempting to forward ports."); - return await Future.wait(<Future<int>>[forwardObsPort, forwardDiagPort]) + return await Future.wait(<Future<Uri>>[forwardObsUri, forwardDiagUri]) .timeout( kPortForwardTimeout, onTimeout: () { @@ -290,11 +296,11 @@ ); }); - printTrace("Local Observatory Port: ${ports[0]}"); - printTrace("Local Diagnostic Server Port: ${ports[1]}"); + printTrace("Observatory Uri on device: ${uris[0]}"); + printTrace("Diagnostic Server Uri on device: ${uris[1]}"); - localObsPort = ports[0]; - localDiagPort = ports[1]; + localObsUri = uris[0]; + localDiagUri = uris[1]; } if (installationResult != 0) { @@ -305,25 +311,25 @@ return new LaunchResult.failed(); } - return new LaunchResult.succeeded(observatoryPort: localObsPort, diagnosticPort: localDiagPort); + return new LaunchResult.succeeded(observatoryUri: localObsUri, diagnosticUri: localDiagUri); } - Future<int> _acquireAndForwardPort( + Future<Uri> _acquireServiceUri( ApplicationPackage app, String serviceName, int localPort) async { Duration stepTimeout = const Duration(seconds: 60); - Future<int> remote = new ProtocolDiscovery(getLogReader(app: app), serviceName).nextPort(); + Future<Uri> remote = new ProtocolDiscovery(getLogReader(app: app), serviceName).nextUri(); - int remotePort = await remote.timeout(stepTimeout, + Uri remoteUri = await remote.timeout(stepTimeout, onTimeout: () { - printTrace("Timeout while attempting to retrieve remote port for $serviceName"); + printTrace("Timeout while attempting to retrieve remote Uri for $serviceName"); return null; }); - if (remotePort == null) { - printTrace("Could not read port on device for $serviceName"); + if (remoteUri == null) { + printTrace("Could not read Uri on device for $serviceName"); return null; } @@ -332,19 +338,22 @@ printTrace("Auto selected local port to $localPort"); } - int forwardResult = await portForwarder.forward(remotePort, - hostPort: localPort).timeout(stepTimeout, onTimeout: () { - printTrace("Timeout while atempting to foward port for $serviceName"); - return null; - }); + int forwardResult = await portForwarder + .forward(remoteUri.port, hostPort: localPort) + .timeout(stepTimeout, onTimeout: () { + printTrace("Timeout while atempting to foward port for $serviceName"); + return null; + }); if (forwardResult == null) { - printTrace("Could not foward remote $serviceName port $remotePort to local port $localPort"); + printTrace("Could not foward remote $serviceName port $remoteUri to local port $localPort"); return null; } - printStatus('$serviceName listening on http://127.0.0.1:$localPort'); - return localPort; + Uri forwardUri = remoteUri.replace(port: forwardResult); + + printStatus('$serviceName listening on $forwardUri'); + return forwardUri; } @override
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 3c30dca..2ddc23e 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -473,12 +473,12 @@ printTrace('Waiting for observatory port to be available...'); try { - int devicePort = await observatoryDiscovery - .nextPort() + Uri deviceUri = await observatoryDiscovery + .nextUri() .timeout(new Duration(seconds: 20)); - printTrace('service protocol port = $devicePort'); - printStatus('Observatory listening on http://127.0.0.1:$devicePort'); - return new LaunchResult.succeeded(observatoryPort: devicePort); + printTrace('Observatory Uri on simulator: $deviceUri'); + printStatus('Observatory listening on $deviceUri'); + return new LaunchResult.succeeded(observatoryUri: deviceUri); } catch (error) { if (error is TimeoutException) printError('Timed out while waiting for a debug connection.');
diff --git a/packages/flutter_tools/lib/src/protocol_discovery.dart b/packages/flutter_tools/lib/src/protocol_discovery.dart index 7c27b13..470d527 100644 --- a/packages/flutter_tools/lib/src/protocol_discovery.dart +++ b/packages/flutter_tools/lib/src/protocol_discovery.dart
@@ -21,37 +21,37 @@ final DeviceLogReader _logReader; final String _serviceName; - Completer<int> _completer = new Completer<int>(); + Completer<Uri> _completer = new Completer<Uri>(); StreamSubscription<String> _subscription; /// The [Future] returned by this function will complete when the next service - /// protocol port is found. - Future<int> nextPort() => _completer.future; + /// Uri is found. + Future<Uri> nextUri() => _completer.future; void cancel() { _subscription.cancel(); } void _onLine(String line) { - int portNumber = 0; - if (line.contains('$_serviceName listening on http://')) { + Uri uri; + String prefix = '$_serviceName listening on '; + int index = line.indexOf(prefix + 'http://'); + if (index >= 0) { try { - RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); - String port = portExp.firstMatch(line).group(1); - portNumber = int.parse(port); + uri = Uri.parse(line.substring(index + prefix.length)); } catch (_) { // Ignore errors. } } - if (portNumber != 0) - _located(portNumber); + if (uri != null) + _located(uri); } - void _located(int port) { + void _located(Uri uri) { assert(_completer != null); assert(!_completer.isCompleted); - _completer.complete(port); - _completer = new Completer<int>(); + _completer.complete(uri); + _completer = new Completer<Uri>(); } }
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 70e161e..1492d81 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -130,12 +130,12 @@ _loggingSubscription = null; } - Future<Null> connectToServiceProtocol(int port) async { + Future<Null> connectToServiceProtocol(Uri uri) async { if (!debuggingOptions.debuggingEnabled) { return new Future<Null>.error('Error the service protocol is not enabled.'); } - vmService = await VMService.connect(port); - printTrace('Connected to service protocol on port $port'); + vmService = await VMService.connect(uri); + printTrace('Connected to service protocol: $uri'); await vmService.getVM(); // Refresh the view list. @@ -298,9 +298,11 @@ } class DebugConnectionInfo { - DebugConnectionInfo({ this.port, this.wsUri, this.baseUri }); + DebugConnectionInfo({ this.httpUri, this.wsUri, this.baseUri }); - final int port; - final String wsUri; + // TODO(danrubel): the httpUri field should be removed as part of + // https://github.com/flutter/flutter/issues/7050 + final Uri httpUri; + final Uri wsUri; final String baseUri; }
diff --git a/packages/flutter_tools/lib/src/run.dart b/packages/flutter_tools/lib/src/run.dart index 55b543e..0d7ba0b 100644 --- a/packages/flutter_tools/lib/src/run.dart +++ b/packages/flutter_tools/lib/src/run.dart
@@ -119,17 +119,16 @@ startTime.stop(); - if (_result.hasObservatory) { - int port = _result.observatoryPort; - connectionInfoCompleter?.complete(new DebugConnectionInfo( - port: port, - wsUri: 'ws://localhost:$port/ws' - )); - } - // Connect to observatory. if (debuggingOptions.debuggingEnabled) { - await connectToServiceProtocol(_result.observatoryPort); + await connectToServiceProtocol(_result.observatoryUri); + } + + if (_result.hasObservatory) { + connectionInfoCompleter?.complete(new DebugConnectionInfo( + httpUri: _result.observatoryUri, + wsUri: vmService.wsAddress, + )); } printTrace('Application running.'); @@ -176,7 +175,7 @@ void printHelp({ @required bool details }) { bool haveDetails = false; if (_result.hasObservatory) - printStatus('The Observatory debugger and profiler is available at: http://127.0.0.1:${_result.observatoryPort}/'); + printStatus('The Observatory debugger and profiler is available at: ${_result.observatoryUri}'); if (supportsServiceProtocol) { haveDetails = true; if (details)
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index e767e2a..4f2a126 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -8,13 +8,14 @@ import 'package:json_rpc_2/json_rpc_2.dart' as rpc; import 'package:json_rpc_2/error_code.dart' as rpc_error_code; +import 'package:path/path.dart' as path; import 'package:web_socket_channel/io.dart'; import 'globals.dart'; /// A connection to the Dart VM Service. class VMService { - VMService._(this.peer, this.port, this.httpAddress) { + VMService._(this.peer, this.httpAddress, this.wsAddress) { _vm = new VM._empty(this); peer.registerMethod('streamNotify', (rpc.Parameters event) { @@ -23,21 +24,20 @@ } /// Connect to '127.0.0.1' at [port]. - static Future<VMService> connect(int port) async { - Uri uri = new Uri(scheme: 'ws', host: '127.0.0.1', port: port, path: 'ws'); + static Future<VMService> connect(Uri httpUri) async { + Uri wsUri = httpUri.replace(scheme: 'ws', path: path.join(httpUri.path, 'ws')); WebSocket ws; try { - ws = await WebSocket.connect(uri.toString()); + ws = await WebSocket.connect(wsUri.toString()); } catch (e) { - return new Future<VMService>.error('Failed to connect to $uri\n $e'); + return new Future<VMService>.error('Failed to connect to $wsUri\n $e'); } rpc.Peer peer = new rpc.Peer(new IOWebSocketChannel(ws).cast()); peer.listen(); - Uri httpAddress = new Uri(scheme: 'http', host: '127.0.0.1', port: port); - return new VMService._(peer, port, httpAddress); + return new VMService._(peer, httpUri, wsUri); } final Uri httpAddress; - final int port; + final Uri wsAddress; final rpc.Peer peer; VM _vm;