Skip to content
Open
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 @@ -36,7 +36,10 @@
public class FirebasePerfEarly {

public FirebasePerfEarly(
FirebaseApp app, @Nullable StartupTime startupTime, Executor uiExecutor, SessionManager sessionManager) {
FirebaseApp app,
@Nullable StartupTime startupTime,
Executor uiExecutor,
SessionManager sessionManager) {
Context context = app.getApplicationContext();

// Initialize ConfigResolver early for accessing device caching layer.
Expand All @@ -45,9 +48,10 @@ public FirebasePerfEarly(

// Register FirebasePerformance as a subscriber ASAP - which will start collecting gauges if the
// FirebaseSession is verbose.
FirebaseSessionsDependencies.register(new FirebasePerformanceSessionSubscriber(configResolver, sessionManager));
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 @@ -171,7 +171,8 @@ public static FirebasePerformance getInstance() {
FirebaseSessionsEnforcementCheck.setEnforcement(BuildConfig.ENFORCE_LEGACY_SESSIONS);

TransportManager.getInstance()
.initialize(firebaseApp, firebaseInstallationsApi, transportFactoryProvider, sessionManager);
.initialize(
firebaseApp, firebaseInstallationsApi, transportFactoryProvider, sessionManager);

Context appContext = firebaseApp.getApplicationContext();
mMetadataBundle = extractMetadata(appContext);
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 @@ -168,12 +168,15 @@ public static void setLauncherActivityOnResumeTime(String activity) {
}

public static AppStartTrace getInstance(SessionManager sessionManager) {
return instance != null ? instance : getInstance(TransportManager.getInstance(), new Clock(), sessionManager);
return instance != null
? instance
: getInstance(TransportManager.getInstance(), new Clock(), sessionManager);
}

// TODO(b/258263016): Migrate to go/firebase-android-executors
@SuppressLint("ThreadPoolCreation")
static AppStartTrace getInstance(TransportManager transportManager, Clock clock, SessionManager sessionManager) {
static AppStartTrace getInstance(
TransportManager transportManager, Clock clock, SessionManager sessionManager) {
if (instance == null) {
synchronized (AppStartTrace.class) {
if (instance == null) {
Expand Down Expand Up @@ -564,11 +567,12 @@ public static boolean isAnyAppProcessInForeground(Context appContext) {
if (appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
continue;
}
// if (appProcess.processName.equals(appProcessName)
// || appProcess.processName.startsWith(allowedAppProcessNamePrefix)) {
// // Returns true if the process with `IMPORTANCE_FOREGROUND` matches current process.
// return true;
// }
// if (appProcess.processName.equals(appProcessName)
// || appProcess.processName.startsWith(allowedAppProcessNamePrefix)) {
// // Returns true if the process with `IMPORTANCE_FOREGROUND` matches current
// process.
// return true;
// }
}
}

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 @@ -157,13 +157,25 @@ public Trace(
}

public Trace(
@NonNull String name,
@NonNull TransportManager transportManager,
@NonNull Clock clock,
@NonNull AppStateMonitor appStateMonitor,
@NonNull GaugeManager gaugeManager) {
this(name, transportManager, clock, appStateMonitor, gaugeManager, SessionManager.getInstance());
@NonNull String name,
@NonNull TransportManager transportManager,
@NonNull Clock clock,
@NonNull AppStateMonitor appStateMonitor,
@NonNull GaugeManager gaugeManager) {
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 Expand Up @@ -272,8 +284,7 @@ public void stop() {
transportManager.log(new TraceMetricBuilder(this).build(), getAppState());

if (sessionManager.perfSession().isVerbose()) {
gaugeManager.collectGaugeMetricOnce(
sessionManager.perfSession().getTimer());
gaugeManager.collectGaugeMetricOnce(sessionManager.perfSession().getTimer());
}
} else {
logger.error("Trace name is empty, no log is sent to server");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import com.google.firebase.perf.config.ConfigResolver
import com.google.firebase.perf.logging.FirebaseSessionsEnforcementCheck.Companion.checkSession
import com.google.firebase.sessions.api.SessionSubscriber

class FirebasePerformanceSessionSubscriber(val configResolver: ConfigResolver, private val sessionManager: SessionManager) : SessionSubscriber {
class FirebasePerformanceSessionSubscriber(
val configResolver: ConfigResolver,
private val sessionManager: SessionManager
) : SessionSubscriber {

override val sessionSubscriberName: SessionSubscriber.Name = SessionSubscriber.Name.PERFORMANCE

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
Loading