Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | import 'dart:async'; |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 6 | |
Ian Hickson | a33b70e | 2016-10-31 21:57:59 -0700 | [diff] [blame] | 7 | import 'package:meta/meta.dart'; |
John McCutchan | dd52b7c | 2016-10-20 09:40:00 -0700 | [diff] [blame] | 8 | |
Todd Volkert | 8bb2703 | 2017-01-06 16:51:44 -0800 | [diff] [blame] | 9 | import 'base/file_system.dart'; |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 10 | import 'device.dart'; |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 11 | import 'globals.dart' as globals; |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 12 | import 'resident_runner.dart'; |
Todd Volkert | 454db9d | 2017-11-09 21:45:31 -0800 | [diff] [blame] | 13 | import 'tracing.dart'; |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 14 | import 'vmservice.dart'; |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 15 | |
Alexandre Ardhuin | 79b5e5b | 2018-11-19 10:37:55 +0100 | [diff] [blame] | 16 | // TODO(mklim): Test this, flutter/flutter#23031. |
Ian Hickson | f888bbe | 2017-01-27 01:03:04 -0800 | [diff] [blame] | 17 | class ColdRunner extends ResidentRunner { |
| 18 | ColdRunner( |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 19 | List<FlutterDevice> devices, { |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 20 | String target, |
| 21 | DebuggingOptions debuggingOptions, |
Alexandre Ardhuin | 09276be | 2018-06-05 08:50:40 +0200 | [diff] [blame] | 22 | this.traceStartup = false, |
Ian Hickson | 31a9626 | 2019-01-19 00:31:05 -0800 | [diff] [blame] | 23 | this.awaitFirstFrameWhenTracing = true, |
Ian Hickson | f888bbe | 2017-01-27 01:03:04 -0800 | [diff] [blame] | 24 | this.applicationBinary, |
Alexandre Ardhuin | 09276be | 2018-06-05 08:50:40 +0200 | [diff] [blame] | 25 | bool ipv6 = false, |
Jonah Williams | adf45d1 | 2019-07-09 13:10:26 -0700 | [diff] [blame] | 26 | bool stayResident = true, |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 27 | }) : super(devices, |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 28 | target: target, |
| 29 | debuggingOptions: debuggingOptions, |
Jonah Williams | adf45d1 | 2019-07-09 13:10:26 -0700 | [diff] [blame] | 30 | hotMode: false, |
Todd Volkert | e792c6b | 2017-11-21 20:12:21 -0800 | [diff] [blame] | 31 | stayResident: stayResident, |
| 32 | ipv6: ipv6); |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 33 | |
Devon Carew | 1448358 | 2016-08-09 14:38:13 -0700 | [diff] [blame] | 34 | final bool traceStartup; |
Ian Hickson | 31a9626 | 2019-01-19 00:31:05 -0800 | [diff] [blame] | 35 | final bool awaitFirstFrameWhenTracing; |
Sigurd Meldgaard | 2d3a5c7 | 2018-07-20 08:00:30 +0200 | [diff] [blame] | 36 | final File applicationBinary; |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 37 | bool _didAttach = false; |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 38 | |
Devon Carew | 30505ae | 2016-08-05 21:09:42 -0700 | [diff] [blame] | 39 | @override |
Jonah Williams | 7b150f8 | 2019-07-12 08:48:14 -0700 | [diff] [blame] | 40 | bool get canHotReload => false; |
| 41 | |
| 42 | @override |
| 43 | bool get canHotRestart => false; |
| 44 | |
| 45 | @override |
Devon Carew | 1d01838 | 2016-08-09 09:03:39 -0700 | [diff] [blame] | 46 | Future<int> run({ |
Devon Carew | 6b1597d | 2016-08-11 09:51:19 -0700 | [diff] [blame] | 47 | Completer<DebugConnectionInfo> connectionInfoCompleter, |
Danny Tuppeny | ed9afbb | 2018-07-19 13:38:29 +0100 | [diff] [blame] | 48 | Completer<void> appStartedCompleter, |
Devon Carew | 1d01838 | 2016-08-09 09:03:39 -0700 | [diff] [blame] | 49 | String route, |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 50 | }) async { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 51 | final bool prebuiltMode = applicationBinary != null; |
John McCutchan | ca8070f | 2016-09-28 08:46:16 -0700 | [diff] [blame] | 52 | if (!prebuiltMode) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 53 | if (!globals.fs.isFileSync(mainPath)) { |
John McCutchan | 6a63af4 | 2017-01-10 07:59:55 -0800 | [diff] [blame] | 54 | String message = 'Tried to run $mainPath, but that file does not exist.'; |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 55 | if (target == null) { |
John McCutchan | ca8070f | 2016-09-28 08:46:16 -0700 | [diff] [blame] | 56 | message += '\nConsider using the -t option to specify the Dart file to start.'; |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 57 | } |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 58 | globals.printError(message); |
John McCutchan | ca8070f | 2016-09-28 08:46:16 -0700 | [diff] [blame] | 59 | return 1; |
| 60 | } |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 61 | } |
| 62 | |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 63 | for (final FlutterDevice device in flutterDevices) { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 64 | final int result = await device.runCold( |
| 65 | coldRunner: this, |
| 66 | route: route, |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 67 | ); |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 68 | if (result != 0) { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 69 | return result; |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 70 | } |
Devon Carew | f29dd4f | 2017-04-20 07:13:35 -0700 | [diff] [blame] | 71 | } |
| 72 | |
Dan Rubel | fcf41fc | 2016-11-28 16:15:19 -0500 | [diff] [blame] | 73 | // Connect to observatory. |
Ian Hickson | 31a9626 | 2019-01-19 00:31:05 -0800 | [diff] [blame] | 74 | if (debuggingOptions.debuggingEnabled) { |
| 75 | try { |
| 76 | await connectToServiceProtocol(); |
| 77 | } on String catch (message) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 78 | globals.printError(message); |
Ian Hickson | 31a9626 | 2019-01-19 00:31:05 -0800 | [diff] [blame] | 79 | return 2; |
| 80 | } |
| 81 | } |
Dan Rubel | a9584e1 | 2016-11-30 20:29:04 -0500 | [diff] [blame] | 82 | |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 83 | if (flutterDevices.first.observatoryUris != null) { |
| 84 | // For now, only support one debugger connection. |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 85 | connectionInfoCompleter?.complete(DebugConnectionInfo( |
Jonah Williams | 598f2ab | 2019-11-27 13:11:04 -0800 | [diff] [blame] | 86 | httpUri: flutterDevices.first.vmService.httpAddress, |
| 87 | wsUri: flutterDevices.first.vmService.wsAddress, |
Dan Rubel | a9584e1 | 2016-11-30 20:29:04 -0500 | [diff] [blame] | 88 | )); |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 89 | } |
| 90 | |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 91 | globals.printTrace('Application running.'); |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 92 | |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 93 | for (final FlutterDevice device in flutterDevices) { |
Jonah Williams | 598f2ab | 2019-11-27 13:11:04 -0800 | [diff] [blame] | 94 | if (device.vmService == null) { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 95 | continue; |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 96 | } |
Jonah Williams | 3778798 | 2020-03-10 11:34:40 -0700 | [diff] [blame] | 97 | await device.initLogReader(); |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 98 | await device.refreshViews(); |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 99 | globals.printTrace('Connected to ${device.device.name}'); |
Jason Simmons | 073f64d | 2016-08-18 06:38:35 -0700 | [diff] [blame] | 100 | } |
John McCutchan | 3a012b3 | 2016-08-17 09:01:04 -0700 | [diff] [blame] | 101 | |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 102 | if (traceStartup) { |
| 103 | // Only trace startup for the first device. |
| 104 | final FlutterDevice device = flutterDevices.first; |
Jonah Williams | 598f2ab | 2019-11-27 13:11:04 -0800 | [diff] [blame] | 105 | if (device.vmService != null) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 106 | globals.printStatus('Tracing startup on ${device.device.name}.'); |
Ian Hickson | 31a9626 | 2019-01-19 00:31:05 -0800 | [diff] [blame] | 107 | await downloadStartupTrace( |
Jonah Williams | 598f2ab | 2019-11-27 13:11:04 -0800 | [diff] [blame] | 108 | device.vmService, |
Ian Hickson | 31a9626 | 2019-01-19 00:31:05 -0800 | [diff] [blame] | 109 | awaitFirstFrame: awaitFirstFrameWhenTracing, |
| 110 | ); |
Yegor | a0aa0ed | 2016-08-09 14:12:15 -0700 | [diff] [blame] | 111 | } |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 112 | appFinished(); |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Dan Rubel | 1f1adca | 2016-11-03 14:29:56 -0400 | [diff] [blame] | 115 | appStartedCompleter?.complete(); |
| 116 | |
Jonah Williams | e22d4aa | 2019-10-15 13:05:47 -0700 | [diff] [blame] | 117 | writeVmserviceFile(); |
| 118 | |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 119 | if (stayResident && !traceStartup) { |
Ian Hickson | f888bbe | 2017-01-27 01:03:04 -0800 | [diff] [blame] | 120 | return waitForAppToFinish(); |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 121 | } |
Ian Hickson | f888bbe | 2017-01-27 01:03:04 -0800 | [diff] [blame] | 122 | await cleanupAtFinish(); |
| 123 | return 0; |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 124 | } |
| 125 | |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 126 | @override |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 127 | Future<int> attach({ |
| 128 | Completer<DebugConnectionInfo> connectionInfoCompleter, |
| 129 | Completer<void> appStartedCompleter, |
| 130 | }) async { |
| 131 | _didAttach = true; |
| 132 | try { |
| 133 | await connectToServiceProtocol(); |
Zachary Anderson | 6c408a0 | 2020-03-06 10:22:12 -0800 | [diff] [blame] | 134 | } on Exception catch (error) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 135 | globals.printError('Error connecting to the service protocol: $error'); |
Emmanuel Garcia | 80ee3dd | 2019-08-02 16:02:02 -0700 | [diff] [blame] | 136 | // https://github.com/flutter/flutter/issues/33050 |
| 137 | // TODO(blasten): Remove this check once https://issuetracker.google.com/issues/132325318 has been fixed. |
| 138 | if (await hasDeviceRunningAndroidQ(flutterDevices) && |
| 139 | error.toString().contains(kAndroidQHttpConnectionClosedExp)) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 140 | globals.printStatus('🔨 If you are using an emulator running Android Q Beta, consider using an emulator running API level 29 or lower.'); |
| 141 | globals.printStatus('Learn more about the status of this issue on https://issuetracker.google.com/issues/132325318'); |
Emmanuel Garcia | 80ee3dd | 2019-08-02 16:02:02 -0700 | [diff] [blame] | 142 | } |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 143 | return 2; |
| 144 | } |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 145 | for (final FlutterDevice device in flutterDevices) { |
Jonah Williams | 3778798 | 2020-03-10 11:34:40 -0700 | [diff] [blame] | 146 | await device.initLogReader(); |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 147 | } |
| 148 | await refreshViews(); |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 149 | for (final FlutterDevice device in flutterDevices) { |
| 150 | for (final FlutterView view in device.views) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 151 | globals.printTrace('Connected to $view.'); |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 152 | } |
| 153 | } |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 154 | appStartedCompleter?.complete(); |
| 155 | if (stayResident) { |
| 156 | return waitForAppToFinish(); |
| 157 | } |
| 158 | await cleanupAtFinish(); |
| 159 | return 0; |
| 160 | } |
| 161 | |
| 162 | @override |
Alexandre Ardhuin | 2d3ff10 | 2018-10-05 07:54:56 +0200 | [diff] [blame] | 163 | Future<void> cleanupAfterSignal() async { |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 164 | await stopEchoingDeviceLog(); |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 165 | if (_didAttach) { |
| 166 | appFinished(); |
Jonah Williams | 830c0df | 2019-01-18 10:09:44 -0800 | [diff] [blame] | 167 | } |
Zachary Anderson | 5555725 | 2019-06-06 11:16:19 -0700 | [diff] [blame] | 168 | await exitApp(); |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 169 | } |
| 170 | |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 171 | @override |
Alexandre Ardhuin | 2d3ff10 | 2018-10-05 07:54:56 +0200 | [diff] [blame] | 172 | Future<void> cleanupAtFinish() async { |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 173 | for (final FlutterDevice flutterDevice in flutterDevices) { |
Zachary Anderson | 99684ce | 2019-12-05 08:48:00 -0800 | [diff] [blame] | 174 | await flutterDevice.device.dispose(); |
Christopher Fujino | 428d7d7 | 2019-10-15 12:50:44 -0700 | [diff] [blame] | 175 | } |
| 176 | |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 177 | await stopEchoingDeviceLog(); |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 178 | } |
| 179 | |
John McCutchan | 81b4e82 | 2016-08-05 12:04:33 -0700 | [diff] [blame] | 180 | @override |
Ian Hickson | a33b70e | 2016-10-31 21:57:59 -0700 | [diff] [blame] | 181 | void printHelp({ @required bool details }) { |
Zachary Anderson | 23ce192 | 2020-01-09 08:18:03 -0800 | [diff] [blame] | 182 | globals.printStatus('Flutter run key commands.'); |
| 183 | if (supportsServiceProtocol) { |
| 184 | if (details) { |
| 185 | printHelpDetails(); |
| 186 | } |
| 187 | } |
Zachary Anderson | 4d096c4 | 2020-01-10 16:53:01 -0800 | [diff] [blame] | 188 | commandHelp.h.print(); |
Zachary Anderson | 23ce192 | 2020-01-09 08:18:03 -0800 | [diff] [blame] | 189 | if (_didAttach) { |
Zachary Anderson | 4d096c4 | 2020-01-10 16:53:01 -0800 | [diff] [blame] | 190 | commandHelp.d.print(); |
Zachary Anderson | 23ce192 | 2020-01-09 08:18:03 -0800 | [diff] [blame] | 191 | } |
Levi Lesches | 149e062 | 2020-02-06 18:53:04 -0500 | [diff] [blame] | 192 | commandHelp.c.print(); |
Zachary Anderson | 4d096c4 | 2020-01-10 16:53:01 -0800 | [diff] [blame] | 193 | commandHelp.q.print(); |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 194 | for (final FlutterDevice device in flutterDevices) { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 195 | final String dname = device.device.name; |
Jonah Williams | 598f2ab | 2019-11-27 13:11:04 -0800 | [diff] [blame] | 196 | if (device.vmService != null) { |
Zachary Anderson | 23ce192 | 2020-01-09 08:18:03 -0800 | [diff] [blame] | 197 | // Caution: This log line is parsed by device lab tests. |
| 198 | globals.printStatus( |
| 199 | 'An Observatory debugger and profiler on $dname is available at: ' |
| 200 | '${device.vmService.httpAddress}', |
| 201 | ); |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 202 | } |
| 203 | } |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 204 | } |
Devon Carew | e6da16b | 2016-11-01 13:01:03 -0700 | [diff] [blame] | 205 | |
| 206 | @override |
Zachary Anderson | 5555725 | 2019-06-06 11:16:19 -0700 | [diff] [blame] | 207 | Future<void> preExit() async { |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 208 | for (final FlutterDevice device in flutterDevices) { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 209 | // If we're running in release mode, stop the app using the device logic. |
Jonah Williams | 598f2ab | 2019-11-27 13:11:04 -0800 | [diff] [blame] | 210 | if (device.vmService == null) { |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 211 | await device.device.stopApp(device.package); |
Zachary Anderson | e2340c6 | 2019-09-13 14:51:35 -0700 | [diff] [blame] | 212 | } |
Zachary Anderson | 0770c3c | 2017-04-26 21:49:38 -0700 | [diff] [blame] | 213 | } |
Jonah Williams | 6d37867 | 2019-09-11 12:57:43 -0700 | [diff] [blame] | 214 | await super.preExit(); |
Devon Carew | e6da16b | 2016-11-01 13:01:03 -0700 | [diff] [blame] | 215 | } |
Devon Carew | 3ba1713 | 2016-06-07 12:13:35 -0700 | [diff] [blame] | 216 | } |