Move platform-specific log-reading implementation details from ResidentRunner/FlutterDevice to DeviceLogReader implementations (#156181)

Cleans up https://github.com/flutter/flutter/pull/155800. In summary, `ResidentRunner`/`FlutterDevice` have branching behavior around logging that depends on the type of `DeviceLogReader` on the `FlutterDevice` instance.  Let's instead move this behavior to the `DeviceLogReader` implementations.

My apologies for the large diff. Much of this is a refactor that was a bit too difficult to separate into its own commits. 

Here are the main two changes

* Replaces the mutable `connectedVmService` field on the `DeviceLogReader` class with a new method `provideVmService`. This serves largely the same purpose as the mutable field, but it allows for asynchronous code. This is where we put the logic that used to exist in `FlutterDevice.tryInitLogReader`.
* Removes the `tryInitLogReader` method from `FlutterDevice`. This method served to set the `appPid` field on the `FlutterDevice`'s `DeviceLogReader` instance. This was only used in the case of Android to filter out logs unrelated to the flutter app coming from the device, so we can move this logic to `AdbLogReader`'s implementation of `provideVmService`.
This commit is contained in:
Andrew Kolos 2024-11-14 13:29:30 -08:00 committed by GitHub
parent 4b818b56c2
commit 21144362f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 136 additions and 127 deletions

View File

@ -6,6 +6,7 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'package:vm_service/vm_service.dart';
import '../application_package.dart';
import '../base/common.dart' show throwToolExit;
@ -21,6 +22,7 @@ import '../device_port_forwarder.dart';
import '../device_vm_service_discovery_for_attach.dart';
import '../project.dart';
import '../protocol_discovery.dart';
import '../vmservice.dart';
import 'android.dart';
import 'android_builder.dart';
import 'android_console.dart';
@ -618,6 +620,7 @@ class AndroidDevice extends Device {
await AdbLogReader.createLogReader(
this,
_processManager,
_logger,
),
portForwarder: portForwarder,
hostPort: debuggingOptions.hostVmServicePort,
@ -796,12 +799,14 @@ class AndroidDevice extends Device {
return _pastLogReader ??= await AdbLogReader.createLogReader(
this,
_processManager,
_logger,
includePastLogs: true,
);
} else {
return _logReader ??= await AdbLogReader.createLogReader(
this,
_processManager,
_logger,
);
}
}
@ -1042,15 +1047,20 @@ class AndroidMemoryInfo extends MemoryInfo {
/// A log reader that logs from `adb logcat`.
class AdbLogReader extends DeviceLogReader {
AdbLogReader._(this._adbProcess, this.name);
AdbLogReader._(this._adbProcess, this.name, this._logger);
@visibleForTesting
factory AdbLogReader.test(Process adbProcess, String name) = AdbLogReader._;
factory AdbLogReader.test(
Process adbProcess,
String name,
Logger logger,
) = AdbLogReader._;
/// Create a new [AdbLogReader] from an [AndroidDevice] instance.
static Future<AdbLogReader> createLogReader(
AndroidDevice device,
ProcessManager processManager, {
ProcessManager processManager,
Logger logger, {
bool includePastLogs = false,
}) async {
// logcat -T is not supported on Android releases before Lollipop.
@ -1085,11 +1095,15 @@ class AdbLogReader extends DeviceLogReader {
]);
}
final Process process = await processManager.start(device.adbCommandForDevice(args));
return AdbLogReader._(process, device.name);
return AdbLogReader._(process, device.name, logger);
}
int? _appPid;
final Process _adbProcess;
final Logger _logger;
@override
final String name;
@ -1101,6 +1115,17 @@ class AdbLogReader extends DeviceLogReader {
@override
Stream<String> get logLines => _linesController.stream;
@override
Future<void> provideVmService(FlutterVmService connectedVmService) async {
final VM? vm = await connectedVmService.getVmGuarded();
if (vm == null) {
_logger.printError('An error occurred when setting up filtering for adb logs. '
'Unable to communicate with the VM service.');
} else {
_appPid = vm.pid;
}
}
void _start() {
// We expect logcat streams to occasionally contain invalid utf-8,
// see: https://github.com/flutter/flutter/pull/8864.
@ -1189,7 +1214,7 @@ class AdbLogReader extends DeviceLogReader {
_fatalCrash = false;
}
}
} else if (appPid != null && int.parse(logMatch.group(1)!) == appPid) {
} else if (_appPid != null && int.parse(logMatch.group(1)!) == _appPid) {
acceptLine = !_surfaceSyncerSpam.hasMatch(line);
if (_fatalLog.hasMatch(line)) {

View File

@ -23,6 +23,7 @@ import '../device_port_forwarder.dart';
import '../features.dart';
import '../project.dart';
import '../protocol_discovery.dart';
import '../vmservice.dart';
import 'custom_device_config.dart';
import 'custom_device_workflow.dart';
import 'custom_devices_config.dart';
@ -111,6 +112,9 @@ class CustomDeviceLogReader extends DeviceLogReader {
@override
Stream<String> get logLines => logLinesController.stream;
@override
Future<void> provideVmService(FlutterVmService connectedVmService) async { }
}
/// A [DevicePortForwarder] that uses commands to forward / unforward a port.

View File

@ -19,6 +19,7 @@ import 'device_port_forwarder.dart';
import 'globals.dart' as globals;
import 'macos/macos_device.dart';
import 'protocol_discovery.dart';
import 'vmservice.dart';
/// A partial implementation of Device for desktop-class devices to inherit
/// from, containing implementations that are common to all desktop devices.
@ -384,4 +385,7 @@ class DesktopLogReader extends DeviceLogReader {
void dispose() {
// Nothing to dispose.
}
@override
Future<void> provideVmService(FlutterVmService connectedVmService) async { }
}

View File

@ -1440,14 +1440,11 @@ abstract class DeviceLogReader {
/// Some logs can be obtained from a VM service stream.
/// Set this after the VM services are connected.
FlutterVmService? connectedVMService;
Future<void> provideVmService(FlutterVmService connectedVmService);
@override
String toString() => name;
/// Process ID of the app on the device.
int? appPid;
// Clean up resources allocated by log reader e.g. subprocesses
void dispose();
}
@ -1466,17 +1463,14 @@ class NoOpDeviceLogReader implements DeviceLogReader {
@override
final String name;
@override
int? appPid;
@override
FlutterVmService? connectedVMService;
@override
Stream<String> get logLines => const Stream<String>.empty();
@override
void dispose() { }
@override
Future<void> provideVmService(FlutterVmService connectedVmService) async {}
}
/// Append --null_assertions to any existing Dart VM flags if

View File

@ -231,9 +231,7 @@ class FlutterDriverService extends DriverService {
_vmService = await _vmServiceConnector(uri, device: _device, logger: _logger);
final DeviceLogReader logReader = await device.getLogReader(app: _applicationPackage);
logReader.logLines.listen(_logger.printStatus);
final vm_service.VM vm = await _vmService.service.getVM();
logReader.appPid = vm.pid;
await logReader.provideVmService(_vmService);
}
@override

View File

@ -1300,16 +1300,12 @@ class IOSDeviceLogReader extends DeviceLogReader {
@override
Stream<String> get logLines => linesController.stream;
@override
FlutterVmService? get connectedVMService => _connectedVMService;
FlutterVmService? _connectedVMService;
FlutterVmService? _connectedVmService;
@override
set connectedVMService(FlutterVmService? connectedVmService) {
if (connectedVmService != null) {
_listenToUnifiedLoggingEvents(connectedVmService);
}
_connectedVMService = connectedVmService;
Future<void> provideVmService(FlutterVmService connectedVmService) async {
await _listenToUnifiedLoggingEvents(connectedVmService);
_connectedVmService = connectedVmService;
}
static const int minimumUniversalLoggingSdkVersion = 13;
@ -1360,7 +1356,7 @@ class IOSDeviceLogReader extends DeviceLogReader {
// CoreDevice and has iOS 13 or greater.
// When using `ios-deploy` and the Dart VM, prefer the more complete logs
// from the attached debugger, if available.
if (connectedVMService != null && (_iosDeployDebugger == null || !_iosDeployDebugger!.debuggerAttached)) {
if (_connectedVmService != null && (_iosDeployDebugger == null || !_iosDeployDebugger!.debuggerAttached)) {
return _IOSDeviceLogSources(
primarySource: IOSDeviceLogSource.unifiedLogging,
fallbackSource: IOSDeviceLogSource.iosDeploy,

View File

@ -26,6 +26,7 @@ import '../globals.dart' as globals;
import '../macos/xcode.dart';
import '../project.dart';
import '../protocol_discovery.dart';
import '../vmservice.dart';
import 'application_package.dart';
import 'mac.dart';
import 'plist_parser.dart';
@ -1022,6 +1023,9 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
void dispose() {
_stop();
}
@override
Future<void> provideVmService(FlutterVmService connectedVmService) async { }
}
class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder {

View File

@ -20,6 +20,7 @@ import '../device_port_forwarder.dart';
import '../device_vm_service_discovery_for_attach.dart';
import '../project.dart';
import '../resident_runner.dart';
import '../vmservice.dart';
import 'debounce_data_stream.dart';
import 'file_transfer.dart';
@ -517,6 +518,9 @@ class _ProxiedLogReader extends DeviceLogReader {
});
}
}
@override
Future<void> provideVmService(FlutterVmService connectedVmService) async { }
}
/// A port forwarded by a [ProxiedPortForwarder].

View File

@ -8,7 +8,6 @@ import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'android/android_device.dart';
import 'application_package.dart';
import 'artifacts.dart';
import 'asset.dart';
@ -346,7 +345,8 @@ class FlutterDevice {
globals.printTrace('Successfully connected to service protocol: $vmServiceUri');
vmService = service;
(await device!.getLogReader(app: package)).connectedVMService = vmService;
await (await device!.getLogReader(app: package))
.provideVmService(vmService!);
completer.complete();
await subscription.cancel();
}, onError: (dynamic error) {
@ -417,24 +417,6 @@ class FlutterDevice {
_loggingSubscription = null;
}
/// Attempts to set up reading logs from the Flutter app on the device.
///
/// This can fail if the device if no longer connected.
Future<void> tryInitLogReader() async {
final vm_service.VM? vm = await vmService!.getVmGuarded();
final DeviceLogReader logReader = await device!.getLogReader(app: package);
if (vm == null && logReader is AdbLogReader) {
// TODO(andrewkolos): This is a temporary, hacky fix for
// https://github.com/flutter/flutter/issues/155795 that emphasizes
// simplicity for the sake of being suitable for cherry-picking.
globals.printError(
'Unable to initiate adb log filtering for device'
'${device?.name}. Logs from the device may be more verbose than usual.',
);
}
logReader.appPid = vm?.pid;
}
Future<int> runHot({
required HotRunner hotRunner,
String? route,

View File

@ -104,7 +104,6 @@ class ColdRunner extends ResidentRunner {
if (device!.vmService == null) {
continue;
}
await device.tryInitLogReader();
globals.printTrace('Connected to ${device.device!.name}');
}
@ -153,9 +152,6 @@ class ColdRunner extends ResidentRunner {
return 2;
}
for (final FlutterDevice? device in flutterDevices) {
await device!.tryInitLogReader();
}
for (final FlutterDevice? device in flutterDevices) {
final List<FlutterView> views = await device!.vmService!.getFlutterViews();
for (final FlutterView view in views) {

View File

@ -261,8 +261,7 @@ class HotRunner extends ResidentRunner {
}
for (final FlutterDevice? device in flutterDevices) {
await device!.tryInitLogReader();
device
device!
.developmentShaderCompiler
.configureCompiler(device.targetPlatform);
}

View File

@ -1262,12 +1262,6 @@ class FakeDeviceLogReader implements DeviceLogReader {
final StreamController<String> logLinesController = StreamController<String>();
bool disposeCalled = false;
@override
int? appPid;
@override
FlutterVmService? connectedVMService;
@override
void dispose() {
disposeCalled = true;
@ -1279,6 +1273,8 @@ class FakeDeviceLogReader implements DeviceLogReader {
@override
String get name => 'device';
@override
Future<void> provideVmService(FlutterVmService? connectedVmService) async { }
}
class FakeApplicationPackageFactory implements ApplicationPackageFactory {

View File

@ -354,10 +354,7 @@ class FakeDeviceLogReader implements DeviceLogReader {
bool disposeCalled = false;
@override
int? appPid;
@override
FlutterVmService? connectedVMService;
Future<void> provideVmService(FlutterVmService? connectedVmService) async { }
@override
void dispose() {

View File

@ -5,7 +5,10 @@
import 'dart:async';
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:test/fake.dart';
import 'package:vm_service/vm_service.dart';
import '../../src/common.dart';
import '../../src/fake_process_manager.dart';
@ -18,6 +21,24 @@ const String kLastLogcatTimestamp = '11-27 15:39:04.506';
/// line as the first input to disable this behavior.
const String kDummyLine = 'Contents are not important\n';
class _FakeVm extends Fake implements VM {
_FakeVm(this._appPid);
final int _appPid;
@override
int? get pid => _appPid;
}
class _FakeFlutterVmService extends Fake implements FlutterVmService {
_FakeFlutterVmService(this._appPid);
final int _appPid;
@override
Future<VM?> getVmGuarded() async => _FakeVm(_appPid);
}
void main() {
testWithoutContext('AdbLogReader ignores spam from SurfaceSyncer', () async {
const int appPid = 1;
@ -44,7 +65,9 @@ void main() {
final AdbLogReader logReader = await AdbLogReader.createLogReader(
createFakeDevice(null),
processManager,
)..appPid = appPid;
BufferLogger.test(),
);
await logReader.provideVmService(_FakeFlutterVmService(appPid));
final Completer<void> onDone = Completer<void>.sync();
final List<String> emittedLines = <String>[];
logReader.logLines.listen((String line) {
@ -76,6 +99,7 @@ void main() {
await AdbLogReader.createLogReader(
createFakeDevice(kLollipopVersionCode),
processManager,
BufferLogger.test(),
);
expect(processManager, hasNoRemainingExpectations);
@ -99,6 +123,7 @@ void main() {
await AdbLogReader.createLogReader(
createFakeDevice(kLollipopVersionCode - 1),
processManager,
BufferLogger.test(),
);
expect(processManager, hasNoRemainingExpectations);
@ -122,6 +147,7 @@ void main() {
await AdbLogReader.createLogReader(
createFakeDevice(null),
processManager,
BufferLogger.test(),
);
expect(processManager, hasNoRemainingExpectations);
@ -147,6 +173,7 @@ void main() {
await AdbLogReader.createLogReader(
createFakeDevice(null),
processManager,
BufferLogger.test(),
includePastLogs: true,
);
@ -173,6 +200,7 @@ void main() {
final AdbLogReader logReader = await AdbLogReader.createLogReader(
createFakeDevice(null),
processManager,
BufferLogger.test(),
);
final Completer<void> onDone = Completer<void>.sync();
logReader.logLines.listen((String _) { }, onDone: onDone.complete);
@ -207,6 +235,7 @@ void main() {
final AdbLogReader logReader = await AdbLogReader.createLogReader(
createFakeDevice(null),
processManager,
BufferLogger.test()
);
await expectLater(logReader.logLines, emitsInOrder(<String>[
'E/AndroidRuntime(11787): FATAL EXCEPTION: main',

View File

@ -16,10 +16,14 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:test/fake.dart';
import 'package:vm_service/vm_service.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fake_process_manager.dart';
void main() {
@ -470,6 +474,34 @@ Uptime: 441088659 Realtime: 521464097
expect(await device.stopApp(null), isFalse);
});
testUsingContext('AdbLogReader.provideVmService catches any RPCError due to VM service disconnection', () async {
final BufferLogger logger = globals.logger as BufferLogger;
final FlutterVmService vmService = FlutterVmService(_MyFakeVmService());
final AdbLogReader logReader = AdbLogReader.test(
FakeProcess(),
'foo',
logger,
);
await logReader.provideVmService(vmService);
expect(
logger.traceText,
'VmService.getVm call failed: null: (-32000) '
'Service connection disposed\n',
);
expect(
logger.errorText,
'An error occurred when setting up filtering for adb logs. '
'Unable to communicate with the VM service.\n',
);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test(),
});
}
class _MyFakeVmService extends Fake implements VmService {
@override Future<VM> getVM() async {
throw RPCError(null, RPCErrorKind.kServerError.code, 'Service connection disposed');
}
}
AndroidDevice setUpAndroidDevice({

View File

@ -163,9 +163,6 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
Future<int> runCold({ColdRunner? coldRunner, String? route}) async {
return runColdCode;
}
@override
Future<void> tryInitLogReader() async { }
}
class FakeDevice extends Fake implements Device {

View File

@ -273,7 +273,6 @@ void main() {
testUsingContext('Writes SkSL to file when provided with out file', () async {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <FakeVmServiceRequest>[
getVM,
listViews,
const FakeVmServiceRequest(
method: '_flutter.getSkSLs',
@ -310,7 +309,6 @@ void main() {
testWithoutContext('Can connect to existing application and stop it during cleanup', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <FakeVmServiceRequest>[
getVM,
getVM,
const FakeVmServiceRequest(
method: 'ext.flutter.exit',
@ -333,7 +331,6 @@ void main() {
testWithoutContext('Can connect to existing application using ws URI', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <FakeVmServiceRequest>[
getVM,
getVM,
const FakeVmServiceRequest(
method: 'ext.flutter.exit',
@ -356,7 +353,6 @@ void main() {
testWithoutContext('Can connect to existing application using ws URI (no trailing slash)', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <FakeVmServiceRequest>[
getVM,
getVM,
const FakeVmServiceRequest(
method: 'ext.flutter.exit',
@ -379,7 +375,6 @@ void main() {
testWithoutContext('Can connect to existing application using ws URI (no trailing slash, ws in auth code)', () async {
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: <FakeVmServiceRequest>[
getVM,
getVM,
const FakeVmServiceRequest(
method: 'ext.flutter.exit',

View File

@ -181,7 +181,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
logger: logger,
),
);
logReader.connectedVMService = vmService;
await logReader.provideVmService(vmService);
// Wait for stream listeners to fire.
await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[
@ -223,7 +223,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
logger: logger,
),
);
logReader.connectedVMService = vmService;
await logReader.provideVmService(vmService);
final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger();
iosDeployDebugger.debuggerAttached = true;
@ -425,7 +425,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.unifiedLogging);
});
testWithoutContext('for iOS 13 or greater non-CoreDevice, _iosDeployDebugger not attached, and VM is connected', () {
testWithoutContext('for iOS 13 or greater non-CoreDevice, _iosDeployDebugger not attached, and VM is connected', () async {
final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
iMobileDevice: IMobileDevice(
artifacts: artifacts,
@ -448,7 +448,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
}),
]).vmService;
logReader.connectedVMService = vmService;
await logReader.provideVmService(vmService);
expect(logReader.useSyslogLogging, isFalse);
expect(logReader.useUnifiedLogging, isTrue);
@ -457,7 +457,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.iosDeploy);
});
testWithoutContext('for iOS 13 or greater non-CoreDevice and _iosDeployDebugger is attached', () {
testWithoutContext('for iOS 13 or greater non-CoreDevice and _iosDeployDebugger is attached', () async {
final IOSDeviceLogReader logReader = IOSDeviceLogReader.test(
iMobileDevice: IMobileDevice(
artifacts: artifacts,
@ -484,7 +484,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
}),
]).vmService;
logReader.connectedVMService = vmService;
await logReader.provideVmService(vmService);
expect(logReader.useSyslogLogging, isFalse);
expect(logReader.useUnifiedLogging, isTrue);
@ -685,7 +685,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
logger: logger,
),
);
logReader.connectedVMService = vmService;
await logReader.provideVmService(vmService);
// Wait for stream listeners to fire.
expect(logReader.useUnifiedLogging, isTrue);
@ -729,7 +729,7 @@ Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
),
majorSdkVersion: 12,
);
logReader.connectedVMService = vmService;
await logReader.provideVmService(vmService);
final List<String> lines = await logReader.logLines.toList();

View File

@ -227,9 +227,6 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
@override
Future<void> stopEchoingDeviceLog() async { }
@override
Future<void> tryInitLogReader() async { }
@override
Future<Uri> setupDevFS(String fsName, Directory rootDirectory) async {
return testUri!;

View File

@ -682,10 +682,6 @@ void main() {
testUsingContext('ResidentRunner reports hot reload time details', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
method: 'getVM',
jsonResponse: fakeVM.toJson(),
),
listViews,
listViews,
FakeVmServiceRequest(
@ -1929,43 +1925,6 @@ flutter:
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('FlutterDevice does not throw when unable to initiate log reader due to VM service disconnection', () async {
fakeVmServiceHost = FakeVmServiceHost(
requests: <VmServiceExpectation>[
FakeVmServiceRequest(
method: 'getVM',
error: FakeRPCError(
code: vm_service.RPCErrorKind.kServerError.code,
error: 'Service connection disposed',
),
),
],
);
final TestFlutterDevice flutterDevice = TestFlutterDevice(device);
flutterDevice.vmService = fakeVmServiceHost!.vmService;
await flutterDevice.tryInitLogReader();
final BufferLogger logger = globals.logger as BufferLogger;
expect(
logger.traceText,
contains(
'VmService.getVm call failed: getVM: (-32000) '
'Service connection disposed\n',
),
);
// We should not print a warning since the device does not have a connected
// adb log reader.
// TODO(andrewkolos): This test is a bit fragile, and is something that
// should be corrected in a follow-up PR (see
// https://github.com/flutter/flutter/issues/155795).
expect(logger.errorText, isEmpty);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test(),
Artifacts: () => Artifacts.test(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Uses existing DDS URI from exception field', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
final FakeDevice device = FakeDevice()

View File

@ -1760,9 +1760,6 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
@override
Future<void> stopEchoingDeviceLog() async {}
@override
Future<void> tryInitLogReader() async {}
@override
Future<Uri?> setupDevFS(String fsName, Directory rootDirectory) async {
return testUri;

View File

@ -8,6 +8,7 @@ import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'fakes.dart';
@ -311,4 +312,7 @@ class FakeDeviceLogReader extends DeviceLogReader {
await _linesController.close();
disposed = true;
}
@override
Future<void> provideVmService(FlutterVmService? connectedVmService) async { }
}