35
35
import com .google .firebase .perf .util .Clock ;
36
36
import com .google .firebase .perf .util .Constants ;
37
37
import com .google .firebase .perf .util .FirstDrawDoneListener ;
38
+ import com .google .firebase .perf .util .PreDrawListener ;
38
39
import com .google .firebase .perf .util .Timer ;
39
40
import com .google .firebase .perf .v1 .ApplicationProcessState ;
40
41
import com .google .firebase .perf .v1 .TraceMetric ;
@@ -75,6 +76,7 @@ public class AppStartTrace implements ActivityLifecycleCallbacks {
75
76
private final TransportManager transportManager ;
76
77
private final Clock clock ;
77
78
private final ConfigResolver configResolver ;
79
+ private final TraceMetric .Builder experimentTtid ;
78
80
private Context appContext ;
79
81
/**
80
82
* The first time onCreate() of any activity is called, the activity is saved as launchActivity.
@@ -96,6 +98,7 @@ public class AppStartTrace implements ActivityLifecycleCallbacks {
96
98
private Timer onStartTime = null ;
97
99
private Timer onResumeTime = null ;
98
100
private Timer firstDrawDone = null ;
101
+ private Timer preDraw = null ;
99
102
100
103
private PerfSession startSession ;
101
104
private boolean isStartedFromBackground = false ;
@@ -163,6 +166,7 @@ static AppStartTrace getInstance(TransportManager transportManager, Clock clock)
163
166
this .clock = clock ;
164
167
this .configResolver = configResolver ;
165
168
this .executorService = executorService ;
169
+ this .experimentTtid = TraceMetric .newBuilder ().setName ("_experiment_app_start_ttid" );
166
170
}
167
171
168
172
/** Called from FirebasePerfProvider to register this callback. */
@@ -196,7 +200,8 @@ public synchronized void unregisterActivityLifecycleCallbacks() {
196
200
*/
197
201
private static Timer getStartTimer () {
198
202
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .N ) {
199
- return Timer .ofElapsedRealtime (Process .getStartElapsedRealtime ());
203
+ return Timer .ofElapsedRealtime (
204
+ Process .getStartElapsedRealtime (), Process .getStartUptimeMillis ());
200
205
}
201
206
return FirebasePerfProvider .getAppStartTime ();
202
207
}
@@ -205,16 +210,73 @@ private void recordFirstDrawDone() {
205
210
if (firstDrawDone != null ) {
206
211
return ;
207
212
}
213
+ Timer start = getStartTimer ();
208
214
this .firstDrawDone = clock .getTime ();
209
- executorService .execute (
210
- () -> this .logColdStart (getStartTimer (), this .firstDrawDone , this .startSession ));
215
+ this .experimentTtid
216
+ .setClientStartTimeUs (start .getMicros ())
217
+ .setDurationUs (start .getDurationMicros (this .firstDrawDone ));
211
218
212
- if (isRegisteredForLifecycleCallbacks ) {
213
- // After AppStart trace is queued to be logged, we can unregister this callback.
214
- unregisterActivityLifecycleCallbacks ();
219
+ TraceMetric .Builder subtrace =
220
+ TraceMetric .newBuilder ()
221
+ .setName ("_experiment_classLoadTime" )
222
+ .setClientStartTimeUs (FirebasePerfProvider .getAppStartTime ().getMicros ())
223
+ .setDurationUs (
224
+ FirebasePerfProvider .getAppStartTime ().getDurationMicros (this .firstDrawDone ));
225
+ this .experimentTtid .addSubtraces (subtrace .build ());
226
+
227
+ subtrace = TraceMetric .newBuilder ();
228
+ subtrace
229
+ .setName ("_experiment_uptimeMillis" )
230
+ .setClientStartTimeUs (start .getMicros ())
231
+ .setDurationUs (start .getDurationUptimeMicros (this .firstDrawDone ));
232
+ this .experimentTtid .addSubtraces (subtrace .build ());
233
+
234
+ this .experimentTtid .addPerfSessions (this .startSession .build ());
235
+
236
+ if (isExperimentTraceDone ()) {
237
+ executorService .execute (() -> this .logExperimentTtid (this .experimentTtid ));
238
+
239
+ if (isRegisteredForLifecycleCallbacks ) {
240
+ // After AppStart trace is queued to be logged, we can unregister this callback.
241
+ unregisterActivityLifecycleCallbacks ();
242
+ }
215
243
}
216
244
}
217
245
246
+ private void recordFirstDrawDonePreDraw () {
247
+ if (preDraw != null ) {
248
+ return ;
249
+ }
250
+ Timer start = getStartTimer ();
251
+ this .preDraw = clock .getTime ();
252
+ TraceMetric .Builder subtrace =
253
+ TraceMetric .newBuilder ()
254
+ .setName ("_experiment_preDraw" )
255
+ .setClientStartTimeUs (start .getMicros ())
256
+ .setDurationUs (start .getDurationMicros (this .preDraw ));
257
+ this .experimentTtid .addSubtraces (subtrace .build ());
258
+
259
+ subtrace = TraceMetric .newBuilder ();
260
+ subtrace
261
+ .setName ("_experiment_preDraw_uptimeMillis" )
262
+ .setClientStartTimeUs (start .getMicros ())
263
+ .setDurationUs (start .getDurationUptimeMicros (this .preDraw ));
264
+ this .experimentTtid .addSubtraces (subtrace .build ());
265
+
266
+ if (isExperimentTraceDone ()) {
267
+ executorService .execute (() -> this .logExperimentTtid (this .experimentTtid ));
268
+
269
+ if (isRegisteredForLifecycleCallbacks ) {
270
+ // After AppStart trace is queued to be logged, we can unregister this callback.
271
+ unregisterActivityLifecycleCallbacks ();
272
+ }
273
+ }
274
+ }
275
+
276
+ private boolean isExperimentTraceDone () {
277
+ return this .preDraw != null && this .firstDrawDone != null ;
278
+ }
279
+
218
280
@ Override
219
281
public synchronized void onActivityCreated (Activity activity , Bundle savedInstanceState ) {
220
282
if (isStartedFromBackground || onCreateTime != null // An activity already called onCreate()
@@ -252,6 +314,7 @@ public synchronized void onActivityResumed(Activity activity) {
252
314
if (isExperimentTTIDEnabled ) {
253
315
View rootView = activity .findViewById (android .R .id .content );
254
316
FirstDrawDoneListener .registerForNextDraw (rootView , this ::recordFirstDrawDone );
317
+ PreDrawListener .registerForNextDraw (rootView , this ::recordFirstDrawDonePreDraw );
255
318
}
256
319
257
320
if (onResumeTime != null ) { // An activity already called onResume()
@@ -280,21 +343,7 @@ public synchronized void onActivityResumed(Activity activity) {
280
343
}
281
344
}
282
345
283
- private void logColdStart (Timer start , Timer end , PerfSession session ) {
284
- TraceMetric .Builder metric =
285
- TraceMetric .newBuilder ()
286
- .setName ("_experiment_app_start_ttid" )
287
- .setClientStartTimeUs (start .getMicros ())
288
- .setDurationUs (start .getDurationMicros (end ));
289
-
290
- TraceMetric .Builder subtrace =
291
- TraceMetric .newBuilder ()
292
- .setName ("_experiment_classLoadTime" )
293
- .setClientStartTimeUs (FirebasePerfProvider .getAppStartTime ().getMicros ())
294
- .setDurationUs (FirebasePerfProvider .getAppStartTime ().getDurationMicros (end ));
295
-
296
- metric .addSubtraces (subtrace ).addPerfSessions (this .startSession .build ());
297
-
346
+ private void logExperimentTtid (TraceMetric .Builder metric ) {
298
347
transportManager .log (metric .build (), ApplicationProcessState .FOREGROUND_BACKGROUND );
299
348
}
300
349
@@ -333,10 +382,32 @@ private void logAppStartTrace() {
333
382
}
334
383
335
384
@ Override
336
- public void onActivityPaused (Activity activity ) {}
385
+ public void onActivityPaused (Activity activity ) {
386
+ if (isExperimentTraceDone ()) {
387
+ return ;
388
+ }
389
+ Timer onPauseTime = clock .getTime ();
390
+ TraceMetric .Builder subtrace =
391
+ TraceMetric .newBuilder ()
392
+ .setName ("_experiment_onPause" )
393
+ .setClientStartTimeUs (onPauseTime .getMicros ())
394
+ .setDurationUs (getStartTimer ().getDurationMicros (onPauseTime ));
395
+ this .experimentTtid .addSubtraces (subtrace .build ());
396
+ }
337
397
338
398
@ Override
339
- public synchronized void onActivityStopped (Activity activity ) {}
399
+ public void onActivityStopped (Activity activity ) {
400
+ if (isExperimentTraceDone ()) {
401
+ return ;
402
+ }
403
+ Timer onStopTime = clock .getTime ();
404
+ TraceMetric .Builder subtrace =
405
+ TraceMetric .newBuilder ()
406
+ .setName ("_experiment_onStop" )
407
+ .setClientStartTimeUs (onStopTime .getMicros ())
408
+ .setDurationUs (getStartTimer ().getDurationMicros (onStopTime ));
409
+ this .experimentTtid .addSubtraces (subtrace .build ());
410
+ }
340
411
341
412
@ Override
342
413
public void onActivityDestroyed (Activity activity ) {}
0 commit comments