[flutter_tools] Adds some support for '-d all' (#9585)

diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart
index 0a7b671..e837799 100644
--- a/packages/flutter_tools/lib/src/run_cold.dart
+++ b/packages/flutter_tools/lib/src/run_cold.dart
@@ -6,10 +6,7 @@
 
 import 'package:meta/meta.dart';
 
-import 'application_package.dart';
 import 'base/file_system.dart';
-import 'base/utils.dart';
-import 'build_info.dart';
 import 'commands/trace.dart';
 import 'device.dart';
 import 'globals.dart';
@@ -17,25 +14,22 @@
 
 class ColdRunner extends ResidentRunner {
   ColdRunner(
-    Device device, {
+    List<FlutterDevice> devices, {
     String target,
     DebuggingOptions debuggingOptions,
     bool usesTerminalUI: true,
     this.traceStartup: false,
     this.applicationBinary,
     bool stayResident: true,
-  }) : super(device,
+  }) : super(devices,
              target: target,
              debuggingOptions: debuggingOptions,
              usesTerminalUI: usesTerminalUI,
              stayResident: stayResident);
 
-  LaunchResult _result;
   final bool traceStartup;
   final String applicationBinary;
 
-  bool get prebuiltMode => applicationBinary != null;
-
   @override
   Future<int> run({
     Completer<DebugConnectionInfo> connectionInfoCompleter,
@@ -43,6 +37,7 @@
     String route,
     bool shouldBuild: true
   }) async {
+    final bool prebuiltMode = applicationBinary != null;
     if (!prebuiltMode) {
       if (!fs.isFileSync(mainPath)) {
         String message = 'Tried to run $mainPath, but that file does not exist.';
@@ -53,79 +48,49 @@
       }
     }
 
-    final String modeName = getModeName(debuggingOptions.buildMode);
-    if (mainPath == null) {
-      assert(prebuiltMode);
-      printStatus('Launching ${package.displayName} on ${device.name} in $modeName mode...');
-    } else {
-      printStatus('Launching ${getDisplayPath(mainPath)} on ${device.name} in $modeName mode...');
+    for (FlutterDevice device in flutterDevices) {
+      final int result = await device.runCold(
+        coldRunner: this,
+        route: route,
+        shouldBuild: shouldBuild,
+      );
+      if (result != 0)
+        return result;
     }
 
-    final TargetPlatform targetPlatform = await device.targetPlatform;
-    package = getApplicationPackageForPlatform(targetPlatform, applicationBinary: applicationBinary);
-
-    if (package == null) {
-      String message = 'No application found for $targetPlatform.';
-      final String hint = getMissingPackageHintForPlatform(targetPlatform);
-      if (hint != null)
-        message += '\n$hint';
-      printError(message);
-      return 1;
-    }
-
-    final Stopwatch startTime = new Stopwatch()..start();
-
-    Map<String, dynamic> platformArgs;
-    if (traceStartup != null)
-      platformArgs = <String, dynamic>{ 'trace-startup': traceStartup };
-
-    await startEchoingDeviceLog(package);
-
-    _result = await device.startApp(
-      package,
-      debuggingOptions.buildMode,
-      mainPath: mainPath,
-      debuggingOptions: debuggingOptions,
-      platformArgs: platformArgs,
-      route: route,
-      prebuiltApplication: prebuiltMode,
-      applicationNeedsRebuild: shouldBuild || hasDirtyDependencies()
-    );
-
-    if (!_result.started) {
-      printError('Error running application on ${device.name}.');
-      await stopEchoingDeviceLog();
-      return 2;
-    }
-
-    startTime.stop();
-
     // Connect to observatory.
     if (debuggingOptions.debuggingEnabled)
-      await connectToServiceProtocol(<Uri>[_result.observatoryUri]);
+      await connectToServiceProtocol();
 
-    if (_result.hasObservatory) {
+    if (flutterDevices.first.observatoryUris != null) {
+      // For now, only support one debugger connection.
       connectionInfoCompleter?.complete(new DebugConnectionInfo(
-        httpUri: _result.observatoryUri,
-        wsUri: vmServices[0].wsAddress,
+        httpUri: flutterDevices.first.observatoryUris.first,
+        wsUri: flutterDevices.first.vmServices.first.wsAddress,
       ));
     }
 
     printTrace('Application running.');
 
-    if (vmServices != null && vmServices.isNotEmpty) {
-      device.getLogReader(app: package).appPid = vmServices[0].vm.pid;
-      await refreshViews();
-      printTrace('Connected to $currentView.');
+    for (FlutterDevice device in flutterDevices) {
+      if (device.vmServices == null)
+        continue;
+      device.initLogReader();
+      await device.refreshViews();
+      printTrace('Connected to ${device.device.name}');
     }
 
-    if (vmServices != null && vmServices.isNotEmpty && traceStartup) {
-      printStatus('Downloading startup trace info...');
-      try {
-        await downloadStartupTrace(vmServices[0]);
-      } catch(error) {
-        printError(error);
-        return 2;
+    if (traceStartup) {
+      // Only trace startup for the first device.
+      final FlutterDevice device = flutterDevices.first;
+      if (device.vmServices != null && device.vmServices.isNotEmpty) {
+        printStatus('Downloading startup trace info for ${device.device.name}');
+        try {
+          await downloadStartupTrace(device.vmServices.first);
+        } catch (error) {
+          printError(error);
+          return 2;
+        }
       }
       appFinished();
     } else if (stayResident) {
@@ -158,8 +123,13 @@
   @override
   void printHelp({ @required bool details }) {
     bool haveDetails = false;
-    if (_result.hasObservatory)
-      printStatus('The Observatory debugger and profiler is available at: ${_result.observatoryUri}');
+    for (FlutterDevice device in flutterDevices) {
+      final String dname = device.device.name;
+      if (device.observatoryUris != null) {
+        for (Uri uri in device.observatoryUris)
+          printStatus('An Observatory debugger and profiler on $dname is available at $uri');
+      }
+    }
     if (supportsServiceProtocol) {
       haveDetails = true;
       if (details)
@@ -174,8 +144,10 @@
 
   @override
   Future<Null> preStop() async {
-    // If we're running in release mode, stop the app using the device logic.
-    if (vmServices == null || vmServices.isEmpty)
-      await device.stopApp(package);
+    for (FlutterDevice device in flutterDevices) {
+      // If we're running in release mode, stop the app using the device logic.
+      if (device.vmServices == null || device.vmServices.isEmpty)
+        await device.device.stopApp(device.package);
+    }
   }
 }