Unverified Commit f4d1bfed authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate tracing to null safety (#92849)

parent 9038fac9
...@@ -2,11 +2,8 @@ ...@@ -2,11 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart';
import 'package:vm_service/vm_service.dart' as vm_service; import 'package:vm_service/vm_service.dart' as vm_service;
import 'base/common.dart'; import 'base/common.dart';
...@@ -24,8 +21,8 @@ const String kFirstFrameRasterizedEventName = 'Rasterized first useful frame'; ...@@ -24,8 +21,8 @@ const String kFirstFrameRasterizedEventName = 'Rasterized first useful frame';
class Tracing { class Tracing {
Tracing({ Tracing({
@required this.vmService, required this.vmService,
@required Logger logger, required Logger logger,
}) : _logger = logger; }) : _logger = logger;
static const String firstUsefulFrameEventName = kFirstFrameRasterizedEventName; static const String firstUsefulFrameEventName = kFirstFrameRasterizedEventName;
...@@ -39,7 +36,7 @@ class Tracing { ...@@ -39,7 +36,7 @@ class Tracing {
} }
/// Stops tracing; optionally wait for first frame. /// Stops tracing; optionally wait for first frame.
Future<Map<String, dynamic>> stopTracingAndDownloadTimeline({ Future<Map<String, Object?>> stopTracingAndDownloadTimeline({
bool awaitFirstFrame = false, bool awaitFirstFrame = false,
}) async { }) async {
if (awaitFirstFrame) { if (awaitFirstFrame) {
...@@ -62,9 +59,10 @@ class Tracing { ...@@ -62,9 +59,10 @@ class Tracing {
bool done = false; bool done = false;
final List<FlutterView> views = await vmService.getFlutterViews(); final List<FlutterView> views = await vmService.getFlutterViews();
for (final FlutterView view in views) { for (final FlutterView view in views) {
if (await vmService final String? uiIsolateId = view.uiIsolate?.id;
if (uiIsolateId != null && await vmService
.flutterAlreadyPaintedFirstUsefulFrame( .flutterAlreadyPaintedFirstUsefulFrame(
isolateId: view.uiIsolate.id, isolateId: uiIsolateId,
)) { )) {
done = true; done = true;
break; break;
...@@ -80,14 +78,15 @@ class Tracing { ...@@ -80,14 +78,15 @@ class Tracing {
} }
status.stop(); status.stop();
} }
final vm_service.Response timeline = await vmService.getTimeline(); final vm_service.Response? timeline = await vmService.getTimeline();
await vmService.setTimelineFlags(<String>[]); await vmService.setTimelineFlags(<String>[]);
if (timeline == null) { final Map<String, Object?>? timelineJson = timeline?.json;
if (timelineJson == null) {
throwToolExit( throwToolExit(
'The device disconnected before the timeline could be retrieved.', 'The device disconnected before the timeline could be retrieved.',
); );
} }
return timeline.json; return timelineJson;
} }
} }
...@@ -95,8 +94,8 @@ class Tracing { ...@@ -95,8 +94,8 @@ class Tracing {
/// store it to `$output/start_up_info.json`. /// store it to `$output/start_up_info.json`.
Future<void> downloadStartupTrace(FlutterVmService vmService, { Future<void> downloadStartupTrace(FlutterVmService vmService, {
bool awaitFirstFrame = true, bool awaitFirstFrame = true,
@required Logger logger, required Logger logger,
@required Directory output, required Directory output,
}) async { }) async {
final File traceInfoFile = output.childFile('start_up_info.json'); final File traceInfoFile = output.childFile('start_up_info.json');
...@@ -110,33 +109,39 @@ Future<void> downloadStartupTrace(FlutterVmService vmService, { ...@@ -110,33 +109,39 @@ Future<void> downloadStartupTrace(FlutterVmService vmService, {
final Tracing tracing = Tracing(vmService: vmService, logger: logger); final Tracing tracing = Tracing(vmService: vmService, logger: logger);
final Map<String, dynamic> timeline = await tracing.stopTracingAndDownloadTimeline( final Map<String, Object?> timeline = await tracing.stopTracingAndDownloadTimeline(
awaitFirstFrame: awaitFirstFrame, awaitFirstFrame: awaitFirstFrame,
); );
final File traceTimelineFile = output.childFile('start_up_timeline.json'); final File traceTimelineFile = output.childFile('start_up_timeline.json');
traceTimelineFile.writeAsStringSync(toPrettyJson(timeline)); traceTimelineFile.writeAsStringSync(toPrettyJson(timeline));
int extractInstantEventTimestamp(String eventName) { int? extractInstantEventTimestamp(String eventName) {
final List<Map<String, dynamic>> events = final List<Object?>? traceEvents = timeline['traceEvents'] as List<Object?>?;
List<Map<String, dynamic>>.from(timeline['traceEvents'] as List<dynamic>); if (traceEvents == null) {
final Map<String, dynamic> event = events.firstWhere( return null;
(Map<String, dynamic> event) => event['name'] == eventName, orElse: () => null, }
); final List<Map<String, Object?>> events = List<Map<String, Object?>>.from(traceEvents);
return event == null ? null : (event['ts'] as int); Map<String, Object?>? matchedEvent;
for (final Map<String, Object?> event in events) {
if (event['name'] == eventName) {
matchedEvent = event;
}
}
return matchedEvent == null ? null : (matchedEvent['ts'] as int?);
} }
String message = 'No useful metrics were gathered.'; String message = 'No useful metrics were gathered.';
final int engineEnterTimestampMicros = extractInstantEventTimestamp(kFlutterEngineMainEnterEventName); final int? engineEnterTimestampMicros = extractInstantEventTimestamp(kFlutterEngineMainEnterEventName);
final int frameworkInitTimestampMicros = extractInstantEventTimestamp(kFrameworkInitEventName); final int? frameworkInitTimestampMicros = extractInstantEventTimestamp(kFrameworkInitEventName);
if (engineEnterTimestampMicros == null) { if (engineEnterTimestampMicros == null) {
logger.printTrace('Engine start event is missing in the timeline: $timeline'); logger.printTrace('Engine start event is missing in the timeline: $timeline');
throwToolExit('Engine start event is missing in the timeline. Cannot compute startup time.'); throwToolExit('Engine start event is missing in the timeline. Cannot compute startup time.');
} }
final Map<String, dynamic> traceInfo = <String, dynamic>{ final Map<String, Object?> traceInfo = <String, Object?>{
'engineEnterTimestampMicros': engineEnterTimestampMicros, 'engineEnterTimestampMicros': engineEnterTimestampMicros,
}; };
...@@ -147,8 +152,8 @@ Future<void> downloadStartupTrace(FlutterVmService vmService, { ...@@ -147,8 +152,8 @@ Future<void> downloadStartupTrace(FlutterVmService vmService, {
} }
if (awaitFirstFrame) { if (awaitFirstFrame) {
final int firstFrameBuiltTimestampMicros = extractInstantEventTimestamp(kFirstFrameBuiltEventName); final int? firstFrameBuiltTimestampMicros = extractInstantEventTimestamp(kFirstFrameBuiltEventName);
final int firstFrameRasterizedTimestampMicros = extractInstantEventTimestamp(kFirstFrameRasterizedEventName); final int? firstFrameRasterizedTimestampMicros = extractInstantEventTimestamp(kFirstFrameRasterizedEventName);
if (firstFrameBuiltTimestampMicros == null || firstFrameRasterizedTimestampMicros == null) { if (firstFrameBuiltTimestampMicros == null || firstFrameRasterizedTimestampMicros == null) {
logger.printTrace('First frame events are missing in the timeline: $timeline'); logger.printTrace('First frame events are missing in the timeline: $timeline');
throwToolExit('First frame events are missing in the timeline. Cannot compute startup time.'); throwToolExit('First frame events are missing in the timeline. Cannot compute startup time.');
......
...@@ -402,7 +402,7 @@ class FlutterView { ...@@ -402,7 +402,7 @@ class FlutterView {
required this.uiIsolate, required this.uiIsolate,
}); });
factory FlutterView.parse(Map<String, Object> json) { factory FlutterView.parse(Map<String, Object?> json) {
final Map<String, Object?>? rawIsolate = json['isolate'] as Map<String, Object?>?; final Map<String, Object?>? rawIsolate = json['isolate'] as Map<String, Object?>?;
vm_service.IsolateRef? isolate; vm_service.IsolateRef? isolate;
if (rawIsolate != null) { if (rawIsolate != null) {
...@@ -822,11 +822,11 @@ class FlutterVmService { ...@@ -822,11 +822,11 @@ class FlutterVmService {
// with cleaning up. // with cleaning up.
return <FlutterView>[]; return <FlutterView>[];
} }
final List<Object>? rawViews = response.json?['views'] as List<Object>?; final List<Object?>? rawViews = response.json?['views'] as List<Object?>?;
final List<FlutterView> views = <FlutterView>[ final List<FlutterView> views = <FlutterView>[
if (rawViews != null) if (rawViews != null)
for (final Object rawView in rawViews) for (final Map<String, Object?> rawView in rawViews.whereType<Map<String, Object?>>())
FlutterView.parse(rawView as Map<String, Object>) FlutterView.parse(rawView)
]; ];
if (views.isNotEmpty || returnEarly) { if (views.isNotEmpty || returnEarly) {
return views; return views;
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart'; import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -90,19 +88,19 @@ void main() { ...@@ -90,19 +88,19 @@ void main() {
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFlutterEngineMainEnterEventName, 'name': kFlutterEngineMainEnterEventName,
'ts': 0, 'ts': 0,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFrameworkInitEventName, 'name': kFrameworkInitEventName,
'ts': 1, 'ts': 1,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFirstFrameBuiltEventName, 'name': kFirstFrameBuiltEventName,
'ts': 2, 'ts': 2,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFirstFrameRasterizedEventName, 'name': kFirstFrameRasterizedEventName,
'ts': 3, 'ts': 3,
}), })!,
], ],
).toJson(), ).toJson(),
), ),
...@@ -197,11 +195,11 @@ void main() { ...@@ -197,11 +195,11 @@ void main() {
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFlutterEngineMainEnterEventName, 'name': kFlutterEngineMainEnterEventName,
'ts': 0, 'ts': 0,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFrameworkInitEventName, 'name': kFrameworkInitEventName,
'ts': 1, 'ts': 1,
}), })!,
], ],
).toJson(), ).toJson(),
), ),
...@@ -232,11 +230,11 @@ void main() { ...@@ -232,11 +230,11 @@ void main() {
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFlutterEngineMainEnterEventName, 'name': kFlutterEngineMainEnterEventName,
'ts': 0, 'ts': 0,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFrameworkInitEventName, 'name': kFrameworkInitEventName,
'ts': 1, 'ts': 1,
}), })!,
], ],
).toJson(), ).toJson(),
), ),
...@@ -277,19 +275,19 @@ void main() { ...@@ -277,19 +275,19 @@ void main() {
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFlutterEngineMainEnterEventName, 'name': kFlutterEngineMainEnterEventName,
'ts': 0, 'ts': 0,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFrameworkInitEventName, 'name': kFrameworkInitEventName,
'ts': 1, 'ts': 1,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFirstFrameBuiltEventName, 'name': kFirstFrameBuiltEventName,
'ts': 2, 'ts': 2,
}), })!,
vm_service.TimelineEvent.parse(<String, Object>{ vm_service.TimelineEvent.parse(<String, Object>{
'name': kFirstFrameRasterizedEventName, 'name': kFirstFrameRasterizedEventName,
'ts': 3, 'ts': 3,
}), })!,
], ],
).toJson(), ).toJson(),
), ),
...@@ -310,25 +308,25 @@ void main() { ...@@ -310,25 +308,25 @@ void main() {
logger: logger, logger: logger,
); );
final Map<String, dynamic> expectedTimeline = <String, dynamic>{ final Map<String, Object> expectedTimeline = <String, Object>{
'type': 'Timeline', 'type': 'Timeline',
'traceEvents': <dynamic>[ 'traceEvents': <Object>[
<String, dynamic>{ <String, Object>{
'name': 'FlutterEngineMainEnter', 'name': 'FlutterEngineMainEnter',
'ts': 0, 'ts': 0,
'type': 'TimelineEvent', 'type': 'TimelineEvent',
}, },
<String, dynamic>{ <String, Object>{
'name': 'Framework initialization', 'name': 'Framework initialization',
'ts': 1, 'ts': 1,
'type': 'TimelineEvent', 'type': 'TimelineEvent',
}, },
<String, dynamic>{ <String, Object>{
'name': 'Widgets built first useful frame', 'name': 'Widgets built first useful frame',
'ts': 2, 'ts': 2,
'type': 'TimelineEvent', 'type': 'TimelineEvent',
}, },
<String, dynamic>{ <String, Object>{
'name': 'Rasterized first useful frame', 'name': 'Rasterized first useful frame',
'ts': 3, 'ts': 3,
'type': 'TimelineEvent', 'type': 'TimelineEvent',
......
...@@ -26,14 +26,14 @@ class FakeVmServiceHost { ...@@ -26,14 +26,14 @@ class FakeVmServiceHost {
), httpAddress: httpAddress, wsAddress: wsAddress); ), httpAddress: httpAddress, wsAddress: wsAddress);
_applyStreamListen(); _applyStreamListen();
_output.stream.listen((String data) { _output.stream.listen((String data) {
final Map<String, Object> request = json.decode(data) as Map<String, Object>; final Map<String, Object?> request = json.decode(data) as Map<String, Object?>;
if (_requests.isEmpty) { if (_requests.isEmpty) {
throw Exception('Unexpected request: $request'); throw Exception('Unexpected request: $request');
} }
final FakeVmServiceRequest fakeRequest = _requests.removeAt(0) as FakeVmServiceRequest; final FakeVmServiceRequest fakeRequest = _requests.removeAt(0) as FakeVmServiceRequest;
expect(request, isA<Map<String, Object>>() expect(request, isA<Map<String, Object?>>()
.having((Map<String, Object> request) => request['method'], 'method', fakeRequest.method) .having((Map<String, Object?> request) => request['method'], 'method', fakeRequest.method)
.having((Map<String, Object> request) => request['params'], 'args', fakeRequest.args) .having((Map<String, Object?> request) => request['params'], 'args', fakeRequest.args)
); );
if (fakeRequest.close) { if (fakeRequest.close) {
unawaited(_vmService.dispose()); unawaited(_vmService.dispose());
...@@ -52,6 +52,7 @@ class FakeVmServiceHost { ...@@ -52,6 +52,7 @@ class FakeVmServiceHost {
'id': request['id'], 'id': request['id'],
'error': <String, Object?>{ 'error': <String, Object?>{
'code': fakeRequest.errorCode, 'code': fakeRequest.errorCode,
'message': 'error',
} }
})); }));
} }
...@@ -108,7 +109,7 @@ class FakeVmServiceRequest implements VmServiceExpectation { ...@@ -108,7 +109,7 @@ class FakeVmServiceRequest implements VmServiceExpectation {
/// standard response. /// standard response.
final int? errorCode; final int? errorCode;
final Map<String, Object>? args; final Map<String, Object>? args;
final Map<String, Object>? jsonResponse; final Map<String, Object?>? jsonResponse;
@override @override
bool get isRequest => true; bool get isRequest => true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment