Skip to content

[firebase-perf] Allow initializing a Trace before the sdk is initialized #4960

Open
@jhansche

Description

@jhansche

What feature would you like to see?

Currently the only way to create a trace is with Trace.newTrace() or start it with Trace.startTrace() (or with @AddTrace annotations, for example).

As of BOM v31.2, that will crash if you try to call it before the FirebaseApp has been initialized (due to requiring Firebase RemoteConfig in the code path of newTrace()), which means it is no longer possible to gather performance trace metrics covering the time between process-start and when the Firebase initializer executes, which happens between Application.attachBaseContext() and Application.onCreate() by way of ContentProvider. Because of that, we lose the ability to trace the pre-create time of the application process, including any ability to profile androidx.startup initializers or other ContentProviders.

We previously had a trace that was started very early in the lifecycle (early, as in: initialized from a static field of the Application class). This worked for many years, and only started crashing while updating to v31.2+.

As far as I can tell, I don't see a reason that the Trace object should require the materialized RemoteConfig instance that early in the trace -- it could instead take a Provider or just obtain it lazily when it is needed. At its core, all the Trace object needs to do is keep track of the start and end times in order to report on the metric later.

How would you use it?

We would like to continue using that out-of-lifecycle Trace. Either by allowing Trace.startTrace() to at least obtain the starting clock time, even if Firebase is not initialized yet, as long as Firebase will be available by the time the Trace is stopped;

class MyApp extends Application {
  static Trace bootstrapTrace = Trace.startTrace("bootstrap")
  ...

Or by allowing us to initialize a Trace object with a previously collected starting time. Such as:

class MyApp extends Application {
  static final long classInitTime = System.nanoTime()

  void onCreate() {
    super.onCreate()
    // By this time Firebase initializer will have started, so it's safe to access Trace now
    this.appStartTrace = Trace.newTrace("bootstrap")
        // but then we want to be able to override the start time of the Trace:
        .setStartTime(classInitTime, TimeUnit.NANOSECONDS)
  }
}

Or some other strictly managed placeholder for that express purpose:

class MyApp extends Application {
  static OfflineTrace offlineTrace = OfflineTrace.startTrace("bootstrap")

  void onCreate() {
    super.onCreate()
    ...
    Trace.fromOffline(offlineTrace) // replacement of newTrace() that initializes itself from the strictly managed OfflineTrace
      .stop();

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions