[flutter_tools] macOS cleanups, attach to log reader in release mode (#61913)

diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart
index 2c6499c..1cb415c 100644
--- a/packages/flutter_tools/lib/src/context_runner.dart
+++ b/packages/flutter_tools/lib/src/context_runner.dart
@@ -142,6 +142,10 @@
         config: globals.config,
         fuchsiaWorkflow: fuchsiaWorkflow,
         xcDevice: globals.xcdevice,
+        macOSWorkflow: MacOSWorkflow(
+          platform: globals.platform,
+          featureFlags: featureFlags,
+        ),
       ),
       Doctor: () => Doctor(logger: globals.logger),
       DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance,
@@ -193,7 +197,10 @@
             outputPreferences: globals.outputPreferences,
             timeoutConfiguration: timeoutConfiguration,
           ),
-      MacOSWorkflow: () => const MacOSWorkflow(),
+      MacOSWorkflow: () => MacOSWorkflow(
+        featureFlags: featureFlags,
+        platform: globals.platform,
+      ),
       MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(),
       OperatingSystemUtils: () => OperatingSystemUtils(
         fileSystem: globals.fs,
diff --git a/packages/flutter_tools/lib/src/desktop_device.dart b/packages/flutter_tools/lib/src/desktop_device.dart
index 937bfcd..26561e5 100644
--- a/packages/flutter_tools/lib/src/desktop_device.dart
+++ b/packages/flutter_tools/lib/src/desktop_device.dart
@@ -5,10 +5,12 @@
 import 'dart:async';
 
 import 'package:meta/meta.dart';
+import 'package:process/process.dart';
 
 import 'application_package.dart';
 import 'base/common.dart';
 import 'base/io.dart';
+import 'base/logger.dart';
 import 'build_info.dart';
 import 'convert.dart';
 import 'device.dart';
@@ -18,15 +20,23 @@
 /// A partial implementation of Device for desktop-class devices to inherit
 /// from, containing implementations that are common to all desktop devices.
 abstract class DesktopDevice extends Device {
-  DesktopDevice(String identifier, {@required PlatformType platformType, @required bool ephemeral}) : super(
-      identifier,
-      category: Category.desktop,
-      platformType: platformType,
-      ephemeral: ephemeral,
-  );
+  DesktopDevice(String identifier, {
+      @required PlatformType platformType,
+      @required bool ephemeral,
+      Logger logger,
+      ProcessManager processManager,
+    }) : _logger = logger ?? globals.logger, // TODO(jonahwilliams): remove after updating google3
+         _processManager = processManager ?? globals.processManager,
+         super(
+          identifier,
+          category: Category.desktop,
+          platformType: platformType,
+          ephemeral: ephemeral,
+        );
 
+  final Logger _logger;
+  final ProcessManager _processManager;
   final Set<Process> _runningProcesses = <Process>{};
-
   final DesktopLogReader _deviceLogReader = DesktopLogReader();
 
   // Since the host and target devices are the same, no work needs to be done
@@ -108,20 +118,20 @@
     final BuildMode buildMode = debuggingOptions?.buildInfo?.mode;
     final String executable = executablePathForDevice(package, buildMode);
     if (executable == null) {
-      globals.printError('Unable to find executable to run');
+      _logger.printError('Unable to find executable to run');
       return LaunchResult.failed();
     }
 
-    final Process process = await globals.processManager.start(<String>[
+    final Process process = await _processManager.start(<String>[
       executable,
     ]);
     _runningProcesses.add(process);
     unawaited(process.exitCode.then((_) => _runningProcesses.remove(process)));
 
+    _deviceLogReader.initializeProcess(process);
     if (debuggingOptions?.buildInfo?.isRelease == true) {
       return LaunchResult.succeeded();
     }
-    _deviceLogReader.initializeProcess(process);
     final ProtocolDiscovery observatoryDiscovery = ProtocolDiscovery.observatory(_deviceLogReader,
       devicePort: debuggingOptions?.deviceVmServicePort,
       hostPort: debuggingOptions?.hostVmServicePort,
@@ -133,12 +143,12 @@
         onAttached(package, buildMode, process);
         return LaunchResult.succeeded(observatoryUri: observatoryUri);
       }
-      globals.printError(
+      _logger.printError(
         'Error waiting for a debug connection: '
         'The log reader stopped unexpectedly.',
       );
     } on Exception catch (error) {
-      globals.printError('Error waiting for a debug connection: $error');
+      _logger.printError('Error waiting for a debug connection: $error');
     } finally {
       await observatoryDiscovery.cancel();
     }
@@ -186,9 +196,7 @@
   void initializeProcess(Process process) {
     process.stdout.listen(_inputController.add);
     process.stderr.listen(_inputController.add);
-    process.exitCode.then((int result) {
-      _inputController.close();
-    });
+    process.exitCode.whenComplete(_inputController.close);
   }
 
   @override
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 2c72599..1130db6 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -33,6 +33,7 @@
 import 'ios/simulators.dart';
 import 'linux/linux_device.dart';
 import 'macos/macos_device.dart';
+import 'macos/macos_workflow.dart';
 import 'macos/xcode.dart';
 import 'project.dart';
 import 'tester/flutter_tester.dart';
@@ -292,6 +293,7 @@
     @required FlutterVersion flutterVersion,
     @required Config config,
     @required Artifacts artifacts,
+    @required MacOSWorkflow macOSWorkflow,
   }) : deviceDiscoverers =  <DeviceDiscovery>[
     AndroidDevices(
       logger: logger,
@@ -322,10 +324,17 @@
       logger: logger,
       artifacts: artifacts,
     ),
-    MacOSDevices(),
+    MacOSDevices(
+      processManager: processManager,
+      macOSWorkflow: macOSWorkflow,
+      logger: logger,
+      platform: platform,
+    ),
     LinuxDevices(
       platform: platform,
       featureFlags: featureFlags,
+      processManager: processManager,
+      logger: logger,
     ),
     WindowsDevices(),
     WebDevices(
diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart
index 389068e..8c40420 100644
--- a/packages/flutter_tools/lib/src/doctor.dart
+++ b/packages/flutter_tools/lib/src/doctor.dart
@@ -65,6 +65,11 @@
     featureFlags: featureFlags,
   );
 
+  final MacOSWorkflow macOSWorkflow = MacOSWorkflow(
+    platform: globals.platform,
+    featureFlags: featureFlags,
+  );
+
   @override
   List<DoctorValidator> get validators {
     if (_validators != null) {
diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart
index 2cc4295..8916f46 100644
--- a/packages/flutter_tools/lib/src/linux/linux_device.dart
+++ b/packages/flutter_tools/lib/src/linux/linux_device.dart
@@ -3,12 +3,15 @@
 // found in the LICENSE file.
 
 import 'package:meta/meta.dart';
+import 'package:process/process.dart';
 
+import '../base/logger.dart';
 import '../base/platform.dart';
 import '../build_info.dart';
 import '../desktop_device.dart';
 import '../device.dart';
 import '../features.dart';
+import '../globals.dart' as globals;
 import '../project.dart';
 import 'application_package.dart';
 import 'build_linux.dart';
@@ -16,10 +19,15 @@
 
 /// A device that represents a desktop Linux target.
 class LinuxDevice extends DesktopDevice {
-  LinuxDevice() : super(
+  LinuxDevice({
+    @required ProcessManager processManager,
+    @required Logger logger,
+  }) : super(
       'linux',
       platformType: PlatformType.linux,
       ephemeral: false,
+      logger: logger,
+      processManager: processManager,
   );
 
   @override
@@ -59,15 +67,21 @@
   LinuxDevices({
     @required Platform platform,
     @required FeatureFlags featureFlags,
-  }) : _platform = platform,
+    ProcessManager processManager,
+    Logger logger,
+  }) : _platform = platform ?? globals.platform, // TODO(jonahwilliams): remove after google3 roll
        _linuxWorkflow = LinuxWorkflow(
           platform: platform,
           featureFlags: featureFlags,
        ),
+       _logger = logger,
+       _processManager = processManager ?? globals.processManager,
        super('linux devices');
 
   final Platform _platform;
   final LinuxWorkflow _linuxWorkflow;
+  final ProcessManager _processManager;
+  final Logger _logger;
 
   @override
   bool get supportsPlatform => _platform.isLinux;
@@ -81,7 +95,10 @@
       return const <Device>[];
     }
     return <Device>[
-      LinuxDevice(),
+      LinuxDevice(
+        logger: _logger,
+        processManager: _processManager,
+      ),
     ];
   }
 
diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart
index 1d7ef01..f92b7f3 100644
--- a/packages/flutter_tools/lib/src/macos/macos_device.dart
+++ b/packages/flutter_tools/lib/src/macos/macos_device.dart
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:meta/meta.dart';
+import 'package:process/process.dart';
+
 import '../base/io.dart';
+import '../base/logger.dart';
+import '../base/platform.dart';
 import '../build_info.dart';
 import '../desktop_device.dart';
 import '../device.dart';
-import '../globals.dart' as globals;
 import '../macos/application_package.dart';
 import '../project.dart';
 import 'build_macos.dart';
@@ -14,11 +18,21 @@
 
 /// A device that represents a desktop MacOS target.
 class MacOSDevice extends DesktopDevice {
-  MacOSDevice() : super(
-      'macos',
-      platformType: PlatformType.macos,
-      ephemeral: false,
-  );
+  MacOSDevice({
+    @required ProcessManager processManager,
+    @required Logger logger,
+  }) : _processManager = processManager,
+       _logger = logger,
+       super(
+        'macos',
+        platformType: PlatformType.macos,
+        ephemeral: false,
+        processManager: processManager,
+        logger: logger,
+      );
+
+  final ProcessManager _processManager;
+  final Logger _logger;
 
   @override
   bool isSupported() => true;
@@ -44,7 +58,7 @@
       flutterProject: FlutterProject.current(),
       buildInfo: buildInfo,
       targetOverride: mainPath,
-      verboseLogging: globals.logger.isVerbose,
+      verboseLogging: _logger.isVerbose,
     );
   }
 
@@ -59,7 +73,7 @@
     // than post-attach, since this won't run for release builds, but there's
     // no general-purpose way of knowing when a process is far enoug along in
     // the launch process for 'open' to foreground it.
-    globals.processManager.run(<String>[
+    _processManager.run(<String>[
       'open', package.applicationBundle(buildMode),
     ]).then((ProcessResult result) {
       if (result.exitCode != 0) {
@@ -70,13 +84,27 @@
 }
 
 class MacOSDevices extends PollingDeviceDiscovery {
-  MacOSDevices() : super('macOS devices');
+  MacOSDevices({
+    @required Platform platform,
+    @required MacOSWorkflow macOSWorkflow,
+    @required ProcessManager processManager,
+    @required Logger logger,
+  }) : _logger = logger,
+       _platform = platform,
+       _macOSWorkflow = macOSWorkflow,
+       _processManager = processManager,
+       super('macOS devices');
+
+  final MacOSWorkflow _macOSWorkflow;
+  final Platform _platform;
+  final ProcessManager _processManager;
+  final Logger _logger;
 
   @override
-  bool get supportsPlatform => globals.platform.isMacOS;
+  bool get supportsPlatform => _platform.isMacOS;
 
   @override
-  bool get canListAnything => macOSWorkflow.canListDevices;
+  bool get canListAnything => _macOSWorkflow.canListDevices;
 
   @override
   Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
@@ -84,7 +112,7 @@
       return const <Device>[];
     }
     return <Device>[
-      MacOSDevice(),
+      MacOSDevice(processManager: _processManager, logger: _logger),
     ];
   }
 
diff --git a/packages/flutter_tools/lib/src/macos/macos_workflow.dart b/packages/flutter_tools/lib/src/macos/macos_workflow.dart
index 0ae1ae4..b91c68c 100644
--- a/packages/flutter_tools/lib/src/macos/macos_workflow.dart
+++ b/packages/flutter_tools/lib/src/macos/macos_workflow.dart
@@ -2,29 +2,35 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '../base/context.dart';
+import 'package:meta/meta.dart';
+
+import '../base/platform.dart';
 import '../doctor.dart';
 import '../features.dart';
-import '../globals.dart' as globals;
 
-/// The [MacOSWorkflow] instance.
-MacOSWorkflow get macOSWorkflow => context.get<MacOSWorkflow>();
 
 /// The macOS-specific implementation of a [Workflow].
 ///
 /// This workflow requires the flutter-desktop-embedding as a sibling
 /// repository to the flutter repo.
 class MacOSWorkflow implements Workflow {
-  const MacOSWorkflow();
+  const MacOSWorkflow({
+    @required Platform platform,
+    @required FeatureFlags featureFlags,
+  }) : _platform = platform,
+       _featureFlags = featureFlags;
+
+  final Platform _platform;
+  final FeatureFlags _featureFlags;
 
   @override
-  bool get appliesToHostPlatform => globals.platform.isMacOS && featureFlags.isMacOSEnabled;
+  bool get appliesToHostPlatform => _platform.isMacOS && _featureFlags.isMacOSEnabled;
 
   @override
-  bool get canLaunchDevices => globals.platform.isMacOS && featureFlags.isMacOSEnabled;
+  bool get canLaunchDevices => _platform.isMacOS && _featureFlags.isMacOSEnabled;
 
   @override
-  bool get canListDevices => globals.platform.isMacOS && featureFlags.isMacOSEnabled;
+  bool get canListDevices => _platform.isMacOS && _featureFlags.isMacOSEnabled;
 
   @override
   bool get canListEmulators => false;