diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfEarly.java b/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfEarly.java index 5b89deaad82..164fe46b502 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfEarly.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerfEarly.java @@ -51,12 +51,8 @@ public FirebasePerfEarly( uiExecutor.execute(new AppStartTrace.StartFromBackgroundRunnable(appStartTrace)); } - // TODO: Bring back Firebase Sessions dependency to watch for updates to sessions. + // In the case of a cold start, we initialize gauge collection with a legacy PerfSession. - // 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/session/FirebasePerformanceSessionSubscriber.kt b/firebase-perf/src/main/java/com/google/firebase/perf/session/FirebasePerformanceSessionSubscriber.kt index d3e13c63aa9..b3fed660d9c 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/session/FirebasePerformanceSessionSubscriber.kt +++ b/firebase-perf/src/main/java/com/google/firebase/perf/session/FirebasePerformanceSessionSubscriber.kt @@ -28,12 +28,19 @@ class FirebasePerformanceSessionSubscriber(override val isDataCollectionEnabled: override fun onSessionChanged(sessionDetails: SessionSubscriber.SessionDetails) { val currentPerfSession = SessionManager.getInstance().perfSession() - // TODO(b/394127311): Add logic to deal with app start gauges. FirebaseSessionsEnforcementCheck.checkSession(currentPerfSession, "onSessionChanged") + if (currentPerfSession.isLegacy() && currentPerfSession.isVerbose) { + GaugeManager.getInstance() + .logGaugeMetadata(sessionDetails.sessionId, ApplicationProcessState.FOREGROUND) + GaugeManager.getInstance() + .logExistingGaugeMetrics(sessionDetails.sessionId, ApplicationProcessState.FOREGROUND) + } + val updatedSession = PerfSession.createWithId(sessionDetails.sessionId) SessionManager.getInstance().updatePerfSession(updatedSession) GaugeManager.getInstance() .logGaugeMetadata(updatedSession.sessionId(), ApplicationProcessState.FOREGROUND) + SessionManager.getInstance().updateGaugeCollectionOnNewSession() } } diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/session/PerfSession.java b/firebase-perf/src/main/java/com/google/firebase/perf/session/PerfSession.java index a89c8987896..47a2a1af9eb 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/session/PerfSession.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/session/PerfSession.java @@ -30,7 +30,7 @@ public class PerfSession implements Parcelable { private final Timer creationTime; private final String sessionId; - private boolean isGaugeAndEventCollectionEnabled = false; + private boolean isGaugeAndEventCollectionEnabled = true; /* * Creates a PerfSession object and decides what metrics to collect. diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java b/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java index 1c06ceac9dd..4b2623d4409 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java @@ -59,8 +59,10 @@ public class GaugeManager { private final TransportManager transportManager; @Nullable private GaugeMetadataManager gaugeMetadataManager; - @Nullable private ScheduledFuture gaugeManagerDataCollectionJob = null; + @Nullable private ScheduledFuture gaugeManagerDataCollectionJob = null; @Nullable private String sessionId = null; + + private boolean isCollectingGauges = false; private ApplicationProcessState applicationProcessState = ApplicationProcessState.APPLICATION_PROCESS_STATE_UNKNOWN; @@ -103,6 +105,34 @@ public static synchronized GaugeManager getInstance() { return instance; } + public void updateGaugeLogging( + String sessionId, ApplicationProcessState applicationProcessState, long collectionFrequency) { + try { + gaugeManagerDataCollectionJob = + gaugeManagerExecutor + .get() + .scheduleWithFixedDelay( + () -> { + syncFlush(sessionId, applicationProcessState); + }, + /* initialDelay= */ collectionFrequency + * APPROX_NUMBER_OF_DATA_POINTS_PER_GAUGE_METRIC, + /* period= */ collectionFrequency * APPROX_NUMBER_OF_DATA_POINTS_PER_GAUGE_METRIC, + TimeUnit.MILLISECONDS); + + } catch (RejectedExecutionException e) { + logger.warn("Unable to start collecting Gauges: " + e.getMessage()); + } + } + + public long updateGaugeCollection( + ApplicationProcessState applicationProcessState, Timer gaugeCollectionTimer) { + if (isCollectingGauges) { + stopCollectingGauges(); + } + return startCollectingGauges(applicationProcessState, gaugeCollectionTimer); + } + /** * Starts the collection of available gauges for the given {@code sessionId} and {@code * applicationProcessState}. The collected Gauge Metrics will be flushed at regular intervals. @@ -190,7 +220,7 @@ private long startCollectingGauges(ApplicationProcessState appState, Timer refer * this.stopCollectingGauges()} should always be called from the same thread. */ public void stopCollectingGauges() { - if (this.sessionId == null) { + if (!this.isCollectingGauges) { return; } @@ -219,6 +249,7 @@ public void stopCollectingGauges() { TimeUnit.MILLISECONDS); this.sessionId = null; + this.isCollectingGauges = false; this.applicationProcessState = ApplicationProcessState.APPLICATION_PROCESS_STATE_UNKNOWN; } @@ -253,16 +284,16 @@ private void syncFlush(String sessionId, ApplicationProcessState appState) { /** * Log the Gauge Metadata information to the transport. * - * @param aqsSessionId The {@link PerfSession#aqsSessionId()} ()} to which the collected Gauge Metrics + * @param sessionId The {@link PerfSession#sessionId()} ()} to which the collected Gauge Metrics * should be associated with. * @param appState The {@link ApplicationProcessState} for which these gauges are collected. * @return true if GaugeMetadata was logged, false otherwise. */ - public boolean logGaugeMetadata(String aqsSessionId, ApplicationProcessState appState) { + public boolean logGaugeMetadata(String sessionId, ApplicationProcessState appState) { if (gaugeMetadataManager != null) { GaugeMetric gaugeMetric = GaugeMetric.newBuilder() - .setSessionId(aqsSessionId) + .setSessionId(sessionId) .setGaugeMetadata(getGaugeMetadata()) .build(); transportManager.log(gaugeMetric, appState); @@ -335,6 +366,22 @@ public void collectGaugeMetricOnce(Timer referenceTime) { collectGaugeMetricOnce(cpuGaugeCollector.get(), memoryGaugeCollector.get(), referenceTime); } + public void logExistingGaugeMetrics( + String sessionId, ApplicationProcessState applicationProcessState) { + // Flush any data that was collected and associate it with the given session ID and + // applicationProcessState. + @SuppressWarnings("FutureReturnValueIgnored") + ScheduledFuture unusedFuture = + gaugeManagerExecutor + .get() + .schedule( + () -> { + syncFlush(sessionId, applicationProcessState); + }, + TIME_TO_WAIT_BEFORE_FLUSHING_GAUGES_QUEUE_MS, + TimeUnit.MILLISECONDS); + } + private static void collectGaugeMetricOnce( CpuGaugeCollector cpuGaugeCollector, MemoryGaugeCollector memoryGaugeCollector, @@ -405,4 +452,10 @@ private long getMemoryGaugeCollectionFrequencyMs( return memoryGaugeCollectionFrequency; } } + + private long getGaugeLoggingFrequency(ApplicationProcessState applicationProcessState) { + return Math.min( + getMemoryGaugeCollectionFrequencyMs(applicationProcessState), + getCpuGaugeCollectionFrequencyMs(applicationProcessState)); + } }