[flutter_tools] replace vm_service extension methods with wrapper class (#76721)

This commit is contained in:
Jonah Williams 2021-02-24 15:40:33 -08:00 committed by GitHub
parent a9eb24d64c
commit a3b14c58ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 185 additions and 225 deletions

View file

@ -132,7 +132,7 @@ class ScreenshotCommand extends FlutterCommand {
Future<bool> runSkia(File outputFile) async { Future<bool> runSkia(File outputFile) async {
final Uri observatoryUri = Uri.parse(stringArg(_kObservatoryUri)); final Uri observatoryUri = Uri.parse(stringArg(_kObservatoryUri));
final vm_service.VmService vmService = await connectToVmService(observatoryUri); final FlutterVmService vmService = await connectToVmService(observatoryUri);
final vm_service.Response skp = await vmService.screenshotSkp(); final vm_service.Response skp = await vmService.screenshotSkp();
if (skp == null) { if (skp == null) {
globals.printError( globals.printError(
@ -156,7 +156,7 @@ class ScreenshotCommand extends FlutterCommand {
Future<bool> runRasterizer(File outputFile) async { Future<bool> runRasterizer(File outputFile) async {
final Uri observatoryUri = Uri.parse(stringArg(_kObservatoryUri)); final Uri observatoryUri = Uri.parse(stringArg(_kObservatoryUri));
final vm_service.VmService vmService = await connectToVmService(observatoryUri); final FlutterVmService vmService = await connectToVmService(observatoryUri);
final vm_service.Response response = await vmService.screenshot(); final vm_service.Response response = await vmService.screenshot();
if (response == null) { if (response == null) {
globals.printError( globals.printError(

View file

@ -226,7 +226,7 @@ abstract class DevFSWriter {
class _DevFSHttpWriter implements DevFSWriter { class _DevFSHttpWriter implements DevFSWriter {
_DevFSHttpWriter( _DevFSHttpWriter(
this.fsName, this.fsName,
vm_service.VmService serviceProtocol, { FlutterVmService serviceProtocol, {
@required OperatingSystemUtils osUtils, @required OperatingSystemUtils osUtils,
@required HttpClient httpClient, @required HttpClient httpClient,
@required Logger logger, @required Logger logger,
@ -372,7 +372,7 @@ class DevFS {
/// ///
/// Failed uploads are retried after [uploadRetryThrottle] duration, defaults to 500ms. /// Failed uploads are retried after [uploadRetryThrottle] duration, defaults to 500ms.
DevFS( DevFS(
vm_service.VmService serviceProtocol, FlutterVmService serviceProtocol,
this.fsName, this.fsName,
this.rootDirectory, { this.rootDirectory, {
@required OperatingSystemUtils osUtils, @required OperatingSystemUtils osUtils,
@ -394,7 +394,7 @@ class DevFS {
: context.get<HttpClientFactory>()()) : context.get<HttpClientFactory>()())
); );
final vm_service.VmService _vmService; final FlutterVmService _vmService;
final _DevFSHttpWriter _httpWriter; final _DevFSHttpWriter _httpWriter;
final Logger _logger; final Logger _logger;
final FileSystem _fileSystem; final FileSystem _fileSystem;

View file

@ -9,7 +9,6 @@ import 'dart:math' as math;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'android/android_device_discovery.dart'; import 'android/android_device_discovery.dart';
import 'android/android_sdk.dart'; import 'android/android_sdk.dart';
@ -45,6 +44,7 @@ import 'macos/xcode.dart';
import 'project.dart'; import 'project.dart';
import 'tester/flutter_tester.dart'; import 'tester/flutter_tester.dart';
import 'version.dart'; import 'version.dart';
import 'vmservice.dart';
import 'web/web_device.dart'; import 'web/web_device.dart';
import 'windows/windows_device.dart'; import 'windows/windows_device.dart';
import 'windows/windows_workflow.dart'; import 'windows/windows_workflow.dart';
@ -1031,7 +1031,7 @@ abstract class DeviceLogReader {
/// Some logs can be obtained from a VM service stream. /// Some logs can be obtained from a VM service stream.
/// Set this after the VM services are connected. /// Set this after the VM services are connected.
vm_service.VmService connectedVMService; FlutterVmService connectedVMService;
@override @override
String toString() => name; String toString() => name;
@ -1061,7 +1061,7 @@ class NoOpDeviceLogReader implements DeviceLogReader {
int appPid; int appPid;
@override @override
vm_service.VmService connectedVMService; FlutterVmService connectedVMService;
@override @override
Stream<String> get logLines => const Stream<String>.empty(); Stream<String> get logLines => const Stream<String>.empty();

View file

@ -127,7 +127,7 @@ class FlutterDriverService extends DriverService {
Device _device; Device _device;
ApplicationPackage _applicationPackage; ApplicationPackage _applicationPackage;
String _vmServiceUri; String _vmServiceUri;
vm_service.VmService _vmService; FlutterVmService _vmService;
@override @override
Future<void> start( Future<void> start(
@ -220,7 +220,7 @@ class FlutterDriverService extends DriverService {
final DeviceLogReader logReader = await device.getLogReader(app: _applicationPackage); final DeviceLogReader logReader = await device.getLogReader(app: _applicationPackage);
logReader.logLines.listen(_logger.printStatus); logReader.logLines.listen(_logger.printStatus);
final vm_service.VM vm = await _vmService.getVM(); final vm_service.VM vm = await _vmService.service.getVM();
logReader.appPid = vm.pid; logReader.appPid = vm.pid;
} }
@ -268,7 +268,7 @@ class FlutterDriverService extends DriverService {
} }
} else if (_device.supportsFlutterExit) { } else if (_device.supportsFlutterExit) {
// Otherwise use the VM Service URI to stop the app as a best effort approach. // Otherwise use the VM Service URI to stop the app as a best effort approach.
final vm_service.VM vm = await _vmService.getVM(); final vm_service.VM vm = await _vmService.service.getVM();
final vm_service.IsolateRef isolateRef = vm.isolates final vm_service.IsolateRef isolateRef = vm.isolates
.firstWhere((vm_service.IsolateRef element) { .firstWhere((vm_service.IsolateRef element) {
return !element.isSystemIsolate; return !element.isSystemIsolate;

View file

@ -7,7 +7,6 @@
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import '../application_package.dart'; import '../application_package.dart';
import '../artifacts.dart'; import '../artifacts.dart';
@ -50,7 +49,7 @@ final String _ipv4Loopback = InternetAddress.loopbackIPv4.address;
final String _ipv6Loopback = InternetAddress.loopbackIPv6.address; final String _ipv6Loopback = InternetAddress.loopbackIPv6.address;
// Enables testing the fuchsia isolate discovery // Enables testing the fuchsia isolate discovery
Future<vm_service.VmService> _kDefaultFuchsiaIsolateDiscoveryConnector(Uri uri) { Future<FlutterVmService> _kDefaultFuchsiaIsolateDiscoveryConnector(Uri uri) {
return connectToVmService(uri); return connectToVmService(uri);
} }
@ -689,7 +688,7 @@ class FuchsiaDevice extends Device {
// netstat shows that the local port is actually being used on the IPv6 // netstat shows that the local port is actually being used on the IPv6
// loopback (::1). // loopback (::1).
final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$port'); final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$port');
final vm_service.VmService vmService = await connectToVmService(uri); final FlutterVmService vmService = await connectToVmService(uri);
final List<FlutterView> flutterViews = await vmService.getFlutterViews(); final List<FlutterView> flutterViews = await vmService.getFlutterViews();
for (final FlutterView flutterView in flutterViews) { for (final FlutterView flutterView in flutterViews) {
if (flutterView.uiIsolate == null) { if (flutterView.uiIsolate == null) {
@ -732,11 +731,11 @@ class FuchsiaIsolateDiscoveryProtocol {
]); ]);
static const Duration _pollDuration = Duration(seconds: 10); static const Duration _pollDuration = Duration(seconds: 10);
final Map<int, vm_service.VmService> _ports = <int, vm_service.VmService>{}; final Map<int, FlutterVmService> _ports = <int, FlutterVmService>{};
final FuchsiaDevice _device; final FuchsiaDevice _device;
final String _isolateName; final String _isolateName;
final Completer<Uri> _foundUri = Completer<Uri>(); final Completer<Uri> _foundUri = Completer<Uri>();
final Future<vm_service.VmService> Function(Uri) _vmServiceConnector; final Future<FlutterVmService> Function(Uri) _vmServiceConnector;
final Future<void> Function(Device, Uri, bool) _ddsStarter; final Future<void> Function(Device, Uri, bool) _ddsStarter;
// whether to only poll once. // whether to only poll once.
final bool _pollOnce; final bool _pollOnce;
@ -772,7 +771,7 @@ class FuchsiaIsolateDiscoveryProtocol {
Future<void> _findIsolate() async { Future<void> _findIsolate() async {
final List<int> ports = await _device.servicePorts(); final List<int> ports = await _device.servicePorts();
for (final int port in ports) { for (final int port in ports) {
vm_service.VmService service; FlutterVmService service;
if (_ports.containsKey(port)) { if (_ports.containsKey(port)) {
service = _ports[port]; service = _ports[port];
} else { } else {

View file

@ -656,29 +656,29 @@ class IOSDeviceLogReader extends DeviceLogReader {
Stream<String> get logLines => _linesController.stream; Stream<String> get logLines => _linesController.stream;
@override @override
vm_service.VmService get connectedVMService => _connectedVMService; FlutterVmService get connectedVMService => _connectedVMService;
vm_service.VmService _connectedVMService; FlutterVmService _connectedVMService;
@override @override
set connectedVMService(vm_service.VmService connectedVmService) { set connectedVMService(FlutterVmService connectedVmService) {
_listenToUnifiedLoggingEvents(connectedVmService); _listenToUnifiedLoggingEvents(connectedVmService);
_connectedVMService = connectedVmService; _connectedVMService = connectedVmService;
} }
static const int minimumUniversalLoggingSdkVersion = 13; static const int minimumUniversalLoggingSdkVersion = 13;
Future<void> _listenToUnifiedLoggingEvents(vm_service.VmService connectedVmService) async { Future<void> _listenToUnifiedLoggingEvents(FlutterVmService connectedVmService) async {
if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) { if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) {
return; return;
} }
try { try {
// The VM service will not publish logging events unless the debug stream is being listened to. // The VM service will not publish logging events unless the debug stream is being listened to.
// Listen to this stream as a side effect. // Listen to this stream as a side effect.
unawaited(connectedVmService.streamListen('Debug')); unawaited(connectedVmService.service.streamListen('Debug'));
await Future.wait(<Future<void>>[ await Future.wait(<Future<void>>[
connectedVmService.streamListen(vm_service.EventStreams.kStdout), connectedVmService.service.streamListen(vm_service.EventStreams.kStdout),
connectedVmService.streamListen(vm_service.EventStreams.kStderr), connectedVmService.service.streamListen(vm_service.EventStreams.kStderr),
]); ]);
} on vm_service.RPCError { } on vm_service.RPCError {
// Do nothing, since the tool is already subscribed. // Do nothing, since the tool is already subscribed.
@ -696,8 +696,8 @@ class IOSDeviceLogReader extends DeviceLogReader {
} }
_loggingSubscriptions.addAll(<StreamSubscription<void>>[ _loggingSubscriptions.addAll(<StreamSubscription<void>>[
connectedVmService.onStdoutEvent.listen(logMessage), connectedVmService.service.onStdoutEvent.listen(logMessage),
connectedVmService.onStderrEvent.listen(logMessage), connectedVmService.service.onStderrEvent.listen(logMessage),
]); ]);
} }

View file

@ -122,8 +122,16 @@ abstract class ResidentWebRunner extends ResidentRunner {
WipConnection _wipConnection; WipConnection _wipConnection;
ChromiumLauncher _chromiumLauncher; ChromiumLauncher _chromiumLauncher;
vmservice.VmService get _vmService => FlutterVmService get _vmService {
_connectionResult?.debugConnection?.vmService; if (_instance != null) {
return _instance;
}
final vmservice.VmService service =_connectionResult?.debugConnection?.vmService;
final Uri websocketUri = Uri.parse(_connectionResult.debugConnection.uri);
final Uri httpUri = _httpUriFromWebsocketUri(websocketUri);
return _instance ??= FlutterVmService(service, wsAddress: websocketUri, httpAddress: httpUri);
}
FlutterVmService _instance;
@override @override
bool get canHotRestart { bool get canHotRestart {
@ -137,7 +145,7 @@ abstract class ResidentWebRunner extends ResidentRunner {
Map<String, dynamic> params, Map<String, dynamic> params,
}) async { }) async {
final vmservice.Response response = final vmservice.Response response =
await _vmService.callServiceExtension(method, args: params); await _vmService.service.callServiceExtension(method, args: params);
return response.toJson(); return response.toJson();
} }
@ -598,7 +606,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
if (!deviceIsDebuggable) { if (!deviceIsDebuggable) {
globals.printStatus('Recompile complete. Page requires refresh.'); globals.printStatus('Recompile complete. Page requires refresh.');
} else if (isRunningDebug) { } else if (isRunningDebug) {
await _vmService.callMethod('hotRestart'); await _vmService.service.callMethod('hotRestart');
} else { } else {
// On non-debug builds, a hard refresh is required to ensure the // On non-debug builds, a hard refresh is required to ensure the
// up to date sources are loaded. // up to date sources are loaded.
@ -771,36 +779,36 @@ class _ResidentWebRunner extends ResidentWebRunner {
globals.printStatus(message); globals.printStatus(message);
} }
_stdOutSub = _vmService.onStdoutEvent.listen(onLogEvent); _stdOutSub = _vmService.service.onStdoutEvent.listen(onLogEvent);
_stdErrSub = _vmService.onStderrEvent.listen(onLogEvent); _stdErrSub = _vmService.service.onStderrEvent.listen(onLogEvent);
_extensionEventSub = _extensionEventSub =
_vmService.onExtensionEvent.listen(printStructuredErrorLog); _vmService.service.onExtensionEvent.listen(printStructuredErrorLog);
try { try {
await _vmService.streamListen(vmservice.EventStreams.kStdout); await _vmService.service.streamListen(vmservice.EventStreams.kStdout);
} on vmservice.RPCError { } on vmservice.RPCError {
// It is safe to ignore this error because we expect an error to be // It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed. // thrown if we're not already subscribed.
} }
try { try {
await _vmService.streamListen(vmservice.EventStreams.kStderr); await _vmService.service.streamListen(vmservice.EventStreams.kStderr);
} on vmservice.RPCError { } on vmservice.RPCError {
// It is safe to ignore this error because we expect an error to be // It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed. // thrown if we're not already subscribed.
} }
try { try {
await _vmService.streamListen(vmservice.EventStreams.kIsolate); await _vmService.service.streamListen(vmservice.EventStreams.kIsolate);
} on vmservice.RPCError { } on vmservice.RPCError {
// It is safe to ignore this error because we expect an error to be // It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed. // thrown if we're not already subscribed.
} }
try { try {
await _vmService.streamListen(vmservice.EventStreams.kExtension); await _vmService.service.streamListen(vmservice.EventStreams.kExtension);
} on vmservice.RPCError { } on vmservice.RPCError {
// It is safe to ignore this error because we expect an error to be // It is safe to ignore this error because we expect an error to be
// thrown if we're not already subscribed. // thrown if we're not already subscribed.
} }
unawaited(_vmService.registerService('reloadSources', 'FlutterTools')); unawaited(_vmService.service.registerService('reloadSources', 'FlutterTools'));
_vmService.registerServiceCallback('reloadSources', (Map<String, Object> params) async { _vmService.service.registerServiceCallback('reloadSources', (Map<String, Object> params) async {
final bool pause = params['pause'] as bool ?? false; final bool pause = params['pause'] as bool ?? false;
await restart(benchmarkMode: false, pause: pause, fullRestart: false); await restart(benchmarkMode: false, pause: pause, fullRestart: false);
return <String, Object>{'type': 'Success'}; return <String, Object>{'type': 'Success'};
@ -808,9 +816,6 @@ class _ResidentWebRunner extends ResidentWebRunner {
websocketUri = Uri.parse(_connectionResult.debugConnection.uri); websocketUri = Uri.parse(_connectionResult.debugConnection.uri);
device.vmService = _vmService; device.vmService = _vmService;
// Update caches to enable the FlutterVmService extensions.
setHttpAddress(_httpUriFromWebsocketUri(websocketUri), device.vmService);
setWsAddress(websocketUri, device.vmService);
// Run main immediately if the app is not started paused or if there // Run main immediately if the app is not started paused or if there
// is no debugger attached. Otherwise, runMain when a resume event // is no debugger attached. Otherwise, runMain when a resume event
@ -865,10 +870,10 @@ class _ResidentWebRunner extends ResidentWebRunner {
await device.exitApps(); await device.exitApps();
appFinished(); appFinished();
} }
}
Uri _httpUriFromWebsocketUri(Uri websocketUri) {
const String wsPath = '/ws'; Uri _httpUriFromWebsocketUri(Uri websocketUri) {
final String path = websocketUri.path; const String wsPath = '/ws';
return websocketUri.replace(scheme: 'http', path: path.substring(0, path.length - wsPath.length)); final String path = websocketUri.path;
} return websocketUri.replace(scheme: 'http', path: path.substring(0, path.length - wsPath.length));
} }

View file

@ -111,7 +111,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
await Future.wait(<Future<void>>[ await Future.wait(<Future<void>>[
for (final FlutterDevice device in flutterDevices) for (final FlutterDevice device in flutterDevices)
if (device.vmService != null) if (device.vmService != null)
waitForExtension(device.vmService, 'ext.flutter.connectedVmServiceUri'), waitForExtension(device.vmService.service, 'ext.flutter.connectedVmServiceUri'),
]); ]);
} }

View file

@ -195,7 +195,7 @@ class FlutterDevice {
DevFSWriter devFSWriter; DevFSWriter devFSWriter;
Stream<Uri> observatoryUris; Stream<Uri> observatoryUris;
vm_service.VmService vmService; FlutterVmService vmService;
DevFS devFS; DevFS devFS;
ApplicationPackage package; ApplicationPackage package;
List<String> fileSystemRoots; List<String> fileSystemRoots;
@ -237,7 +237,7 @@ class FlutterDevice {
globals.printTrace('Connecting to service protocol: $observatoryUri'); globals.printTrace('Connecting to service protocol: $observatoryUri');
isWaitingForVm = true; isWaitingForVm = true;
bool existingDds = false; bool existingDds = false;
vm_service.VmService service; FlutterVmService service;
if (!disableDds) { if (!disableDds) {
void handleError(Exception e, StackTrace st) { void handleError(Exception e, StackTrace st) {
globals.printTrace('Fail to connect to service protocol: $observatoryUri: $e'); globals.printTrace('Fail to connect to service protocol: $observatoryUri: $e');
@ -250,9 +250,6 @@ class FlutterDevice {
// from an old application instance, we shouldn't try and start DDS. // from an old application instance, we shouldn't try and start DDS.
try { try {
service = await connectToVmService(observatoryUri); service = await connectToVmService(observatoryUri);
// TODO(dnfield): Remove ignore once internal repo is up to date
// https://github.com/flutter/flutter/issues/74518
// ignore: await_only_futures
await service.dispose(); await service.dispose();
} on Exception catch (exception) { } on Exception catch (exception) {
globals.printTrace('Fail to connect to service protocol: $observatoryUri: $exception'); globals.printTrace('Fail to connect to service protocol: $observatoryUri: $exception');
@ -306,7 +303,7 @@ class FlutterDevice {
if (!existingDds) if (!existingDds)
device.dds.done.whenComplete(() => throw Exception('DDS shut down too early')), device.dds.done.whenComplete(() => throw Exception('DDS shut down too early')),
] ]
) as vm_service.VmService; ) as FlutterVmService;
} on Exception catch (exception) { } on Exception catch (exception) {
globals.printTrace('Fail to connect to service protocol: $observatoryUri: $exception'); globals.printTrace('Fail to connect to service protocol: $observatoryUri: $exception');
if (!completer.isCompleted && !_isListeningForObservatoryUri) { if (!completer.isCompleted && !_isListeningForObservatoryUri) {
@ -365,7 +362,7 @@ class FlutterDevice {
)); ));
} }
} }
return vmService.onDone return vmService.service.onDone
.catchError((dynamic error, StackTrace stackTrace) { .catchError((dynamic error, StackTrace stackTrace) {
globals.logger.printError( globals.logger.printError(
'unhandled error waiting for vm service exit:\n $error', 'unhandled error waiting for vm service exit:\n $error',
@ -556,7 +553,7 @@ class FlutterDevice {
} }
Future<void> initLogReader() async { Future<void> initLogReader() async {
final vm_service.VM vm = await vmService.getVM(); final vm_service.VM vm = await vmService.service.getVM();
final DeviceLogReader logReader = await device.getLogReader(app: package); final DeviceLogReader logReader = await device.getLogReader(app: package);
logReader.appPid = vm.pid; logReader.appPid = vm.pid;
} }
@ -1275,7 +1272,7 @@ abstract class ResidentRunner {
// This hooks up callbacks for when the connection stops in the future. // This hooks up callbacks for when the connection stops in the future.
// We don't want to wait for them. We don't handle errors in those callbacks' // We don't want to wait for them. We don't handle errors in those callbacks'
// futures either because they just print to logger and is not critical. // futures either because they just print to logger and is not critical.
unawaited(device.vmService.onDone.then<void>( unawaited(device.vmService.service.onDone.then<void>(
_serviceProtocolDone, _serviceProtocolDone,
onError: _serviceProtocolError, onError: _serviceProtocolError,
).whenComplete(_serviceDisconnected)); ).whenComplete(_serviceDisconnected));
@ -1682,8 +1679,6 @@ class TerminalHandler {
class DebugConnectionInfo { class DebugConnectionInfo {
DebugConnectionInfo({ this.httpUri, this.wsUri, this.baseUri }); DebugConnectionInfo({ this.httpUri, this.wsUri, this.baseUri });
// TODO(danrubel): the httpUri field should be removed as part of
// https://github.com/flutter/flutter/issues/7050
final Uri httpUri; final Uri httpUri;
final Uri wsUri; final Uri wsUri;
final String baseUri; final String baseUri;

View file

@ -278,7 +278,7 @@ class HotRunner extends ResidentRunner {
// Measure time to perform a hot restart. // Measure time to perform a hot restart.
globals.printStatus('Benchmarking hot restart'); globals.printStatus('Benchmarking hot restart');
await restart(fullRestart: true); await restart(fullRestart: true);
// Wait multiple seconds to stabilize benchmark on slower devicelab hardware. // Wait multiple seconds to stabilize benchmark on slower device lab hardware.
// Hot restart finishes when the new isolate is started, not when the new isolate // Hot restart finishes when the new isolate is started, not when the new isolate
// is ready. This process can actually take multiple seconds. // is ready. This process can actually take multiple seconds.
await Future<void>.delayed(const Duration(seconds: 10)); await Future<void>.delayed(const Duration(seconds: 10));
@ -532,17 +532,17 @@ class HotRunner extends ResidentRunner {
// The embedder requires that the isolate is unpaused, because the // The embedder requires that the isolate is unpaused, because the
// runInView method requires interaction with dart engine APIs that // runInView method requires interaction with dart engine APIs that
// are not thread-safe, and thus must be run on the same thread that // are not thread-safe, and thus must be run on the same thread that
// would be blocked by the pause. Simply unpausing is not sufficient, // would be blocked by the pause. Simply un-pausing is not sufficient,
// because this does not prevent the isolate from immediately hitting // because this does not prevent the isolate from immediately hitting
// a breakpoint, for example if the breakpoint was placed in a loop // a breakpoint, for example if the breakpoint was placed in a loop
// or in a frequently called method. Instead, all breakpoints are first // or in a frequently called method. Instead, all breakpoints are first
// disabled and then the isolate resumed. // disabled and then the isolate resumed.
final List<Future<void>> breakpointRemoval = <Future<void>>[ final List<Future<void>> breakpointRemoval = <Future<void>>[
for (final vm_service.Breakpoint breakpoint in isolate.breakpoints) for (final vm_service.Breakpoint breakpoint in isolate.breakpoints)
device.vmService.removeBreakpoint(isolate.id, breakpoint.id) device.vmService.service.removeBreakpoint(isolate.id, breakpoint.id)
]; ];
await Future.wait(breakpointRemoval); await Future.wait(breakpointRemoval);
await device.vmService.resume(view.uiIsolate.id); await device.vmService.service.resume(view.uiIsolate.id);
} }
})); }));
} }
@ -550,12 +550,12 @@ class HotRunner extends ResidentRunner {
// The engine handles killing and recreating isolates that it has spawned // The engine handles killing and recreating isolates that it has spawned
// ("uiIsolates"). The isolates that were spawned from these uiIsolates // ("uiIsolates"). The isolates that were spawned from these uiIsolates
// will not be restarted, and so they must be manually killed. // will not be restarted, and so they must be manually killed.
final vm_service.VM vm = await device.vmService.getVM(); final vm_service.VM vm = await device.vmService.service.getVM();
for (final vm_service.IsolateRef isolateRef in vm.isolates) { for (final vm_service.IsolateRef isolateRef in vm.isolates) {
if (uiIsolatesIds.contains(isolateRef.id)) { if (uiIsolatesIds.contains(isolateRef.id)) {
continue; continue;
} }
operations.add(device.vmService.kill(isolateRef.id) operations.add(device.vmService.service.kill(isolateRef.id)
.catchError((dynamic error, StackTrace stackTrace) { .catchError((dynamic error, StackTrace stackTrace) {
// Do nothing on a SentinelException since it means the isolate // Do nothing on a SentinelException since it means the isolate
// has already been killed. // has already been killed.
@ -788,10 +788,10 @@ class HotRunner extends ResidentRunner {
}) async { }) async {
final String deviceEntryUri = device.devFS.baseUri final String deviceEntryUri = device.devFS.baseUri
.resolve(entryPath).toString(); .resolve(entryPath).toString();
final vm_service.VM vm = await device.vmService.getVM(); final vm_service.VM vm = await device.vmService.service.getVM();
return <Future<vm_service.ReloadReport>>[ return <Future<vm_service.ReloadReport>>[
for (final vm_service.IsolateRef isolateRef in vm.isolates) for (final vm_service.IsolateRef isolateRef in vm.isolates)
device.vmService.reloadSources( device.vmService.service.reloadSources(
isolateRef.id, isolateRef.id,
pause: pause, pause: pause,
rootLibUri: deviceEntryUri, rootLibUri: deviceEntryUri,
@ -850,7 +850,7 @@ class HotRunner extends ResidentRunner {
await _evictDirtyAssets(); await _evictDirtyAssets();
// Check if any isolates are paused and reassemble those that aren't. // Check if any isolates are paused and reassemble those that aren't.
final Map<FlutterView, vm_service.VmService> reassembleViews = <FlutterView, vm_service.VmService>{}; final Map<FlutterView, FlutterVmService> reassembleViews = <FlutterView, FlutterVmService>{};
final List<Future<void>> reassembleFutures = <Future<void>>[]; final List<Future<void>> reassembleFutures = <Future<void>>[];
String serviceEventKind; String serviceEventKind;
int pausedIsolatesFound = 0; int pausedIsolatesFound = 0;

View file

@ -202,7 +202,7 @@ class CoverageCollector extends TestWatcher {
Future<void> handleTestTimedOut(TestDevice testDevice) async { } Future<void> handleTestTimedOut(TestDevice testDevice) async { }
} }
Future<vm_service.VmService> _defaultConnect(Uri serviceUri) { Future<FlutterVmService> _defaultConnect(Uri serviceUri) {
return connectToVmService( return connectToVmService(
serviceUri, compression: CompressionOptions.compressionOff); serviceUri, compression: CompressionOptions.compressionOff);
} }
@ -210,14 +210,10 @@ Future<vm_service.VmService> _defaultConnect(Uri serviceUri) {
Future<Map<String, dynamic>> collect(Uri serviceUri, bool Function(String) libraryPredicate, { Future<Map<String, dynamic>> collect(Uri serviceUri, bool Function(String) libraryPredicate, {
bool waitPaused = false, bool waitPaused = false,
String debugName, String debugName,
Future<vm_service.VmService> Function(Uri) connector = _defaultConnect, Future<FlutterVmService> Function(Uri) connector = _defaultConnect,
}) async { }) async {
final vm_service.VmService vmService = await connector(serviceUri); final FlutterVmService vmService = await connector(serviceUri);
final Map<String, dynamic> result = await _getAllCoverage( final Map<String, dynamic> result = await _getAllCoverage(vmService.service, libraryPredicate);
vmService, libraryPredicate);
// TODO(dnfield): Remove ignore once internal repo is up to date
// https://github.com/flutter/flutter/issues/74518
// ignore: await_only_futures
await vmService.dispose(); await vmService.dispose();
return result; return result;
} }

View file

@ -11,7 +11,6 @@ import 'package:dds/dds.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:stream_channel/stream_channel.dart'; import 'package:stream_channel/stream_channel.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
@ -165,11 +164,11 @@ class FlutterTesterTestDevice extends TestDevice {
} }
logger.printTrace('Connecting to service protocol: $forwardingUri'); logger.printTrace('Connecting to service protocol: $forwardingUri');
final Future<vm_service.VmService> localVmService = connectToVmService( final Future<FlutterVmService> localVmService = connectToVmService(
forwardingUri, forwardingUri,
compileExpression: compileExpression, compileExpression: compileExpression,
); );
unawaited(localVmService.then((vm_service.VmService vmservice) { unawaited(localVmService.then((FlutterVmService vmservice) {
logger.printTrace('test $id: Successfully connected to service protocol: $forwardingUri'); logger.printTrace('test $id: Successfully connected to service protocol: $forwardingUri');
})); }));

View file

@ -30,12 +30,12 @@ class Tracing {
static const String firstUsefulFrameEventName = kFirstFrameRasterizedEventName; static const String firstUsefulFrameEventName = kFirstFrameRasterizedEventName;
final vm_service.VmService vmService; final FlutterVmService vmService;
final Logger _logger; final Logger _logger;
Future<void> startTracing() async { Future<void> startTracing() async {
await vmService.setTimelineFlags(<String>['Compiler', 'Dart', 'Embedder', 'GC']); await vmService.setTimelineFlags(<String>['Compiler', 'Dart', 'Embedder', 'GC']);
await vmService.clearVMTimeline(); await vmService.service.clearVMTimeline();
} }
/// Stops tracing; optionally wait for first frame. /// Stops tracing; optionally wait for first frame.
@ -49,12 +49,12 @@ class Tracing {
try { try {
final Completer<void> whenFirstFrameRendered = Completer<void>(); final Completer<void> whenFirstFrameRendered = Completer<void>();
try { try {
await vmService.streamListen(vm_service.EventStreams.kExtension); await vmService.service.streamListen(vm_service.EventStreams.kExtension);
} on vm_service.RPCError { } on vm_service.RPCError {
// It is safe to ignore this error because we expect an error to be // It is safe to ignore this error because we expect an error to be
// thrown if we're already subscribed. // thrown if we're already subscribed.
} }
vmService.onExtensionEvent.listen((vm_service.Event event) { vmService.service.onExtensionEvent.listen((vm_service.Event event) {
if (event.extensionKind == 'Flutter.FirstFrame') { if (event.extensionKind == 'Flutter.FirstFrame') {
whenFirstFrameRendered.complete(); whenFirstFrameRendered.complete();
} }
@ -93,7 +93,7 @@ class Tracing {
/// Download the startup trace information from the given observatory client and /// Download the startup trace information from the given observatory client and
/// store it to build/start_up_info.json. /// store it to build/start_up_info.json.
Future<void> downloadStartupTrace(vm_service.VmService vmService, { Future<void> downloadStartupTrace(FlutterVmService vmService, {
bool awaitFirstFrame = true, bool awaitFirstFrame = true,
@required Logger logger, @required Logger logger,
@required Directory output, @required Directory output,

View file

@ -146,7 +146,7 @@ Future<io.WebSocket> _defaultOpenChannel(String url, {
/// Override `VMServiceConnector` in [context] to return a different VMService /// Override `VMServiceConnector` in [context] to return a different VMService
/// from [VMService.connect] (used by tests). /// from [VMService.connect] (used by tests).
typedef VMServiceConnector = Future<vm_service.VmService> Function(Uri httpUri, { typedef VMServiceConnector = Future<FlutterVmService> Function(Uri httpUri, {
ReloadSources reloadSources, ReloadSources reloadSources,
Restart restart, Restart restart,
CompileExpression compileExpression, CompileExpression compileExpression,
@ -156,24 +156,6 @@ typedef VMServiceConnector = Future<vm_service.VmService> Function(Uri httpUri,
Device device, Device device,
}); });
final Expando<Uri> _httpAddressExpando = Expando<Uri>();
final Expando<Uri> _wsAddressExpando = Expando<Uri>();
void setHttpAddress(Uri uri, vm_service.VmService vmService) {
if(vmService == null) {
return;
}
_httpAddressExpando[vmService] = uri;
}
void setWsAddress(Uri uri, vm_service.VmService vmService) {
if(vmService == null) {
return;
}
_wsAddressExpando[vmService] = uri;
}
/// A connection to the Dart VM Service. /// A connection to the Dart VM Service.
vm_service.VmService setUpVmService( vm_service.VmService setUpVmService(
ReloadSources reloadSources, ReloadSources reloadSources,
@ -292,7 +274,7 @@ vm_service.VmService setUpVmService(
/// protocol itself. /// protocol itself.
/// ///
/// See: https://github.com/dart-lang/sdk/commit/df8bf384eb815cf38450cb50a0f4b62230fba217 /// See: https://github.com/dart-lang/sdk/commit/df8bf384eb815cf38450cb50a0f4b62230fba217
Future<vm_service.VmService> connectToVmService( Future<FlutterVmService> connectToVmService(
Uri httpUri, { Uri httpUri, {
ReloadSources reloadSources, ReloadSources reloadSources,
Restart restart, Restart restart,
@ -314,7 +296,7 @@ Future<vm_service.VmService> connectToVmService(
); );
} }
Future<vm_service.VmService> _connect( Future<FlutterVmService> _connect(
Uri httpUri, { Uri httpUri, {
ReloadSources reloadSources, ReloadSources reloadSources,
Restart restart, Restart restart,
@ -344,13 +326,11 @@ Future<vm_service.VmService> _connect(
printStructuredErrorLogMethod, printStructuredErrorLogMethod,
delegateService, delegateService,
); );
_httpAddressExpando[service] = httpUri;
_wsAddressExpando[service] = wsUri;
// This call is to ensure we are able to establish a connection instead of // This call is to ensure we are able to establish a connection instead of
// keeping on trucking and failing farther down the process. // keeping on trucking and failing farther down the process.
await delegateService.getVersion(); await delegateService.getVersion();
return service; return FlutterVmService(service, httpAddress: httpUri, wsAddress: wsUri);
} }
String _validateRpcStringParam(String methodName, Map<String, dynamic> params, String paramName) { String _validateRpcStringParam(String methodName, Map<String, dynamic> params, String paramName) {
@ -414,10 +394,12 @@ class FlutterView {
} }
/// Flutter specific VM Service functionality. /// Flutter specific VM Service functionality.
extension FlutterVmService on vm_service.VmService { class FlutterVmService {
Uri get wsAddress => this != null ? _wsAddressExpando[this] : null; FlutterVmService(this.service, {this.wsAddress, this.httpAddress});
Uri get httpAddress => this != null ? _httpAddressExpando[this] : null; final vm_service.VmService service;
final Uri wsAddress;
final Uri httpAddress;
Future<vm_service.Response> callMethodWrapper( Future<vm_service.Response> callMethodWrapper(
String method, { String method, {
@ -425,7 +407,7 @@ extension FlutterVmService on vm_service.VmService {
Map<String, dynamic> args Map<String, dynamic> args
}) async { }) async {
try { try {
return await callMethod(method, isolateId: isolateId, args: args); return await service.callMethod(method, isolateId: isolateId, args: args);
} on vm_service.RPCError catch (e) { } on vm_service.RPCError catch (e) {
// If the service disappears mid-request the tool is unable to recover // If the service disappears mid-request the tool is unable to recover
// and should begin to shutdown due to the service connection closing. // and should begin to shutdown due to the service connection closing.
@ -497,11 +479,11 @@ extension FlutterVmService on vm_service.VmService {
@required Uri assetsDirectory, @required Uri assetsDirectory,
}) async { }) async {
try { try {
await streamListen('Isolate'); await service.streamListen('Isolate');
} on vm_service.RPCError { } on vm_service.RPCError {
// Do nothing, since the tool is already subscribed. // Do nothing, since the tool is already subscribed.
} }
final Future<void> onRunnable = onIsolateEvent.firstWhere((vm_service.Event event) { final Future<void> onRunnable = service.onIsolateEvent.firstWhere((vm_service.Event event) {
return event.kind == vm_service.EventKind.kIsolateRunnable; return event.kind == vm_service.EventKind.kIsolateRunnable;
}); });
await callMethodWrapper( await callMethodWrapper(
@ -741,7 +723,7 @@ extension FlutterVmService on vm_service.VmService {
Map<String, dynamic> args, Map<String, dynamic> args,
}) async { }) async {
try { try {
return await callServiceExtension(method, args: args); return await service.callServiceExtension(method, args: args);
} on vm_service.RPCError catch (err) { } on vm_service.RPCError catch (err) {
// If an application is not using the framework or the VM service // If an application is not using the framework or the VM service
// disappears while handling a request, return null. // disappears while handling a request, return null.
@ -805,7 +787,7 @@ extension FlutterVmService on vm_service.VmService {
/// Attempt to retrieve the isolate with id [isolateId], or `null` if it has /// Attempt to retrieve the isolate with id [isolateId], or `null` if it has
/// been collected. /// been collected.
Future<vm_service.Isolate> getIsolateOrNull(String isolateId) { Future<vm_service.Isolate> getIsolateOrNull(String isolateId) {
return getIsolate(isolateId) return service.getIsolate(isolateId)
.catchError((dynamic error, StackTrace stackTrace) { .catchError((dynamic error, StackTrace stackTrace) {
return null; return null;
}, test: (dynamic error) { }, test: (dynamic error) {
@ -818,7 +800,7 @@ extension FlutterVmService on vm_service.VmService {
Future<vm_service.Response> createDevFS(String fsName) { Future<vm_service.Response> createDevFS(String fsName) {
// Call the unchecked version of `callServiceExtension` because the caller // Call the unchecked version of `callServiceExtension` because the caller
// has custom handling of certain RPCErrors. // has custom handling of certain RPCErrors.
return callServiceExtension( return service.callServiceExtension(
'_createDevFS', '_createDevFS',
args: <String, dynamic>{'fsName': fsName}, args: <String, dynamic>{'fsName': fsName},
); );
@ -854,6 +836,13 @@ extension FlutterVmService on vm_service.VmService {
Future<vm_service.Response> getTimeline() { Future<vm_service.Response> getTimeline() {
return _checkedCallServiceExtension('getVMTimeline'); return _checkedCallServiceExtension('getVMTimeline');
} }
Future<void> dispose() async {
// TODO(dnfield): Remove ignore once internal repo is up to date
// https://github.com/flutter/flutter/issues/74518
// ignore: await_only_futures
await service.dispose();
}
} }
/// Whether the event attached to an [Isolate.pauseEvent] should be considered /// Whether the event attached to an [Isolate.pauseEvent] should be considered

View file

@ -115,8 +115,8 @@ void main() {
final OperatingSystemUtils osUtils = MockOperatingSystemUtils(); final OperatingSystemUtils osUtils = MockOperatingSystemUtils();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[failingCreateDevFSRequest], requests: <VmServiceExpectation>[failingCreateDevFSRequest],
httpAddress: Uri.parse('http://localhost'),
); );
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
final DevFS devFS = DevFS( final DevFS devFS = DevFS(
fakeVmServiceHost.vmService, fakeVmServiceHost.vmService,
@ -138,9 +138,8 @@ void main() {
createDevFSRequest, createDevFSRequest,
failingDeleteDevFSRequest, failingDeleteDevFSRequest,
], ],
httpAddress: Uri.parse('http://localhost'),
); );
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
final DevFS devFS = DevFS( final DevFS devFS = DevFS(
fakeVmServiceHost.vmService, fakeVmServiceHost.vmService,
@ -162,8 +161,8 @@ void main() {
final MockResidentCompiler residentCompiler = MockResidentCompiler(); final MockResidentCompiler residentCompiler = MockResidentCompiler();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[createDevFSRequest], requests: <VmServiceExpectation>[createDevFSRequest],
httpAddress: Uri.parse('http://localhost'),
); );
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
when(residentCompiler.recompile( when(residentCompiler.recompile(
any, any,
@ -215,8 +214,9 @@ void main() {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[createDevFSRequest], requests: <VmServiceExpectation>[createDevFSRequest],
httpAddress: Uri.parse('http://localhost'),
); );
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
final DevFS devFS = DevFS( final DevFS devFS = DevFS(
fakeVmServiceHost.vmService, fakeVmServiceHost.vmService,
'test', 'test',
@ -258,8 +258,8 @@ void main() {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[createDevFSRequest], requests: <VmServiceExpectation>[createDevFSRequest],
httpAddress: Uri.parse('http://localhost'),
); );
setHttpAddress(Uri.parse('http://localhost'), fakeVmServiceHost.vmService);
final DevFS devFS = DevFS( final DevFS devFS = DevFS(
fakeVmServiceHost.vmService, fakeVmServiceHost.vmService,

View file

@ -363,7 +363,7 @@ void main() {
FlutterDriverService setUpDriverService({ FlutterDriverService setUpDriverService({
Logger logger, Logger logger,
ProcessManager processManager, ProcessManager processManager,
vm_service.VmService vmService, FlutterVmService vmService,
}) { }) {
logger ??= BufferLogger.test(); logger ??= BufferLogger.test();
return FlutterDriverService( return FlutterDriverService(

View file

@ -747,6 +747,7 @@ void main() {
}, },
), ),
], ],
httpAddress: Uri.parse('example'),
); );
final MockFuchsiaDevice fuchsiaDevice = final MockFuchsiaDevice fuchsiaDevice =
MockFuchsiaDevice('123', portForwarder, false); MockFuchsiaDevice('123', portForwarder, false);
@ -766,7 +767,6 @@ void main() {
.thenAnswer((Invocation invocation) async => <int>[1]); .thenAnswer((Invocation invocation) async => <int>[1]);
when(portForwarder.forward(1)) when(portForwarder.forward(1))
.thenAnswer((Invocation invocation) async => 2); .thenAnswer((Invocation invocation) async => 2);
setHttpAddress(Uri.parse('example'), fakeVmServiceHost.vmService);
return await discoveryProtocol.uri; return await discoveryProtocol.uri;
} }

View file

@ -14,6 +14,7 @@ import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/ios/ios_deploy.dart'; import 'package:flutter_tools/src/ios/ios_deploy.dart';
import 'package:flutter_tools/src/ios/mac.dart'; import 'package:flutter_tools/src/ios/mac.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
@ -149,7 +150,29 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
group('VM service', () { group('VM service', () {
testWithoutContext('IOSDeviceLogReader can listen to VM Service logs', () async { testWithoutContext('IOSDeviceLogReader can listen to VM Service logs', () async {
final MockVmService vmService = MockVmService(); final Event stdoutEvent = Event(
kind: 'Stdout',
timestamp: 0,
bytes: base64.encode(utf8.encode(' This is a message ')),
);
final Event stderrEvent = Event(
kind: 'Stderr',
timestamp: 0,
bytes: base64.encode(utf8.encode(' And this is an error ')),
);
final FlutterVmService vmService = FakeVmServiceHost(requests: <VmServiceExpectation>[
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Debug',
}),
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Stdout',
}),
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Stderr',
}),
FakeVmServiceStreamResponse(event: stdoutEvent, streamId: 'Stdout'),
FakeVmServiceStreamResponse(event: stderrEvent, streamId: 'Stderr'),
]).vmService;
final DeviceLogReader logReader = IOSDeviceLogReader.test( final DeviceLogReader logReader = IOSDeviceLogReader.test(
useSyslog: false, useSyslog: false,
iMobileDevice: IMobileDevice( iMobileDevice: IMobileDevice(
@ -159,47 +182,39 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
logger: logger, logger: logger,
), ),
); );
final StreamController<Event> stdoutController = StreamController<Event>();
final StreamController<Event> stderController = StreamController<Event>();
final Completer<Success> stdoutCompleter = Completer<Success>();
final Completer<Success> stderrCompleter = Completer<Success>();
when(vmService.streamListen('Stdout')).thenAnswer((Invocation invocation) {
return stdoutCompleter.future;
});
when(vmService.streamListen('Stderr')).thenAnswer((Invocation invocation) {
return stderrCompleter.future;
});
when(vmService.onStdoutEvent).thenAnswer((Invocation invocation) {
return stdoutController.stream;
});
when(vmService.onStderrEvent).thenAnswer((Invocation invocation) {
return stderController.stream;
});
logReader.connectedVMService = vmService; logReader.connectedVMService = vmService;
stdoutCompleter.complete(Success());
stderrCompleter.complete(Success());
stdoutController.add(Event(
kind: 'Stdout',
timestamp: 0,
bytes: base64.encode(utf8.encode(' This is a message ')),
));
stderController.add(Event(
kind: 'Stderr',
timestamp: 0,
bytes: base64.encode(utf8.encode(' And this is an error ')),
));
// Wait for stream listeners to fire. // Wait for stream listeners to fire.
await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[ await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[
equals(' This is a message '), equals(' This is a message '),
equals(' And this is an error '), equals(' And this is an error '),
])); ]));
verify(vmService.streamListen('Debug'));
}); });
testWithoutContext('IOSDeviceLogReader ignores VM Service logs when attached to debugger', () async { testWithoutContext('IOSDeviceLogReader ignores VM Service logs when attached to debugger', () async {
final MockVmService vmService = MockVmService(); final Event stdoutEvent = Event(
kind: 'Stdout',
timestamp: 0,
bytes: base64.encode(utf8.encode(' This is a message ')),
);
final Event stderrEvent = Event(
kind: 'Stderr',
timestamp: 0,
bytes: base64.encode(utf8.encode(' And this is an error ')),
);
final FlutterVmService vmService = FakeVmServiceHost(requests: <VmServiceExpectation>[
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Debug',
}),
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Stdout',
}),
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
'streamId': 'Stderr',
}),
FakeVmServiceStreamResponse(event: stdoutEvent, streamId: 'Stdout'),
FakeVmServiceStreamResponse(event: stderrEvent, streamId: 'Stderr'),
]).vmService;
final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
useSyslog: false, useSyslog: false,
iMobileDevice: IMobileDevice( iMobileDevice: IMobileDevice(
@ -209,37 +224,8 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
logger: logger, logger: logger,
), ),
); );
final StreamController<Event> stdoutController = StreamController<Event>();
final StreamController<Event> stderController = StreamController<Event>();
final Completer<Success> stdoutCompleter = Completer<Success>();
final Completer<Success> stderrCompleter = Completer<Success>();
when(vmService.streamListen('Stdout')).thenAnswer((Invocation invocation) {
return stdoutCompleter.future;
});
when(vmService.streamListen('Stderr')).thenAnswer((Invocation invocation) {
return stderrCompleter.future;
});
when(vmService.onStdoutEvent).thenAnswer((Invocation invocation) {
return stdoutController.stream;
});
when(vmService.onStderrEvent).thenAnswer((Invocation invocation) {
return stderController.stream;
});
logReader.connectedVMService = vmService; logReader.connectedVMService = vmService;
stdoutCompleter.complete(Success());
stderrCompleter.complete(Success());
stdoutController.add(Event(
kind: 'Stdout',
timestamp: 0,
bytes: base64.encode(utf8.encode(' This is a message ')),
));
stderController.add(Event(
kind: 'Stderr',
timestamp: 0,
bytes: base64.encode(utf8.encode(' And this is an error ')),
));
final MockIOSDeployDebugger iosDeployDebugger = MockIOSDeployDebugger(); final MockIOSDeployDebugger iosDeployDebugger = MockIOSDeployDebugger();
when(iosDeployDebugger.debuggerAttached).thenReturn(true); when(iosDeployDebugger.debuggerAttached).thenReturn(true);
@ -327,5 +313,4 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
}); });
} }
class MockVmService extends Mock implements VmService {}
class MockIOSDeployDebugger extends Mock implements IOSDeployDebugger {} class MockIOSDeployDebugger extends Mock implements IOSDeployDebugger {}

View file

@ -208,11 +208,10 @@ void main() {
'value': 'http://localhost:1234', 'value': 'http://localhost:1234',
}, },
), ),
]); ], httpAddress: Uri.parse('http://localhost:1234'));
final FakeFlutterDevice device = FakeFlutterDevice() final FakeFlutterDevice device = FakeFlutterDevice()
..vmService = fakeVmServiceHost.vmService; ..vmService = fakeVmServiceHost.vmService;
setHttpAddress(Uri.parse('http://localhost:1234'), fakeVmServiceHost.vmService);
await handler.serveAndAnnounceDevTools( await handler.serveAndAnnounceDevTools(
flutterDevices: <FlutterDevice>[device], flutterDevices: <FlutterDevice>[device],
@ -236,7 +235,7 @@ void main() {
}, },
), ),
]); ]);
waitForExtension(fakeVmServiceHost.vmService, 'foo'); waitForExtension(fakeVmServiceHost.vmService.service, 'foo');
}); });
testWithoutContext('wait for extension handles no isolates', () { testWithoutContext('wait for extension handles no isolates', () {
@ -270,7 +269,7 @@ void main() {
), ),
), ),
]); ]);
waitForExtension(fakeVmServiceHost.vmService, 'foo'); waitForExtension(fakeVmServiceHost.vmService.service, 'foo');
}); });
} }
@ -298,5 +297,5 @@ class FakeResidentRunner extends Fake implements ResidentRunner {
class FakeFlutterDevice extends Fake implements FlutterDevice { class FakeFlutterDevice extends Fake implements FlutterDevice {
@override @override
vm_service.VmService vmService; FlutterVmService vmService;
} }

View file

@ -2246,8 +2246,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2277,8 +2276,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2308,8 +2306,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2347,8 +2344,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2386,8 +2382,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2418,8 +2413,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
setWsAddress(testUri, fakeVmServiceHost.vmService);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2454,7 +2448,7 @@ void main() {
listViews, listViews,
listViews, listViews,
setAssetBundlePath, setAssetBundlePath,
]); ], wsAddress: testUri);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
<FlutterDevice>[ <FlutterDevice>[
@ -2514,9 +2508,8 @@ void main() {
testUsingContext('ColdRunner writes vm service file when providing debugging option', () => testbed.run(() async { testUsingContext('ColdRunner writes vm service file when providing debugging option', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[ fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews, listViews,
]); ], wsAddress: testUri);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
setWsAddress(testUri, fakeVmServiceHost.vmService);
residentRunner = ColdRunner( residentRunner = ColdRunner(
<FlutterDevice>[ <FlutterDevice>[
mockFlutterDevice, mockFlutterDevice,
@ -2804,7 +2797,7 @@ void main() {
class MockFlutterDevice extends Mock implements FlutterDevice {} class MockFlutterDevice extends Mock implements FlutterDevice {}
class MockDartDevelopmentService extends Mock implements DartDevelopmentService {} class MockDartDevelopmentService extends Mock implements DartDevelopmentService {}
class MockVMService extends Mock implements vm_service.VmService {} class MockVMService extends Mock implements FlutterVmService {}
class MockDevFS extends Mock implements DevFS {} class MockDevFS extends Mock implements DevFS {}
class MockDeviceLogReader extends Mock implements DeviceLogReader {} class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockDevtoolsLauncher extends Mock implements DevtoolsLauncher {} class MockDevtoolsLauncher extends Mock implements DevtoolsLauncher {}

View file

@ -143,7 +143,7 @@ void main() {
return UpdateFSReport(success: true, syncedBytes: 0); return UpdateFSReport(success: true, syncedBytes: 0);
}); });
when(mockDebugConnection.vmService).thenAnswer((Invocation invocation) { when(mockDebugConnection.vmService).thenAnswer((Invocation invocation) {
return fakeVmServiceHost.vmService; return fakeVmServiceHost.vmService.service;
}); });
when(mockDebugConnection.onDone).thenAnswer((Invocation invocation) { when(mockDebugConnection.onDone).thenAnswer((Invocation invocation) {
return Completer<void>().future; return Completer<void>().future;

View file

@ -224,8 +224,9 @@ void main() {
const Stream<String>.empty(), const Stream<String>.empty(),
completer.complete, completer.complete,
); );
final FlutterVmService flutterVmService = FlutterVmService(vmService);
unawaited(vmService.setAssetDirectory( unawaited(flutterVmService.setAssetDirectory(
assetsDirectory: Uri(path: 'abc', scheme: 'file'), assetsDirectory: Uri(path: 'abc', scheme: 'file'),
viewId: 'abc', viewId: 'abc',
uiIsolateId: 'def', uiIsolateId: 'def',
@ -249,8 +250,9 @@ void main() {
const Stream<String>.empty(), const Stream<String>.empty(),
completer.complete, completer.complete,
); );
final FlutterVmService flutterVmService = FlutterVmService(vmService);
unawaited(vmService.getSkSLs( unawaited(flutterVmService.getSkSLs(
viewId: 'abc', viewId: 'abc',
)); ));
@ -266,12 +268,13 @@ void main() {
testWithoutContext('flushUIThreadTasks forwards arguments correctly', () async { testWithoutContext('flushUIThreadTasks forwards arguments correctly', () async {
final Completer<String> completer = Completer<String>(); final Completer<String> completer = Completer<String>();
final vm_service.VmService vmService = vm_service.VmService( final vm_service.VmService vmService = vm_service.VmService(
const Stream<String>.empty(), const Stream<String>.empty(),
completer.complete, completer.complete,
); );
final FlutterVmService flutterVmService = FlutterVmService(vmService);
unawaited(vmService.flushUIThreadTasks( unawaited(flutterVmService.flushUIThreadTasks(
uiIsolateId: 'def', uiIsolateId: 'def',
)); ));
@ -449,13 +452,6 @@ void main() {
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}); });
testWithoutContext('expandos are null safe', () {
vm_service.VmService vmService;
expect(vmService.httpAddress, null);
expect(vmService.wsAddress, null);
});
testWithoutContext('Can process log events from the vm service', () { testWithoutContext('Can process log events from the vm service', () {
final vm_service.Event event = vm_service.Event( final vm_service.Event event = vm_service.Event(
bytes: base64.encode(utf8.encode('Hello There\n')), bytes: base64.encode(utf8.encode('Hello There\n')),

View file

@ -15,6 +15,7 @@ import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:vm_service/vm_service.dart' as vm_service; import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:path/path.dart' as path; // ignore: package_path_import import 'package:path/path.dart' as path; // ignore: package_path_import
@ -287,11 +288,13 @@ class NoContext implements AppContext {
class FakeVmServiceHost { class FakeVmServiceHost {
FakeVmServiceHost({ FakeVmServiceHost({
@required List<VmServiceExpectation> requests, @required List<VmServiceExpectation> requests,
Uri httpAddress,
Uri wsAddress,
}) : _requests = requests { }) : _requests = requests {
_vmService = vm_service.VmService( _vmService = FlutterVmService(vm_service.VmService(
_input.stream, _input.stream,
_output.add, _output.add,
); ), httpAddress: httpAddress, wsAddress: wsAddress);
_applyStreamListen(); _applyStreamListen();
_output.stream.listen((String data) { _output.stream.listen((String data) {
final Map<String, Object> request = json.decode(data) as Map<String, Object>; final Map<String, Object> request = json.decode(data) as Map<String, Object>;
@ -331,8 +334,9 @@ class FakeVmServiceHost {
final StreamController<String> _input = StreamController<String>(); final StreamController<String> _input = StreamController<String>();
final StreamController<String> _output = StreamController<String>(); final StreamController<String> _output = StreamController<String>();
vm_service.VmService get vmService => _vmService; FlutterVmService get vmService => _vmService;
vm_service.VmService _vmService; FlutterVmService _vmService;
bool get hasRemainingExpectations => _requests.isNotEmpty; bool get hasRemainingExpectations => _requests.isNotEmpty;