@@ -15,6 +15,9 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
15
15
final SentryNative _native;
16
16
final FrameCallbackHandler _frameCallbackHandler;
17
17
18
+ /// Timeout duration to wait for the app start info to be fetched.
19
+ static const _timeoutDuration = Duration (seconds: 30 );
20
+
18
21
/// We filter out App starts more than 60s
19
22
static const _maxAppStartMillis = 60000 ;
20
23
@@ -39,7 +42,8 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
39
42
if (_appStartInfo != null ) {
40
43
return Future .value (_appStartInfo);
41
44
}
42
- return _appStartCompleter.future;
45
+ return _appStartCompleter.future
46
+ .timeout (_timeoutDuration, onTimeout: () => null );
43
47
}
44
48
45
49
@visibleForTesting
@@ -62,31 +66,31 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
62
66
return ;
63
67
}
64
68
65
- if (options.autoAppStart) {
66
- _frameCallbackHandler.addPostFrameCallback ((timeStamp) async {
67
- if (_native.didFetchAppStart) {
68
- return ;
69
- }
69
+ if (_native.didFetchAppStart) {
70
+ return ;
71
+ }
70
72
73
+ _frameCallbackHandler.addPostFrameCallback ((timeStamp) async {
74
+ final nativeAppStart = await _native.fetchNativeAppStart ();
75
+ if (nativeAppStart == null ) {
76
+ setAppStartInfo (null );
77
+ return ;
78
+ }
79
+
80
+ final mainIsolateStartDateTime = SentryFlutter .mainIsolateStartTime;
81
+ final appStartDateTime = DateTime .fromMillisecondsSinceEpoch (
82
+ nativeAppStart.appStartTime.toInt ());
83
+ final pluginRegistrationDateTime = DateTime .fromMillisecondsSinceEpoch (
84
+ nativeAppStart.pluginRegistrationTime);
85
+ DateTime ? appStartEndDateTime;
86
+
87
+ if (options.autoAppStart) {
71
88
// We only assign the current time if it's not already set - this is useful in tests
72
89
// ignore: invalid_use_of_internal_member
73
90
_native.appStartEnd ?? = options.clock ();
74
- final appStartEndDateTime = _native.appStartEnd;
75
- final nativeAppStart = await _native.fetchNativeAppStart ();
76
- final pluginRegistrationTime = nativeAppStart? .pluginRegistrationTime;
77
- final mainIsolateStartDateTime = SentryFlutter .mainIsolateStartTime;
78
-
79
- if (nativeAppStart == null ||
80
- appStartEndDateTime == null ||
81
- pluginRegistrationTime == null ) {
82
- return ;
83
- }
91
+ appStartEndDateTime = _native.appStartEnd;
84
92
85
- final appStartDateTime = DateTime .fromMillisecondsSinceEpoch (
86
- nativeAppStart.appStartTime.toInt ());
87
- final duration = appStartEndDateTime.difference (appStartDateTime);
88
- final pluginRegistrationDateTime =
89
- DateTime .fromMillisecondsSinceEpoch (pluginRegistrationTime);
93
+ final duration = appStartEndDateTime? .difference (appStartDateTime);
90
94
91
95
// We filter out app start more than 60s.
92
96
// This could be due to many different reasons.
@@ -96,23 +100,23 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
96
100
// If the system forked the process earlier to accelerate the app start.
97
101
// And some unknown reasons that could not be reproduced.
98
102
// We've seen app starts with hours, days and even months.
99
- if (duration.inMilliseconds > _maxAppStartMillis) {
103
+ if (duration != null && duration .inMilliseconds > _maxAppStartMillis) {
100
104
setAppStartInfo (null );
101
105
return ;
102
106
}
107
+ }
103
108
104
- final appStartInfo = AppStartInfo (
105
- nativeAppStart.isColdStart ? AppStartType .cold : AppStartType .warm,
106
- start: appStartDateTime,
107
- end: appStartEndDateTime,
108
- pluginRegistration: pluginRegistrationDateTime,
109
- mainIsolateStart: mainIsolateStartDateTime);
109
+ final appStartInfo = AppStartInfo (
110
+ nativeAppStart.isColdStart ? AppStartType .cold : AppStartType .warm,
111
+ start: appStartDateTime,
112
+ end: appStartEndDateTime,
113
+ pluginRegistration: pluginRegistrationDateTime,
114
+ mainIsolateStart: mainIsolateStartDateTime);
110
115
111
- setAppStartInfo (appStartInfo);
112
- });
113
- }
116
+ setAppStartInfo (appStartInfo);
117
+ });
114
118
115
- options.addEventProcessor (NativeAppStartEventProcessor (_native));
119
+ options.addEventProcessor (NativeAppStartEventProcessor (_native, hub : hub ));
116
120
117
121
options.sdk.addIntegration ('nativeAppStartIntegration' );
118
122
}
@@ -121,21 +125,31 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
121
125
enum AppStartType { cold, warm }
122
126
123
127
class AppStartInfo {
124
- AppStartInfo (this .type,
125
- {required this .start,
126
- required this .end,
127
- required this .pluginRegistration,
128
- required this .mainIsolateStart});
128
+ AppStartInfo (
129
+ this .type, {
130
+ required this .start,
131
+ required this .pluginRegistration,
132
+ required this .mainIsolateStart,
133
+ this .end,
134
+ });
129
135
130
136
final AppStartType type;
131
137
final DateTime start;
132
- final DateTime end;
138
+
139
+ // We allow the end to be null, since it might be set at a later time
140
+ // with setAppStartEnd when autoAppStart is disabled
141
+ DateTime ? end;
142
+
133
143
final DateTime pluginRegistration;
134
144
final DateTime mainIsolateStart;
135
145
136
- Duration get duration => end.difference (start);
146
+ Duration ? get duration => end? .difference (start);
137
147
138
- SentryMeasurement toMeasurement () {
148
+ SentryMeasurement ? toMeasurement () {
149
+ final duration = this .duration;
150
+ if (duration == null ) {
151
+ return null ;
152
+ }
139
153
return type == AppStartType .cold
140
154
? SentryMeasurement .coldAppStart (duration)
141
155
: SentryMeasurement .warmAppStart (duration);
0 commit comments