Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public FirebasePerfEarly(
// FirebaseSession is verbose.
FirebaseSessionsDependencies.register(new FirebasePerformanceSessionSubscriber(configResolver, sessionManager));

AppStateMonitor appStateMonitor = AppStateMonitor.getInstance();
AppStateMonitor appStateMonitor = AppStateMonitor.getInstance(sessionManager);
appStateMonitor.registerActivityLifecycleCallbacks(context);
appStateMonitor.registerForAppColdStart(new FirebasePerformanceInitializer());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ public List<Component<?>> getComponents() {
container.get(SessionManager.class)))
.build(),
Component.builder(SessionManager.class)
.factory(container -> SessionManager.getInstance())
.factory(
container ->
new SessionManager(GaugeManager.getInstance(), PerfSession.createWithId(null)))
.build(),
/**
* Fireperf SDK is lazily by {@link FirebasePerformanceInitializer} during {@link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import com.google.firebase.perf.logging.AndroidLogger;
import com.google.firebase.perf.metrics.FrameMetricsCalculator.PerfFrameMetrics;
import com.google.firebase.perf.metrics.Trace;
import com.google.firebase.perf.session.PerfSession;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.session.gauges.GaugeManager;
import com.google.firebase.perf.transport.TransportManager;
import com.google.firebase.perf.util.Clock;
import com.google.firebase.perf.util.Constants;
Expand Down Expand Up @@ -81,11 +83,34 @@ public class AppStateMonitor implements ActivityLifecycleCallbacks {
private boolean isRegisteredForLifecycleCallbacks = false;
private boolean isColdStart = true;

public static AppStateMonitor getInstance(SessionManager sessionManager) {
if (instance == null) {
synchronized (AppStateMonitor.class) {
if (instance == null) {
instance = new AppStateMonitor(TransportManager.getInstance(), new Clock(), sessionManager);
}
}
}
return instance;
}

/**
* Returns the singleton instance, creating it with a default {@link SessionManager} if not
* already initialized. In production, {@link #getInstance(SessionManager)} is always called
* first by {@link com.google.firebase.perf.FirebasePerfEarly}, so the pre-seeded instance is
* returned. This overload exists for call sites that run after early initialization (e.g.
* {@link com.google.firebase.perf.application.AppStateUpdateHandler}) and for test environments.
*/
public static AppStateMonitor getInstance() {
if (instance == null) {
synchronized (AppStateMonitor.class) {
if (instance == null) {
instance = new AppStateMonitor(TransportManager.getInstance(), new Clock(), SessionManager.getInstance());
instance =
new AppStateMonitor(
TransportManager.getInstance(),
new Clock(),
new SessionManager(
GaugeManager.getInstance(), PerfSession.createWithId(null)));
}
}
}
Expand Down Expand Up @@ -115,6 +140,15 @@ public static AppStateMonitor getInstance() {
this.screenPerformanceRecordingSupported = screenPerformanceRecordingSupported;
}

public SessionManager getSessionManager() {
return sessionManager;
}

@VisibleForTesting
public static void resetInstance() {
instance = null;
}

public synchronized void registerActivityLifecycleCallbacks(Context context) {
// Make sure the callback is registered only once.
if (isRegisteredForLifecycleCallbacks) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public ConfigResolver(
@Nullable ImmutableBundle metadataBundle,
@Nullable DeviceCacheManager deviceCacheManager) {
this.remoteConfigManager =
remoteConfigManager == null ? RemoteConfigManager.getInstance() : remoteConfigManager;
remoteConfigManager == null ? new RemoteConfigManager() : remoteConfigManager;
this.metadataBundle = metadataBundle == null ? new ImmutableBundle() : metadataBundle;
this.deviceCacheManager =
deviceCacheManager == null ? DeviceCacheManager.getInstance() : deviceCacheManager;
Expand Down Expand Up @@ -916,4 +916,8 @@ private boolean isGaugeCaptureFrequencyMsValid(long frequencyMilliseconds) {
private boolean isSessionsMaxDurationMinutesValid(long maxDurationMin) {
return maxDurationMin > 0;
}

public RemoteConfigManager getRemoteConfigManager() {
return remoteConfigManager;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
public class RemoteConfigManager {

private static final AndroidLogger logger = AndroidLogger.getInstance();
private static final RemoteConfigManager instance = new RemoteConfigManager();
private static final String FIREPERF_FRC_NAMESPACE_NAME = "fireperf";
private static final long TIME_AFTER_WHICH_A_FETCH_IS_CONSIDERED_STALE_MS =
TimeUnit.HOURS.toMillis(12);
Expand All @@ -67,7 +66,7 @@ public class RemoteConfigManager {

// TODO(b/258263016): Migrate to go/firebase-android-executors
@SuppressLint("ThreadPoolCreation")
private RemoteConfigManager() {
public RemoteConfigManager() {
this(
DeviceCacheManager.getInstance(),
new ThreadPoolExecutor(
Expand Down Expand Up @@ -96,11 +95,6 @@ private RemoteConfigManager() {
this.remoteConfigFetchDelayInMs = remoteConfigFetchDelayInMs;
}

/** Gets the singleton instance. */
public static RemoteConfigManager getInstance() {
return instance;
}

/**
* Sets the {@link Provider} for {@link RemoteConfigComponent} from which we can extract the
* {@link FirebaseRemoteConfig} instance whenever it gets available.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Provider<TransportFactory> providesTransportFactoryProvider() {

@Provides
RemoteConfigManager providesRemoteConfigManager() {
return RemoteConfigManager.getInstance();
return ConfigResolver.getInstance().getRemoteConfigManager();
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ public static NetworkRequestMetricBuilder builder(TransportManager transportMana
* initialize them.
*/
private NetworkRequestMetricBuilder(TransportManager transportManager) {
this(transportManager, AppStateMonitor.getInstance(), GaugeManager.getInstance(), SessionManager.getInstance());
this(
transportManager,
AppStateMonitor.getInstance(),
GaugeManager.getInstance(),
AppStateMonitor.getInstance().getSessionManager());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,20 @@ public Trace(
@NonNull Clock clock,
@NonNull AppStateMonitor appStateMonitor,
@NonNull GaugeManager gaugeManager) {
this(name, transportManager, clock, appStateMonitor, gaugeManager, SessionManager.getInstance());
this(
name,
transportManager,
clock,
appStateMonitor,
gaugeManager,
sessionManagerFrom(appStateMonitor));
}

private static SessionManager sessionManagerFrom(AppStateMonitor appStateMonitor) {
SessionManager sm = appStateMonitor.getSessionManager();
return sm != null ? sm : new SessionManager(null, PerfSession.createWithId(null));
}

/**
* Creates a Trace object with the given name. TransportManager, Clock and GaugeManager instances
* are for testing.
Expand Down Expand Up @@ -213,7 +225,7 @@ private Trace(@NonNull Parcel in, boolean isDataOnly) {
clock = new Clock();
gaugeManager = GaugeManager.getInstance();
}
sessionManager = SessionManager.getInstance();
sessionManager = TransportManager.getInstance().getSessionManager();
}

/** Starts this trace. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

package com.google.firebase.perf.session;

import android.annotation.SuppressLint;
import android.content.Context;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;
Expand All @@ -30,30 +29,17 @@
/** Session manager to generate sessionIDs and broadcast to the application. */
@Keep // Needed because of b/117526359.
public class SessionManager {
@SuppressLint("StaticFieldLeak")
private static final SessionManager instance = new SessionManager();

private final GaugeManager gaugeManager;
private final Set<WeakReference<SessionAwareObject>> clients = new HashSet<>();

private PerfSession perfSession;

/** Returns the singleton instance of SessionManager. */
public static SessionManager getInstance() {
return instance;
}

/** Returns the currently active PerfSession. */
public final PerfSession perfSession() {
return perfSession;
}

private SessionManager() {
// Creates a legacy session by default. This is a safety net to allow initializing
// SessionManager - but the current implementation replaces it immediately.
this(GaugeManager.getInstance(), PerfSession.createWithId(null));
}

@VisibleForTesting
public SessionManager(GaugeManager gaugeManager, PerfSession perfSession) {
this.gaugeManager = gaugeManager;
Expand All @@ -65,7 +51,9 @@ public SessionManager(GaugeManager gaugeManager, PerfSession perfSession) {
* (currently that is before onResume finishes) to ensure gauge collection starts on time.
*/
public void setApplicationContext(final Context appContext) {
gaugeManager.initializeGaugeMetadataManager(appContext);
if (gaugeManager != null) {
gaugeManager.initializeGaugeMetadataManager(appContext);
}
}

/**
Expand All @@ -74,7 +62,7 @@ public void setApplicationContext(final Context appContext) {
* @see PerfSession#isSessionRunningTooLong()
*/
public void stopGaugeCollectionIfSessionRunningTooLong() {
if (perfSession.isSessionRunningTooLong()) {
if (perfSession.isSessionRunningTooLong() && gaugeManager != null) {
gaugeManager.stopCollectingGauges();
}
}
Expand Down Expand Up @@ -151,12 +139,15 @@ public void unregisterForSessionUpdates(WeakReference<SessionAwareObject> client
}

private void logGaugeMetadataIfCollectionEnabled() {
if (perfSession.isVerbose()) {
if (perfSession.isVerbose() && gaugeManager != null) {
gaugeManager.logGaugeMetadata(perfSession.sessionId());
}
}

private void startOrStopCollectingGauges() {
if (gaugeManager == null) {
return;
}
if (perfSession.isVerbose()) {
gaugeManager.startCollectingGauges(perfSession);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ void initializeForTest(
RateLimiter rateLimiter,
AppStateMonitor appStateMonitor,
FlgTransport flgTransport,
ExecutorService executorService) {
ExecutorService executorService,
SessionManager sessionManager) {

this.firebaseApp = firebaseApp;
this.projectId = firebaseApp.getOptions().getProjectId();
Expand All @@ -179,6 +180,7 @@ void initializeForTest(
this.appStateMonitor = appStateMonitor;
this.flgTransport = flgTransport;
this.executorService = executorService;
this.sessionManager = sessionManager;

// Re-init the cache, otherwise the cache might get consumed/exhausted after a few tests
cacheMap.put(KEY_AVAILABLE_TRACES_FOR_CACHING, MAX_TRACE_METRICS_CACHE_SIZE);
Expand Down Expand Up @@ -396,6 +398,11 @@ private void syncLog(PerfMetric.Builder perfMetricBuilder, ApplicationProcessSta
}
}

/** Returns the {@link SessionManager} associated with this transport. */
public SessionManager getSessionManager() {
return sessionManager;
}

@WorkerThread
private boolean isAllowedToCache(PerfMetricOrBuilder perfMetricOrBuilder) {
final int availableTracesForCaching = cacheMap.get(KEY_AVAILABLE_TRACES_FOR_CACHING);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.firebase.components.Dependency;
import com.google.firebase.components.Qualified;
import com.google.firebase.installations.FirebaseInstallationsApi;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
import java.util.List;
import java.util.concurrent.Executor;
Expand All @@ -39,7 +40,8 @@ public void testGetComponents() {
FirebasePerfRegistrar firebasePerfRegistrar = new FirebasePerfRegistrar();
List<Component<?>> components = firebasePerfRegistrar.getComponents();

assertThat(components).hasSize(3);
// FirebasePerformance, FirebasePerfEarly, SessionManager, LibraryVersionComponent
assertThat(components).hasSize(4);

Component<?> firebasePerfComponent = components.get(0);

Expand All @@ -49,7 +51,8 @@ public void testGetComponents() {
Dependency.requiredProvider(RemoteConfigComponent.class),
Dependency.required(FirebaseInstallationsApi.class),
Dependency.requiredProvider(TransportFactory.class),
Dependency.required(FirebasePerfEarly.class));
Dependency.required(FirebasePerfEarly.class),
Dependency.required(SessionManager.class));

assertThat(firebasePerfComponent.isLazy()).isTrue();

Expand All @@ -59,7 +62,8 @@ public void testGetComponents() {
.containsExactly(
Dependency.required(Qualified.qualified(UiThread.class, Executor.class)),
Dependency.required(FirebaseApp.class),
Dependency.optionalProvider(StartupTime.class));
Dependency.optionalProvider(StartupTime.class),
Dependency.required(SessionManager.class));

assertThat(firebasePerfEarlyComponent.isLazy()).isFalse();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
import com.google.firebase.perf.config.ConfigResolver;
import com.google.firebase.perf.config.DeviceCacheManager;
import com.google.firebase.perf.config.RemoteConfigManager;
import com.google.firebase.perf.session.PerfSession;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.session.gauges.GaugeManager;
import com.google.firebase.perf.util.Clock;
import com.google.firebase.perf.util.Constants;
import com.google.firebase.perf.util.ImmutableBundle;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
Expand Down Expand Up @@ -100,11 +103,14 @@ public void setUp() throws NameNotFoundException {
sharedPreferences.edit().clear().commit();
DeviceCacheManager.clearInstance();

spyRemoteConfigManager = spy(RemoteConfigManager.getInstance());
ConfigResolver.clearInstance();
spyConfigResolver = spy(ConfigResolver.getInstance());
spyRemoteConfigManager = spy(ConfigResolver.getInstance().getRemoteConfigManager());

spySessionManager = spy(SessionManager.getInstance());
spySessionManager =
spy(
new SessionManager(
mock(GaugeManager.class), new PerfSession("sessionId", new Clock())));
fakeDirectExecutorService = new FakeDirectExecutorService();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public void setUp() {

@Test
public void getInstance_verifiesSingleton() {
RemoteConfigManager instanceOne = RemoteConfigManager.getInstance();
RemoteConfigManager instanceTwo = RemoteConfigManager.getInstance();
RemoteConfigManager instanceOne = ConfigResolver.getInstance().getRemoteConfigManager();
RemoteConfigManager instanceTwo = ConfigResolver.getInstance().getRemoteConfigManager();

assertThat(instanceOne).isSameInstanceAs(instanceTwo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@
import android.view.View;
import androidx.test.core.app.ApplicationProvider;
import com.google.firebase.perf.FirebasePerformanceTestBase;
import com.google.firebase.perf.application.AppStateMonitor;
import com.google.firebase.perf.config.ConfigResolver;
import com.google.firebase.perf.session.PerfSession;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.session.gauges.GaugeManager;
import com.google.firebase.perf.transport.TransportManager;
import com.google.firebase.perf.util.Clock;
Expand Down Expand Up @@ -99,7 +97,7 @@ public Timer answer(InvocationOnMock invocationOnMock) throws Throwable {

@After
public void reset() {
SessionManager.getInstance().updatePerfSession(PerfSession.createWithId("randomSessionId"));
sessionManager.updatePerfSession(PerfSession.createWithId("randomSessionId"));
}

/** Test activity sequentially goes through onCreate()->onStart()->onResume() state change. */
Expand Down
Loading