From 9904a7f472bbde23f6cd19fca64d30b8c5795ede Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 16 Apr 2021 17:27:35 -0700 Subject: [PATCH] Refactor core resident runner logic (#80462) --- .../lib/src/base/file_system.dart | 34 +- .../lib/src/commands/daemon.dart | 14 +- .../lib/src/isolated/resident_web_runner.dart | 21 +- .../lib/src/resident_runner.dart | 846 +++++++++--------- packages/flutter_tools/lib/src/run_cold.dart | 6 +- packages/flutter_tools/lib/src/run_hot.dart | 7 +- .../general.shard/resident_runner_test.dart | 375 +------- .../resident_web_runner_cold_test.dart | 1 - .../resident_web_runner_test.dart | 11 +- .../general.shard/terminal_handler_test.dart | 19 +- 10 files changed, 496 insertions(+), 838 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/file_system.dart b/packages/flutter_tools/lib/src/base/file_system.dart index 6cf75adb1bd..11b5046963c 100644 --- a/packages/flutter_tools/lib/src/base/file_system.dart +++ b/packages/flutter_tools/lib/src/base/file_system.dart @@ -41,18 +41,7 @@ class FileSystemUtils { /// Appends a number to a filename in order to make it unique under a /// directory. File getUniqueFile(Directory dir, String baseName, String ext) { - final FileSystem fs = dir.fileSystem; - int i = 1; - - while (true) { - final String name = '${baseName}_${i.toString().padLeft(2, '0')}.$ext'; - final File file = fs.file(_fileSystem.path.join(dir.path, name)); - if (!file.existsSync()) { - file.createSync(recursive: true); - return file; - } - i += 1; - } + return _getUniqueFile(dir, baseName, ext); } /// Appends a number to a directory name in order to make it unique under a @@ -157,6 +146,27 @@ void copyDirectory( } } +File _getUniqueFile(Directory dir, String baseName, String ext) { + final FileSystem fs = dir.fileSystem; + int i = 1; + + while (true) { + final String name = '${baseName}_${i.toString().padLeft(2, '0')}.$ext'; + final File file = fs.file(dir.fileSystem.path.join(dir.path, name)); + if (!file.existsSync()) { + file.createSync(recursive: true); + return file; + } + i += 1; + } +} + +/// Appends a number to a filename in order to make it unique under a +/// directory. +File getUniqueFile(Directory dir, String baseName, String ext) { + return _getUniqueFile(dir, baseName, ext); +} + /// This class extends [local_fs.LocalFileSystem] in order to clean up /// directories and files that the tool creates under the system temporary /// directory when the tool exits either normally or when killed by a signal. diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index ea921833239..f6a3f1fd62e 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -29,6 +29,7 @@ import '../resident_runner.dart'; import '../run_cold.dart'; import '../run_hot.dart'; import '../runner/flutter_command.dart'; +import '../vmservice.dart'; import '../web/web_runner.dart'; const String protocolVersion = '0.6.0'; @@ -687,9 +688,16 @@ class AppDomain extends Domain { if (app == null) { throw "app '$appId' not found"; } - - final Map result = await app.runner - .invokeFlutterExtensionRpcRawOnFirstIsolate(methodName, params: params); + final FlutterDevice device = app.runner.flutterDevices.first; + final List views = await device.vmService.getFlutterViews(); + final Map result = await device + .vmService + .invokeFlutterExtensionRpcRaw( + methodName, + args: params, + isolateId: views + .first.uiIsolate.id + ); if (result == null) { throw 'method not available: $methodName'; } diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index e988bc121ea..13ee47afcea 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -76,7 +76,6 @@ class DwdsWebRunnerFactory extends WebRunnerFactory { systemClock: systemClock, fileSystem: fileSystem, logger: logger, - featureFlags: featureFlags, ); } } @@ -99,14 +98,12 @@ class ResidentWebRunner extends ResidentRunner { @required SystemClock systemClock, @required Usage usage, @required UrlTunneller urlTunneller, - @required FeatureFlags featureFlags, ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler, }) : _fileSystem = fileSystem, _logger = logger, _systemClock = systemClock, _usage = usage, _urlTunneller = urlTunneller, - _featureFlags = featureFlags, super( [device], target: target ?? fileSystem.path.join('lib', 'main.dart'), @@ -122,7 +119,6 @@ class ResidentWebRunner extends ResidentRunner { final SystemClock _systemClock; final Usage _usage; final UrlTunneller _urlTunneller; - final FeatureFlags _featureFlags; FlutterDevice get device => flutterDevices.first; final FlutterProject flutterProject; @@ -167,20 +163,7 @@ class ResidentWebRunner extends ResidentRunner { FlutterVmService _instance; @override - bool get canHotRestart { - return true; - } - - @override - Future> invokeFlutterExtensionRpcRawOnFirstIsolate( - String method, { - FlutterDevice device, - Map params, - }) async { - final vmservice.Response response = - await _vmService.service.callServiceExtension(method, args: params); - return response.toJson(); - } + bool get supportsRestart => true; @override Future cleanupAfterSignal() async { @@ -313,7 +296,7 @@ class ResidentWebRunner extends ResidentRunner { ?.flutterPlatformOverride( isolateId: null, ); - final String platform = nextPlatform(currentPlatform, _featureFlags); + final String platform = nextPlatform(currentPlatform); await _vmService ?.flutterPlatformOverride( platform: platform, diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 01cababd5e9..8f2f73c594e 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -192,11 +192,11 @@ class FlutterDevice { ); } + final TargetPlatform targetPlatform; final Device device; final ResidentCompiler generator; final BuildInfo buildInfo; final String userIdentifier; - final TargetPlatform targetPlatform; DevFSWriter devFSWriter; Stream observatoryUris; @@ -401,138 +401,16 @@ class FlutterDevice { return devFS.create(); } - Future debugDumpApp() async { + Future> _getCurrentIsolates() async { + if (targetPlatform == TargetPlatform.web_javascript) { + final vm_service.VM vm = await vmService.service.getVM(); + return vm.isolates; + } final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - final String data = await vmService.flutterDebugDumpApp( - isolateId: view.uiIsolate.id, - ); - globals.printStatus(data); - } - } - - Future debugDumpRenderTree() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - final String data = await vmService.flutterDebugDumpRenderTree( - isolateId: view.uiIsolate.id, - ); - globals.printStatus(data); - } - } - - Future debugDumpLayerTree() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - final String data = await vmService.flutterDebugDumpLayerTree( - isolateId: view.uiIsolate.id, - ); - globals.printStatus(data); - } - } - - Future debugDumpSemanticsTreeInTraversalOrder() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - final String data = await vmService.flutterDebugDumpSemanticsTreeInTraversalOrder( - isolateId: view.uiIsolate.id, - ); - globals.printStatus(data); - } - } - - Future debugDumpSemanticsTreeInInverseHitTestOrder() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - final String data = await vmService.flutterDebugDumpSemanticsTreeInInverseHitTestOrder( - isolateId: view.uiIsolate.id, - ); - globals.printStatus(data); - } - } - - Future toggleDebugPaintSizeEnabled() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - await vmService.flutterToggleDebugPaintSizeEnabled( - isolateId: view.uiIsolate.id, - ); - } - } - - Future toggleDebugCheckElevationsEnabled() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - await vmService.flutterToggleDebugCheckElevationsEnabled( - isolateId: view.uiIsolate.id, - ); - } - } - - Future debugTogglePerformanceOverlayOverride() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - await vmService.flutterTogglePerformanceOverlayOverride( - isolateId: view.uiIsolate.id, - ); - } - } - - Future toggleWidgetInspector() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - await vmService.flutterToggleWidgetInspector( - isolateId: view.uiIsolate.id, - ); - } - } - - Future toggleInvertOversizedImages() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - await vmService.flutterToggleInvertOversizedImages( - isolateId: view.uiIsolate.id, - ); - } - } - - Future toggleProfileWidgetBuilds() async { - final List views = await vmService.getFlutterViews(); - for (final FlutterView view in views) { - await vmService.flutterToggleProfileWidgetBuilds( - isolateId: view.uiIsolate.id, - ); - } - } - - Future toggleBrightness({ Brightness current }) async { - final List views = await vmService.getFlutterViews(); - Brightness next; - if (current == Brightness.light) { - next = Brightness.dark; - } else if (current == Brightness.dark) { - next = Brightness.light; - } - - for (final FlutterView view in views) { - next = await vmService.flutterBrightnessOverride( - isolateId: view.uiIsolate.id, - brightness: next, - ); - } - return next; - } - - Future togglePlatform({ String from }) async { - final List views = await vmService.getFlutterViews(); - final String to = nextPlatform(from, featureFlags); - for (final FlutterView view in views) { - await vmService.flutterPlatformOverride( - platform: to, - isolateId: view.uiIsolate.id, - ); - } - return to; + return [ + for (FlutterView view in views) + view.uiIsolate, + ]; } Future startEchoingDeviceLog() async { @@ -629,7 +507,6 @@ class FlutterDevice { return 0; } - Future runCold({ ColdRunner coldRunner, String route, @@ -755,8 +632,389 @@ class FlutterDevice { } } +/// A subset of the [ResidentRunner] for delegating to attached flutter devices. +abstract class ResidentHandlers { + List get flutterDevices; + + /// Whether the resident runner has hot reload and restart enabled. + bool get hotMode; + + /// Whether the resident runner is connect to the device's VM Service. + bool get supportsServiceProtocol; + + /// The application is running in debug mode. + bool get isRunningDebug; + + /// The application is running in profile mode. + bool get isRunningProfile; + + /// The application is running in release mode. + bool get isRunningRelease; + + /// The resident runner should stay resident after establishing a connection with the + /// application. + bool get stayResident; + + /// Whether all of the connected devices support hot restart. + /// + /// To prevent scenarios where only a subset of devices are hot restarted, + /// the runner requires that all attached devices can support hot restart + /// before enabling it. + bool get supportsRestart; + + /// Whether all of the connected devices support gathering SkSL. + bool get supportsWriteSkSL; + + /// Whether all of the connected devices support hot reload. + bool get canHotReload; + + @protected + Logger get logger; + + @protected + FileSystem get fileSystem; + + /// Called to print help to the terminal. + void printHelp({ @required bool details }); + + /// Perfor a hot reload or hot restart of all attached applications. + /// + /// If [fullRestart] is true, a hot restart is performed. Otherwise a hot reload + /// is run instead. On web devices, this only performs a hot restart regardless of + /// the value of [fullRestart]. + Future restart({ bool fullRestart = false, bool pause = false, String reason }) { + final String mode = isRunningProfile ? 'profile' :isRunningRelease ? 'release' : 'this'; + throw '${fullRestart ? 'Restart' : 'Reload'} is not supported in $mode mode'; + } + + /// Dump the application's current widget tree to the terminal. + Future debugDumpApp() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + final String data = await device.vmService.flutterDebugDumpApp( + isolateId: view.id, + ); + logger.printStatus(data); + } + } + return true; + } + + /// Dump the application's current render tree to the terminal. + Future debugDumpRenderTree() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + final String data = await device.vmService.flutterDebugDumpRenderTree( + isolateId: view.id, + ); + logger.printStatus(data); + } + } + return true; + } + + /// Dump the application's current layer tree to the terminal. + Future debugDumpLayerTree() async { + if (!supportsServiceProtocol || !isRunningDebug) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + final String data = await device.vmService.flutterDebugDumpLayerTree( + isolateId: view.id, + ); + logger.printStatus(data); + } + } + return true; + } + + /// Dump the application's current semantics tree to the terminal. + /// + /// If semantics are not enabled, nothing is returned. + Future debugDumpSemanticsTreeInTraversalOrder() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + final String data = await device.vmService.flutterDebugDumpSemanticsTreeInTraversalOrder( + isolateId: view.id, + ); + logger.printStatus(data); + } + } + return true; + } + + /// Dump the application's current semantics tree to the terminal. + /// + /// If semantics are not enabled, nothing is returned. + Future debugDumpSemanticsTreeInInverseHitTestOrder() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + final String data = await device.vmService.flutterDebugDumpSemanticsTreeInInverseHitTestOrder( + isolateId: view.id, + ); + logger.printStatus(data); + } + } + return true; + } + + /// Toggle the "paint size" debugging feature. + Future debugToggleDebugPaintSizeEnabled() async { + if (!supportsServiceProtocol || !isRunningDebug) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterToggleDebugPaintSizeEnabled( + isolateId: view.id, + ); + } + } + return true; + } + + /// Toggle the "elevation check" debugging feature. + Future debugToggleDebugCheckElevationsEnabled() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterToggleDebugCheckElevationsEnabled( + isolateId: view.id, + ); + } + } + return true; + } + + /// Toggle the performance overlay. + /// + /// This is not supported in web mode. + Future debugTogglePerformanceOverlayOverride() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + if (device.targetPlatform == TargetPlatform.web_javascript) { + continue; + } + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterTogglePerformanceOverlayOverride( + isolateId: view.id, + ); + } + } + return true; + } + + /// Toggle the widget inspector. + Future debugToggleWidgetInspector() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterToggleWidgetInspector( + isolateId: view.id, + ); + } + } + return true; + } + + /// Toggle the "invert images" debugging feature. + Future debugToggleInvertOversizedImages() async { + if (!supportsServiceProtocol || !isRunningDebug) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterToggleInvertOversizedImages( + isolateId: view.id, + ); + } + } + return true; + } + + /// Toggle the "profile widget builds" debugging feature. + Future debugToggleProfileWidgetBuilds() async { + if (!supportsServiceProtocol) { + return false; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterToggleProfileWidgetBuilds( + isolateId: view.id, + ); + } + } + return true; + } + + /// Toggle the operating system brightness (light or dart). + Future debugToggleBrightness() async { + if (!supportsServiceProtocol) { + return false; + } + final List views = await flutterDevices.first._getCurrentIsolates(); + final Brightness current = await flutterDevices.first.vmService.flutterBrightnessOverride( + isolateId: views.first.id, + ); + Brightness next; + if (current == Brightness.light) { + next = Brightness.dark; + } else { + next = Brightness.light; + } + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterBrightnessOverride( + isolateId: view.id, + brightness: next, + ); + } + logger.printStatus('Changed brightness to $next.'); + } + return true; + } + + /// Rotate the application through different `defaultTargetPlatform` values. + Future debugTogglePlatform() async { + if (!supportsServiceProtocol || !isRunningDebug) { + return false; + } + final List views = await flutterDevices.first._getCurrentIsolates(); + final String from = await flutterDevices + .first.vmService.flutterPlatformOverride( + isolateId: views.first.id, + ); + final String to = nextPlatform(from); + for (final FlutterDevice device in flutterDevices) { + for (final vm_service.IsolateRef view in await device._getCurrentIsolates()) { + await device.vmService.flutterPlatformOverride( + platform: to, + isolateId: view.id, + ); + } + } + logger.printStatus('Switched operating system to $to'); + return true; + } + + /// Write the SkSL shaders to a zip file in build directory. + /// + /// Returns the name of the file, or `null` on failures. + Future writeSkSL() async { + if (!supportsWriteSkSL) { + throw Exception('writeSkSL is not supported by this runner.'); + } + final List views = await flutterDevices + .first + .vmService.getFlutterViews(); + final Map data = await flutterDevices.first.vmService.getSkSLs( + viewId: views.first.id, + ); + final Device device = flutterDevices.first.device; + return sharedSkSlWriter(device, data); + } + + /// Take a screenshot on the provided [device]. + /// + /// If the device has a connected vmservice, this method will attempt to hide + /// and restore the debug banner before taking the screenshot. + /// + /// Throws an [AssertionError] if [Device.supportsScreenshot] is not true. + Future screenshot(FlutterDevice device) async { + assert(device.device.supportsScreenshot); + + final Status status = logger.startProgress( + 'Taking screenshot for ${device.device.name}...', + ); + final File outputFile = getUniqueFile( + fileSystem.currentDirectory, + 'flutter', + 'png', + ); + List views = []; + Future setDebugBanner(bool value) async { + try { + for (final FlutterView view in views) { + await device.vmService.flutterDebugAllowBanner( + value, + isolateId: view.uiIsolate.id, + ); + } + return true; + } on Exception catch (error) { + status.cancel(); + logger.printError('Error communicating with Flutter on the device: $error'); + return false; + } + } + + try { + if (supportsServiceProtocol && isRunningDebug) { + // Ensure that the vmService access is guarded by supportsServiceProtocol, it + // will be null in release mode. + views = await device.vmService.getFlutterViews(); + if (!await setDebugBanner(false)) { + return; + } + } + try { + await device.device.takeScreenshot(outputFile); + } finally { + if (supportsServiceProtocol && isRunningDebug) { + await setDebugBanner(true); + } + } + final int sizeKB = outputFile.lengthSync() ~/ 1024; + status.stop(); + logger.printStatus( + 'Screenshot written to ${fileSystem.path.relative(outputFile.path)} (${sizeKB}kB).', + ); + } on Exception catch (error) { + status.cancel(); + logger.printError('Error taking screenshot: $error'); + } + } + + /// Remove sigusr signal handlers. + Future cleanupAfterSignal(); + + /// Tear down the runner and leave the application running. + /// + /// This is not supported on web devices where the runner is running + /// the application server as well. + Future detach(); + + /// Tear down the runner and exit the application. + Future exit(); + + /// Run any source generators, such as localizations. + /// + /// These are automatically run during hot restart, but can be + /// triggered manually to see the updated generated code. + Future runSourceGenerators(); +} + // Shared code between different resident application runners. -abstract class ResidentRunner { +abstract class ResidentRunner extends ResidentHandlers { ResidentRunner( this.flutterDevices, { @required this.target, @@ -788,12 +1046,19 @@ abstract class ResidentRunner { _residentDevtoolsHandler = devtoolsHandler(DevtoolsLauncher.instance, this, globals.logger); } - @protected - @visibleForTesting + @override + Logger get logger => globals.logger; + + @override + FileSystem get fileSystem => globals.fs; + + @override final List flutterDevices; final String target; final DebuggingOptions debuggingOptions; + + @override final bool stayResident; final bool ipv6; final String _dillOutputPath; @@ -812,6 +1077,10 @@ abstract class ResidentRunner { bool _exited = false; Completer _finished = Completer(); + BuildResult _lastBuild; + Environment _environment; + + @override bool hotMode; /// Returns true if every device is streaming observatory URIs. @@ -833,11 +1102,22 @@ abstract class ResidentRunner { } bool get debuggingEnabled => debuggingOptions.debuggingEnabled; + + @override bool get isRunningDebug => debuggingOptions.buildInfo.isDebug; + + @override bool get isRunningProfile => debuggingOptions.buildInfo.isProfile; + + @override bool get isRunningRelease => debuggingOptions.buildInfo.isRelease; + + @override bool get supportsServiceProtocol => isRunningDebug || isRunningProfile; + + @override bool get supportsWriteSkSL => supportsServiceProtocol; + bool get trackWidgetCreation => debuggingOptions.buildInfo.trackWidgetCreation; // Returns the Uri of the first connected device for mobile, @@ -850,38 +1130,14 @@ abstract class ResidentRunner { /// Returns [true] if the resident runner exited after invoking [exit()]. bool get exited => _exited; - /// Whether this runner can hot restart. - /// - /// To prevent scenarios where only a subset of devices are hot restarted, - /// the runner requires that all attached devices can support hot restart - /// before enabling it. - bool get canHotRestart { - return flutterDevices.every((FlutterDevice device) { + @override + bool get supportsRestart { + return isRunningDebug && flutterDevices.every((FlutterDevice device) { return device.device.supportsHotRestart; }); } - /// Invoke an RPC extension method on the first attached ui isolate of the first device. - // TODO(jonahwilliams): Update/Remove this method when refactoring the resident - // runner to support a single flutter device. - Future> invokeFlutterExtensionRpcRawOnFirstIsolate( - String method, { - FlutterDevice device, - Map params, - }) async { - device ??= flutterDevices.first; - final List views = await device.vmService.getFlutterViews(); - return device - .vmService - .invokeFlutterExtensionRpcRaw( - method, - args: params, - isolateId: views - .first.uiIsolate.id - ); - } - - /// Whether this runner can hot reload. + @override bool get canHotReload => hotMode; /// Start the app and keep the process running during its lifetime. @@ -902,17 +1158,7 @@ abstract class ResidentRunner { bool enableDevTools = false, }); - bool get supportsRestart => false; - - Future restart({ bool fullRestart = false, bool pause = false, String reason }) { - final String mode = isRunningProfile ? 'profile' : - isRunningRelease ? 'release' : 'this'; - throw '${fullRestart ? 'Restart' : 'Reload'} is not supported in $mode mode'; - } - - - BuildResult _lastBuild; - Environment _environment; + @override Future runSourceGenerators() async { _environment ??= Environment( artifacts: globals.artifacts, @@ -944,23 +1190,6 @@ abstract class ResidentRunner { globals.logger.printTrace('complete'); } - /// Write the SkSL shaders to a zip file in build directory. - /// - /// Returns the name of the file, or `null` on failures. - Future writeSkSL() async { - if (!supportsWriteSkSL) { - throw Exception('writeSkSL is not supported by this runner.'); - } - final List views = await flutterDevices - .first - .vmService.getFlutterViews(); - final Map data = await flutterDevices.first.vmService.getSkSLs( - viewId: views.first.id, - ); - final Device device = flutterDevices.first.device; - return sharedSkSlWriter(device, data); - } - @protected void writeVmServiceFile() { if (debuggingOptions.vmserviceOutFile != null) { @@ -975,6 +1204,7 @@ abstract class ResidentRunner { } } + @override Future exit() async { _exited = true; await residentDevtoolsHandler.shutdown(); @@ -984,6 +1214,7 @@ abstract class ResidentRunner { await shutdownDartDevelopmentService(); } + @override Future detach() async { await residentDevtoolsHandler.shutdown(); await stopEchoingDeviceLog(); @@ -992,212 +1223,6 @@ abstract class ResidentRunner { appFinished(); } - Future debugDumpApp() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.debugDumpApp(); - } - return true; - } - - Future debugDumpRenderTree() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.debugDumpRenderTree(); - } - return true; - } - - Future debugDumpLayerTree() async { - if (!supportsServiceProtocol || !isRunningDebug) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.debugDumpLayerTree(); - } - return true; - } - - Future debugDumpSemanticsTreeInTraversalOrder() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.debugDumpSemanticsTreeInTraversalOrder(); - } - return true; - } - - Future debugDumpSemanticsTreeInInverseHitTestOrder() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.debugDumpSemanticsTreeInInverseHitTestOrder(); - } - return true; - } - - Future debugToggleDebugPaintSizeEnabled() async { - if (!supportsServiceProtocol || !isRunningDebug) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.toggleDebugPaintSizeEnabled(); - } - return true; - } - - Future debugToggleDebugCheckElevationsEnabled() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.toggleDebugCheckElevationsEnabled(); - } - return true; - } - - Future debugTogglePerformanceOverlayOverride() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.debugTogglePerformanceOverlayOverride(); - } - return true; - } - - Future debugToggleWidgetInspector() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.toggleWidgetInspector(); - } - return true; - } - - Future debugToggleInvertOversizedImages() async { - if (!supportsServiceProtocol || !isRunningDebug) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.toggleInvertOversizedImages(); - } - return true; - } - - Future debugToggleProfileWidgetBuilds() async { - if (!supportsServiceProtocol) { - return false; - } - for (final FlutterDevice device in flutterDevices) { - await device.toggleProfileWidgetBuilds(); - } - return true; - } - - Future debugToggleBrightness() async { - if (!supportsServiceProtocol) { - return false; - } - final Brightness brightness = await flutterDevices.first.toggleBrightness(); - Brightness next; - for (final FlutterDevice device in flutterDevices) { - next = await device.toggleBrightness( - current: brightness, - ); - globals.logger.printStatus('Changed brightness to $next.'); - } - return true; - } - - /// Take a screenshot on the provided [device]. - /// - /// If the device has a connected vmservice, this method will attempt to hide - /// and restore the debug banner before taking the screenshot. - /// - /// Throws an [AssertionError] if [Device.supportsScreenshot] is not true. - Future screenshot(FlutterDevice device) async { - assert(device.device.supportsScreenshot); - - final Status status = globals.logger.startProgress( - 'Taking screenshot for ${device.device.name}...', - ); - final File outputFile = globals.fsUtils.getUniqueFile( - globals.fs.currentDirectory, - 'flutter', - 'png', - ); - List views = []; - Future setDebugBanner(bool value) async { - try { - for (final FlutterView view in views) { - await device.vmService.flutterDebugAllowBanner( - value, - isolateId: view.uiIsolate.id, - ); - } - return true; - } on Exception catch (error) { - status.cancel(); - globals.printError('Error communicating with Flutter on the device: $error'); - return false; - } - } - - try { - if (supportsServiceProtocol && isRunningDebug) { - // Ensure that the vmService access is guarded by supportsServiceProtocol, it - // will be null in release mode. - views = await device.vmService.getFlutterViews(); - if (!await setDebugBanner(false)) { - return; - } - } - try { - await device.device.takeScreenshot(outputFile); - } finally { - if (supportsServiceProtocol && isRunningDebug) { - await setDebugBanner(true); - } - } - final int sizeKB = outputFile.lengthSync() ~/ 1024; - status.stop(); - globals.printStatus( - 'Screenshot written to ${globals.fs.path.relative(outputFile.path)} (${sizeKB}kB).', - ); - } on Exception catch (error) { - status.cancel(); - globals.printError('Error taking screenshot: $error'); - } - } - - Future debugTogglePlatform() async { - if (!supportsServiceProtocol || !isRunningDebug) { - return false; - } - final List views = await flutterDevices - .first - .vmService.getFlutterViews(); - final String isolateId = views.first.uiIsolate.id; - final String from = await flutterDevices - .first.vmService.flutterPlatformOverride( - isolateId: isolateId, - ); - String to; - for (final FlutterDevice device in flutterDevices) { - to = await device.togglePlatform(from: from); - } - globals.printStatus('Switched operating system to $to'); - return true; - } - Future stopEchoingDeviceLog() async { await Future.wait( flutterDevices.map>((FlutterDevice device) => device.stopEchoingDeviceLog()) @@ -1379,9 +1404,6 @@ abstract class ResidentRunner { _reportedDebuggers = true; } - /// Called to print help to the terminal. - void printHelp({ @required bool details }); - void printHelpDetails() { if (flutterDevices.any((FlutterDevice d) => d.device.supportsScreenshot)) { commandHelp.s.print(); @@ -1413,14 +1435,11 @@ abstract class ResidentRunner { } } - /// Called when a signal has requested we exit. + @override Future cleanupAfterSignal(); /// Called right before we exit. Future cleanupAtFinish(); - - // Clears the screen. - void clearScreen() => globals.logger.clear(); } class OperationResult { @@ -1479,7 +1498,7 @@ class TerminalHandler { final bool _reportReady; final String _pidFile; - final ResidentRunner residentRunner; + final ResidentHandlers residentRunner; bool _processingUserRequest = false; StreamSubscription subscription; File _actualPidFile; @@ -1487,6 +1506,10 @@ class TerminalHandler { @visibleForTesting String lastReceivedCommand; + /// This is only a buffer logger in unit tests + @visibleForTesting + BufferLogger get logger => _logger as BufferLogger; + void setupTerminal() { if (!_logger.quiet) { _logger.printStatus(''); @@ -1544,7 +1567,7 @@ class TerminalHandler { case 'b': return residentRunner.debugToggleBrightness(); case 'c': - residentRunner.clearScreen(); + _logger.clear(); return true; case 'd': case 'D': @@ -1597,7 +1620,7 @@ class TerminalHandler { return true; case 'R': // If hot restart is not supported for all devices, ignore the command. - if (!residentRunner.canHotRestart || !residentRunner.hotMode) { + if (!residentRunner.supportsRestart || !residentRunner.hotMode) { return false; } final OperationResult result = await residentRunner.restart(fullRestart: true); @@ -1694,17 +1717,14 @@ class DebugConnectionInfo { /// /// These values must match what is available in /// `packages/flutter/lib/src/foundation/binding.dart`. -String nextPlatform(String currentPlatform, FeatureFlags featureFlags) { +String nextPlatform(String currentPlatform) { switch (currentPlatform) { case 'android': return 'iOS'; case 'iOS': return 'fuchsia'; case 'fuchsia': - if (featureFlags.isMacOSEnabled) { - return 'macOS'; - } - return 'android'; + return 'macOS'; case 'macOS': return 'android'; default: diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart index 5bcd6a66f6a..198fc93b136 100644 --- a/packages/flutter_tools/lib/src/run_cold.dart +++ b/packages/flutter_tools/lib/src/run_cold.dart @@ -10,6 +10,7 @@ import 'package:meta/meta.dart'; import 'base/common.dart'; import 'base/file_system.dart'; +import 'base/logger.dart'; import 'build_info.dart'; import 'device.dart'; import 'globals_null_migrated.dart' as globals; @@ -51,7 +52,10 @@ class ColdRunner extends ResidentRunner { bool get canHotReload => false; @override - bool get canHotRestart => false; + Logger get logger => globals.logger; + + @override + FileSystem get fileSystem => globals.fs; @override Future run({ diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 22d9a4a6532..d53ac8d14a6 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -598,9 +598,6 @@ class HotRunner extends ResidentRunner { return true; } - @override - bool get supportsRestart => true; - @override Future restart({ bool fullRestart = false, @@ -670,7 +667,7 @@ class HotRunner extends ResidentRunner { String reason, bool silent, }) async { - if (!canHotRestart) { + if (!supportsRestart) { return OperationResult(1, 'hotRestart not supported'); } Status status; @@ -1089,7 +1086,7 @@ class HotRunner extends ResidentRunner { void printHelp({ @required bool details }) { globals.printStatus('Flutter run key commands.'); commandHelp.r.print(); - if (canHotRestart) { + if (supportsRestart) { commandHelp.R.print(); } commandHelp.h.print(); // TODO(ianh): print different message if "details" is false diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 64aaf80b0eb..d84fdc9dd9f 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -1684,16 +1684,6 @@ void main() { expect(testLogger.statusText, contains('1kB')); })); - testUsingContext('ResidentRunner clears the screen when it should', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - const String message = 'This should be cleared'; - expect(testLogger.statusText, equals('')); - testLogger.printStatus(message); - expect(testLogger.statusText, equals(message + '\n')); // printStatus makes a newline - residentRunner.clearScreen(); - expect(testLogger.statusText, equals('')); - })); - testUsingContext('ResidentRunner bails taking screenshot on debug device if debugAllowBanner throws RpcError', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, @@ -1906,361 +1896,6 @@ void main() { expect(fakeVmServiceHost.hasRemainingExpectations, false); })); - testUsingContext('ResidentRunner debugDumpApp calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugDumpApp(), true); - verify(mockFlutterDevice.debugDumpApp()).called(1); - })); - - testUsingContext('ResidentRunner debugDumpApp does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugDumpApp(), false); - verifyNever(mockFlutterDevice.debugDumpApp()); - })); - - testUsingContext('ResidentRunner debugDumpRenderTree calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugDumpRenderTree(), true); - verify(mockFlutterDevice.debugDumpRenderTree()).called(1); - })); - - testUsingContext('ResidentRunner debugDumpRenderTree does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugDumpRenderTree(), false); - verifyNever(mockFlutterDevice.debugDumpRenderTree()); - })); - - testUsingContext('ResidentRunner debugDumpLayerTree calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugDumpLayerTree(), true); - verify(mockFlutterDevice.debugDumpLayerTree()).called(1); - })); - - testUsingContext('ResidentRunner debugDumpLayerTree does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugDumpLayerTree(), false); - verifyNever(mockFlutterDevice.debugDumpLayerTree()); - })); - - testUsingContext('ResidentRunner debugDumpLayerTree does not call flutter device if not running in debug mode', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugDumpLayerTree(), false); - verifyNever(mockFlutterDevice.debugDumpLayerTree()); - })); - - testUsingContext('ResidentRunner debugDumpSemanticsTreeInTraversalOrder calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugDumpSemanticsTreeInTraversalOrder(), true); - verify(mockFlutterDevice.debugDumpSemanticsTreeInTraversalOrder()).called(1); - })); - - testUsingContext('ResidentRunner debugDumpSemanticsTreeInTraversalOrder does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugDumpSemanticsTreeInTraversalOrder(), false); - verifyNever(mockFlutterDevice.debugDumpSemanticsTreeInTraversalOrder()); - })); - - testUsingContext('ResidentRunner debugDumpSemanticsTreeInInverseHitTestOrder calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugDumpSemanticsTreeInInverseHitTestOrder(), true); - verify(mockFlutterDevice.debugDumpSemanticsTreeInInverseHitTestOrder()).called(1); - })); - - testUsingContext('ResidentRunner debugDumpSemanticsTreeInInverseHitTestOrder does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugDumpSemanticsTreeInInverseHitTestOrder(), false); - verifyNever(mockFlutterDevice.debugDumpSemanticsTreeInInverseHitTestOrder()); - })); - - testUsingContext('ResidentRunner debugToggleDebugPaintSizeEnabled calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugToggleDebugPaintSizeEnabled(), true); - verify(mockFlutterDevice.toggleDebugPaintSizeEnabled()).called(1); - })); - - testUsingContext('ResidentRunner debugToggleDebugPaintSizeEnabled does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleDebugPaintSizeEnabled(), false); - verifyNever(mockFlutterDevice.toggleDebugPaintSizeEnabled()); - })); - - testUsingContext('ResidentRunner debugToggleBrightness calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugToggleBrightness(), true); - verify(mockFlutterDevice.toggleBrightness()).called(2); - })); - - testUsingContext('ResidentRunner debugToggleBrightness does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleBrightness(), false); - verifyNever(mockFlutterDevice.toggleBrightness()); - })); - - testUsingContext('FlutterDevice.toggleBrightness invokes correct VM service request', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - const FakeVmServiceRequest( - method: 'ext.flutter.brightnessOverride', - args: { - 'isolateId': '1', - }, - jsonResponse: { - 'value': 'Brightness.dark' - }, - ), - ]); - final FlutterDevice flutterDevice = FlutterDevice( - mockDevice, - buildInfo: BuildInfo.debug, - ); - flutterDevice.vmService = fakeVmServiceHost.vmService; - - expect(await flutterDevice.toggleBrightness(), Brightness.dark); - expect(fakeVmServiceHost.hasRemainingExpectations, false); - })); - - testUsingContext('ResidentRunner debugToggleInvertOversizedImages calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugToggleInvertOversizedImages(), true); - verify(mockFlutterDevice.toggleInvertOversizedImages()).called(1); - })); - - testUsingContext('ResidentRunner debugToggleInvertOversizedImages does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleInvertOversizedImages(), false); - verifyNever(mockFlutterDevice.toggleInvertOversizedImages()); - })); - - testUsingContext('ResidentRunner debugToggleInvertOversizedImages does not call flutter device if in profile mode', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleInvertOversizedImages(), false); - verifyNever(mockFlutterDevice.toggleInvertOversizedImages()); - })); - - testUsingContext('FlutterDevice.toggleInvertOversizedImages invokes correct VM service request', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - const FakeVmServiceRequest( - method: 'ext.flutter.invertOversizedImages', - args: { - 'isolateId': '1', - }, - jsonResponse: { - 'value': 'false' - }, - ), - ]); - final FlutterDevice flutterDevice = FlutterDevice( - mockDevice, - buildInfo: BuildInfo.debug, - ); - flutterDevice.vmService = fakeVmServiceHost.vmService; - - await flutterDevice.toggleInvertOversizedImages(); - expect(fakeVmServiceHost.hasRemainingExpectations, false); - })); - - testUsingContext('ResidentRunner debugToggleDebugCheckElevationsEnabled calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugToggleDebugCheckElevationsEnabled(), true); - verify(mockFlutterDevice.toggleDebugCheckElevationsEnabled()).called(1); - })); - - testUsingContext('ResidentRunner debugToggleDebugCheckElevationsEnabled does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleDebugCheckElevationsEnabled(), false); - verifyNever(mockFlutterDevice.toggleDebugCheckElevationsEnabled()); - })); - - testUsingContext('ResidentRunner debugTogglePerformanceOverlayOverride calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugTogglePerformanceOverlayOverride(), true); - verify(mockFlutterDevice.debugTogglePerformanceOverlayOverride()).called(1); - })); - - testUsingContext('ResidentRunner debugTogglePerformanceOverlayOverride does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugTogglePerformanceOverlayOverride(), false); - verifyNever(mockFlutterDevice.debugTogglePerformanceOverlayOverride()); - })); - - - testUsingContext('ResidentRunner debugToggleWidgetInspector calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - - expect(await residentRunner.debugToggleWidgetInspector(), true); - verify(mockFlutterDevice.toggleWidgetInspector()).called(1); - })); - - testUsingContext('ResidentRunner debugToggleWidgetInspector does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleWidgetInspector(), false); - verifyNever(mockFlutterDevice.toggleWidgetInspector()); - })); - - testUsingContext('ResidentRunner debugToggleProfileWidgetBuilds calls flutter device', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - await residentRunner.debugToggleProfileWidgetBuilds(); - - verify(mockFlutterDevice.toggleProfileWidgetBuilds()).called(1); - })); - - testUsingContext('ResidentRunner debugToggleProfileWidgetBuilds does not call flutter device if service protocol is unsupported', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - residentRunner = HotRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - - expect(await residentRunner.debugToggleProfileWidgetBuilds(), false); - verifyNever(mockFlutterDevice.toggleProfileWidgetBuilds()); - })); - testUsingContext('HotRunner writes vm service file when providing debugging option', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, @@ -2811,11 +2446,11 @@ void main() { })); testUsingContext('nextPlatform moves through expected platforms', () { - expect(nextPlatform('android', TestFeatureFlags()), 'iOS'); - expect(nextPlatform('iOS', TestFeatureFlags()), 'fuchsia'); - expect(nextPlatform('fuchsia', TestFeatureFlags()), 'android'); - expect(nextPlatform('fuchsia', TestFeatureFlags(isMacOSEnabled: true)), 'macOS'); - expect(() => nextPlatform('unknown', TestFeatureFlags()), throwsAssertionError); + expect(nextPlatform('android'), 'iOS'); + expect(nextPlatform('iOS'), 'fuchsia'); + expect(nextPlatform('fuchsia'), 'macOS'); + expect(nextPlatform('macOS'), 'android'); + expect(() => nextPlatform('unknown'), throwsAssertionError); }); } diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart index 20334503b4a..ad9383991bf 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_cold_test.dart @@ -55,7 +55,6 @@ void main() { ipv6: true, stayResident: true, urlTunneller: null, - featureFlags: TestFeatureFlags(), fileSystem: globals.fs, logger: globals.logger, systemClock: globals.systemClock, diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index f12042d9d59..f65a4a4bfc4 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -195,7 +195,6 @@ void main() { fileSystem: fileSystem, logger: BufferLogger.test(), usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); @@ -229,7 +228,7 @@ void main() { fileSystem: fileSystem, logger: BufferLogger.test(), usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), + systemClock: globals.systemClock, ); @@ -253,7 +252,6 @@ void main() { fileSystem: fileSystem, logger: BufferLogger.test(), usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); fakeVmServiceHost = FakeVmServiceHost(requests: []); @@ -268,7 +266,6 @@ void main() { fileSystem: fileSystem, logger: BufferLogger.test(), usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); @@ -373,7 +370,6 @@ void main() { fileSystem: fileSystem, logger: logger, usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); @@ -398,7 +394,6 @@ void main() { fileSystem: fileSystem, logger: BufferLogger.test(), usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); @@ -517,7 +512,6 @@ void main() { fileSystem: fileSystem, logger: BufferLogger.test(), usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); fakeVmServiceHost = FakeVmServiceHost(requests: kAttachExpectations.toList()); @@ -1439,7 +1433,6 @@ void main() { fileSystem: fileSystem, logger: logger, usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); @@ -1487,7 +1480,6 @@ void main() { fileSystem: fileSystem, logger: logger, usage: globals.flutterUsage, - featureFlags: TestFeatureFlags(), systemClock: globals.systemClock, ); @@ -1606,7 +1598,6 @@ ResidentRunner setUpResidentRunner(FlutterDevice flutterDevice, { systemClock: systemClock ?? SystemClock.fixed(DateTime.now()), fileSystem: globals.fs, logger: logger ?? BufferLogger.test(), - featureFlags: TestFeatureFlags(), ); } diff --git a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart index 7b7d59f9d99..8a4408af5e3 100644 --- a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart +++ b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart @@ -240,7 +240,7 @@ void main() { }); testWithoutContext('R - hotRestart supported and succeeds', () async { - when(mockResidentRunner.canHotRestart).thenReturn(true); + when(mockResidentRunner.supportsRestart).thenReturn(true); when(mockResidentRunner.hotMode).thenReturn(true); when(mockResidentRunner.restart(fullRestart: true)) .thenAnswer((Invocation invocation) async { @@ -252,7 +252,7 @@ void main() { }); testWithoutContext('R - hotRestart supported and fails', () async { - when(mockResidentRunner.canHotRestart).thenReturn(true); + when(mockResidentRunner.supportsRestart).thenReturn(true); when(mockResidentRunner.hotMode).thenReturn(true); when(mockResidentRunner.restart(fullRestart: true)) .thenAnswer((Invocation invocation) async { @@ -266,7 +266,7 @@ void main() { }); testWithoutContext('R - hotRestart supported and fails fatally', () async { - when(mockResidentRunner.canHotRestart).thenReturn(true); + when(mockResidentRunner.supportsRestart).thenReturn(true); when(mockResidentRunner.hotMode).thenReturn(true); when(mockResidentRunner.restart(fullRestart: true)) .thenAnswer((Invocation invocation) async { @@ -276,12 +276,23 @@ void main() { }); testWithoutContext('R - hot restart unsupported', () async { - when(mockResidentRunner.canHotRestart).thenReturn(false); + when(mockResidentRunner.supportsRestart).thenReturn(false); await terminalHandler.processTerminalInput('R'); verifyNever(mockResidentRunner.restart(fullRestart: true)); }); + testWithoutContext('ResidentRunner clears the screen when it should', () async { + const String message = 'This should be cleared'; + + expect(testLogger.statusText, equals('')); + testLogger.printStatus(message); + expect(testLogger.statusText, equals(message + '\n')); // printStatus makes a newline + + await terminalHandler.processTerminalInput('c'); + expect(testLogger.statusText, equals('')); + }); + testWithoutContext('S - debugDumpSemanticsTreeInTraversalOrder with service protocol', () async { await terminalHandler.processTerminalInput('S');