Added support for authentication codes for the VM service. (#30857)
* Added support for authentication codes for the VM service.
Previously, a valid web socket connection would use the following URI:
`ws://127.0.0.1/ws`
Now, by default, the VM service requires a connection to be made with a
URI similar to the following:
`ws://127.0.0.1:8181/Ug_U0QVsqFs=/ws`
where `Ug_U0QVsqFs` is an authentication code generated and shared by
the
service.
This behavior can be disabled with the `--disable-service-auth-codes`
flag.
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index f7e75b1..00091dd 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-4b9966f5cb412a73fa50462b3aee9082f436a62a
+ca31a7c57bada458fa7f5c0d3f36bc1af4ccbc79
diff --git a/dev/devicelab/bin/tasks/commands_test.dart b/dev/devicelab/bin/tasks/commands_test.dart
index 1611fd3..1441384 100644
--- a/dev/devicelab/bin/tasks/commands_test.dart
+++ b/dev/devicelab/bin/tasks/commands_test.dart
@@ -26,7 +26,7 @@
print('run: starting...');
final Process run = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
- <String>['run', '--verbose', '-d', device.deviceId, 'lib/commands.dart'],
+ <String>['run', '--verbose', '--disable-service-auth-codes', '-d', device.deviceId, 'lib/commands.dart'],
);
final StreamController<String> stdout = StreamController<String>.broadcast();
run.stdout
diff --git a/dev/devicelab/bin/tasks/named_isolates_test.dart b/dev/devicelab/bin/tasks/named_isolates_test.dart
index c0ca4c1..9ebe3b8 100644
--- a/dev/devicelab/bin/tasks/named_isolates_test.dart
+++ b/dev/devicelab/bin/tasks/named_isolates_test.dart
@@ -21,7 +21,8 @@
section('Compile and run the tester app');
Completer<void> firstNameFound = Completer<void>();
Completer<void> secondNameFound = Completer<void>();
- final Process runProcess = await _run(device: device, command: <String>['run'], stdoutListener: (String line) {
+ final Process runProcess = await _run(device: device, command:
+ <String>['run', '--disable-service-auth-codes'], stdoutListener: (String line) {
if (line.contains(_kFirstIsolateName)) {
firstNameFound.complete();
} else if (line.contains(_kSecondIsolateName)) {
diff --git a/dev/devicelab/bin/tasks/routing_test.dart b/dev/devicelab/bin/tasks/routing_test.dart
index 6098132..aa7ca5f 100644
--- a/dev/devicelab/bin/tasks/routing_test.dart
+++ b/dev/devicelab/bin/tasks/routing_test.dart
@@ -34,7 +34,7 @@
print('run: starting...');
final Process run = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
- <String>['run', '--verbose', '-d', device.deviceId, '--route', '/smuggle-it', 'lib/route.dart'],
+ <String>['run', '--verbose', '--disable-service-auth-codes', '-d', device.deviceId, '--route', '/smuggle-it', 'lib/route.dart'],
);
run.stdout
.transform<String>(utf8.decoder)
diff --git a/dev/devicelab/bin/tasks/service_extensions_test.dart b/dev/devicelab/bin/tasks/service_extensions_test.dart
index d946f40..728cc33 100644
--- a/dev/devicelab/bin/tasks/service_extensions_test.dart
+++ b/dev/devicelab/bin/tasks/service_extensions_test.dart
@@ -26,7 +26,7 @@
print('run: starting...');
final Process run = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
- <String>['run', '--verbose', '-d', device.deviceId, 'lib/main.dart'],
+ <String>['run', '--verbose', '--disable-service-auth-codes', '-d', device.deviceId, 'lib/main.dart'],
);
run.stdout
.transform<String>(utf8.decoder)
diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart
index 69cbe36..e6a0fa4 100644
--- a/dev/devicelab/lib/framework/runner.dart
+++ b/dev/devicelab/lib/framework/runner.dart
@@ -41,16 +41,16 @@
runnerFinished = true;
});
- final Completer<int> port = Completer<int>();
+ final Completer<Uri> uri = Completer<Uri>();
final StreamSubscription<String> stdoutSub = runner.stdout
.transform<String>(const Utf8Decoder())
.transform<String>(const LineSplitter())
.listen((String line) {
- if (!port.isCompleted) {
- final int portValue = parseServicePort(line, prefix: 'Observatory listening on ');
- if (portValue != null)
- port.complete(portValue);
+ if (!uri.isCompleted) {
+ final Uri serviceUri = parseServiceUri(line, prefix: 'Observatory listening on ');
+ if (serviceUri != null)
+ uri.complete(serviceUri);
}
if (!silent) {
stdout.writeln('[$taskName] [STDOUT] $line');
@@ -66,7 +66,7 @@
String waitingFor = 'connection';
try {
- final VMIsolateRef isolate = await _connectToRunnerIsolate(await port.future);
+ final VMIsolateRef isolate = await _connectToRunnerIsolate(await uri.future);
waitingFor = 'task completion';
final Map<String, dynamic> taskResult =
await isolate.invokeExtension('ext.cocoonRunTask').timeout(taskTimeoutWithGracePeriod);
@@ -88,8 +88,15 @@
}
}
-Future<VMIsolateRef> _connectToRunnerIsolate(int vmServicePort) async {
- final String url = 'ws://localhost:$vmServicePort/ws';
+Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async {
+ final List<String> pathSegments = <String>[];
+ if (vmServiceUri.pathSegments.isNotEmpty) {
+ // Add authentication code.
+ pathSegments.add(vmServiceUri.pathSegments[0]);
+ }
+ pathSegments.add('ws');
+ final String url = vmServiceUri.replace(scheme: 'ws', pathSegments:
+ pathSegments).toString();
final DateTime started = DateTime.now();
// TODO(yjbanov): due to lack of imagination at the moment the handshake with
@@ -163,4 +170,4 @@
} else {
print('Could not determine JAVA_HOME; not shutting down Gradle.');
}
-}
\ No newline at end of file
+}
diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart
index c562a3f..72067a8 100644
--- a/dev/devicelab/lib/framework/utils.dart
+++ b/dev/devicelab/lib/framework/utils.dart
@@ -529,19 +529,43 @@
return token;
}
+final RegExp _obsRegExp =
+ RegExp('An Observatory debugger .* is available at: ');
+final RegExp _obsPortRegExp = RegExp('(\\S+:(\\d+)/\\S*)\$');
+final RegExp _obsUriRegExp = RegExp('((http|\/\/)[a-zA-Z0-9:/=_\\-\.\\[\\]]+)');
+
/// Tries to extract a port from the string.
///
/// The `prefix`, if specified, is a regular expression pattern and must not contain groups.
-///
-/// The `multiLine` flag should be set to true if `line` is actually a buffer of many lines.
+/// `prefix` defaults to the RegExp: `An Observatory debugger .* is available at: `.
int parseServicePort(String line, {
- String prefix = 'An Observatory debugger .* is available at: ',
- bool multiLine = false,
+ Pattern prefix,
}) {
- // e.g. "An Observatory debugger and profiler on ... is available at: http://127.0.0.1:8100/"
- final RegExp pattern = RegExp('$prefix(\\S+:(\\d+)/\\S*)\$', multiLine: multiLine);
- final Match match = pattern.firstMatch(line);
- return match == null ? null : int.parse(match.group(2));
+ prefix ??= _obsRegExp;
+ final Match prefixMatch = prefix.matchAsPrefix(line);
+ if (prefixMatch == null) {
+ return null;
+ }
+ final List<Match> matches =
+ _obsPortRegExp.allMatches(line, prefixMatch.end).toList();
+ return matches.isEmpty ? null : int.parse(matches[0].group(2));
+}
+
+/// Tries to extract a Uri from the string.
+///
+/// The `prefix`, if specified, is a regular expression pattern and must not contain groups.
+/// `prefix` defaults to the RegExp: `An Observatory debugger .* is available at: `.
+Uri parseServiceUri(String line, {
+ Pattern prefix,
+}) {
+ prefix ??= _obsRegExp;
+ final Match prefixMatch = prefix.matchAsPrefix(line);
+ if (prefixMatch == null) {
+ return null;
+ }
+ final List<Match> matches =
+ _obsUriRegExp.allMatches(line, prefixMatch.end).toList();
+ return matches.isEmpty ? null : Uri.parse(matches[0].group(0));
}
/// If FLUTTER_ENGINE environment variable is set then we need to pass
diff --git a/dev/devicelab/test/utils_test.dart b/dev/devicelab/test/utils_test.dart
index 10d17b1..c1932b1 100644
--- a/dev/devicelab/test/utils_test.dart
+++ b/dev/devicelab/test/utils_test.dart
@@ -16,4 +16,21 @@
expect(grep(RegExp('^b'), from: 'ab\nba'), <String>['ba']);
});
});
+
+ group('parse service', () {
+ const String badOutput = 'No uri here';
+ const String sampleOutput = 'An Observatory debugger and profiler on '
+ 'Pixel 3 XL is available at: http://127.0.0.1:9090/LpjUpsdEjqI=/';
+
+ test('uri', () {
+ expect(parseServiceUri(sampleOutput),
+ Uri.parse('http://127.0.0.1:9090/LpjUpsdEjqI=/'));
+ expect(parseServiceUri(badOutput), null);
+ });
+
+ test('port', () {
+ expect(parseServicePort(sampleOutput), 9090);
+ expect(parseServicePort(badOutput), null);
+ });
+ });
}
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index 335a149..6a1c88c 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -438,6 +438,8 @@
}
if (debuggingOptions.startPaused)
cmd.addAll(<String>['--ez', 'start-paused', 'true']);
+ if (debuggingOptions.disableServiceAuthCodes)
+ cmd.addAll(<String>['--ez', 'disable-service-auth-codes', 'true']);
if (debuggingOptions.useTestFonts)
cmd.addAll(<String>['--ez', 'use-test-fonts', 'true']);
if (debuggingOptions.verboseSystemLogs) {
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index 43f15a1..4703d97 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -31,6 +31,12 @@
/// With an application already running, a HotRunner can be attached to it
/// with:
/// ```
+/// $ flutter attach --debug-uri http://127.0.0.1:12345/QqL7EFEDNG0=/
+/// ```
+///
+/// If `--disable-service-auth-codes` was provided to the application at startup
+/// time, a HotRunner can be attached with just a port:
+/// ```
/// $ flutter attach --debug-port 12345
/// ```
///
@@ -56,7 +62,14 @@
argParser
..addOption(
'debug-port',
- help: 'Device port where the observatory is listening.',
+ hide: !verboseHelp,
+ help: 'Device port where the observatory is listening. Requires '
+ '--disable-service-auth-codes to also be provided to the Flutter '
+ 'application at launch, otherwise this command will fail to connect to '
+ 'the application. In general, --debug-uri should be used instead.',
+ )..addOption(
+ 'debug-uri',
+ help: 'The URI at which the observatory is listening.',
)..addOption(
'app-id',
help: 'The package name (Android) or bundle identifier (iOS) for the application. '
@@ -102,6 +115,17 @@
return null;
}
+ Uri get debugUri {
+ if (argResults['debug-uri'] == null) {
+ return null;
+ }
+ final Uri uri = Uri.parse(argResults['debug-uri']);
+ if (!uri.hasPort) {
+ throwToolExit('Port not specified for `--debug-uri`: $uri');
+ }
+ return uri;
+ }
+
String get appId {
return argResults['app-id'];
}
@@ -112,24 +136,26 @@
if (await findTargetDevice() == null)
throwToolExit(null);
debugPort;
- if (debugPort == null && argResults.wasParsed(FlutterCommand.ipv6Flag)) {
+ if (debugPort == null && debugUri == null && argResults.wasParsed(FlutterCommand.ipv6Flag)) {
throwToolExit(
- 'When the --debug-port is unknown, this command determines '
+ 'When the --debug-port or --debug-uri is unknown, this command determines '
'the value of --ipv6 on its own.',
);
}
- if (debugPort == null && argResults.wasParsed(FlutterCommand.observatoryPortOption)) {
+ if (debugPort == null && debugUri == null && argResults.wasParsed(FlutterCommand.observatoryPortOption)) {
throwToolExit(
- 'When the --debug-port is unknown, this command does not use '
+ 'When the --debug-port or --debug-uri is unknown, this command does not use '
'the value of --observatory-port.',
);
}
+ if (debugPort != null && debugUri != null) {
+ throwToolExit(
+ 'Either --debugPort or --debugUri can be provided, not both.');
+ }
}
@override
Future<FlutterCommandResult> runCommand() async {
- final String ipv4Loopback = InternetAddress.loopbackIPv4.address;
- final String ipv6Loopback = InternetAddress.loopbackIPv6.address;
final FlutterProject flutterProject = await FlutterProject.current();
Cache.releaseLockEarly();
@@ -147,7 +173,6 @@
// simulators support it.
// If/when we do this on Android or other platforms, we can update it here.
if (device is IOSDevice || device is IOSSimulator) {
- return MDnsObservatoryPortDiscovery().queryForPort(applicationId: appId);
}
return null;
}
@@ -159,9 +184,13 @@
: null;
Uri observatoryUri;
- bool usesIpv6 = false;
+ bool usesIpv6 = ipv6;
+ final String ipv6Loopback = InternetAddress.loopbackIPv6.address;
+ final String ipv4Loopback = InternetAddress.loopbackIPv4.address;
+ final String hostname = usesIpv6 ? ipv6Loopback : ipv4Loopback;
+
bool attachLogger = false;
- if (devicePort == null) {
+ if (devicePort == null && debugUri == null) {
if (device is FuchsiaDevice) {
attachLogger = true;
final String module = argResults['module'];
@@ -181,7 +210,12 @@
}
rethrow;
}
- } else {
+ } else if ((device is IOSDevice) || (device is IOSSimulator)) {
+ final MDnsObservatoryDiscoveryResult result = await MDnsObservatoryDiscovery().query(applicationId: appId);
+ observatoryUri = await _buildObservatoryUri(device, hostname, result.port, result.authCode);
+ }
+ // If MDNS discovery fails or we're not on iOS, fallback to ProtocolDiscovery.
+ if (observatoryUri == null) {
ProtocolDiscovery observatoryDiscovery;
try {
observatoryDiscovery = ProtocolDiscovery.observatory(
@@ -198,12 +232,8 @@
}
}
} else {
- usesIpv6 = ipv6;
- final int localPort = observatoryPort
- ?? await device.portForwarder.forward(devicePort);
- observatoryUri = usesIpv6
- ? Uri.parse('http://[$ipv6Loopback]:$localPort/')
- : Uri.parse('http://$ipv4Loopback:$localPort/');
+ observatoryUri = await _buildObservatoryUri(device,
+ debugUri?.host ?? hostname, devicePort, debugUri?.path);
}
try {
final bool useHot = getBuildInfo().isDebug;
@@ -277,6 +307,22 @@
}
Future<void> _validateArguments() async { }
+
+ Future<Uri> _buildObservatoryUri(Device device,
+ String host, int devicePort, [String authCode]) async {
+ String path = '/';
+ if (authCode != null) {
+ path = authCode;
+ }
+ // Not having a trailing slash can cause problems in some situations.
+ // Ensure that there's one present.
+ if (!path.endsWith('/')) {
+ path += '/';
+ }
+ final int localPort = observatoryPort
+ ?? await device.portForwarder.forward(devicePort);
+ return Uri(scheme: 'http', host: host, port: localPort, path: path);
+ }
}
class HotRunnerFactory {
@@ -310,15 +356,21 @@
);
}
-/// A wrapper around [MDnsClient] to find a Dart observatory port.
-class MDnsObservatoryPortDiscovery {
- /// Creates a new [MDnsObservatoryPortDiscovery] object.
+class MDnsObservatoryDiscoveryResult {
+ MDnsObservatoryDiscoveryResult(this.port, this.authCode);
+ final int port;
+ final String authCode;
+}
+
+/// A wrapper around [MDnsClient] to find a Dart observatory instance.
+class MDnsObservatoryDiscovery {
+ /// Creates a new [MDnsObservatoryDiscovery] object.
///
/// The [client] parameter will be defaulted to a new [MDnsClient] if null.
/// The [applicationId] parameter may be null, and can be used to
/// automatically select which application to use if multiple are advertising
/// Dart observatory ports.
- MDnsObservatoryPortDiscovery({MDnsClient mdnsClient})
+ MDnsObservatoryDiscovery({MDnsClient mdnsClient})
: client = mdnsClient ?? MDnsClient();
/// The [MDnsClient] used to do a lookup.
@@ -326,14 +378,14 @@
static const String dartObservatoryName = '_dartobservatory._tcp.local';
- /// Executes an mDNS query for a Dart Observatory port.
+ /// Executes an mDNS query for a Dart Observatory.
///
/// The [applicationId] parameter may be used to specify which application
/// to find. For Android, it refers to the package name; on iOS, it refers to
/// the bundle ID.
///
- /// If it is not null, this method will find the port of the
- /// Dart Observatory for that application. If it cannot find a Dart
+ /// If it is not null, this method will find the port and authentication code
+ /// of the Dart Observatory for that application. If it cannot find a Dart
/// Observatory matching that application identifier, it will call
/// [throwToolExit].
///
@@ -341,9 +393,10 @@
/// prompted with a list of available observatory ports and asked to select
/// one.
///
- /// If it is null and there is only one available port, it will return that
- /// port regardless of what application the port is for.
- Future<int> queryForPort({String applicationId}) async {
+ /// If it is null and there is only one available instance of Observatory,
+ /// it will return that instance's information regardless of what application
+ /// the Observatory instance is for.
+ Future<MDnsObservatoryDiscoveryResult> query({String applicationId}) async {
printStatus('Checking for advertised Dart observatories...');
try {
await client.start();
@@ -378,7 +431,7 @@
buffer.writeln('There are multiple observatory ports available.');
buffer.writeln('Rerun this command with one of the following passed in as the appId:');
buffer.writeln('');
- for (final String uniqueDomainName in uniqueDomainNames) {
+ for (final String uniqueDomainName in uniqueDomainNames) {
buffer.writeln(' flutter attach --app-id ${uniqueDomainName.replaceAll('.$dartObservatoryName', '')}');
}
throwToolExit(buffer.toString());
@@ -399,7 +452,33 @@
printError('Unexpectedly found more than one observatory report for $domainName '
'- using first one (${srv.first.port}).');
}
- return srv.first.port;
+ printStatus('Checking for authentication code for $domainName');
+ final List<TxtResourceRecord> txt = await client
+ .lookup<TxtResourceRecord>(
+ ResourceRecordQuery.text(domainName),
+ )
+ ?.toList();
+ if (txt == null || txt.isEmpty) {
+ return MDnsObservatoryDiscoveryResult(srv.first.port, '');
+ }
+ String authCode = '';
+ const String authCodePrefix = 'authCode=';
+ String raw = txt.first.text;
+ // TXT has a format of [<length byte>, text], so if the length is 2,
+ // that means that TXT is empty.
+ if (raw.length > 2) {
+ // Remove length byte from raw txt.
+ raw = raw.substring(1);
+ if (raw.startsWith(authCodePrefix)) {
+ authCode = raw.substring(authCodePrefix.length);
+ // The Observatory currently expects a trailing '/' as part of the
+ // URI, otherwise an invalid authentication code response is given.
+ if (!authCode.endsWith('/')) {
+ authCode += '/';
+ }
+ }
+ }
+ return MDnsObservatoryDiscoveryResult(srv.first.port, authCode);
} finally {
client.stop();
}
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 926154c..959fb9d 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -169,6 +169,11 @@
'results out to "refresh_benchmark.json", and exit. This flag is '
'intended for use in generating automated flutter benchmarks.',
)
+ ..addFlag('disable-service-auth-codes',
+ negatable: false,
+ hide: !verboseHelp,
+ help: 'No longer require an authentication code to connect to the VM '
+ 'service (not recommended).')
..addOption(FlutterOptions.kExtraFrontEndOptions, hide: true)
..addOption(FlutterOptions.kExtraGenSnapshotOptions, hide: true)
..addMultiOption(FlutterOptions.kEnableExperiment,
@@ -262,6 +267,7 @@
return DebuggingOptions.enabled(
buildInfo,
startPaused: argResults['start-paused'],
+ disableServiceAuthCodes: argResults['disable-service-auth-codes'],
useTestFonts: argResults['use-test-fonts'],
enableSoftwareRendering: argResults['enable-software-rendering'],
skiaDeterministicRendering: argResults['skia-deterministic-rendering'],
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart
index c776bd7..aa93bf0 100644
--- a/packages/flutter_tools/lib/src/commands/test.dart
+++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -43,6 +43,13 @@
'Instructions for connecting with a debugger and printed to the '
'console once the test has started.',
)
+ ..addFlag('disable-service-auth-codes',
+ hide: !verboseHelp,
+ defaultsTo: false,
+ negatable: false,
+ help: 'No longer require an authentication code to connect to the VM '
+ 'service (not recommended).'
+ )
..addFlag('coverage',
defaultsTo: false,
negatable: false,
@@ -194,6 +201,9 @@
}
}
+ final bool disableServiceAuthCodes =
+ argResults['disable-service-auth-codes'];
+
final int result = await runTests(
files,
workDir: workDir,
@@ -202,6 +212,7 @@
watcher: watcher,
enableObservatory: collector != null || startPaused,
startPaused: startPaused,
+ disableServiceAuthCodes: disableServiceAuthCodes,
ipv6: argResults['ipv6'],
machine: machine,
trackWidgetCreation: argResults['track-widget-creation'],
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 1ff9e38..29bb3e7 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -367,6 +367,7 @@
DebuggingOptions.enabled(
this.buildInfo, {
this.startPaused = false,
+ this.disableServiceAuthCodes = false,
this.enableSoftwareRendering = false,
this.skiaDeterministicRendering = false,
this.traceSkia = false,
@@ -381,6 +382,7 @@
: debuggingEnabled = false,
useTestFonts = false,
startPaused = false,
+ disableServiceAuthCodes = false,
enableSoftwareRendering = false,
skiaDeterministicRendering = false,
traceSkia = false,
@@ -393,6 +395,7 @@
final BuildInfo buildInfo;
final bool startPaused;
+ final bool disableServiceAuthCodes;
final bool enableSoftwareRendering;
final bool skiaDeterministicRendering;
final bool traceSkia;
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 9cc4272..d469da1 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -279,6 +279,9 @@
if (debuggingOptions.startPaused)
launchArguments.add('--start-paused');
+ if (debuggingOptions.disableServiceAuthCodes)
+ launchArguments.add('--disable-service-auth-codes');
+
if (debuggingOptions.useTestFonts)
launchArguments.add('--use-test-fonts');
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 82f2ecf..a60ba54 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -325,6 +325,8 @@
]);
if (debuggingOptions.startPaused)
args.add('--start-paused');
+ if (debuggingOptions.disableServiceAuthCodes)
+ args.add('--disable-service-auth-codes');
if (debuggingOptions.skiaDeterministicRendering)
args.add('--skia-deterministic-rendering');
if (debuggingOptions.useTestFonts)
diff --git a/packages/flutter_tools/lib/src/protocol_discovery.dart b/packages/flutter_tools/lib/src/protocol_discovery.dart
index cfd6b6f..96ea8d2 100644
--- a/packages/flutter_tools/lib/src/protocol_discovery.dart
+++ b/packages/flutter_tools/lib/src/protocol_discovery.dart
@@ -59,8 +59,7 @@
void _handleLine(String line) {
Uri uri;
-
- final RegExp r = RegExp('${RegExp.escape(serviceName)} listening on ((http|\/\/)[a-zA-Z0-9:/=\.\\[\\]]+)');
+ final RegExp r = RegExp('${RegExp.escape(serviceName)} listening on ((http|\/\/)[a-zA-Z0-9:/=_\\-\.\\[\\]]+)');
final Match match = r.firstMatch(line);
if (match != null) {
diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart
index 6e43615..6230059 100644
--- a/packages/flutter_tools/lib/src/test/flutter_platform.dart
+++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart
@@ -83,6 +83,7 @@
bool enableObservatory = false,
bool machine = false,
bool startPaused = false,
+ bool disableServiceAuthCodes = false,
int port = 0,
String precompiledDillPath,
Map<String, String> precompiledDillFiles,
@@ -104,6 +105,7 @@
machine: machine,
enableObservatory: enableObservatory,
startPaused: startPaused,
+ disableServiceAuthCodes: disableServiceAuthCodes,
explicitObservatoryPort: observatoryPort,
host: _kHosts[serverType],
port: port,
@@ -385,6 +387,7 @@
this.enableObservatory,
this.machine,
this.startPaused,
+ this.disableServiceAuthCodes,
this.explicitObservatoryPort,
this.host,
this.port,
@@ -403,6 +406,7 @@
final bool enableObservatory;
final bool machine;
final bool startPaused;
+ final bool disableServiceAuthCodes;
final int explicitObservatoryPort;
final InternetAddress host;
final int port;
@@ -585,6 +589,7 @@
packages: PackageMap.globalPackagesPath,
enableObservatory: enableObservatory,
startPaused: startPaused,
+ disableServiceAuthCodes: disableServiceAuthCodes,
observatoryPort: explicitObservatoryPort,
serverPort: server.port,
);
@@ -932,6 +937,7 @@
String packages,
bool enableObservatory = false,
bool startPaused = false,
+ bool disableServiceAuthCodes = false,
int observatoryPort,
int serverPort,
}) {
@@ -953,6 +959,9 @@
if (startPaused) {
command.add('--start-paused');
}
+ if (disableServiceAuthCodes) {
+ command.add('--disable-service-auth-codes');
+ }
} else {
command.add('--disable-observatory');
}
diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart
index 26ce0db..2e1bc76 100644
--- a/packages/flutter_tools/lib/src/test/runner.dart
+++ b/packages/flutter_tools/lib/src/test/runner.dart
@@ -27,6 +27,7 @@
List<String> plainNames = const <String>[],
bool enableObservatory = false,
bool startPaused = false,
+ bool disableServiceAuthCodes = false,
bool ipv6 = false,
bool machine = false,
String precompiledDillPath,
@@ -79,6 +80,7 @@
enableObservatory: enableObservatory,
machine: machine,
startPaused: startPaused,
+ disableServiceAuthCodes: disableServiceAuthCodes,
serverType: serverType,
precompiledDillPath: precompiledDillPath,
precompiledDillFiles: precompiledDillFiles,
diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
index d5f5c22..14c5d3e 100644
--- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart
+++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
@@ -120,6 +120,8 @@
if (debuggingOptions.debuggingEnabled) {
if (debuggingOptions.startPaused)
command.add('--start-paused');
+ if (debuggingOptions.disableServiceAuthCodes)
+ command.add('--disable-service-auth-codes');
if (debuggingOptions.hasObservatoryPort)
command.add('--observatory-port=${debuggingOptions.observatoryPort}');
}
diff --git a/packages/flutter_tools/test/commands/attach_test.dart b/packages/flutter_tools/test/commands/attach_test.dart
index 87dcb92..7093640 100644
--- a/packages/flutter_tools/test/commands/attach_test.dart
+++ b/packages/flutter_tools/test/commands/attach_test.dart
@@ -178,7 +178,7 @@
await expectLater(
createTestCommandRunner(command).run(<String>['attach', '--ipv6']),
throwsToolExit(
- message: 'When the --debug-port is unknown, this command determines '
+ message: 'When the --debug-port or --debug-uri is unknown, this command determines '
'the value of --ipv6 on its own.',
),
);
@@ -193,7 +193,7 @@
await expectLater(
createTestCommandRunner(command).run(<String>['attach', '--observatory-port', '100']),
throwsToolExit(
- message: 'When the --debug-port is unknown, this command does not use '
+ message: 'When the --debug-port or --debug-uri is unknown, this command does not use '
'the value of --observatory-port.',
),
);
@@ -438,7 +438,7 @@
final MDnsClient client = MockMDnsClient();
when(client.lookup<PtrResourceRecord>(
- ResourceRecordQuery.serverPointer(MDnsObservatoryPortDiscovery.dartObservatoryName),
+ ResourceRecordQuery.serverPointer(MDnsObservatoryDiscovery.dartObservatoryName),
)).thenAnswer((_) => Stream<PtrResourceRecord>.fromIterable(ptrRecords));
for (final MapEntry<String, List<SrvResourceRecord>> entry in srvResponse.entries) {
@@ -452,8 +452,8 @@
testUsingContext('No ports available', () async {
final MDnsClient client = getMockClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{});
- final MDnsObservatoryPortDiscovery portDiscovery = MDnsObservatoryPortDiscovery(mdnsClient: client);
- final int port = await portDiscovery.queryForPort();
+ final MDnsObservatoryDiscovery portDiscovery = MDnsObservatoryDiscovery(mdnsClient: client);
+ final int port = (await portDiscovery.query())?.port;
expect(port, isNull);
});
@@ -469,8 +469,8 @@
},
);
- final MDnsObservatoryPortDiscovery portDiscovery = MDnsObservatoryPortDiscovery(mdnsClient: client);
- final int port = await portDiscovery.queryForPort();
+ final MDnsObservatoryDiscovery portDiscovery = MDnsObservatoryDiscovery(mdnsClient: client);
+ final int port = (await portDiscovery.query())?.port;
expect(port, 123);
});
@@ -490,8 +490,8 @@
},
);
- final MDnsObservatoryPortDiscovery portDiscovery = MDnsObservatoryPortDiscovery(mdnsClient: client);
- expect(() => portDiscovery.queryForPort(), throwsToolExit());
+ final MDnsObservatoryDiscovery portDiscovery = MDnsObservatoryDiscovery(mdnsClient: client);
+ expect(() => portDiscovery.query(), throwsToolExit());
});
testUsingContext('Multiple ports available, with appId', () async {
@@ -510,8 +510,8 @@
},
);
- final MDnsObservatoryPortDiscovery portDiscovery = MDnsObservatoryPortDiscovery(mdnsClient: client);
- final int port = await portDiscovery.queryForPort(applicationId: 'fiz');
+ final MDnsObservatoryDiscovery portDiscovery = MDnsObservatoryDiscovery(mdnsClient: client);
+ final int port = (await portDiscovery.query(applicationId: 'fiz'))?.port;
expect(port, 321);
});
@@ -533,8 +533,8 @@
},
);
- final MDnsObservatoryPortDiscovery portDiscovery = MDnsObservatoryPortDiscovery(mdnsClient: client);
- final int port = await portDiscovery.queryForPort(applicationId: 'bar');
+ final MDnsObservatoryDiscovery portDiscovery = MDnsObservatoryDiscovery(mdnsClient: client);
+ final int port = (await portDiscovery.query(applicationId: 'bar'))?.port;
expect(port, 1234);
});
});
diff --git a/packages/flutter_tools/test/integration/test_driver.dart b/packages/flutter_tools/test/integration/test_driver.dart
index de34674..7bb3ceb 100644
--- a/packages/flutter_tools/test/integration/test_driver.dart
+++ b/packages/flutter_tools/test/integration/test_driver.dart
@@ -417,6 +417,7 @@
await _setupProcess(
<String>[
'run',
+ '--disable-service-auth-codes',
'--machine',
'-d',
'flutter-tester',
@@ -607,6 +608,7 @@
}) async {
await _setupProcess(<String>[
'test',
+ '--disable-service-auth-codes',
'--machine',
'-d',
'flutter-tester',