Skip to content

Commit a78ec7e

Browse files
committed
convert perf session to use aqs support session id
1 parent fcd270c commit a78ec7e

File tree

10 files changed

+134
-111
lines changed

10 files changed

+134
-111
lines changed

firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerformance.java

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.google.firebase.perf.config.RemoteConfigManager;
3535
import com.google.firebase.perf.logging.AndroidLogger;
3636
import com.google.firebase.perf.logging.ConsoleUrlGenerator;
37+
import com.google.firebase.perf.logging.DebugEnforcementCheck;
3738
import com.google.firebase.perf.metrics.HttpMetric;
3839
import com.google.firebase.perf.metrics.Trace;
3940
import com.google.firebase.perf.session.FirebasePerformanceSessionSubscriber;
@@ -43,6 +44,7 @@
4344
import com.google.firebase.perf.util.ImmutableBundle;
4445
import com.google.firebase.perf.util.Timer;
4546
import com.google.firebase.remoteconfig.RemoteConfigComponent;
47+
import com.google.firebase.sessions.BuildConfig;
4648
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
4749
import java.lang.annotation.Retention;
4850
import java.lang.annotation.RetentionPolicy;
@@ -169,6 +171,7 @@ public static FirebasePerformance getInstance() {
169171
this.mMetadataBundle = new ImmutableBundle(new Bundle());
170172
return;
171173
}
174+
DebugEnforcementCheck.setEnforcement(BuildConfig.DEBUG);
172175

173176
TransportManager.getInstance()
174177
.initialize(firebaseApp, firebaseInstallationsApi, transportFactoryProvider);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.perf.logging
18+
19+
class DebugEnforcementCheck {
20+
companion object {
21+
/** When enabled, failed preconditions will cause assertion errors for debugging. */
22+
@JvmStatic var enforcement: Boolean = false
23+
private var logger: AndroidLogger = AndroidLogger.getInstance()
24+
25+
public fun checkSession(isAqsAvailable: Boolean, failureMessage: String) {
26+
if (!isAqsAvailable) {
27+
Companion.logger.debug(failureMessage)
28+
assert(!enforcement) { failureMessage }
29+
}
30+
}
31+
}
32+
}

firebase-perf/src/main/java/com/google/firebase/perf/session/FirebasePerformanceSessionSubscriber.kt

+2-14
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,16 @@ package com.google.firebase.perf.session
1919
import com.google.firebase.perf.session.gauges.GaugeManager
2020
import com.google.firebase.perf.v1.ApplicationProcessState
2121
import com.google.firebase.sessions.api.SessionSubscriber
22-
import java.util.UUID
2322

2423
class FirebasePerformanceSessionSubscriber(override val isDataCollectionEnabled: Boolean) :
2524
SessionSubscriber {
2625

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

2928
override fun onSessionChanged(sessionDetails: SessionSubscriber.SessionDetails) {
30-
val currentPerfSession = SessionManager.getInstance().perfSession()
31-
32-
// A [PerfSession] was created before a session was started.
33-
if (currentPerfSession.aqsSessionId() == null) {
34-
currentPerfSession.setAQSId(sessionDetails)
35-
GaugeManager.getInstance()
36-
.logGaugeMetadata(currentPerfSession.aqsSessionId(), ApplicationProcessState.FOREGROUND)
37-
return
38-
}
39-
40-
val updatedSession = PerfSession.createWithId(UUID.randomUUID().toString())
41-
updatedSession.setAQSId(sessionDetails)
29+
val updatedSession = PerfSession.createWithId(sessionDetails.sessionId)
4230
SessionManager.getInstance().updatePerfSession(updatedSession)
4331
GaugeManager.getInstance()
44-
.logGaugeMetadata(updatedSession.aqsSessionId(), ApplicationProcessState.FOREGROUND)
32+
.logGaugeMetadata(updatedSession.sessionId(), ApplicationProcessState.FOREGROUND)
4533
}
4634
}

firebase-perf/src/main/java/com/google/firebase/perf/session/PerfSession.java

+31-41
Original file line numberDiff line numberDiff line change
@@ -23,62 +23,53 @@
2323
import com.google.firebase.perf.util.Clock;
2424
import com.google.firebase.perf.util.Timer;
2525
import com.google.firebase.perf.v1.SessionVerbosity;
26-
import com.google.firebase.sessions.api.SessionSubscriber;
2726
import java.util.List;
27+
import java.util.UUID;
2828
import java.util.concurrent.TimeUnit;
2929

