Migrate device_port_forwarder to null safety (#78949)

diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index e5af683..a808fb9 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -21,6 +21,7 @@
 import '../build_info.dart';
 import '../convert.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../project.dart';
 import '../protocol_discovery.dart';
 
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index c66ad94..2173f1e 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -19,6 +19,7 @@
 import '../commands/daemon.dart';
 import '../compile.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../fuchsia/fuchsia_device.dart';
 import '../globals.dart' as globals;
 import '../ios/devices.dart';
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index cad2cab..44c3d11 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -20,6 +20,7 @@
 import '../build_info.dart';
 import '../convert.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../emulator.dart';
 import '../features.dart';
 import '../globals.dart' as globals;
diff --git a/packages/flutter_tools/lib/src/desktop_device.dart b/packages/flutter_tools/lib/src/desktop_device.dart
index 0a8d1b9..82f6e25 100644
--- a/packages/flutter_tools/lib/src/desktop_device.dart
+++ b/packages/flutter_tools/lib/src/desktop_device.dart
@@ -19,6 +19,7 @@
 import 'convert.dart';
 import 'devfs.dart';
 import 'device.dart';
+import 'device_port_forwader.dart';
 import 'protocol_discovery.dart';
 
 /// A partial implementation of Device for desktop-class devices to inherit
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index e975d29..900b7f0 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -20,7 +20,6 @@
 import 'base/context.dart';
 import 'base/dds.dart';
 import 'base/file_system.dart';
-import 'base/io.dart';
 import 'base/logger.dart';
 import 'base/os.dart';
 import 'base/platform.dart';
@@ -29,6 +28,7 @@
 import 'base/utils.dart';
 import 'build_info.dart';
 import 'devfs.dart';
+import 'device_port_forwader.dart';
 import 'features.dart';
 import 'fuchsia/fuchsia_device.dart';
 import 'fuchsia/fuchsia_sdk.dart';
@@ -989,43 +989,6 @@
   }
 }
 
-class ForwardedPort {
-  ForwardedPort(this.hostPort, this.devicePort) : context = null;
-  ForwardedPort.withContext(this.hostPort, this.devicePort, this.context);
-
-  final int hostPort;
-  final int devicePort;
-  final Process context;
-
-  @override
-  String toString() => 'ForwardedPort HOST:$hostPort to DEVICE:$devicePort';
-
-  /// Kill subprocess (if present) used in forwarding.
-  void dispose() {
-    if (context != null) {
-      context.kill();
-    }
-  }
-}
-
-/// Forward ports from the host machine to the device.
-abstract class DevicePortForwarder {
-  /// Returns a Future that completes with the current list of forwarded
-  /// ports for this device.
-  List<ForwardedPort> get forwardedPorts;
-
-  /// Forward [hostPort] on the host to [devicePort] on the device.
-  /// If [hostPort] is null or zero, will auto select a host port.
-  /// Returns a Future that completes with the host port.
-  Future<int> forward(int devicePort, { int hostPort });
-
-  /// Stops forwarding [forwardedPort].
-  Future<void> unforward(ForwardedPort forwardedPort);
-
-  /// Cleanup allocated resources, like [forwardedPorts].
-  Future<void> dispose();
-}
-
 /// Read the log for a particular device.
 abstract class DeviceLogReader {
   String get name;
@@ -1074,23 +1037,6 @@
   void dispose() { }
 }
 
