run_cold.dart 6.04 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 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';

7
import 'package:meta/meta.dart';
8

9
import 'base/file_system.dart';
10 11
import 'device.dart';
import 'globals.dart';
12
import 'resident_runner.dart';
13
import 'tracing.dart';
14
import 'vmservice.dart';
15

16
// TODO(mklim): Test this, flutter/flutter#23031.
17 18
class ColdRunner extends ResidentRunner {
  ColdRunner(
19
    List<FlutterDevice> devices, {
20 21
    String target,
    DebuggingOptions debuggingOptions,
22 23
    bool usesTerminalUI = true,
    this.traceStartup = false,
24
    this.awaitFirstFrameWhenTracing = true,
25
    this.applicationBinary,
26
    bool saveCompilationTrace = false,
27 28
    bool stayResident = true,
    bool ipv6 = false,
29
  }) : super(devices,
30 31
             target: target,
             debuggingOptions: debuggingOptions,
32
             usesTerminalUI: usesTerminalUI,
33
             saveCompilationTrace: saveCompilationTrace,
34 35
             stayResident: stayResident,
             ipv6: ipv6);
36

37
  final bool traceStartup;
38
  final bool awaitFirstFrameWhenTracing;
39
  final File applicationBinary;
40
  bool _didAttach = false;
41

42
  @override
43
  Future<int> run({
44
    Completer<DebugConnectionInfo> connectionInfoCompleter,
45
    Completer<void> appStartedCompleter,
46
    String route,
47
    bool shouldBuild = true,
48
  }) async {
49
    final bool prebuiltMode = applicationBinary != null;
50
    if (!prebuiltMode) {
51 52
      if (!fs.isFileSync(mainPath)) {
        String message = 'Tried to run $mainPath, but that file does not exist.';
53 54 55 56 57
        if (target == null)
          message += '\nConsider using the -t option to specify the Dart file to start.';
        printError(message);
        return 1;
      }
58 59
    }

60 61 62 63 64 65 66 67
    for (FlutterDevice device in flutterDevices) {
      final int result = await device.runCold(
        coldRunner: this,
        route: route,
        shouldBuild: shouldBuild,
      );
      if (result != 0)
        return result;
68 69
    }

70
    // Connect to observatory.
71 72 73 74 75 76 77 78
    if (debuggingOptions.debuggingEnabled) {
      try {
        await connectToServiceProtocol();
      } on String catch (message) {
        printError(message);
        return 2;
      }
    }
79

80 81
    if (flutterDevices.first.observatoryUris != null) {
      // For now, only support one debugger connection.
82
      connectionInfoCompleter?.complete(DebugConnectionInfo(
83 84
        httpUri: flutterDevices.first.observatoryUris.first,
        wsUri: flutterDevices.first.vmServices.first.wsAddress,
85 86
      ));
    }
87

88
    printTrace('Application running.');
89

90 91 92 93 94 95
    for (FlutterDevice device in flutterDevices) {
      if (device.vmServices == null)
        continue;
      device.initLogReader();
      await device.refreshViews();
      printTrace('Connected to ${device.device.name}');
96
    }
97

98 99 100 101
    if (traceStartup) {
      // Only trace startup for the first device.
      final FlutterDevice device = flutterDevices.first;
      if (device.vmServices != null && device.vmServices.isNotEmpty) {
102 103 104 105 106
        printStatus('Tracing startup on ${device.device.name}.');
        await downloadStartupTrace(
          device.vmServices.first,
          awaitFirstFrame: awaitFirstFrameWhenTracing,
        );
107
      }
108
      appFinished();
109
    } else if (stayResident) {
110 111
      setupTerminal();
      registerSignalHandlers();
112 113
    }

114 115
    appStartedCompleter?.complete();

116
    if (stayResident && !traceStartup)
117 118 119
      return waitForAppToFinish();
    await cleanupAtFinish();
    return 0;
120 121
  }

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  @override
  Future<int> attach({
    Completer<DebugConnectionInfo> connectionInfoCompleter,
    Completer<void> appStartedCompleter,
  }) async {
    _didAttach = true;
    try {
      await connectToServiceProtocol();
    } catch (error) {
      printError('Error connecting to the service protocol: $error');
      return 2;
    }
    for (FlutterDevice device in flutterDevices) {
      device.initLogReader();
    }
    await refreshViews();
    for (FlutterDevice device in flutterDevices) {
      for (FlutterView view in device.views) {
        printTrace('Connected to $view.');
      }
    }
    if (stayResident) {
      setupTerminal();
      registerSignalHandlers();
    }
    appStartedCompleter?.complete();
    if (stayResident) {
      return waitForAppToFinish();
    }
    await cleanupAtFinish();
    return 0;
  }

155
  @override
156
  Future<void> handleTerminalCommand(String code) async { }
157

158
  @override
159
  Future<void> cleanupAfterSignal() async {
160
    await stopEchoingDeviceLog();
161 162 163 164 165
    if (_didAttach) {
      appFinished();
    } else {
      await stopApp();
    }
166
    await stopApp();
167 168
  }

169
  @override
170
  Future<void> cleanupAtFinish() async {
171
    await stopEchoingDeviceLog();
172 173
  }

174
  @override
175
  void printHelp({ @required bool details }) {
176
    bool haveDetails = false;
177
    bool haveAnything = false;
178 179 180
    for (FlutterDevice device in flutterDevices) {
      final String dname = device.device.name;
      if (device.observatoryUris != null) {
181
        for (Uri uri in device.observatoryUris) {
182
          printStatus('An Observatory debugger and profiler on $dname is available at $uri');
183 184
          haveAnything = true;
        }
185 186
      }
    }
187 188
    if (supportsServiceProtocol) {
      haveDetails = true;
189
      if (details) {
190
        printHelpDetails();
191 192
        haveAnything = true;
      }
193
    }
194 195 196
    final String quitMessage = _didAttach
      ? 'To detach, press "d"; to quit, press "q".'
      : 'To quit, press "q".';
197
    if (haveDetails && !details) {
198
      if (saveCompilationTrace) {
199
        printStatus('Compilation training data will be saved when flutter run quits...');
200
      }
201
      printStatus('For a more detailed help message, press "h". $quitMessage');
202
    } else if (haveAnything) {
203
      printStatus('To repeat this help message, press "h". $quitMessage');
204
    } else {
205
      printStatus(quitMessage);
206
    }
207
  }
208 209

  @override
210
  Future<void> preStop() async {
211 212 213 214 215
    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);
    }
216
  }
217
}