@@ -75,6 +75,8 @@ public class AppStartTrace implements ActivityLifecycleCallbacks, LifecycleObser
75
75
private static final @ NonNull Timer PERF_CLASS_LOAD_TIME = new Clock ().getTime ();
76
76
private static final long MAX_LATENCY_BEFORE_UI_INIT = TimeUnit .MINUTES .toMicros (1 );
77
77
78
+ private static final long MAX_BACKGROUND_RUNNABLE_DELAY = TimeUnit .MILLISECONDS .toMicros (100 );
79
+
78
80
// Core pool size 0 allows threads to shut down if they're idle
79
81
private static final int CORE_POOL_SIZE = 0 ;
80
82
private static final int MAX_POOL_SIZE = 1 ; // Only need single thread
@@ -111,6 +113,8 @@ public class AppStartTrace implements ActivityLifecycleCallbacks, LifecycleObser
111
113
private final @ Nullable Timer processStartTime ;
112
114
private final @ Nullable Timer firebaseClassLoadTime ;
113
115
private Timer onCreateTime = null ;
116
+
117
+ private Timer mainThreadRunnableTime = null ;
114
118
private Timer onStartTime = null ;
115
119
private Timer onResumeTime = null ;
116
120
private Timer firstForegroundTime = null ;
@@ -319,8 +323,26 @@ private void recordOnDrawFrontOfQueue() {
319
323
logExperimentTrace (this .experimentTtid );
320
324
}
321
325
326
+ private void resolveIsStartedFromBackground () {
327
+ // If the mainThreadRunnableTime is null, either the runnable hasn't run, or this check has
328
+ // already been made.
329
+ if (mainThreadRunnableTime == null ) {
330
+ return ;
331
+ }
332
+
333
+ // Set it to true if the runnable ran more than 100ms prior to onActivityCreated()
334
+ if (mainThreadRunnableTime .getDurationMicros () > MAX_BACKGROUND_RUNNABLE_DELAY ) {
335
+ isStartedFromBackground = true ;
336
+ }
337
+
338
+ // Set this to null to prevent additional checks if `onActivityCreated()` is called again.
339
+ mainThreadRunnableTime = null ;
340
+ }
341
+
322
342
@ Override
323
343
public synchronized void onActivityCreated (Activity activity , Bundle savedInstanceState ) {
344
+ resolveIsStartedFromBackground ();
345
+
324
346
if (isStartedFromBackground || onCreateTime != null // An activity already called onCreate()
325
347
) {
326
348
return ;
@@ -560,8 +582,7 @@ public static boolean isScreenOn(Context appContext) {
560
582
* We use StartFromBackgroundRunnable to detect if app is started from background or foreground.
561
583
* If app is started from background, we do not generate AppStart trace. This runnable is posted
562
584
* to main UI thread from FirebasePerfEarly. If app is started from background, this runnable will
563
- * be executed before any activity's onCreate() method. If app is started from foreground,
564
- * activity's onCreate() method is executed before this runnable.
585
+ * be executed earlier than 100ms of any activity's onCreate() method.
565
586
*/
566
587
public static class StartFromBackgroundRunnable implements Runnable {
567
588
private final AppStartTrace trace ;
@@ -572,10 +593,7 @@ public StartFromBackgroundRunnable(final AppStartTrace trace) {
572
593
573
594
@ Override
574
595
public void run () {
575
- // if no activity has ever been created.
576
- if (trace .onCreateTime == null ) {
577
- trace .isStartedFromBackground = true ;
578
- }
596
+ trace .mainThreadRunnableTime = new Timer ();
579
597
}
580
598
}
581
599
@@ -614,7 +632,7 @@ Timer getOnResumeTime() {
614
632
}
615
633
616
634
@ VisibleForTesting
617
- void setIsStartFromBackground ( ) {
618
- isStartedFromBackground = true ;
635
+ void setMainThreadRunnableTime ( Timer timer ) {
636
+ mainThreadRunnableTime = timer ;
619
637
}
620
638
}
0 commit comments