-// A port forwarder which does not support forwarding ports.
-class NoOpDevicePortForwarder implements DevicePortForwarder {
-  const NoOpDevicePortForwarder();
-
-  @override
-  Future<int> forward(int devicePort, { int hostPort }) async => devicePort;
-
-  @override
-  List<ForwardedPort> get forwardedPorts => <ForwardedPort>[];
-
-  @override
-  Future<void> unforward(ForwardedPort forwardedPort) async { }
-
-  @override
-  Future<void> dispose() async { }
-}
-
 /// Append --null_assertions to any existing Dart VM flags if
 /// [debuggingOptions.nullAssertions] is true.
 String computeDartVmFlags(DebuggingOptions debuggingOptions) {
diff --git a/packages/flutter_tools/lib/src/device_port_forwader.dart b/packages/flutter_tools/lib/src/device_port_forwader.dart
new file mode 100644
index 0000000..36725de
--- /dev/null
+++ b/packages/flutter_tools/lib/src/device_port_forwader.dart
@@ -0,0 +1,61 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'base/io.dart';
+
+class ForwardedPort {
+  ForwardedPort(this.hostPort, this.devicePort) : context = null;
+  ForwardedPort.withContext(this.hostPort, this.devicePort, this.context);
+
+  final int hostPort;
+  final int devicePort;
+  final Process? context;
+
+  @override
+  String toString() => 'ForwardedPort HOST:$hostPort to DEVICE:$devicePort';
+
+  /// Kill subprocess (if present) used in forwarding.
+  void dispose() {
+    if (context != null) {
+      context!.kill();
+    }
+  }
+}
+
+/// Forward ports from the host machine to the device.
+abstract class DevicePortForwarder {
+  /// Returns a Future that completes with the current list of forwarded
+  /// ports for this device.
+  List<ForwardedPort> get forwardedPorts;
+
+  /// Forward [hostPort] on the host to [devicePort] on the device.
+  /// If [hostPort] is null or zero, will auto select a host port.
+  /// Returns a Future that completes with the host port.
+  Future<int> forward(int devicePort, { int? hostPort });
+
+  /// Stops forwarding [forwardedPort].
+  Future<void> unforward(ForwardedPort forwardedPort);
+
+  /// Cleanup allocated resources, like [forwardedPorts].
+  Future<void> dispose();
+}
+
+// A port forwarder which does not support forwarding ports.
+class NoOpDevicePortForwarder implements DevicePortForwarder {
+  const NoOpDevicePortForwarder();
+
+  @override
+  Future<int> forward(int devicePort, { int? hostPort }) async => devicePort;
+
+  @override
+  List<ForwardedPort> get forwardedPorts => <ForwardedPort>[];
+
+  @override
+  Future<void> unforward(ForwardedPort forwardedPort) async { }
+
+  @override
+  Future<void> dispose() async { }
+}
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
index 9abb974..f702894 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
@@ -21,6 +21,7 @@
 import '../base/time.dart';
 import '../build_info.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../globals.dart' as globals;
 import '../project.dart';
 import '../vmservice.dart';
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index d87efa9..20ee1d5 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -21,6 +21,7 @@
 import '../build_info.dart';
 import '../convert.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../globals.dart' as globals;
 import '../macos/xcode.dart';
 import '../project.dart';
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 68a8d15..e374f11 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -21,6 +21,7 @@
 import '../convert.dart';
 import '../devfs.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../globals.dart' as globals;
 import '../macos/xcode.dart';
 import '../project.dart';
diff --git a/packages/flutter_tools/lib/src/protocol_discovery.dart b/packages/flutter_tools/lib/src/protocol_discovery.dart
index bfcc5a2..fd52cad 100644
--- a/packages/flutter_tools/lib/src/protocol_discovery.dart
+++ b/packages/flutter_tools/lib/src/protocol_discovery.dart
@@ -11,6 +11,7 @@
 import 'base/io.dart';
 import 'base/logger.dart';
 import 'device.dart';
+import 'device_port_forwader.dart';
 import 'globals.dart' as globals;
 
 /// Discovers a specific service protocol on a device, and forwards the service
diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
index 9d86ac0..c28383c 100644
--- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart
+++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
@@ -21,6 +21,7 @@
 import '../desktop_device.dart';
 import '../devfs.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../project.dart';
 import '../protocol_discovery.dart';
 import '../version.dart';
diff --git a/packages/flutter_tools/lib/src/web/web_device.dart b/packages/flutter_tools/lib/src/web/web_device.dart
index df30ece..d5e933f 100644
--- a/packages/flutter_tools/lib/src/web/web_device.dart
+++ b/packages/flutter_tools/lib/src/web/web_device.dart
@@ -16,6 +16,7 @@
 import '../base/version.dart';
 import '../build_info.dart';
 import '../device.dart';
+import '../device_port_forwader.dart';
 import '../features.dart';
 import '../project.dart';
 import 'chrome.dart';
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
index 4ce6ef4..f6e6854 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
@@ -17,6 +17,7 @@
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/commands/attach.dart';
 import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/globals.dart' as globals;
 import 'package:flutter_tools/src/ios/devices.dart';
 import 'package:flutter_tools/src/project.dart';
diff --git a/packages/flutter_tools/test/general.shard/android/android_device_port_forwarder_test.dart b/packages/flutter_tools/test/general.shard/android/android_device_port_forwarder_test.dart
index 22a438a..758dd4a 100644
--- a/packages/flutter_tools/test/general.shard/android/android_device_port_forwarder_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_device_port_forwarder_test.dart
@@ -7,7 +7,7 @@
 import 'package:flutter_tools/src/android/android_device.dart';
 import 'package:flutter_tools/src/base/io.dart';
 import 'package:flutter_tools/src/base/logger.dart';
-import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 
 import '../../src/common.dart';
 import '../../src/context.dart';
diff --git a/packages/flutter_tools/test/general.shard/desktop_device_test.dart b/packages/flutter_tools/test/general.shard/desktop_device_test.dart
index ce68147..18c4aba 100644
--- a/packages/flutter_tools/test/general.shard/desktop_device_test.dart
+++ b/packages/flutter_tools/test/general.shard/desktop_device_test.dart
@@ -15,6 +15,7 @@
 import 'package:flutter_tools/src/desktop_device.dart';
 import 'package:flutter_tools/src/devfs.dart';
 import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/project.dart';
 
 import 'package:meta/meta.dart';
diff --git a/packages/flutter_tools/test/general.shard/device_port_forwarder_test.dart b/packages/flutter_tools/test/general.shard/device_port_forwarder_test.dart
new file mode 100644
index 0000000..5f8b3fd
--- /dev/null
+++ b/packages/flutter_tools/test/general.shard/device_port_forwarder_test.dart
@@ -0,0 +1,30 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// @dart = 2.8
+
+import 'package:flutter_tools/src/base/io.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
+import 'package:mockito/mockito.dart';
+
+import '../src/common.dart';
+import '../src/context.dart';
+
+void main() {
+  testUsingContext('dispose does not throw exception if no process is present', () {
+    final ForwardedPort forwardedPort = ForwardedPort(123, 456);
+    expect(forwardedPort.context, isNull);
+    forwardedPort.dispose();
+  });
+
+  testUsingContext('dispose kills process if process was available', () {
+    final MockProcess mockProcess = MockProcess();
+    final ForwardedPort forwardedPort = ForwardedPort.withContext(123, 456, mockProcess);
+    forwardedPort.dispose();
+    expect(forwardedPort.context, isNotNull);
+    verify(mockProcess.kill());
+  });
+}
+
+class MockProcess extends Mock implements Process {}
diff --git a/packages/flutter_tools/test/general.shard/device_test.dart b/packages/flutter_tools/test/general.shard/device_test.dart
index ef70d47..1cb94c7 100644
--- a/packages/flutter_tools/test/general.shard/device_test.dart
+++ b/packages/flutter_tools/test/general.shard/device_test.dart
@@ -5,7 +5,6 @@
 // @dart = 2.8
 
 import 'package:flutter_tools/src/base/common.dart';
-import 'package:flutter_tools/src/base/io.dart';
 import 'package:flutter_tools/src/base/logger.dart';
 import 'package:flutter_tools/src/base/terminal.dart';
 import 'package:flutter_tools/src/base/user_messages.dart';
@@ -481,24 +480,6 @@
     });
   });
 
