@@ -29,6 +29,9 @@ class FlutterDriver {
29
29
FlutterDriver .connectedTo (this ._serviceClient, this ._appIsolate);
30
30
31
31
static const String _kFlutterExtensionMethod = 'ext.flutter_driver' ;
32
+ static const String _kStartTracingMethod = 'ext.flutter_startTracing' ;
33
+ static const String _kStopTracingMethod = 'ext.flutter_stopTracing' ;
34
+ static const String _kDownloadTraceDataMethod = 'ext.flutter_downloadTraceData' ;
32
35
static const Duration _kDefaultTimeout = const Duration (seconds: 5 );
33
36
static const Duration _kDefaultPauseBetweenRetries = const Duration (milliseconds: 160 );
34
37
@@ -205,6 +208,63 @@ class FlutterDriver {
205
208
return result.text;
206
209
}
207
210
211
+ /// Starts recording performance traces.
212
+ Future <Null > startTracing () async {
213
+ try {
214
+ await _appIsolate.invokeExtension (_kStartTracingMethod);
215
+ return null ;
216
+ } catch (error, stackTrace) {
217
+ throw new DriverError (
218
+ 'Failed to start tracing due to remote error' ,
219
+ error,
220
+ stackTrace
221
+ );
222
+ }
223
+ }
224
+
225
+ /// Stops recording performance traces and downloads the trace profile.
226
+ // TODO(yjbanov): return structured data rather than raw JSON once we have a
227
+ // stable protocol to talk to.
228
+ Future <Map <String , dynamic >> stopTracingAndDownloadProfile () async {
229
+ Map <String , dynamic > stopResult =
230
+ await _appIsolate.invokeExtension (_kStopTracingMethod);
231
+ String traceFilePath = stopResult['trace_file_path' ];
232
+
233
+ // Tracing data isn't available immediately as some of it is queued up in
234
+ // the event loop.
235
+ Stopwatch sw = new Stopwatch ()..start ();
236
+ while (sw.elapsed < const Duration (seconds: 30 )) {
237
+ Map <String , dynamic > downloadResult =
238
+ await _appIsolate.invokeExtension (_kDownloadTraceDataMethod, < String , String > {
239
+ 'trace_file_path' : traceFilePath,
240
+ });
241
+
242
+ if (downloadResult['success' ] == false )
243
+ throw new DriverError ('Failed to download trace file: $traceFilePath ' );
244
+ else if (downloadResult['status' ] != 'not ready' )
245
+ return downloadResult;
246
+
247
+ // Give the event loop a chance to flush the trace log
248
+ await new Future <Null >.delayed (const Duration (milliseconds: 200 ));
249
+ }
250
+ throw new DriverError (
251
+ 'Timed out waiting for tracing profile to become ready for download.'
252
+ );
253
+ }
254
+
255
+ /// Runs [action] and outputs a performance trace for it.
256
+ ///
257
+ /// Waits for the `Future` returned by [action] to complete prior to stopping
258
+ /// the trace.
259
+ ///
260
+ /// This is merely a convenience wrapper on top of [startTracing] and
261
+ /// [stopTracingAndDownloadProfile] .
262
+ Future <Map <String , dynamic >> traceAction (Future <dynamic > action ()) async {
263
+ await startTracing ();
264
+ await action ();
265
+ return stopTracingAndDownloadProfile ();
266
+ }
267
+
208
268
/// Calls the [evaluator] repeatedly until the result of the evaluation
209
269
/// satisfies the [matcher] .
210
270
///
0 commit comments