diff --git a/flutter/lib/src/span_frame_metrics_collector.dart b/flutter/lib/src/span_frame_metrics_collector.dart index ecf0ca961c..fae7a67428 100644 --- a/flutter/lib/src/span_frame_metrics_collector.dart +++ b/flutter/lib/src/span_frame_metrics_collector.dart @@ -12,6 +12,8 @@ import 'native/sentry_native_binding.dart'; @internal class SpanFrameMetricsCollector implements PerformanceContinuousCollector { static const _frozenFrameThresholdMs = 700; + static const _defaultRefreshRate = 60; + static const totalFramesKey = 'frames.total'; static const framesDelayKey = 'frames.delay'; static const slowFramesKey = 'frames.slow'; @@ -39,7 +41,7 @@ class SpanFrameMetricsCollector implements PerformanceContinuousCollector { bool get isTrackingRegistered => _isTrackingRegistered; bool _isTrackingRegistered = false; - int displayRefreshRate = 60; + int displayRefreshRate = _defaultRefreshRate; final _stopwatch = Stopwatch(); @@ -59,7 +61,7 @@ class SpanFrameMetricsCollector implements PerformanceContinuousCollector { } final fetchedDisplayRefreshRate = await _native?.displayRefreshRate(); - if (fetchedDisplayRefreshRate != null) { + if (fetchedDisplayRefreshRate != null && fetchedDisplayRefreshRate > 0) { options.logger(SentryLevel.debug, 'Retrieved display refresh rate at $fetchedDisplayRefreshRate'); displayRefreshRate = fetchedDisplayRefreshRate; @@ -251,6 +253,6 @@ class SpanFrameMetricsCollector implements PerformanceContinuousCollector { _isTrackingPaused = true; frames.clear(); activeSpans.clear(); - displayRefreshRate = 60; + displayRefreshRate = _defaultRefreshRate; } } diff --git a/flutter/test/span_frame_metrics_collector_test.dart b/flutter/test/span_frame_metrics_collector_test.dart index 41cb56b6d5..43c89f43c9 100644 --- a/flutter/test/span_frame_metrics_collector_test.dart +++ b/flutter/test/span_frame_metrics_collector_test.dart @@ -74,6 +74,33 @@ void main() { expect(tracer.data['frames.total'], expectedTotalFrames); }); + test( + 'captures metrics with display refresh rate of 60 if native refresh rate is 0', + () async { + final sut = fixture.sut; + fixture.options.tracesSampleRate = 1.0; + fixture.options.addPerformanceCollector(sut); + final startTimestamp = DateTime.now(); + final endTimestamp = + startTimestamp.add(Duration(milliseconds: 1000)).toUtc(); + + when(fixture.mockSentryNative.displayRefreshRate()) + .thenAnswer((_) async => 0); + + final tracer = SentryTracer( + SentryTransactionContext('name', 'op', description: 'tracerDesc'), + fixture.hub, + startTimestamp: startTimestamp); + + await Future.delayed(Duration(milliseconds: 500)); + await tracer.finish(endTimestamp: endTimestamp); + + expect(tracer.data['frames.slow'], expectedSlowFrames); + expect(tracer.data['frames.frozen'], expectedFrozenFrames); + expect(tracer.data['frames.delay'], expectedFramesDelay); + expect(tracer.data['frames.total'], expectedTotalFrames); + }); + test('onSpanFinished removes frames older than span start timestamp', () async { // Using multiple spans to test frame removal. When the last span is finished,