-  group('ForwardedPort', () {
-    group('dispose()', () {
-      testUsingContext('does not throw exception if no process is present', () {
-        final ForwardedPort forwardedPort = ForwardedPort(123, 456);
-        expect(forwardedPort.context, isNull);
-        forwardedPort.dispose();
-      });
-
-      testUsingContext('kills process if process was available', () {
-        final MockProcess mockProcess = MockProcess();
-        final ForwardedPort forwardedPort = ForwardedPort.withContext(123, 456, mockProcess);
-        forwardedPort.dispose();
-        expect(forwardedPort.context, isNotNull);
-        verify(mockProcess.kill());
-      });
-    });
-  });
-
   group('JSON encode devices', () {
     testUsingContext('Consistency of JSON representation', () async {
       expect(
@@ -555,4 +536,3 @@
 class MockTerminal extends Mock implements AnsiTerminal {}
 class MockDeviceDiscovery extends Mock implements DeviceDiscovery {}
 class FakeFlutterProject extends Fake implements FlutterProject {}
-class MockProcess extends Mock implements Process {}
diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart
index d96799f..32485d8 100644
--- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart
+++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart
@@ -21,6 +21,7 @@
 import 'package:flutter_tools/src/build_info.dart';
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/fuchsia/amber_ctl.dart';
 import 'package:flutter_tools/src/fuchsia/application_package.dart';
 import 'package:flutter_tools/src/fuchsia/fuchsia_dev_finder.dart';
diff --git a/packages/flutter_tools/test/general.shard/ios/devices_test.dart b/packages/flutter_tools/test/general.shard/ios/devices_test.dart
index 5c72c8d..d1ab8ae 100644
--- a/packages/flutter_tools/test/general.shard/ios/devices_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/devices_test.dart
@@ -18,6 +18,7 @@
 import 'package:flutter_tools/src/build_info.dart';
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/ios/devices.dart';
 import 'package:flutter_tools/src/ios/ios_deploy.dart';
 import 'package:flutter_tools/src/ios/ios_workflow.dart';
diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
index 1bb13cb..12b8f7c 100644
--- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart
@@ -15,6 +15,7 @@
 import 'package:flutter_tools/src/build_info.dart';
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/ios/devices.dart';
 import 'package:flutter_tools/src/ios/ios_deploy.dart';
 import 'package:flutter_tools/src/ios/iproxy.dart';
diff --git a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart
index 74fda51..479c96e 100644
--- a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart
+++ b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart
@@ -13,6 +13,7 @@
 import 'package:flutter_tools/src/build_info.dart';
 import 'package:flutter_tools/src/devfs.dart';
 import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/globals.dart' as globals;
 import 'package:flutter_tools/src/ios/plist_parser.dart';
 import 'package:flutter_tools/src/ios/simulators.dart';
diff --git a/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart b/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart
index c41f110..085ec03 100644
--- a/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart
+++ b/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart
@@ -7,7 +7,7 @@
 import 'package:flutter_tools/src/base/io.dart';
 import 'package:flutter_tools/src/base/logger.dart';
 import 'package:flutter_tools/src/build_info.dart';
-import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/ios/devices.dart';
 import 'package:flutter_tools/src/mdns_discovery.dart';
 import 'package:flutter_tools/src/project.dart';
diff --git a/packages/flutter_tools/test/general.shard/protocol_discovery_test.dart b/packages/flutter_tools/test/general.shard/protocol_discovery_test.dart
index 929fb95..3037a48 100644
--- a/packages/flutter_tools/test/general.shard/protocol_discovery_test.dart
+++ b/packages/flutter_tools/test/general.shard/protocol_discovery_test.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.8
 
-import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/protocol_discovery.dart';
 import 'package:fake_async/fake_async.dart';
 
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 8a3c09b..0875508 100644
--- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart
+++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart
@@ -9,6 +9,7 @@
 import 'package:flutter_tools/src/application_package.dart';
 import 'package:flutter_tools/src/base/dds.dart';
 import 'package:flutter_tools/src/base/platform.dart';
+import 'package:flutter_tools/src/device_port_forwader.dart';
 import 'package:flutter_tools/src/features.dart';
 import 'package:flutter_tools/src/resident_devtools_handler.dart';
 import 'package:flutter_tools/src/version.dart';