3030
/** Details of a session including a unique Id and related information. */
3131
public class PerfSession implements Parcelable {
32-
33-
private final String sessionId;
3432
private final Timer creationTime;
35-
@Nullable private String aqsSessionId;
36-
33+
private final String sessionId;
3734
private boolean isGaugeAndEventCollectionEnabled = false;
35+
public final boolean isAqsReady;
3836

3937
/*
4038
* Creates a PerfSession object and decides what metrics to collect.
4139
*/
42-
public static PerfSession createWithId(@NonNull String sessionId) {
43-
String prunedSessionId = sessionId.replace("-", "");
44-
PerfSession session = new PerfSession(prunedSessionId, new Clock());
45-
session.setGaugeAndEventCollectionEnabled(shouldCollectGaugesAndEvents());
46-
40+
public static PerfSession createWithId(@Nullable String aqsSessionId) {
41+
String sessionId = UUID.randomUUID().toString().replace("-", "");
42+
Boolean isAqsReady = false;
43+
if (aqsSessionId != null) {
44+
sessionId = aqsSessionId;
45+
isAqsReady = true;
46+
}
47+
PerfSession session = new PerfSession(sessionId, new Clock(), isAqsReady);
48+
session.setGaugeAndEventCollectionEnabled(shouldCollectGaugesAndEvents(sessionId));
4749
return session;
4850
}
4951

5052
/** Creates a PerfSession with the provided {@code sessionId} and {@code clock}. */
5153
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
52-
public PerfSession(String sessionId, Clock clock) {
54+
public PerfSession(String sessionId, Clock clock, boolean isAqsReady) {
5355
this.sessionId = sessionId;
56+
this.isAqsReady = isAqsReady;
5457
creationTime = clock.getTime();
5558
}
5659

5760
private PerfSession(@NonNull Parcel in) {
5861
super();
5962
sessionId = in.readString();
6063
isGaugeAndEventCollectionEnabled = in.readByte() != 0;
64+
isAqsReady = in.readByte() != 0;
6165
creationTime = in.readParcelable(Timer.class.getClassLoader());
6266
}
6367

64-
/** Returns the sessionId of the session. */
68+
/** Returns the sessionId for the given session. */
6569
public String sessionId() {
6670
return sessionId;
6771
}
6872

69-
/** Returns the AQS sessionId for the given session. */
70-
@Nullable
71-
public String aqsSessionId() {
72-
return aqsSessionId;
73-
}
74-
75-
/** Sets the AQS sessionId for the given session. */
76-
public void setAQSId(SessionSubscriber.SessionDetails aqs) {
77-
if (aqsSessionId == null) {
78-
aqsSessionId = aqs.getSessionId();
79-
}
80-
}
81-
8273
/**
8374
* Returns a timer object that has been seeded with the system time at which the session began.
8475
*/
@@ -105,18 +96,6 @@ public boolean isVerbose() {
10596
return isGaugeAndEventCollectionEnabled;
10697
}
10798

108-
/** Checks if the current {@link com.google.firebase.perf.v1.PerfSession} is verbose or not. */
109-
@VisibleForTesting
110-
static boolean isVerbose(@NonNull com.google.firebase.perf.v1.PerfSession perfSession) {
111-
for (SessionVerbosity sessionVerbosity : perfSession.getSessionVerbosityList()) {
112-
if (sessionVerbosity == SessionVerbosity.GAUGES_AND_SYSTEM_EVENTS) {
113-
return true;
114-
}
115-
}
116-
117-
return false;
118-
}
119-
12099
/**
121100
* Checks if it has been more than {@link ConfigResolver#getSessionsMaxDurationMinutes()} time
122101
* since the creation time of the current session.
@@ -128,7 +107,6 @@ public boolean isSessionRunningTooLong() {
128107

129108
/** Creates and returns the proto object for PerfSession object. */
130109
public com.google.firebase.perf.v1.PerfSession build() {
131-
// TODO(b/394127311): Switch to using AQS.
132110
com.google.firebase.perf.v1.PerfSession.Builder sessionMetric =
133111
com.google.firebase.perf.v1.PerfSession.newBuilder().setSessionId(sessionId);
134112

@@ -179,11 +157,10 @@ public static com.google.firebase.perf.v1.PerfSession[] buildAndSort(
179157
}
180158

181159
/** If true, Session Gauge collection is enabled. */
182-
public static boolean shouldCollectGaugesAndEvents() {
160+
public static boolean shouldCollectGaugesAndEvents(String sessionId) {
183161
ConfigResolver configResolver = ConfigResolver.getInstance();
184-
185162
return configResolver.isPerformanceMonitoringEnabled()
186-
&& Math.random() < configResolver.getSessionsSamplingRate();
163+
&& (Math.abs(sessionId.hashCode() % 100) < configResolver.getSessionsSamplingRate() * 100);
187164
}
188165

189166
/**
@@ -207,6 +184,7 @@ public int describeContents() {
207184
public void writeToParcel(@NonNull Parcel out, int flags) {
208185
out.writeString(sessionId);
209186
out.writeByte((byte) (isGaugeAndEventCollectionEnabled ? 1 : 0));
187+
out.writeByte((byte) (isAqsReady ? 1 : 0));
210188
out.writeParcelable(creationTime, 0);
211189
}
212190

@@ -224,4 +202,16 @@ public PerfSession[] newArray(int size) {
224202
return new PerfSession[size];
225203
}
226204
};
205+
206+
/** Checks if the current {@link com.google.firebase.perf.v1.PerfSession} is verbose or not. */
207+
@VisibleForTesting
208+
static boolean isVerbose(@NonNull com.google.firebase.perf.v1.PerfSession perfSession) {
209+
for (SessionVerbosity sessionVerbosity : perfSession.getSessionVerbosityList()) {
210+
if (sessionVerbosity == SessionVerbosity.GAUGES_AND_SYSTEM_EVENTS) {
211+
return true;
212+
}
213+
}
214+
215+
return false;
216+
}
227217
}

firebase-perf/src/main/java/com/google/firebase/perf/session/SessionManager.java

+13-7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import androidx.annotation.Keep;
2020
import androidx.annotation.VisibleForTesting;
2121
import com.google.firebase.perf.application.AppStateMonitor;
22+
import com.google.firebase.perf.logging.DebugEnforcementCheck;
2223
import com.google.firebase.perf.session.gauges.GaugeManager;
2324
import com.google.firebase.perf.v1.ApplicationProcessState;
2425
import com.google.firebase.perf.v1.GaugeMetadata;
@@ -28,12 +29,10 @@
2829
import java.util.Iterator;
2930
import java.util.Objects;
3031
import java.util.Set;
31-
import java.util.UUID;
3232

3333
/** Session manager to generate sessionIDs and broadcast to the application. */
3434
@Keep // Needed because of b/117526359.
3535
public class SessionManager {
36-
3736
@SuppressLint("StaticFieldLeak")
3837
private static final SessionManager instance = new SessionManager();
3938

@@ -50,15 +49,15 @@ public static SessionManager getInstance() {
5049

5150
/** Returns the currently active PerfSession. */
5251
public final PerfSession perfSession() {
52+
DebugEnforcementCheck.Companion.checkSession(
53+
perfSession.isAqsReady, "Access perf session from manger without aqs ready");
54+
5355
return perfSession;
5456
}
5557

5658
private SessionManager() {
57-
// Generate a new sessionID for every cold start.
58-
this(
59-
GaugeManager.getInstance(),
60-
PerfSession.createWithId(UUID.randomUUID().toString()),
61-
AppStateMonitor.getInstance());
59+
// session should quickly updated by session subscriber.
60+
this(GaugeManager.getInstance(), PerfSession.createWithId(null), AppStateMonitor.getInstance());
6261
}
6362

6463
@VisibleForTesting
@@ -83,6 +82,10 @@ public void setApplicationContext(final Context appContext) {
8382
* @see PerfSession#isSessionRunningTooLong()
8483
*/
8584
public void stopGaugeCollectionIfSessionRunningTooLong() {
85+
DebugEnforcementCheck.Companion.checkSession(
86+
perfSession.isAqsReady,
87+
"Session is not ready while trying to stopGaugeCollectionIfSessionRunningTooLong");
88+
8689
if (perfSession.isSessionRunningTooLong()) {
8790
gaugeManager.stopCollectingGauges();
8891
}
@@ -156,6 +159,9 @@ public void unregisterForSessionUpdates(WeakReference<SessionAwareObject> client
156159
}
157160

158161
private void startOrStopCollectingGauges(ApplicationProcessState appState) {
162+
DebugEnforcementCheck.Companion.checkSession(
163+
perfSession.isAqsReady, "Session is not ready while trying to startOrStopCollectingGauges");
164+
159165
if (perfSession.isGaugeAndEventCollectionEnabled()) {
160166
gaugeManager.startCollectingGauges(perfSession, appState);
161167
} else {

firebase-perf/src/test/java/com/google/firebase/perf/application/AppStateMonitorTest.java

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import com.google.firebase.perf.config.DeviceCacheManager;
4040
import com.google.firebase.perf.metrics.NetworkRequestMetricBuilder;
4141
import com.google.firebase.perf.metrics.Trace;
42+
import com.google.firebase.perf.session.PerfSession;
43+
import com.google.firebase.perf.session.SessionManager;
4244
import com.google.firebase.perf.session.gauges.GaugeManager;
4345
import com.google.firebase.perf.transport.TransportManager;
4446
import com.google.firebase.perf.util.Clock;
@@ -80,6 +82,7 @@ public class AppStateMonitorTest extends FirebasePerformanceTestBase {
8082
@Before
8183
public void setUp() {
8284
currentTime = 0;
85+
SessionManager.getInstance().updatePerfSession(PerfSession.createWithId("sessionId"));
8386
initMocks(this);
8487
doAnswer((Answer<Timer>) invocationOnMock -> new Timer(currentTime)).when(clock).getTime();
8588

0 commit comments

Comments
 (0)