Skip to content

Commit 67c817b

Browse files
Merge pull request #613 from Instabug/feat/screen-render-testing
feat/screen-render-testing
2 parents 2266836 + a49ae10 commit 67c817b

File tree

8 files changed

+70
-109
lines changed

8 files changed

+70
-109
lines changed

example/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ target 'Runner' do
3030

3131
use_frameworks!
3232
use_modular_headers!
33-
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec'
33+
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec'
3434
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
3535
end
3636

example/ios/Podfile.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
PODS:
22
- Flutter (1.0.0)
3-
- Instabug (15.1.13)
3+
- Instabug (15.1.17)
44
- instabug_flutter (14.3.0):
55
- Flutter
6-
- Instabug (= 15.1.13)
6+
- Instabug (= 15.1.17)
77
- OCMock (3.6)
88

99
DEPENDENCIES:
1010
- Flutter (from `Flutter`)
11-
- Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec`)
11+
- Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec`)
1212
- instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`)
1313
- OCMock (= 3.6)
1414

@@ -20,16 +20,16 @@ EXTERNAL SOURCES:
2020
Flutter:
2121
:path: Flutter
2222
Instabug:
23-
:podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec
23+
:podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec
2424
instabug_flutter:
2525
:path: ".symlinks/plugins/instabug_flutter/ios"
2626

2727
SPEC CHECKSUMS:
2828
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
29-
Instabug: 697dc090bbdb9b99a9a91758558f8a2014ee5725
30-
instabug_flutter: 1093324eaca70f9d310a4bc7f1f3537c746c1d6c
29+
Instabug: 316559a02c9b752a3854a6453c2fa414d36252f3
30+
instabug_flutter: 7ae7f3d1c47b9a699e76a7358b6a3e818a253ac3
3131
OCMock: 5ea90566be239f179ba766fd9fbae5885040b992
3232

33-
PODFILE CHECKSUM: 509cc3728286920762d8cbecfac090a3af93635d
33+
PODFILE CHECKSUM: 8f3e14dab36cc02b0a8767c3086e109fadaa55f3
3434

3535
COCOAPODS: 1.15.2

ios/instabug_flutter.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ Pod::Spec.new do |s|
1717
s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'}
1818

1919
s.dependency 'Flutter'
20-
s.dependency 'Instabug', '15.1.13'
20+
s.dependency 'Instabug', '15.1.17'
2121
end
2222

lib/src/modules/apm.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,10 @@ class APM {
392392
///
393393
/// Returns:
394394
/// A Future<void> is being returned.
395-
static Future<void> setScreenRenderEnabled(bool isEnabled) {
396-
return _host.setScreenRenderEnabled(isEnabled).then((_) {
395+
static Future<void> setScreenRenderEnabled(bool isEnabled) async {
396+
return _host.setScreenRenderEnabled(isEnabled).then((_) async {
397397
if (isEnabled) {
398-
InstabugScreenRenderManager.I.init(WidgetsBinding.instance);
398+
await InstabugScreenRenderManager.I.init(WidgetsBinding.instance);
399399
} else {
400400
InstabugScreenRenderManager.I.dispose();
401401
}

lib/src/modules/instabug.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ import 'package:instabug_flutter/src/utils/feature_flags_manager.dart';
2323
import 'package:instabug_flutter/src/utils/ibg_build_info.dart';
2424
import 'package:instabug_flutter/src/utils/instabug_logger.dart';
2525
import 'package:instabug_flutter/src/utils/screen_name_masker.dart';
26-
import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart';
2726
import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart';
28-
import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart';
2927
import 'package:meta/meta.dart';
3028

3129
enum InvocationEvent {
@@ -198,10 +196,6 @@ class Instabug {
198196
debugLogsLevel.toString(),
199197
);
200198

201-
if (await FlagsConfig.screenRendering.isEnabled()) {
202-
InstabugScreenRenderManager.I.init(WidgetsBinding.instance);
203-
}
204-
205199
return FeatureFlagsManager().registerW3CFlagsListener();
206200
}
207201

lib/src/utils/instabug_navigator_observer.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,18 @@ class InstabugNavigatorObserver extends NavigatorObserver {
6666
}
6767

6868
FutureOr<void> _startScreenRenderCollector(int? uiTraceId) async {
69-
final isScreenRender = await FlagsConfig.screenRendering.isEnabled();
70-
_checkForScreenRenderInitialization(isScreenRender);
71-
if (uiTraceId != null && isScreenRender) {
69+
final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled();
70+
await _checkForScreenRenderInitialization(isScreenRenderEnabled);
71+
if (uiTraceId != null && isScreenRenderEnabled) {
7272
InstabugScreenRenderManager.I
7373
.startScreenRenderCollectorForTraceId(uiTraceId);
7474
}
7575
}
7676

77-
void _checkForScreenRenderInitialization(bool isScreenRender) {
77+
Future<void> _checkForScreenRenderInitialization(bool isScreenRender) async {
7878
if (isScreenRender) {
7979
if (!InstabugScreenRenderManager.I.screenRenderEnabled) {
80-
InstabugScreenRenderManager.I.init(WidgetsBinding.instance);
80+
await InstabugScreenRenderManager.I.init(WidgetsBinding.instance);
8181
}
8282
} else {
8383
if (InstabugScreenRenderManager.I.screenRenderEnabled) {

lib/src/utils/screen_rendering/instabug_screen_render_manager.dart

Lines changed: 48 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'dart:async';
2-
import 'dart:ui';
2+
import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase;
33

44
import 'package:flutter/widgets.dart';
55
import 'package:instabug_flutter/src/models/instabug_frame_data.dart';
@@ -18,14 +18,14 @@ enum UiTraceType {
1818
@internal
1919
class InstabugScreenRenderManager {
2020
WidgetsBinding? _widgetsBinding;
21-
late int _buildTime;
22-
late int _rasterTime;
23-
late int _totalTime;
21+
late int _buildTimeMs;
22+
late int _rasterTimeMs;
23+
late int _totalTimeMs;
2424
late TimingsCallback _timingsCallback;
2525
late InstabugScreenRenderData _screenRenderForAutoUiTrace;
2626
late InstabugScreenRenderData _screenRenderForCustomUiTrace;
27-
int _slowFramesTotalDurationMs = 0;
28-
int _frozenFramesTotalDurationMs = 0;
27+
int _slowFramesTotalDurationMicro = 0;
28+
int _frozenFramesTotalDurationMicro = 0;
2929
int? _epochOffset;
3030
bool _isTimingsListenerAttached = false;
3131
bool screenRenderEnabled = false;
@@ -42,7 +42,7 @@ class InstabugScreenRenderManager {
4242
/// Default frozen frame threshold in milliseconds (700ms)
4343
final _frozenFrameThresholdMs = 700;
4444

45-
final _microsecondsPerMillisecond = 1000;
45+
// final _microsecondsPerMillisecond = 1000;
4646

4747
InstabugScreenRenderManager._();
4848

@@ -75,46 +75,45 @@ class InstabugScreenRenderManager {
7575
}
7676
}
7777

78-
/// analyze frame data in order to detect slow/frozen frame.
78+
/// Analyze frame data to detect slow or frozen frames efficiently.
7979
@visibleForTesting
8080
void analyzeFrameTiming(FrameTiming frameTiming) {
81-
_buildTime = frameTiming.buildDuration.inMilliseconds;
82-
_rasterTime = frameTiming.rasterDuration.inMilliseconds;
83-
_totalTime = frameTiming.totalSpan.inMilliseconds;
84-
85-
if (_isUiFrozen) {
86-
_frozenFramesTotalDurationMs += _buildTime;
87-
} else if (_isRasterFrozen) {
88-
_frozenFramesTotalDurationMs += _rasterTime;
89-
} else if (_isTotalTimeLarge) {
90-
_frozenFramesTotalDurationMs += _totalTime;
91-
}
92-
if (_isUiSlow) {
93-
_slowFramesTotalDurationMs += _buildTime;
94-
} else if (_isRasterSlow) {
95-
_slowFramesTotalDurationMs += _rasterTime;
96-
}
81+
_buildTimeMs = frameTiming.buildDuration.inMilliseconds;
82+
_rasterTimeMs = frameTiming.rasterDuration.inMilliseconds;
83+
_totalTimeMs = frameTiming.totalSpan.inMilliseconds;
9784

98-
if (_isUiDelayed) {
85+
if (_isTotalTimeLarge) {
86+
final micros = frameTiming.totalSpan.inMicroseconds;
87+
_frozenFramesTotalDurationMicro += micros;
9988
_onDelayedFrameDetected(
10089
_getMicrosecondsSinceEpoch(
101-
frameTiming.timestampInMicroseconds(FramePhase.buildStart),
90+
frameTiming.timestampInMicroseconds(FramePhase.vsyncStart),
10291
),
103-
_buildTime,
92+
micros,
10493
);
105-
} else if (_isRasterDelayed) {
94+
return;
95+
}
96+
97+
if (_isUiSlow) {
98+
final micros = frameTiming.buildDuration.inMicroseconds;
99+
_slowFramesTotalDurationMicro += micros;
106100
_onDelayedFrameDetected(
107101
_getMicrosecondsSinceEpoch(
108-
frameTiming.timestampInMicroseconds(FramePhase.rasterStart),
102+
frameTiming.timestampInMicroseconds(FramePhase.buildStart),
109103
),
110-
_rasterTime,
104+
micros,
111105
);
112-
} else if (_isTotalTimeLarge) {
106+
return;
107+
}
108+
109+
if (_isRasterSlow) {
110+
final micros = frameTiming.rasterDuration.inMicroseconds;
111+
_slowFramesTotalDurationMicro += micros;
113112
_onDelayedFrameDetected(
114113
_getMicrosecondsSinceEpoch(
115-
frameTiming.timestampInMicroseconds(FramePhase.vsyncStart),
114+
frameTiming.timestampInMicroseconds(FramePhase.rasterStart),
116115
),
117-
_totalTime,
116+
micros,
118117
);
119118
}
120119
}
@@ -215,23 +214,15 @@ class InstabugScreenRenderManager {
215214

216215
/// --------------------------- private methods ---------------------
217216
218-
bool get _isUiDelayed => _isUiSlow || _isUiFrozen;
219-
220-
bool get _isRasterDelayed => _isRasterSlow || _isRasterFrozen;
221-
222217
bool get _isUiSlow =>
223-
_buildTime > _slowFrameThresholdMs &&
224-
_buildTime < _frozenFrameThresholdMs;
218+
_buildTimeMs > _slowFrameThresholdMs &&
219+
_buildTimeMs < _frozenFrameThresholdMs;
225220

226221
bool get _isRasterSlow =>
227-
_rasterTime > _slowFrameThresholdMs &&
228-
_rasterTime < _frozenFrameThresholdMs;
229-
230-
bool get _isTotalTimeLarge => _totalTime >= _frozenFrameThresholdMs;
231-
232-
bool get _isUiFrozen => _buildTime >= _frozenFrameThresholdMs;
222+
_rasterTimeMs > _slowFrameThresholdMs &&
223+
_rasterTimeMs < _frozenFrameThresholdMs;
233224

234-
bool get _isRasterFrozen => _rasterTime >= _frozenFrameThresholdMs;
225+
bool get _isTotalTimeLarge => _totalTimeMs >= _frozenFrameThresholdMs;
235226

236227
/// Calculate the target time for the frame to be drawn in milliseconds based on the device refresh rate.
237228
double _targetMsPerFrame(double displayRefreshRate) =>
@@ -302,18 +293,17 @@ class InstabugScreenRenderManager {
302293

303294
/// Reset the memory cashed data
304295
void _resetCachedFrameData() {
305-
_slowFramesTotalDurationMs = 0;
306-
_frozenFramesTotalDurationMs = 0;
296+
_slowFramesTotalDurationMicro = 0;
297+
_frozenFramesTotalDurationMicro = 0;
307298
_delayedFrames.clear();
308299
}
309300

310301
/// Save Slow/Frozen Frames data
311-
void _onDelayedFrameDetected(int startTime, int durationInMilliseconds) {
302+
void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) {
312303
_delayedFrames.add(
313304
InstabugFrameData(
314305
startTime,
315-
durationInMilliseconds *
316-
_microsecondsPerMillisecond, // Convert duration from milliseconds to microSeconds
306+
durationInMicroseconds,
317307
),
318308
);
319309
}
@@ -342,8 +332,8 @@ class InstabugScreenRenderManager {
342332
try {
343333
// Save the end time for the running ui trace, it's only needed in Android SDK.
344334
screenRenderData.saveEndTime();
345-
346335
await APM.endScreenRenderForAutoUiTrace(screenRenderData);
336+
347337
return true;
348338
} catch (error, stackTrace) {
349339
_logExceptionErrorAndStackTrace(error, stackTrace);
@@ -370,9 +360,9 @@ class InstabugScreenRenderManager {
370360
/// or synced with the native side.
371361
void _updateCustomUiData() {
372362
_screenRenderForCustomUiTrace.slowFramesTotalDurationMicro +=
373-
_slowFramesTotalDurationMs * _microsecondsPerMillisecond;
363+
_slowFramesTotalDurationMicro;
374364
_screenRenderForCustomUiTrace.frozenFramesTotalDurationMicro +=
375-
_frozenFramesTotalDurationMs * _microsecondsPerMillisecond;
365+
_frozenFramesTotalDurationMicro;
376366
_screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames);
377367
}
378368

@@ -385,9 +375,9 @@ class InstabugScreenRenderManager {
385375
/// or synced with the native side.
386376
void _updateAutoUiData() {
387377
_screenRenderForAutoUiTrace.slowFramesTotalDurationMicro +=
388-
_slowFramesTotalDurationMs * _microsecondsPerMillisecond;
378+
_slowFramesTotalDurationMicro;
389379
_screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro +=
390-
_frozenFramesTotalDurationMs * _microsecondsPerMillisecond;
380+
_frozenFramesTotalDurationMicro;
391381
_screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames);
392382
}
393383

@@ -426,9 +416,7 @@ class InstabugScreenRenderManager {
426416
@visibleForTesting
427417
void setFrameData(InstabugScreenRenderData data) {
428418
_delayedFrames.addAll(data.frameData);
429-
_frozenFramesTotalDurationMs =
430-
data.frozenFramesTotalDurationMicro ~/ _microsecondsPerMillisecond;
431-
_slowFramesTotalDurationMs =
432-
data.slowFramesTotalDurationMicro ~/ _microsecondsPerMillisecond;
419+
_frozenFramesTotalDurationMicro = data.frozenFramesTotalDurationMicro;
420+
_slowFramesTotalDurationMicro = data.slowFramesTotalDurationMicro;
433421
}
434422
}

test/utils/screen_render/instabug_screen_render_manager_test.dart

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -380,40 +380,19 @@ void main() {
380380
});
381381

382382
test(
383-
'should detect frozen frame on build thread when durations are greater than or equal 700 ms',
383+
'should detect frozen frame when durations are greater than or equal 700 ms',
384384
() {
385-
const buildDuration = 700;
386-
when(mockFrameTiming.buildDuration)
387-
.thenReturn(const Duration(milliseconds: buildDuration));
388-
manager.startScreenRenderCollectorForTraceId(1); // start new collector
389-
manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing
390-
manager.stopScreenRenderCollector(); // should save data
391-
392-
expect(manager.screenRenderForAutoUiTrace.frameData.length, 1);
393-
expect(
394-
manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro,
395-
buildDuration * 1000,
396-
); // * 1000 to convert from milliseconds to microseconds
397-
expect(
398-
manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro,
399-
0,
400-
);
401-
});
402-
403-
test(
404-
'should detect frozen frame on raster thread when durations are greater than or equal 700 ms',
405-
() {
406-
const rasterBuild = 700;
407-
when(mockFrameTiming.buildDuration)
408-
.thenReturn(const Duration(milliseconds: rasterBuild));
385+
const totalTime = 700;
386+
when(mockFrameTiming.totalSpan)
387+
.thenReturn(const Duration(milliseconds: totalTime));
409388
manager.startScreenRenderCollectorForTraceId(1); // start new collector
410389
manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing
411390
manager.stopScreenRenderCollector(); // should save data
412391

413392
expect(manager.screenRenderForAutoUiTrace.frameData.length, 1);
414393
expect(
415394
manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro,
416-
rasterBuild * 1000,
395+
totalTime * 1000,
417396
); // * 1000 to convert from milliseconds to microseconds
418397
expect(
419398
manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro,

0 commit comments

Comments
 (0)