Re-organize flutter_tools code to better support proper layering. (#12957)

* executable.dart#main() depends on runner.dart#run()
* Refactor code such that non-commands don't depend on commands.

No code was actually changed in this PR - code was merely moved from
point A to point B.
diff --git a/packages/flutter_tools/lib/src/tracing.dart b/packages/flutter_tools/lib/src/tracing.dart
new file mode 100644
index 0000000..e2e258e
--- /dev/null
+++ b/packages/flutter_tools/lib/src/tracing.dart
@@ -0,0 +1,132 @@
+// Copyright 2015 The Chromium 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/file_system.dart';
+import 'base/utils.dart';
+import 'build_info.dart';
+import 'globals.dart';
+import 'vmservice.dart';
+
+// Names of some of the Timeline events we care about.
+const String _kFlutterEngineMainEnterEventName = 'FlutterEngineMainEnter';
+const String _kFrameworkInitEventName = 'Framework initialization';
+const String _kFirstUsefulFrameEventName = 'Widgets completed first useful frame';
+
+class Tracing {
+  Tracing(this.vmService);
+
+  static Future<Tracing> connect(Uri uri) async {
+    final VMService observatory = await VMService.connect(uri);
+    return new Tracing(observatory);
+  }
+
+  final VMService vmService;
+
+  Future<Null> startTracing() async {
+    await vmService.vm.setVMTimelineFlags(<String>['Compiler', 'Dart', 'Embedder', 'GC']);
+    await vmService.vm.clearVMTimeline();
+  }
+
+  /// Stops tracing; optionally wait for first frame.
+  Future<Map<String, dynamic>> stopTracingAndDownloadTimeline({
+    bool waitForFirstFrame: false
+  }) async {
+    Map<String, dynamic> timeline;
+
+    if (!waitForFirstFrame) {
+      // Stop tracing immediately and get the timeline
+      await vmService.vm.setVMTimelineFlags(<String>[]);
+      timeline = await vmService.vm.getVMTimeline();
+    } else {
+      final Completer<Null> whenFirstFrameRendered = new Completer<Null>();
+
+      vmService.onTimelineEvent.listen((ServiceEvent timelineEvent) {
+        final List<Map<String, dynamic>> events = timelineEvent.timelineEvents;
+        for (Map<String, dynamic> event in events) {
+          if (event['name'] == _kFirstUsefulFrameEventName)
+            whenFirstFrameRendered.complete();
+        }
+      });
+
+      await whenFirstFrameRendered.future.timeout(
+          const Duration(seconds: 10),
+          onTimeout: () {
+            printError(
+                'Timed out waiting for the first frame event. Either the '
+                    'application failed to start, or the event was missed because '
+                    '"flutter run" took too long to subscribe to timeline events.'
+            );
+            return null;
+          }
+      );
+
+      timeline = await vmService.vm.getVMTimeline();
+
+      await vmService.vm.setVMTimelineFlags(<String>[]);
+    }
+
+    return timeline;
+  }
+}
+
+/// Download the startup trace information from the given observatory client and
+/// store it to build/start_up_info.json.
+Future<Null> downloadStartupTrace(VMService observatory) async {
+  final String traceInfoFilePath = fs.path.join(getBuildDirectory(), 'start_up_info.json');
+  final File traceInfoFile = fs.file(traceInfoFilePath);
+
+  // Delete old startup data, if any.
+  if (await traceInfoFile.exists())
+    await traceInfoFile.delete();
+
+  // Create "build" directory, if missing.
+  if (!(await traceInfoFile.parent.exists()))
+    await traceInfoFile.parent.create();
+
+  final Tracing tracing = new Tracing(observatory);
+
+  final Map<String, dynamic> timeline = await tracing.stopTracingAndDownloadTimeline(
+      waitForFirstFrame: true
+  );
+
+  int extractInstantEventTimestamp(String eventName) {
+    final List<Map<String, dynamic>> events = timeline['traceEvents'];
+    final Map<String, dynamic> event = events.firstWhere(
+            (Map<String, dynamic> event) => event['name'] == eventName, orElse: () => null
+    );
+    return event == null ? null : event['ts'];
+  }
+
+  final int engineEnterTimestampMicros = extractInstantEventTimestamp(_kFlutterEngineMainEnterEventName);
+  final int frameworkInitTimestampMicros = extractInstantEventTimestamp(_kFrameworkInitEventName);
+  final int firstFrameTimestampMicros = extractInstantEventTimestamp(_kFirstUsefulFrameEventName);
+
+  if (engineEnterTimestampMicros == null) {
+    printTrace('Engine start event is missing in the timeline: $timeline');
+    throw 'Engine start event is missing in the timeline. Cannot compute startup time.';
+  }
+
+  if (firstFrameTimestampMicros == null) {
+    printTrace('First frame event is missing in the timeline: $timeline');
+    throw 'First frame event is missing in the timeline. Cannot compute startup time.';
+  }
+
+  final int timeToFirstFrameMicros = firstFrameTimestampMicros - engineEnterTimestampMicros;
+  final Map<String, dynamic> traceInfo = <String, dynamic>{
+    'engineEnterTimestampMicros': engineEnterTimestampMicros,
+    'timeToFirstFrameMicros': timeToFirstFrameMicros,
+  };
+
+  if (frameworkInitTimestampMicros != null) {
+    traceInfo['timeToFrameworkInitMicros'] = frameworkInitTimestampMicros - engineEnterTimestampMicros;
+    traceInfo['timeAfterFrameworkInitMicros'] = firstFrameTimestampMicros - frameworkInitTimestampMicros;
+  }
+
+  traceInfoFile.writeAsStringSync(toPrettyJson(traceInfo));
+
+  printStatus('Time to first frame: ${timeToFirstFrameMicros ~/ 1000}ms.');
+  printStatus('Saved startup trace info in ${traceInfoFile.path}.');
+}