Commit 99684ce1 authored by Zachary Anderson's avatar Zachary Anderson Committed by Flutter GitHub Bot

[flutter_tool] Make Device.dispose() abstract (#46006)

parent 649e1885
...@@ -719,6 +719,12 @@ class AndroidDevice extends Device { ...@@ -719,6 +719,12 @@ class AndroidDevice extends Device {
bool isSupportedForProject(FlutterProject flutterProject) { bool isSupportedForProject(FlutterProject flutterProject) {
return flutterProject.android.existsSync(); return flutterProject.android.existsSync();
} }
@override
Future<void> dispose() async {
_logReader?._stop();
await _portForwarder?.dispose();
}
} }
Map<String, String> parseAdbDeviceProperties(String str) { Map<String, String> parseAdbDeviceProperties(String str) {
...@@ -1123,10 +1129,13 @@ class _AdbLogReader extends DeviceLogReader { ...@@ -1123,10 +1129,13 @@ class _AdbLogReader extends DeviceLogReader {
} }
void _stop() { void _stop() {
// TODO(devoncarew): We should remove adb port forwarding here.
_process?.kill(); _process?.kill();
} }
@override
void dispose() {
_stop();
}
} }
class _AndroidDevicePortForwarder extends DevicePortForwarder { class _AndroidDevicePortForwarder extends DevicePortForwarder {
...@@ -1135,7 +1144,6 @@ class _AndroidDevicePortForwarder extends DevicePortForwarder { ...@@ -1135,7 +1144,6 @@ class _AndroidDevicePortForwarder extends DevicePortForwarder {
final AndroidDevice device; final AndroidDevice device;
static int _extractPort(String portString) { static int _extractPort(String portString) {
return int.tryParse(portString.trim()); return int.tryParse(portString.trim());
} }
...@@ -1247,4 +1255,11 @@ class _AndroidDevicePortForwarder extends DevicePortForwarder { ...@@ -1247,4 +1255,11 @@ class _AndroidDevicePortForwarder extends DevicePortForwarder {
throwOnError: true, throwOnError: true,
); );
} }
@override
Future<void> dispose() async {
for (ForwardedPort port in forwardedPorts) {
await unforward(port);
}
}
} }
...@@ -137,6 +137,11 @@ abstract class DesktopDevice extends Device { ...@@ -137,6 +137,11 @@ abstract class DesktopDevice extends Device {
return succeeded; return succeeded;
} }
@override
Future<void> dispose() async {
await portForwarder?.dispose();
}
/// Builds the current project for this device, with the given options. /// Builds the current project for this device, with the given options.
Future<void> buildForDevice( Future<void> buildForDevice(
ApplicationPackage package, { ApplicationPackage package, {
...@@ -173,4 +178,9 @@ class DesktopLogReader extends DeviceLogReader { ...@@ -173,4 +178,9 @@ class DesktopLogReader extends DeviceLogReader {
@override @override
String get name => 'desktop'; String get name => 'desktop';
@override
void dispose() {
// Nothing to dispose.
}
} }
...@@ -492,7 +492,7 @@ abstract class Device { ...@@ -492,7 +492,7 @@ abstract class Device {
/// Clean up resources allocated by device /// Clean up resources allocated by device
/// ///
/// For example log readers or port forwarders. /// For example log readers or port forwarders.
void dispose() {} Future<void> dispose();
} }
/// Information about an application's memory usage. /// Information about an application's memory usage.
...@@ -633,7 +633,7 @@ abstract class DevicePortForwarder { ...@@ -633,7 +633,7 @@ abstract class DevicePortForwarder {
Future<void> unforward(ForwardedPort forwardedPort); Future<void> unforward(ForwardedPort forwardedPort);
/// Cleanup allocated resources, like forwardedPorts /// Cleanup allocated resources, like forwardedPorts
Future<void> dispose() async { } Future<void> dispose();
} }
/// Read the log for a particular device. /// Read the log for a particular device.
...@@ -654,7 +654,7 @@ abstract class DeviceLogReader { ...@@ -654,7 +654,7 @@ abstract class DeviceLogReader {
int appPid; int appPid;
// Clean up resources allocated by log reader e.g. subprocesses // Clean up resources allocated by log reader e.g. subprocesses
void dispose() { } void dispose();
} }
/// Describes an app running on the device. /// Describes an app running on the device.
......
...@@ -93,6 +93,12 @@ class _FuchsiaLogReader extends DeviceLogReader { ...@@ -93,6 +93,12 @@ class _FuchsiaLogReader extends DeviceLogReader {
@override @override
String toString() => name; String toString() => name;
@override
void dispose() {
// The Fuchsia SDK syslog process is killed when the subscription to the
// logLines Stream is canceled.
}
} }
class _FuchsiaLogSink implements EventSink<String> { class _FuchsiaLogSink implements EventSink<String> {
...@@ -458,7 +464,12 @@ class FuchsiaDevice extends Device { ...@@ -458,7 +464,12 @@ class FuchsiaDevice extends Device {
@override @override
DevicePortForwarder get portForwarder => DevicePortForwarder get portForwarder =>
_portForwarder ??= _FuchsiaPortForwarder(this); _portForwarder ??= _FuchsiaPortForwarder(this);
_FuchsiaPortForwarder _portForwarder; DevicePortForwarder _portForwarder;
@visibleForTesting
set portForwarder(DevicePortForwarder forwarder) {
_portForwarder = forwarder;
}
@override @override
void clearLogs() {} void clearLogs() {}
...@@ -583,6 +594,11 @@ class FuchsiaDevice extends Device { ...@@ -583,6 +594,11 @@ class FuchsiaDevice extends Device {
bool isSupportedForProject(FlutterProject flutterProject) { bool isSupportedForProject(FlutterProject flutterProject) {
return flutterProject.fuchsia.existsSync(); return flutterProject.fuchsia.existsSync();
} }
@override
Future<void> dispose() async {
await _portForwarder?.dispose();
}
} }
class FuchsiaIsolateDiscoveryProtocol { class FuchsiaIsolateDiscoveryProtocol {
...@@ -736,4 +752,11 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { ...@@ -736,4 +752,11 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
throwToolExit('Unforward command failed: $result'); throwToolExit('Unforward command failed: $result');
} }
} }
@override
Future<void> dispose() async {
for (ForwardedPort port in forwardedPorts) {
await unforward(port);
}
}
} }
...@@ -472,11 +472,11 @@ class IOSDevice extends Device { ...@@ -472,11 +472,11 @@ class IOSDevice extends Device {
} }
@override @override
void dispose() { Future<void> dispose() async {
_logReaders.forEach((IOSApp application, DeviceLogReader logReader) { _logReaders.forEach((IOSApp application, DeviceLogReader logReader) {
logReader.dispose(); logReader.dispose();
}); });
_portForwarder?.dispose(); await _portForwarder?.dispose();
} }
} }
......
...@@ -536,6 +536,16 @@ class IOSSimulator extends Device { ...@@ -536,6 +536,16 @@ class IOSSimulator extends Device {
bool isSupportedForProject(FlutterProject flutterProject) { bool isSupportedForProject(FlutterProject flutterProject) {
return flutterProject.ios.existsSync(); return flutterProject.ios.existsSync();
} }
@override
Future<void> dispose() async {
_logReaders?.forEach(
(ApplicationPackage application, _IOSSimulatorLogReader logReader) {
logReader.dispose();
},
);
await _portForwarder?.dispose();
}
} }
/// Launches the device log reader process on the host. /// Launches the device log reader process on the host.
...@@ -721,6 +731,11 @@ class _IOSSimulatorLogReader extends DeviceLogReader { ...@@ -721,6 +731,11 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
_deviceProcess?.kill(); _deviceProcess?.kill();
_systemProcess?.kill(); _systemProcess?.kill();
} }
@override
void dispose() {
_stop();
}
} }
int compareIosVersions(String v1, String v2) { int compareIosVersions(String v1, String v2) {
...@@ -777,9 +792,7 @@ class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder { ...@@ -777,9 +792,7 @@ class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder {
final List<ForwardedPort> _ports = <ForwardedPort>[]; final List<ForwardedPort> _ports = <ForwardedPort>[];
@override @override
List<ForwardedPort> get forwardedPorts { List<ForwardedPort> get forwardedPorts => _ports;
return _ports;
}
@override @override
Future<int> forward(int devicePort, { int hostPort }) async { Future<int> forward(int devicePort, { int hostPort }) async {
...@@ -795,4 +808,11 @@ class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder { ...@@ -795,4 +808,11 @@ class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder {
Future<void> unforward(ForwardedPort forwardedPort) async { Future<void> unforward(ForwardedPort forwardedPort) async {
_ports.remove(forwardedPort); _ports.remove(forwardedPort);
} }
@override
Future<void> dispose() async {
for (ForwardedPort port in _ports) {
await unforward(port);
}
}
} }
...@@ -171,7 +171,7 @@ class ColdRunner extends ResidentRunner { ...@@ -171,7 +171,7 @@ class ColdRunner extends ResidentRunner {
@override @override
Future<void> cleanupAtFinish() async { Future<void> cleanupAtFinish() async {
for (FlutterDevice flutterDevice in flutterDevices) { for (FlutterDevice flutterDevice in flutterDevices) {
flutterDevice.device.dispose(); await flutterDevice.device.dispose();
} }
await stopEchoingDeviceLog(); await stopEchoingDeviceLog();
......
...@@ -1031,7 +1031,7 @@ class HotRunner extends ResidentRunner { ...@@ -1031,7 +1031,7 @@ class HotRunner extends ResidentRunner {
@override @override
Future<void> cleanupAtFinish() async { Future<void> cleanupAtFinish() async {
for (FlutterDevice flutterDevice in flutterDevices) { for (FlutterDevice flutterDevice in flutterDevices) {
flutterDevice.device.dispose(); await flutterDevice.device.dispose();
} }
await _cleanupDevFS(); await _cleanupDevFS();
await stopEchoingDeviceLog(); await stopEchoingDeviceLog();
......
...@@ -212,6 +212,12 @@ class FlutterTesterDevice extends Device { ...@@ -212,6 +212,12 @@ class FlutterTesterDevice extends Device {
@override @override
bool isSupportedForProject(FlutterProject flutterProject) => true; bool isSupportedForProject(FlutterProject flutterProject) => true;
@override
Future<void> dispose() async {
_logReader?.dispose();
await _portForwarder?.dispose();
}
} }
class FlutterTesterDevices extends PollingDeviceDiscovery { class FlutterTesterDevices extends PollingDeviceDiscovery {
...@@ -250,6 +256,9 @@ class _FlutterTesterDeviceLogReader extends DeviceLogReader { ...@@ -250,6 +256,9 @@ class _FlutterTesterDeviceLogReader extends DeviceLogReader {
String get name => 'flutter tester log reader'; String get name => 'flutter tester log reader';
void addLine(String line) => _logLinesController.add(line); void addLine(String line) => _logLinesController.add(line);
@override
void dispose() {}
} }
/// A fake port forwarder that doesn't do anything. Used by flutter tester /// A fake port forwarder that doesn't do anything. Used by flutter tester
...@@ -268,4 +277,7 @@ class _NoopPortForwarder extends DevicePortForwarder { ...@@ -268,4 +277,7 @@ class _NoopPortForwarder extends DevicePortForwarder {
@override @override
Future<void> unforward(ForwardedPort forwardedPort) async { } Future<void> unforward(ForwardedPort forwardedPort) async { }
@override
Future<void> dispose() async { }
} }
...@@ -59,9 +59,11 @@ class ChromeDevice extends Device { ...@@ -59,9 +59,11 @@ class ChromeDevice extends Device {
@override @override
void clearLogs() { } void clearLogs() { }
DeviceLogReader _logReader;
@override @override
DeviceLogReader getLogReader({ApplicationPackage app}) { DeviceLogReader getLogReader({ApplicationPackage app}) {
return NoOpDeviceLogReader(app?.name); return _logReader ??= NoOpDeviceLogReader(app?.name);
} }
@override @override
...@@ -160,6 +162,12 @@ class ChromeDevice extends Device { ...@@ -160,6 +162,12 @@ class ChromeDevice extends Device {
bool isSupportedForProject(FlutterProject flutterProject) { bool isSupportedForProject(FlutterProject flutterProject) {
return flutterProject.web.existsSync(); return flutterProject.web.existsSync();
} }
@override
Future<void> dispose() async {
_logReader?.dispose();
await portForwarder?.dispose();
}
} }
class WebDevices extends PollingDeviceDiscovery { class WebDevices extends PollingDeviceDiscovery {
...@@ -206,9 +214,11 @@ class WebServerDevice extends Device { ...@@ -206,9 +214,11 @@ class WebServerDevice extends Device {
@override @override
Future<String> get emulatorId => null; Future<String> get emulatorId => null;
DeviceLogReader _logReader;
@override @override
DeviceLogReader getLogReader({ApplicationPackage app}) { DeviceLogReader getLogReader({ApplicationPackage app}) {
return NoOpDeviceLogReader(app.name); return _logReader ??= NoOpDeviceLogReader(app.name);
} }
@override @override
...@@ -271,4 +281,10 @@ class WebServerDevice extends Device { ...@@ -271,4 +281,10 @@ class WebServerDevice extends Device {
Future<bool> uninstallApp(ApplicationPackage app) async { Future<bool> uninstallApp(ApplicationPackage app) async {
return true; return true;
} }
@override
Future<void> dispose() async {
_logReader?.dispose();
await portForwarder?.dispose();
}
} }
...@@ -665,6 +665,36 @@ flutter: ...@@ -665,6 +665,36 @@ flutter:
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
}); });
testUsingContext('disposing device disposes the portForwarder', () async {
bool unforwardCalled = false;
when(mockProcessManager.run(argThat(containsAll(<String>[
'forward',
'tcp:0',
'tcp:123',
])))).thenAnswer((_) async {
return ProcessResult(0, 0, '456', '');
});
when(mockProcessManager.runSync(argThat(containsAll(<String>[
'forward',
'--list',
])))).thenReturn(ProcessResult(0, 0, '1234 tcp:456 tcp:123', ''));
when(mockProcessManager.run(argThat(containsAll(<String>[
'forward',
'--remove',
'tcp:456',
])))).thenAnswer((_) async {
unforwardCalled = true;
return ProcessResult(0, 0, '', '');
});
expect(await forwarder.forward(123), equals(456));
await device.dispose();
expect(unforwardCalled, isTrue);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
}); });
group('lastLogcatTimestamp', () { group('lastLogcatTimestamp', () {
......
...@@ -71,6 +71,14 @@ void main() { ...@@ -71,6 +71,14 @@ void main() {
expect(names.length, 0); expect(names.length, 0);
}); });
testUsingContext('disposing device disposes the portForwarder', () async {
final MockPortForwarder mockPortForwarder = MockPortForwarder();
final FuchsiaDevice device = FuchsiaDevice('123');
device.portForwarder = mockPortForwarder;
await device.dispose();
verify(mockPortForwarder.dispose()).called(1);
});
testUsingContext('default capabilities', () async { testUsingContext('default capabilities', () async {
final FuchsiaDevice device = FuchsiaDevice('123'); final FuchsiaDevice device = FuchsiaDevice('123');
fs.directory('fuchsia').createSync(recursive: true); fs.directory('fuchsia').createSync(recursive: true);
......
...@@ -138,7 +138,7 @@ void main() { ...@@ -138,7 +138,7 @@ void main() {
device.setLogReader(appPackage2, logReader2); device.setLogReader(appPackage2, logReader2);
device.portForwarder = portForwarder; device.portForwarder = portForwarder;
device.dispose(); await device.dispose();
verify(mockProcess1.kill()); verify(mockProcess1.kill());
verify(mockProcess2.kill()); verify(mockProcess2.kill());
...@@ -249,6 +249,16 @@ void main() { ...@@ -249,6 +249,16 @@ void main() {
Cache.enableLocking(); Cache.enableLocking();
}); });
testUsingContext('disposing device disposes the portForwarder', () async {
final IOSDevice device = IOSDevice('123');
device.portForwarder = mockPortForwarder;
device.setLogReader(mockApp, mockLogReader);
await device.dispose();
verify(mockPortForwarder.dispose()).called(1);
}, overrides: <Type, Generator>{
Platform: () => macPlatform,
});
testUsingContext('returns failed if the IOSDevice is not found', () async { testUsingContext('returns failed if the IOSDevice is not found', () async {
final IOSDevice device = IOSDevice('123'); final IOSDevice device = IOSDevice('123');
when(mockIMobileDevice.getInfoForDevice(any, 'CPUArchitecture')).thenThrow( when(mockIMobileDevice.getInfoForDevice(any, 'CPUArchitecture')).thenThrow(
......
...@@ -381,4 +381,7 @@ class MockPortForwarder extends DevicePortForwarder { ...@@ -381,4 +381,7 @@ class MockPortForwarder extends DevicePortForwarder {
Future<void> unforward(ForwardedPort forwardedPort) { Future<void> unforward(ForwardedPort forwardedPort) {
throw 'not implemented'; throw 'not implemented';
} }
@override
Future<void> dispose() async {}
} }
...@@ -550,6 +550,33 @@ void main() { ...@@ -550,6 +550,33 @@ void main() {
expect(await fs.file('foo').readAsString(), testUri.toString()); expect(await fs.file('foo').readAsString(), testUri.toString());
})); }));
test('HotRunner unforwards device ports', () => testbed.run(() async {
final MockDevicePortForwarder mockPortForwarder = MockDevicePortForwarder();
when(mockDevice.portForwarder).thenReturn(mockPortForwarder);
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner(
<FlutterDevice>[
mockFlutterDevice,
],
stayResident: false,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
);
when(mockFlutterDevice.runHot(
hotRunner: anyNamed('hotRunner'),
route: anyNamed('route'),
)).thenAnswer((Invocation invocation) async {
return 0;
});
when(mockDevice.dispose()).thenAnswer((Invocation invocation) async {
await mockDevice.portForwarder.dispose();
});
await residentRunner.run();
verify(mockPortForwarder.dispose()).called(1);
}));
test('HotRunner handles failure to write vmservice file', () => testbed.run(() async { test('HotRunner handles failure to write vmservice file', () => testbed.run(() async {
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true); fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner( residentRunner = HotRunner(
...@@ -650,6 +677,7 @@ class MockDevFS extends Mock implements DevFS {} ...@@ -650,6 +677,7 @@ class MockDevFS extends Mock implements DevFS {}
class MockIsolate extends Mock implements Isolate {} class MockIsolate extends Mock implements Isolate {}
class MockDevice extends Mock implements Device {} class MockDevice extends Mock implements Device {}
class MockDeviceLogReader extends Mock implements DeviceLogReader {} class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockDevicePortForwarder extends Mock implements DevicePortForwarder {}
class MockUsage extends Mock implements Usage {} class MockUsage extends Mock implements Usage {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockServiceEvent extends Mock implements ServiceEvent {} class MockServiceEvent extends Mock implements ServiceEvent {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment