diff --git a/firebase-common/src/main/java/com/google/firebase/FirebaseApp.java b/firebase-common/src/main/java/com/google/firebase/FirebaseApp.java
index 8fc7767388e..ee16ff412e6 100644
--- a/firebase-common/src/main/java/com/google/firebase/FirebaseApp.java
+++ b/firebase-common/src/main/java/com/google/firebase/FirebaseApp.java
@@ -50,6 +50,7 @@
import com.google.firebase.heartbeatinfo.DefaultHeartBeatController;
import com.google.firebase.inject.Provider;
import com.google.firebase.internal.DataCollectionConfigStorage;
+import com.google.firebase.provider.FirebaseInitProvider;
import com.google.firebase.tracing.ComponentMonitor;
import com.google.firebase.tracing.FirebaseTrace;
import java.nio.charset.Charset;
@@ -408,6 +409,7 @@ protected FirebaseApp(Context applicationContext, String name, FirebaseOptions o
this.applicationContext = Preconditions.checkNotNull(applicationContext);
this.name = Preconditions.checkNotEmpty(name);
this.options = Preconditions.checkNotNull(options);
+ StartupTime startupTime = FirebaseInitProvider.getStartupTime();
FirebaseTrace.pushTrace("Firebase");
@@ -418,7 +420,7 @@ protected FirebaseApp(Context applicationContext, String name, FirebaseOptions o
FirebaseTrace.popTrace(); // ComponentDiscovery
FirebaseTrace.pushTrace("Runtime");
- componentRuntime =
+ ComponentRuntime.Builder builder =
ComponentRuntime.builder(com.google.firebase.concurrent.UiExecutor.INSTANCE)
.addLazyComponentRegistrars(registrars)
.addComponentRegistrar(new FirebaseCommonRegistrar())
@@ -426,8 +428,15 @@ protected FirebaseApp(Context applicationContext, String name, FirebaseOptions o
.addComponent(Component.of(applicationContext, Context.class))
.addComponent(Component.of(this, FirebaseApp.class))
.addComponent(Component.of(options, FirebaseOptions.class))
- .setProcessor(new ComponentMonitor())
- .build();
+ .setProcessor(new ComponentMonitor());
+
+ // Don't provide StartupTime in direct boot mode or if Firebase was manually started
+ if (UserManagerCompat.isUserUnlocked(applicationContext)
+ && FirebaseInitProvider.isCurrentlyInitializing()) {
+ builder.addComponent(Component.of(startupTime, StartupTime.class));
+ }
+
+ componentRuntime = builder.build();
FirebaseTrace.popTrace(); // Runtime
dataCollectionConfigStorage =
diff --git a/firebase-common/src/main/java/com/google/firebase/StartupTime.java b/firebase-common/src/main/java/com/google/firebase/StartupTime.java
new file mode 100644
index 00000000000..972b0ed3c2c
--- /dev/null
+++ b/firebase-common/src/main/java/com/google/firebase/StartupTime.java
@@ -0,0 +1,56 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase;
+
+import android.os.SystemClock;
+import androidx.annotation.NonNull;
+import com.google.auto.value.AutoValue;
+
+/**
+ * Represents Firebase's startup time in several timing methods. Represented in unix time/epoch
+ * milliseconds milliseconds since boot, and uptime milliseconds. The absence of a StartupTime
+ * indicates an unreliable or misleading time, such as a launch in direct boot mode. Because of
+ * this, StartupTime cannot be guaranteed to be present, and instead should be optionally depended
+ * on, and its absence handled.
+ *
+ * @hide
+ */
+@AutoValue
+public abstract class StartupTime {
+
+ /** @return The epoch time that Firebase began initializing, in milliseconds */
+ public abstract long getEpochMillis();
+
+ /** @return The number of milliseconds from boot to when Firebase began initializing */
+ public abstract long getElapsedRealtime();
+
+ /** @return The number of milliseconds of uptime measured by SystemClock.uptimeMillis() */
+ public abstract long getUptimeMillis();
+
+ /**
+ * @param epochMillis Time in milliseconds since epoch
+ * @param elapsedRealtime Time in milliseconds since boot
+ */
+ public static @NonNull StartupTime create(
+ long epochMillis, long elapsedRealtime, long uptimeMillis) {
+ return new AutoValue_StartupTime(epochMillis, elapsedRealtime, uptimeMillis);
+ }
+
+ /** @return A StartupTime represented by the current epoch time and JVM nano time */
+ public static @NonNull StartupTime now() {
+ return create(
+ System.currentTimeMillis(), SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+ }
+}
diff --git a/firebase-common/src/main/java/com/google/firebase/provider/FirebaseInitProvider.java b/firebase-common/src/main/java/com/google/firebase/provider/FirebaseInitProvider.java
index e4db850fa63..a43c884ed1d 100644
--- a/firebase-common/src/main/java/com/google/firebase/provider/FirebaseInitProvider.java
+++ b/firebase-common/src/main/java/com/google/firebase/provider/FirebaseInitProvider.java
@@ -27,11 +27,24 @@
import androidx.annotation.VisibleForTesting;
import com.google.android.gms.common.internal.Preconditions;
import com.google.firebase.FirebaseApp;
+import com.google.firebase.StartupTime;
+import java.util.concurrent.atomic.AtomicBoolean;
/** Initializes Firebase APIs at app startup time. */
public class FirebaseInitProvider extends ContentProvider {
-
private static final String TAG = "FirebaseInitProvider";
+ @Nullable private static StartupTime startupTime = StartupTime.now();
+ @NonNull private static AtomicBoolean currentlyInitializing = new AtomicBoolean(false);
+
+ /** @hide */
+ public static @Nullable StartupTime getStartupTime() {
+ return startupTime;
+ }
+
+ /** @hide */
+ public static boolean isCurrentlyInitializing() {
+ return currentlyInitializing.get();
+ }
/** Should match the {@link FirebaseInitProvider} authority if $androidId is empty. */
@VisibleForTesting
@@ -48,12 +61,17 @@ public void attachInfo(@NonNull Context context, @NonNull ProviderInfo info) {
/** Called before {@link Application#onCreate()}. */
@Override
public boolean onCreate() {
- if (FirebaseApp.initializeApp(getContext()) == null) {
- Log.i(TAG, "FirebaseApp initialization unsuccessful");
- } else {
- Log.i(TAG, "FirebaseApp initialization successful");
+ try {
+ currentlyInitializing.set(true);
+ if (FirebaseApp.initializeApp(getContext()) == null) {
+ Log.i(TAG, "FirebaseApp initialization unsuccessful");
+ } else {
+ Log.i(TAG, "FirebaseApp initialization successful");
+ }
+ return false;
+ } finally {
+ currentlyInitializing.set(false);
}
- return false;
}
/**
diff --git a/firebase-perf/src/main/AndroidManifest.xml b/firebase-perf/src/main/AndroidManifest.xml
index 48ae28f8c6e..c40a7de8422 100644
--- a/firebase-perf/src/main/AndroidManifest.xml
+++ b/firebase-perf/src/main/AndroidManifest.xml
@@ -6,11 +6,6 @@
-
Responsible for initializing the AppStartTrace, and early initialization of ConfigResolver
+ */
+public class FirebasePerfEarly {
+ @NonNull private final Handler mainHandler = new Handler(Looper.getMainLooper());
+
+ public FirebasePerfEarly(@NonNull FirebaseApp app, @Nullable StartupTime startupTime) {
+ Context context = app.getApplicationContext();
+
+ // Initialize ConfigResolver early for accessing device caching layer.
+ ConfigResolver configResolver = ConfigResolver.getInstance();
+ configResolver.setApplicationContext(context);
+
+ AppStateMonitor appStateMonitor = AppStateMonitor.getInstance();
+ appStateMonitor.registerActivityLifecycleCallbacks(context);
+ appStateMonitor.registerForAppColdStart(new FirebasePerformanceInitializer());
+
+ if (startupTime != null) {
+ AppStartTrace appStartTrace = AppStartTrace.getInstance();
+ appStartTrace.registerActivityLifecycleCallbacks(context);
+ mainHandler.post(new AppStartTrace.StartFromBackgroundRunnable(appStartTrace));
+ }
+
+ // In the case of cold start, we create a session and start collecting gauges as early as
+ // possible.
+ // There is code in SessionManager that prevents us from resetting the session twice in case
+ // of app cold start.
+ SessionManager.getInstance().initializeGaugeCollection();
+ }
+}
diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfRegistrar.java b/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfRegistrar.java
index 3dc56578866..335dc7b33f0 100644
--- a/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfRegistrar.java
+++ b/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfRegistrar.java
@@ -17,6 +17,7 @@
import androidx.annotation.Keep;
import com.google.android.datatransport.TransportFactory;
import com.google.firebase.FirebaseApp;
+import com.google.firebase.StartupTime;
import com.google.firebase.components.Component;
import com.google.firebase.components.ComponentContainer;
import com.google.firebase.components.ComponentRegistrar;
@@ -41,6 +42,7 @@
@Keep
public class FirebasePerfRegistrar implements ComponentRegistrar {
private static final String LIBRARY_NAME = "fire-perf";
+ private static final String EARLY_LIBRARY_NAME = "fire-perf-early";
@Override
@Keep
@@ -52,8 +54,16 @@ public List> getComponents() {
.add(Dependency.requiredProvider(RemoteConfigComponent.class))
.add(Dependency.required(FirebaseInstallationsApi.class))
.add(Dependency.requiredProvider(TransportFactory.class))
+ .add(Dependency.required(FirebasePerfEarly.class))
.factory(FirebasePerfRegistrar::providesFirebasePerformance)
.build(),
+ Component.builder(FirebasePerfEarly.class)
+ .name(EARLY_LIBRARY_NAME)
+ .add(Dependency.required(FirebaseApp.class))
+ .add(Dependency.optionalProvider(StartupTime.class))
+ .eagerInDefaultApp()
+ .factory(FirebasePerfRegistrar::providesFirebasePerformanceEarly)
+ .build(),
/**
* Fireperf SDK is lazily by {@link FirebasePerformanceInitializer} during {@link
* com.google.firebase.perf.application.AppStateMonitor#onActivityResumed(Activity)}. we use
@@ -65,6 +75,8 @@ public List> getComponents() {
}
private static FirebasePerformance providesFirebasePerformance(ComponentContainer container) {
+ // Ensure FirebasePerfEarly was initialized
+ container.get(FirebasePerfEarly.class);
FirebasePerformanceComponent component =
DaggerFirebasePerformanceComponent.builder()
.firebasePerformanceModule(
@@ -77,4 +89,9 @@ private static FirebasePerformance providesFirebasePerformance(ComponentContaine
return component.getFirebasePerformance();
}
+
+ private static FirebasePerfEarly providesFirebasePerformanceEarly(ComponentContainer container) {
+ return new FirebasePerfEarly(
+ container.get(FirebaseApp.class), container.getProvider(StartupTime.class).get());
+ }
}
diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java b/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java
index 06c505ddd51..d4166dd1c70 100644
--- a/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java
+++ b/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java
@@ -23,9 +23,10 @@
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import com.google.android.gms.common.util.VisibleForTesting;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.StartupTime;
import com.google.firebase.inject.Provider;
import com.google.firebase.perf.logging.AndroidLogger;
-import com.google.firebase.perf.provider.FirebasePerfProvider;
import com.google.firebase.perf.util.Optional;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue;
@@ -80,7 +81,19 @@ private RemoteConfigManager() {
new LinkedBlockingQueue()),
/* firebaseRemoteConfig= */ null, // set once FirebaseRemoteConfig is initialized
MIN_APP_START_CONFIG_FETCH_DELAY_MS
- + new Random().nextInt(RANDOM_APP_START_CONFIG_FETCH_DELAY_MS));
+ + new Random().nextInt(RANDOM_APP_START_CONFIG_FETCH_DELAY_MS),
+ getInitialStartupMillis());
+ }
+
+ @VisibleForTesting
+ @SuppressWarnings("FirebaseUseExplicitDependencies")
+ static long getInitialStartupMillis() {
+ StartupTime startupTime = FirebaseApp.getInstance().get(StartupTime.class);
+ if (startupTime != null) {
+ return startupTime.getEpochMillis();
+ } else {
+ return System.currentTimeMillis();
+ }
}
@VisibleForTesting
@@ -88,7 +101,8 @@ private RemoteConfigManager() {
DeviceCacheManager cache,
Executor executor,
FirebaseRemoteConfig firebaseRemoteConfig,
- long appStartConfigFetchDelayInMs) {
+ long appStartConfigFetchDelayInMs,
+ long appStartTimeInMs) {
this.cache = cache;
this.executor = executor;
this.firebaseRemoteConfig = firebaseRemoteConfig;
@@ -96,8 +110,7 @@ private RemoteConfigManager() {
firebaseRemoteConfig == null
? new ConcurrentHashMap<>()
: new ConcurrentHashMap<>(firebaseRemoteConfig.getAll());
- this.appStartTimeInMs =
- TimeUnit.MICROSECONDS.toMillis(FirebasePerfProvider.getAppStartTime().getMicros());
+ this.appStartTimeInMs = appStartTimeInMs;
this.appStartConfigFetchDelayInMs = appStartConfigFetchDelayInMs;
}
diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java
index 5463ed04dd9..2d91f2e2262 100644
--- a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java
+++ b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java
@@ -27,9 +27,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.common.util.VisibleForTesting;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.StartupTime;
import com.google.firebase.perf.config.ConfigResolver;
import com.google.firebase.perf.logging.AndroidLogger;
-import com.google.firebase.perf.provider.FirebasePerfProvider;
import com.google.firebase.perf.session.PerfSession;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.transport.TransportManager;
@@ -94,6 +95,8 @@ public class AppStartTrace implements ActivityLifecycleCallbacks {
*/
private boolean isTooLateToInitUI = false;
+ private static Timer firebaseStartupTime = null;
+
private Timer appStartTime = null;
private Timer onCreateTime = null;
private Timer onStartTime = null;
@@ -160,6 +163,7 @@ static AppStartTrace getInstance(TransportManager transportManager, Clock clock)
return instance;
}
+ @SuppressWarnings("FirebaseUseExplicitDependencies")
AppStartTrace(
@NonNull TransportManager transportManager,
@NonNull Clock clock,
@@ -169,10 +173,18 @@ static AppStartTrace getInstance(TransportManager transportManager, Clock clock)
this.clock = clock;
this.configResolver = configResolver;
this.executorService = executorService;
+
+ StartupTime startupTime = FirebaseApp.getInstance().get(StartupTime.class);
+ if (startupTime == null) {
+ firebaseStartupTime = new Timer();
+ } else {
+ firebaseStartupTime =
+ Timer.ofElapsedRealtime(startupTime.getElapsedRealtime(), startupTime.getUptimeMillis());
+ }
this.experimentTtid = TraceMetric.newBuilder().setName("_experiment_app_start_ttid");
}
- /** Called from FirebasePerfProvider to register this callback. */
+ /** Called from FirebasePerfEarly to register this callback. */
public synchronized void registerActivityLifecycleCallbacks(@NonNull Context context) {
// Make sure the callback is registered only once.
if (isRegisteredForLifecycleCallbacks) {
@@ -197,7 +209,7 @@ public synchronized void unregisterActivityLifecycleCallbacks() {
/**
* Gets the timetamp that marks the beginning of app start, currently defined as the beginning of
- * BIND_APPLICATION. Fallback to class-load time of {@link FirebasePerfProvider} when API < 24.
+ * BIND_APPLICATION. Fallback to class-load time of {@link StartupTime} when API < 24.
*
* @return {@link Timer} at the beginning of app start by Fireperf definition.
*/
@@ -206,7 +218,7 @@ private static Timer getStartTimer() {
return Timer.ofElapsedRealtime(
Process.getStartElapsedRealtime(), Process.getStartUptimeMillis());
}
- return FirebasePerfProvider.getAppStartTime();
+ return firebaseStartupTime;
}
private void recordFirstDrawDone() {
@@ -222,9 +234,8 @@ private void recordFirstDrawDone() {
TraceMetric.Builder subtrace =
TraceMetric.newBuilder()
.setName("_experiment_classLoadTime")
- .setClientStartTimeUs(FirebasePerfProvider.getAppStartTime().getMicros())
- .setDurationUs(
- FirebasePerfProvider.getAppStartTime().getDurationMicros(this.firstDrawDone));
+ .setClientStartTimeUs(firebaseStartupTime.getMicros())
+ .setDurationUs(firebaseStartupTime.getDurationMicros(this.firstDrawDone));
this.experimentTtid.addSubtraces(subtrace.build());
subtrace = TraceMetric.newBuilder();
@@ -290,8 +301,7 @@ public synchronized void onActivityCreated(Activity activity, Bundle savedInstan
launchActivity = new WeakReference(activity);
onCreateTime = clock.getTime();
- if (FirebasePerfProvider.getAppStartTime().getDurationMicros(onCreateTime)
- > MAX_LATENCY_BEFORE_UI_INIT) {
+ if (firebaseStartupTime.getDurationMicros(onCreateTime) > MAX_LATENCY_BEFORE_UI_INIT) {
isTooLateToInitUI = true;
}
}
@@ -327,7 +337,7 @@ public synchronized void onActivityResumed(Activity activity) {
appStartActivity = new WeakReference(activity);
onResumeTime = clock.getTime();
- this.appStartTime = FirebasePerfProvider.getAppStartTime();
+ this.appStartTime = firebaseStartupTime;
this.startSession = SessionManager.getInstance().perfSession();
AndroidLogger.getInstance()
.debug(
@@ -421,8 +431,8 @@ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
/**
* We use StartFromBackgroundRunnable to detect if app is started from background or foreground.
* If app is started from background, we do not generate AppStart trace. This runnable is posted
- * to main UI thread from FirebasePerfProvider. If app is started from background, this runnable
- * will be executed before any activity's onCreate() method. If app is started from foreground,
+ * to main UI thread from FirebasePerfEarly. If app is started from background, this runnable will
+ * be executed before any activity's onCreate() method. If app is started from foreground,
* activity's onCreate() method is executed before this runnable.
*/
public static class StartFromBackgroundRunnable implements Runnable {
diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/provider/FirebasePerfProvider.java b/firebase-perf/src/main/java/com/google/firebase/perf/provider/FirebasePerfProvider.java
deleted file mode 100644
index cd3df8158fb..00000000000
--- a/firebase-perf/src/main/java/com/google/firebase/perf/provider/FirebasePerfProvider.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-//
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.firebase.perf.provider;
-
-import android.app.Application;
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.ProviderInfo;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import androidx.annotation.Keep;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.google.android.gms.common.internal.Preconditions;
-import com.google.android.gms.common.util.VisibleForTesting;
-import com.google.firebase.perf.FirebasePerformanceInitializer;
-import com.google.firebase.perf.application.AppStateMonitor;
-import com.google.firebase.perf.config.ConfigResolver;
-import com.google.firebase.perf.metrics.AppStartTrace;
-import com.google.firebase.perf.session.SessionManager;
-import com.google.firebase.perf.util.Clock;
-import com.google.firebase.perf.util.Timer;
-
-/** Initializes app start time at app startup time. */
-@Keep
-public class FirebasePerfProvider extends ContentProvider {
-
- private static final Timer APP_START_TIME = new Clock().getTime();
- /** Should match the {@link FirebasePerfProvider} authority if $androidId is empty. */
- @VisibleForTesting
- static final String EMPTY_APPLICATION_ID_PROVIDER_AUTHORITY =
- "com.google.firebase.firebaseperfprovider";
-
- private final Handler mainHandler = new Handler(Looper.getMainLooper());
-
- public static Timer getAppStartTime() {
- return APP_START_TIME;
- }
-
- @Override
- public void attachInfo(Context context, ProviderInfo info) {
- // super.attachInfo calls onCreate(). Fail as early as possible.
- checkContentProviderAuthority(info);
- super.attachInfo(context, info);
-
- // Initialize ConfigResolver early for accessing device caching layer.
- ConfigResolver configResolver = ConfigResolver.getInstance();
- configResolver.setContentProviderContext(getContext());
-
- AppStateMonitor appStateMonitor = AppStateMonitor.getInstance();
- appStateMonitor.registerActivityLifecycleCallbacks(getContext());
- appStateMonitor.registerForAppColdStart(new FirebasePerformanceInitializer());
-
- AppStartTrace appStartTrace = AppStartTrace.getInstance();
- appStartTrace.registerActivityLifecycleCallbacks(getContext());
-
- mainHandler.post(new AppStartTrace.StartFromBackgroundRunnable(appStartTrace));
-
- // In the case of cold start, we create a session and start collecting gauges as early as
- // possible.
- // There is code in SessionManager that prevents us from resetting the session twice in case
- // of app cold start.
- SessionManager.getInstance().initializeGaugeCollection();
- }
-
- /** Called before {@link Application#onCreate()}. */
- @Override
- public boolean onCreate() {
- return false;
- }
-
- /**
- * Check that the content provider's authority does not use firebase-common's package name. If it
- * does, crash in order to alert the developer of the problem before they distribute the app.
- */
- private static void checkContentProviderAuthority(@NonNull ProviderInfo info) {
- Preconditions.checkNotNull(info, "FirebasePerfProvider ProviderInfo cannot be null.");
- if (EMPTY_APPLICATION_ID_PROVIDER_AUTHORITY.equals(info.authority)) {
- throw new IllegalStateException(
- "Incorrect provider authority in manifest. Most likely due to a missing "
- + "applicationId variable in application's build.gradle.");
- }
- }
-
- @Nullable
- @Override
- public Cursor query(
- Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
- return null;
- }
-
- @Nullable
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Nullable
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-}
diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/provider/package-info.java b/firebase-perf/src/main/java/com/google/firebase/perf/provider/package-info.java
deleted file mode 100644
index d3aff47a348..00000000000
--- a/firebase-perf/src/main/java/com/google/firebase/perf/provider/package-info.java
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-//
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/** @hide */
-package com.google.firebase.perf.provider;
diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/FirebasePerfRegistrarTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/FirebasePerfRegistrarTest.java
index 8fd5c68d354..f76f1bb9679 100644
--- a/firebase-perf/src/test/java/com/google/firebase/perf/FirebasePerfRegistrarTest.java
+++ b/firebase-perf/src/test/java/com/google/firebase/perf/FirebasePerfRegistrarTest.java
@@ -18,6 +18,7 @@
import com.google.android.datatransport.TransportFactory;
import com.google.firebase.FirebaseApp;
+import com.google.firebase.StartupTime;
import com.google.firebase.components.Component;
import com.google.firebase.components.Dependency;
import com.google.firebase.installations.FirebaseInstallationsApi;
@@ -35,9 +36,7 @@ public void testGetComponents() {
FirebasePerfRegistrar firebasePerfRegistrar = new FirebasePerfRegistrar();
List> components = firebasePerfRegistrar.getComponents();
- // Note: Although we have 3 deps but looks like size doesn't count deps towards interface like
- // FirebaseInstallationsApi
- assertThat(components).hasSize(2);
+ assertThat(components).hasSize(3);
Component> firebasePerfComponent = components.get(0);
@@ -46,8 +45,17 @@ public void testGetComponents() {
Dependency.required(FirebaseApp.class),
Dependency.requiredProvider(RemoteConfigComponent.class),
Dependency.required(FirebaseInstallationsApi.class),
- Dependency.requiredProvider(TransportFactory.class));
+ Dependency.requiredProvider(TransportFactory.class),
+ Dependency.required(FirebasePerfEarly.class));
assertThat(firebasePerfComponent.isLazy()).isTrue();
+
+ Component> firebasePerfEarlyComponent = components.get(1);
+
+ assertThat(firebasePerfEarlyComponent.getDependencies())
+ .containsExactly(
+ Dependency.required(FirebaseApp.class), Dependency.optionalProvider(StartupTime.class));
+
+ assertThat(firebasePerfEarlyComponent.isLazy()).isFalse();
}
}
diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java
index af1b971d9a1..91db4227536 100644
--- a/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java
+++ b/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java
@@ -28,7 +28,6 @@
import com.google.common.util.concurrent.MoreExecutors;
import com.google.firebase.inject.Provider;
import com.google.firebase.perf.FirebasePerformanceTestBase;
-import com.google.firebase.perf.provider.FirebasePerfProvider;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
@@ -840,8 +839,7 @@ public void triggerRemoteConfigFetchIfNecessary_doesNotFetchBeforeAppStartRandom
appStartConfigFetchDelay));
// Simulate time fast forward to some time before fetch time is up
- long appStartTimeInMs =
- TimeUnit.MICROSECONDS.toMillis(FirebasePerfProvider.getAppStartTime().getMicros());
+ long appStartTimeInMs = System.currentTimeMillis();
when(remoteConfigManagerPartialMock.getCurrentSystemTimeMillis())
.thenReturn(appStartTimeInMs + appStartConfigFetchDelay - 2000);
@@ -867,8 +865,7 @@ public void triggerRemoteConfigFetchIfNecessary_fetchesAfterAppStartRandomDelay(
appStartConfigFetchDelay));
// Simulate time fast forward to 2s after fetch delay time is up
- long appStartTimeInMs =
- TimeUnit.MICROSECONDS.toMillis(FirebasePerfProvider.getAppStartTime().getMicros());
+ long appStartTimeInMs = System.currentTimeMillis();
when(remoteConfigManagerPartialMock.getCurrentSystemTimeMillis())
.thenReturn(appStartTimeInMs + appStartConfigFetchDelay + 2000);
@@ -920,13 +917,18 @@ private RemoteConfigManager setupTestRemoteConfigManager(
when(mockFirebaseRemoteConfig.getAll()).thenReturn(configs);
if (initializeFrc) {
return new RemoteConfigManager(
- cacheManager, fakeExecutor, mockFirebaseRemoteConfig, appStartConfigFetchDelayInMs);
+ cacheManager,
+ fakeExecutor,
+ mockFirebaseRemoteConfig,
+ appStartConfigFetchDelayInMs,
+ RemoteConfigManager.getInitialStartupMillis());
} else {
return new RemoteConfigManager(
cacheManager,
fakeExecutor,
/* firebaseRemoteConfig= */ null,
- appStartConfigFetchDelayInMs);
+ appStartConfigFetchDelayInMs,
+ RemoteConfigManager.getInitialStartupMillis());
}
}
diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java
index 550accd2b92..65f4071ea81 100644
--- a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java
+++ b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java
@@ -15,7 +15,6 @@
package com.google.firebase.perf.metrics;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.firebase.perf.util.TimerTest.getElapsedRealtimeMicros;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -26,7 +25,6 @@
import static org.robolectric.Shadows.shadowOf;
import android.app.Activity;
-import android.content.pm.ProviderInfo;
import android.os.Bundle;
import android.os.Looper;
import android.os.Process;
@@ -35,7 +33,6 @@
import androidx.test.core.app.ApplicationProvider;
import com.google.firebase.perf.FirebasePerformanceTestBase;
import com.google.firebase.perf.config.ConfigResolver;
-import com.google.firebase.perf.provider.FirebasePerfProvider;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.transport.TransportManager;
import com.google.firebase.perf.util.Clock;
@@ -78,9 +75,6 @@ public class AppStartTraceTest extends FirebasePerformanceTestBase {
// a mocked current wall-clock time in microseconds.
private long currentTime = 0;
- // Timer at the beginning of app startup
- private Timer appStart;
-
@Before
public void setUp() {
initMocks(this);
@@ -95,7 +89,6 @@ public Timer answer(InvocationOnMock invocationOnMock) throws Throwable {
.getTime();
transportManager = mock(TransportManager.class);
traceArgumentCaptor = ArgumentCaptor.forClass(TraceMetric.class);
- appStart = FirebasePerfProvider.getAppStartTime();
}
@After
@@ -156,15 +149,10 @@ private void verifyFinalState(
TraceMetric metric = traceArgumentCaptor.getValue();
Assert.assertEquals(Constants.TraceNames.APP_START_TRACE_NAME.toString(), metric.getName());
- Assert.assertEquals(appStart.getMicros(), metric.getClientStartTimeUs());
- Assert.assertEquals(resumeTime - getElapsedRealtimeMicros(appStart), metric.getDurationUs());
Assert.assertEquals(3, metric.getSubtracesCount());
Assert.assertEquals(
Constants.TraceNames.ON_CREATE_TRACE_NAME.toString(), metric.getSubtraces(0).getName());
- Assert.assertEquals(appStart.getMicros(), metric.getSubtraces(0).getClientStartTimeUs());
- Assert.assertEquals(
- createTime - getElapsedRealtimeMicros(appStart), metric.getSubtraces(0).getDurationUs());
Assert.assertEquals(
Constants.TraceNames.ON_START_TRACE_NAME.toString(), metric.getSubtraces(1).getName());
@@ -225,7 +213,10 @@ public void testDelayedAppStart() {
AppStartTrace trace =
new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService);
// Delays activity creation after 1 minute from app start time.
- currentTime = appStart.getMicros() + TimeUnit.MINUTES.toMicros(1) + 1;
+ currentTime =
+ TimeUnit.MILLISECONDS.toMicros(SystemClock.elapsedRealtime())
+ + TimeUnit.MINUTES.toMicros(1)
+ + 1;
trace.onActivityCreated(activity1, bundle);
Assert.assertEquals(currentTime, trace.getOnCreateTime().getMicros());
++currentTime;
@@ -262,24 +253,6 @@ public void testStartFromBackground() {
ArgumentMatchers.nullable(ApplicationProcessState.class));
}
- @Test
- public void testFirebasePerfProviderOnAttachInfo_initializesGaugeCollection() {
- com.google.firebase.perf.session.PerfSession mockPerfSession =
- mock(com.google.firebase.perf.session.PerfSession.class);
- when(mockPerfSession.sessionId()).thenReturn("sessionId");
- when(mockPerfSession.isGaugeAndEventCollectionEnabled()).thenReturn(true);
-
- SessionManager.getInstance().setPerfSession(mockPerfSession);
- String oldSessionId = SessionManager.getInstance().perfSession().sessionId();
- Assert.assertEquals(oldSessionId, SessionManager.getInstance().perfSession().sessionId());
-
- FirebasePerfProvider provider = new FirebasePerfProvider();
- provider.attachInfo(ApplicationProvider.getApplicationContext(), new ProviderInfo());
-
- Assert.assertEquals(oldSessionId, SessionManager.getInstance().perfSession().sessionId());
- verify(mockPerfSession, times(2)).isGaugeAndEventCollectionEnabled();
- }
-
@Test
@Config(sdk = 26)
public void timeToInitialDisplay_isLogged() {