@@ -75,6 +75,8 @@ public class AppStartTrace implements ActivityLifecycleCallbacks, LifecycleObser
7575 private static final @ NonNull Timer PERF_CLASS_LOAD_TIME = new Clock ().getTime ();
7676 private static final long MAX_LATENCY_BEFORE_UI_INIT = TimeUnit .MINUTES .toMicros (1 );
7777
78+ private static final long MAX_BACKGROUND_RUNNABLE_DELAY = TimeUnit .MILLISECONDS .toMicros (100 );
79+
7880 // Core pool size 0 allows threads to shut down if they're idle
7981 private static final int CORE_POOL_SIZE = 0 ;
8082 private static final int MAX_POOL_SIZE = 1 ; // Only need single thread
@@ -111,6 +113,8 @@ public class AppStartTrace implements ActivityLifecycleCallbacks, LifecycleObser
111113 private final @ Nullable Timer processStartTime ;
112114 private final @ Nullable Timer firebaseClassLoadTime ;
113115 private Timer onCreateTime = null ;
116+
117+ private Timer mainThreadRunnableTime = null ;
114118 private Timer onStartTime = null ;
115119 private Timer onResumeTime = null ;
116120 private Timer firstForegroundTime = null ;
@@ -319,8 +323,26 @@ private void recordOnDrawFrontOfQueue() {
319323 logExperimentTrace (this .experimentTtid );
320324 }
321325
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+
322342 @ Override
323343 public synchronized void onActivityCreated (Activity activity , Bundle savedInstanceState ) {
344+ resolveIsStartedFromBackground ();
345+
324346 if (isStartedFromBackground || onCreateTime != null // An activity already called onCreate()
325347 ) {
326348 return ;
@@ -560,8 +582,7 @@ public static boolean isScreenOn(Context appContext) {
560582 * We use StartFromBackgroundRunnable to detect if app is started from background or foreground.
561583 * If app is started from background, we do not generate AppStart trace. This runnable is posted
562584 * 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.
565586 */
566587 public static class StartFromBackgroundRunnable implements Runnable {
567588 private final AppStartTrace trace ;
@@ -572,10 +593,7 @@ public StartFromBackgroundRunnable(final AppStartTrace trace) {
572593
573594 @ Override
574595 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 ();
579597 }
580598 }
581599
@@ -614,7 +632,7 @@ Timer getOnResumeTime() {
614632 }
615633
616634 @ VisibleForTesting
617- void setIsStartFromBackground ( ) {
618- isStartedFromBackground = true ;
635+ void setMainThreadRunnableTime ( Timer timer ) {
636+ mainThreadRunnableTime = timer ;
619637 }
620638}
0 commit comments