@@ -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