@@ -37,21 +37,8 @@ class VMServiceFlutterDriver extends FlutterDriver {
37
37
bool logCommunicationToFile = true ,
38
38
}) : _printCommunication = printCommunication,
39
39
_logCommunicationToFile = logCommunicationToFile,
40
- _isolateSubscription = _initIsolateHandler (_serviceClient),
41
40
_driverId = _nextDriverId++ ;
42
41
43
- // The Dart VM may be running with --pause-isolates-on-start.
44
- // Set a listener to unpause new isolates as they are ready to run,
45
- // otherwise they'll hang indefinitely.
46
- static StreamSubscription <VMIsolateRef > _initIsolateHandler (
47
- VMServiceClient serviceClient) {
48
- return serviceClient.onIsolateRunnable.listen (
49
- (VMIsolateRef isolateRef) async {
50
- await _resumeLeniently (isolateRef);
51
- }
52
- );
53
- }
54
-
55
42
/// Connects to a Flutter application.
56
43
///
57
44
/// See [FlutterDriver.connect] for more documentation.
@@ -113,12 +100,9 @@ class VMServiceFlutterDriver extends FlutterDriver {
113
100
null ? vm.isolates.first :
114
101
vm.isolates.firstWhere (
115
102
(VMIsolateRef isolate) => isolate.number == isolateNumber);
116
-
117
103
_log ('Isolate found with number: ${isolateRef .number }' );
118
- // There is a race condition here, the isolate may have been destroyed before
119
- // we get around to loading it.
104
+
120
105
VMIsolate isolate = await isolateRef.loadRunnable ();
121
- _log ('Loaded isolate: ${isolate .number }' );
122
106
123
107
// TODO(yjbanov): vm_service_client does not support "None" pause event yet.
124
108
// It is currently reported as null, but we cannot rely on it because
@@ -133,22 +117,9 @@ class VMServiceFlutterDriver extends FlutterDriver {
133
117
isolate.pauseEvent is ! VMPauseExceptionEvent &&
134
118
isolate.pauseEvent is ! VMPauseInterruptedEvent &&
135
119
isolate.pauseEvent is ! VMResumeEvent ) {
136
- _log ('Reloading first isolate.' );
137
120
isolate = await isolateRef.loadRunnable ();
138
- _log ('Reloaded first isolate.' );
139
121
}
140
122
141
- // Tells the Dart VM Service to notify us about "Isolate" events.
142
- //
143
- // This is a workaround for an issue in package:vm_service_client, which
144
- // subscribes to the "Isolate" stream lazily upon subscription, which
145
- // results in lost events.
146
- //
147
- // Details: https://github.com/dart-lang/vm_service_client/issues/17
148
- await connection.peer.sendRequest ('streamListen' , < String , String > {
149
- 'streamId' : 'Isolate' ,
150
- });
151
-
152
123
final VMServiceFlutterDriver driver = VMServiceFlutterDriver .connectedTo (
153
124
client, connection.peer, isolate,
154
125
printCommunication: printCommunication,
@@ -157,6 +128,27 @@ class VMServiceFlutterDriver extends FlutterDriver {
157
128
158
129
driver._dartVmReconnectUrl = dartVmServiceUrl;
159
130
131
+ // Attempts to resume the isolate, but does not crash if it fails because
132
+ // the isolate is already resumed. There could be a race with other tools,
133
+ // such as a debugger, any of which could have resumed the isolate.
134
+ Future <dynamic > resumeLeniently () {
135
+ _log ('Attempting to resume isolate' );
136
+ return isolate.resume ().catchError ((dynamic e) {
137
+ const int vmMustBePausedCode = 101 ;
138
+ if (e is rpc.RpcException && e.code == vmMustBePausedCode) {
139
+ // No biggie; something else must have resumed the isolate
140
+ _log (
141
+ 'Attempted to resume an already resumed isolate. This may happen '
142
+ 'when we lose a race with another tool (usually a debugger) that '
143
+ 'is connected to the same isolate.'
144
+ );
145
+ } else {
146
+ // Failed to resume due to another reason. Fail hard.
147
+ throw e;
148
+ }
149
+ });
150
+ }
151
+
160
152
/// Waits for a signal from the VM service that the extension is registered.
161
153
///
162
154
/// Looks at the list of loaded extensions for the current [isolateRef] , as
@@ -191,8 +183,42 @@ class VMServiceFlutterDriver extends FlutterDriver {
191
183
]);
192
184
}
193
185
186
+ /// Tells the Dart VM Service to notify us about "Isolate" events.
187
+ ///
188
+ /// This is a workaround for an issue in package:vm_service_client, which
189
+ /// subscribes to the "Isolate" stream lazily upon subscription, which
190
+ /// results in lost events.
191
+ ///
192
+ /// Details: https://github.com/dart-lang/vm_service_client/issues/17
193
+ Future <void > enableIsolateStreams () async {
194
+ await connection.peer.sendRequest ('streamListen' , < String , String > {
195
+ 'streamId' : 'Isolate' ,
196
+ });
197
+ }
198
+
194
199
// Attempt to resume isolate if it was paused
195
- await _resumeLeniently (isolate);
200
+ if (isolate.pauseEvent is VMPauseStartEvent ) {
201
+ _log ('Isolate is paused at start.' );
202
+
203
+ await resumeLeniently ();
204
+ } else if (isolate.pauseEvent is VMPauseExitEvent ||
205
+ isolate.pauseEvent is VMPauseBreakpointEvent ||
206
+ isolate.pauseEvent is VMPauseExceptionEvent ||
207
+ isolate.pauseEvent is VMPauseInterruptedEvent ) {
208
+ // If the isolate is paused for any other reason, assume the extension is
209
+ // already there.
210
+ _log ('Isolate is paused mid-flight.' );
211
+ await resumeLeniently ();
212
+ } else if (isolate.pauseEvent is VMResumeEvent ) {
213
+ _log ('Isolate is not paused. Assuming application is ready.' );
214
+ } else {
215
+ _log (
216
+ 'Unknown pause event type ${isolate .pauseEvent .runtimeType }. '
217
+ 'Assuming application is ready.'
218
+ );
219
+ }
220
+
221
+ await enableIsolateStreams ();
196
222
197
223
// We will never receive the extension event if the user does not register
198
224
// it. If that happens, show a message but continue waiting.
@@ -215,58 +241,6 @@ class VMServiceFlutterDriver extends FlutterDriver {
215
241
return driver;
216
242
}
217
243
218
- static bool _alreadyRunning (VMIsolate isolate) {
219
- // Expected pause events.
220
- if (isolate.pauseEvent is VMPauseStartEvent ||
221
- isolate.pauseEvent is VMPauseExitEvent ||
222
- isolate.pauseEvent is VMPauseBreakpointEvent ||
223
- isolate.pauseEvent is VMPauseExceptionEvent ||
224
- isolate.pauseEvent is VMPauseInterruptedEvent ||
225
- isolate.pauseEvent is VMNoneEvent ) {
226
- return false ;
227
- }
228
- // Already running.
229
- if (isolate.pauseEvent is VMResumeEvent ) {
230
- _log ('Isolate is not paused. Assuming application is ready.' );
231
- return true ;
232
- }
233
- _log ('Unknown pause event type ${isolate .pauseEvent .runtimeType }. '
234
- 'Assuming application is ready.' );
235
- return true ;
236
- }
237
-
238
- /// Attempts to resume the isolate, but does not crash if it fails because
239
- /// the isolate is already resumed. There could be a race with other tools,
240
- /// such as a debugger, any of which could have resumed the isolate.
241
- /// Returns the isolate if it is runnable, null otherwise.
242
- static Future <void > _resumeLeniently (VMIsolateRef isolateRef) async {
243
- try {
244
- _log ('New runnable isolate ${isolateRef .number }' );
245
- final VMIsolate isolate = await isolateRef.load ();
246
- if (_alreadyRunning (isolate)) {
247
- return ;
248
- }
249
- _log ('Attempting to resume isolate ${isolate .number }' );
250
- await isolate.resume ();
251
- _log ('Resumed isolate ${isolate .number }' );
252
- } on VMSentinelException {
253
- // Probably OK, the isolate vanished before we got to it.
254
- _log ('Failed to load isolate, proceeding.' );
255
- } on rpc.RpcException catch (e) {
256
- const int vmMustBePausedCode = 101 ;
257
- if (e.code == vmMustBePausedCode) {
258
- // No biggie; something else must have resumed the isolate
259
- _log ('Attempted to resume an already resumed isolate. This may happen '
260
- 'when we lose a race with another tool (usually a debugger) that '
261
- 'is connected to the same isolate.'
262
- );
263
- } else {
264
- // Failed to resume due to another reason. Fail hard.
265
- rethrow ;
266
- }
267
- }
268
- }
269
-
270
244
static int _nextDriverId = 0 ;
271
245
272
246
static const String _flutterExtensionMethodName = 'ext.flutter.driver' ;
@@ -301,9 +275,6 @@ class VMServiceFlutterDriver extends FlutterDriver {
301
275
/// would like to instrument.
302
276
final VMServiceClient _serviceClient;
303
277
304
- /// Subscription to isolate events happening in the app.
305
- final StreamSubscription <VMIsolateRef > _isolateSubscription;
306
-
307
278
/// JSON-RPC client useful for sending raw JSON requests.
308
279
rpc.Peer _peer;
309
280
@@ -581,7 +552,6 @@ class VMServiceFlutterDriver extends FlutterDriver {
581
552
@override
582
553
Future <void > close () async {
583
554
// Don't leak vm_service_client-specific objects, if any
584
- await _isolateSubscription.cancel ();
585
555
await _serviceClient.close ();
586
556
await _peer.close ();
587
557
}
0 commit comments