Skip to content

Commit acbffec

Browse files
authored
Merge 0d9ba90 into 5aff679
2 parents 5aff679 + 0d9ba90 commit acbffec

23 files changed

+448
-514
lines changed

firebase-perf/firebase-perf.gradle

+3-1
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,15 @@ android {
7070
buildConfigField("String", "TRANSPORT_LOG_SRC", "String.valueOf(\"FIREPERF\")")
7171
buildConfigField("Boolean", "ENFORCE_DEFAULT_LOG_SRC", "Boolean.valueOf(false)")
7272
buildConfigField("String", "FIREPERF_VERSION_NAME", "String.valueOf(\"" + property("version") + "\")")
73+
buildConfigField("Boolean", "ENFORCE_LEGACY_SESSIONS", "Boolean.valueOf(false)")
7374

7475
if (project.hasProperty("fireperfBuildForAutopush")) {
7576
// This allows the SDK to be built for "Autopush" env when the mentioned flag
7677
// (-PfireperfBuildForAutopush) is passed in the gradle build command (of either the
7778
// SDK or the Test App).
7879
buildConfigField("String", "TRANSPORT_LOG_SRC", "String.valueOf(\"FIREPERF_AUTOPUSH\")")
7980
buildConfigField("Boolean", "ENFORCE_DEFAULT_LOG_SRC", "Boolean.valueOf(true)")
81+
buildConfigField("Boolean", "ENFORCE_LEGACY_SESSIONS", "Boolean.valueOf(true)")
8082
}
8183

8284
minSdkVersion project.minSdkVersion
@@ -118,7 +120,7 @@ dependencies {
118120
api("com.google.firebase:firebase-components:18.0.0")
119121
api("com.google.firebase:firebase-config:21.5.0")
120122
api("com.google.firebase:firebase-installations:17.2.0")
121-
api("com.google.firebase:firebase-sessions:2.0.7") {
123+
api(project(":firebase-sessions")) {
122124
exclude group: 'com.google.firebase', module: 'firebase-common'
123125
exclude group: 'com.google.firebase', module: 'firebase-common-ktx'
124126
exclude group: 'com.google.firebase', module: 'firebase-components'

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,8 @@ public FirebasePerfEarly(
5151
uiExecutor.execute(new AppStartTrace.StartFromBackgroundRunnable(appStartTrace));
5252
}
5353

54-
// TODO: Bring back Firebase Sessions dependency to watch for updates to sessions.
54+
// In the case of a cold start, we initialize gauge collection with a legacy PerfSession.
5555

56-
// In the case of cold start, we create a session and start collecting gauges as early as
57-
// possible.
58-
// There is code in SessionManager that prevents us from resetting the session twice in case
59-
// of app cold start.
6056
SessionManager.getInstance().initializeGaugeCollection();
6157
}
6258
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import com.google.firebase.perf.injection.modules.FirebasePerformanceModule;
3131
import com.google.firebase.platforminfo.LibraryVersionComponent;
3232
import com.google.firebase.remoteconfig.RemoteConfigComponent;
33+
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
34+
import com.google.firebase.sessions.api.SessionSubscriber;
3335
import java.util.Arrays;
3436
import java.util.List;
3537
import java.util.concurrent.Executor;
@@ -47,6 +49,11 @@ public class FirebasePerfRegistrar implements ComponentRegistrar {
4749
private static final String LIBRARY_NAME = "fire-perf";
4850
private static final String EARLY_LIBRARY_NAME = "fire-perf-early";
4951

52+
static {
53+
// Add Firebase Performance as a dependency of Sessions when this class is loaded into memory.
54+
FirebaseSessionsDependencies.addDependency(SessionSubscriber.Name.PERFORMANCE);
55+
}
56+
5057
@Override
5158
@Keep
5259
public List<Component<?>> getComponents() {

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

+17-12
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,18 @@
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.FirebaseSessionsEnforcementCheck;
3738
import com.google.firebase.perf.metrics.HttpMetric;
3839
import com.google.firebase.perf.metrics.Trace;
40+
import com.google.firebase.perf.session.FirebasePerformanceSessionSubscriber;
3941
import com.google.firebase.perf.session.SessionManager;
4042
import com.google.firebase.perf.transport.TransportManager;
4143
import com.google.firebase.perf.util.Constants;
4244
import com.google.firebase.perf.util.ImmutableBundle;
4345
import com.google.firebase.perf.util.Timer;
4446
import com.google.firebase.remoteconfig.RemoteConfigComponent;
47+
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
48+
import com.google.firebase.sessions.api.SessionSubscriber;
4549
import java.lang.annotation.Retention;
4650
import java.lang.annotation.RetentionPolicy;
4751
import java.net.URL;
@@ -92,6 +96,8 @@ public class FirebasePerformance implements FirebasePerformanceAttributable {
9296
// once during initialization and cache it.
9397
private final ImmutableBundle mMetadataBundle;
9498

99+
private final SessionSubscriber sessionSubscriber;
100+
95101
/** Valid HttpMethods for manual network APIs */
96102
@StringDef({
97103
HttpMethod.GET,
@@ -136,11 +142,6 @@ public static FirebasePerformance getInstance() {
136142
// to false if it's been force disabled or it is set to null if neither.
137143
@Nullable private Boolean mPerformanceCollectionForceEnabledState = null;
138144

139-
private final FirebaseApp firebaseApp;
140-
private final Provider<RemoteConfigComponent> firebaseRemoteConfigProvider;
141-
private final FirebaseInstallationsApi firebaseInstallationsApi;
142-
private final Provider<TransportFactory> transportFactoryProvider;
143-
144145
/**
145146
* Constructs the FirebasePerformance class and allows injecting dependencies.
146147
*
@@ -166,23 +167,19 @@ public static FirebasePerformance getInstance() {
166167
ConfigResolver configResolver,
167168
SessionManager sessionManager) {
168169

169-
this.firebaseApp = firebaseApp;
170-
this.firebaseRemoteConfigProvider = firebaseRemoteConfigProvider;
171-
this.firebaseInstallationsApi = firebaseInstallationsApi;
172-
this.transportFactoryProvider = transportFactoryProvider;
173-
174170
if (firebaseApp == null) {
175171
this.mPerformanceCollectionForceEnabledState = false;
176172
this.configResolver = configResolver;
177173
this.mMetadataBundle = new ImmutableBundle(new Bundle());
174+
this.sessionSubscriber = new FirebasePerformanceSessionSubscriber(false);
178175
return;
179176
}
177+
FirebaseSessionsEnforcementCheck.setEnforcement(BuildConfig.ENFORCE_LEGACY_SESSIONS);
180178

181179
TransportManager.getInstance()
182180
.initialize(firebaseApp, firebaseInstallationsApi, transportFactoryProvider);
183181

184182
Context appContext = firebaseApp.getApplicationContext();
185-
// TODO(b/110178816): Explore moving off of main thread.
186183
mMetadataBundle = extractMetadata(appContext);
187184

188185
remoteConfigManager.setFirebaseRemoteConfigProvider(firebaseRemoteConfigProvider);
@@ -192,6 +189,9 @@ public static FirebasePerformance getInstance() {
192189
sessionManager.setApplicationContext(appContext);
193190

194191
mPerformanceCollectionForceEnabledState = configResolver.getIsPerformanceCollectionEnabled();
192+
sessionSubscriber = new FirebasePerformanceSessionSubscriber(isPerformanceCollectionEnabled());
193+
FirebaseSessionsDependencies.register(sessionSubscriber);
194+
195195
if (logger.isLogcatEnabled() && isPerformanceCollectionEnabled()) {
196196
logger.info(
197197
String.format(
@@ -282,7 +282,7 @@ public synchronized void setPerformanceCollectionEnabled(@Nullable Boolean enabl
282282
return;
283283
}
284284

285-
if (configResolver.getIsPerformanceCollectionDeactivated()) {
285+
if (Boolean.TRUE.equals(configResolver.getIsPerformanceCollectionDeactivated())) {
286286
logger.info("Firebase Performance is permanently disabled");
287287
return;
288288
}
@@ -466,4 +466,9 @@ private static ImmutableBundle extractMetadata(Context appContext) {
466466
Boolean getPerformanceCollectionForceEnabledState() {
467467
return mPerformanceCollectionForceEnabledState;
468468
}
469+
470+
@VisibleForTesting
471+
SessionSubscriber getSessionSubscriber() {
472+
return sessionSubscriber;
473+
}
469474
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
import com.google.firebase.perf.session.PerfSession
20+
import com.google.firebase.perf.session.isLegacy
21+
22+
class FirebaseSessionsEnforcementCheck {
23+
companion object {
24+
/** When enabled, failed preconditions will cause assertion errors for debugging. */
25+
@JvmStatic var enforcement: Boolean = false
26+
private var logger: AndroidLogger = AndroidLogger.getInstance()
27+
28+
@JvmStatic
29+
fun checkSession(session: PerfSession, failureMessage: String) {
30+
if (session.isLegacy()) {
31+
logger.debug("legacy session ${session.sessionId()}: $failureMessage")
32+
assert(!enforcement) { failureMessage }
33+
}
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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.session
18+
19+
import com.google.firebase.perf.logging.FirebaseSessionsEnforcementCheck
20+
import com.google.firebase.perf.session.gauges.GaugeManager
21+
import com.google.firebase.perf.v1.ApplicationProcessState
22+
import com.google.firebase.sessions.api.SessionSubscriber
23+
24+
class FirebasePerformanceSessionSubscriber(override val isDataCollectionEnabled: Boolean) :
25+
SessionSubscriber {
26+
27+
override val sessionSubscriberName: SessionSubscriber.Name = SessionSubscriber.Name.PERFORMANCE
28+
29+
override fun onSessionChanged(sessionDetails: SessionSubscriber.SessionDetails) {
30+
val currentPerfSession = SessionManager.getInstance().perfSession()
31+
// TODO(b/394127311): Add logic to deal with app start gauges.
32+
FirebaseSessionsEnforcementCheck.checkSession(currentPerfSession, "onSessionChanged")
33+
34+
val updatedSession = PerfSession.createWithId(sessionDetails.sessionId)
35+
SessionManager.getInstance().updatePerfSession(updatedSession)
36+
GaugeManager.getInstance()
37+
.logGaugeMetadata(updatedSession.sessionId(), ApplicationProcessState.FOREGROUND)
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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.session
18+
19+
import com.google.firebase.perf.util.Constants
20+
import java.util.UUID
21+
22+
/** Identifies whether the [PerfSession] is legacy or not. */
23+
fun PerfSession.isLegacy(): Boolean {
24+
return this.sessionId().isLegacy()
25+
}
26+
27+
/** Identifies whether the string is from a legacy [PerfSession]. */
28+
fun String.isLegacy(): Boolean {
29+
return this.startsWith(Constants.UNDEFINED_AQS_ID_PREFIX)
30+
}
31+
32+
/** Creates a valid session ID for [PerfSession] that can be predictably identified as legacy. */
33+
fun createLegacySessionId(): String {
34+
val uuid = UUID.randomUUID().toString().replace("-", "")
35+
return uuid.replaceRange(
36+
0,
37+
Constants.UNDEFINED_AQS_ID_PREFIX.length,
38+
Constants.UNDEFINED_AQS_ID_PREFIX
39+
)
40+
}

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

+25-24
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,20 @@
2828

2929
/** Details of a session including a unique Id and related information. */
3030
public class PerfSession implements Parcelable {
31-
32-
private final String sessionId;
3331
private final Timer creationTime;
34-
32+
private final String sessionId;
3533
private boolean isGaugeAndEventCollectionEnabled = false;
3634

3735
/*
3836
* Creates a PerfSession object and decides what metrics to collect.
3937
*/
40-
public static PerfSession createWithId(@NonNull String sessionId) {
41-
String prunedSessionId = sessionId.replace("-", "");
42-
PerfSession session = new PerfSession(prunedSessionId, new Clock());
43-
session.setGaugeAndEventCollectionEnabled(shouldCollectGaugesAndEvents());
44-
38+
public static PerfSession createWithId(@Nullable String aqsSessionId) {
39+
String sessionId = aqsSessionId;
40+
if (sessionId == null) {
41+
sessionId = FirebaseSessionsHelperKt.createLegacySessionId();
42+
}
43+
PerfSession session = new PerfSession(sessionId, new Clock());
44+
session.setGaugeAndEventCollectionEnabled(session.shouldCollectGaugesAndEvents());
4545
return session;
4646
}
4747

@@ -59,7 +59,8 @@ private PerfSession(@NonNull Parcel in) {
5959
creationTime = in.readParcelable(Timer.class.getClassLoader());
6060
}
6161

62-
/** Returns the sessionId of the object. */
62+
/** Returns the sessionId for the given session. */
63+
@NonNull
6364
public String sessionId() {
6465
return sessionId;
6566
}
@@ -90,18 +91,6 @@ public boolean isVerbose() {
9091
return isGaugeAndEventCollectionEnabled;
9192
}
9293

93-
/** Checks if the current {@link com.google.firebase.perf.v1.PerfSession} is verbose or not. */
94-
@VisibleForTesting
95-
static boolean isVerbose(@NonNull com.google.firebase.perf.v1.PerfSession perfSession) {
96-
for (SessionVerbosity sessionVerbosity : perfSession.getSessionVerbosityList()) {
97-
if (sessionVerbosity == SessionVerbosity.GAUGES_AND_SYSTEM_EVENTS) {
98-
return true;
99-
}
100-
}
101-
102-
return false;
103-
}
104-
10594
/**
10695
* Checks if it has been more than {@link ConfigResolver#getSessionsMaxDurationMinutes()} time
10796
* since the creation time of the current session.
@@ -163,11 +152,11 @@ public static com.google.firebase.perf.v1.PerfSession[] buildAndSort(
163152
}
164153

165154
/** If true, Session Gauge collection is enabled. */
166-
public static boolean shouldCollectGaugesAndEvents() {
155+
public boolean shouldCollectGaugesAndEvents() {
167156
ConfigResolver configResolver = ConfigResolver.getInstance();
168-
169157
return configResolver.isPerformanceMonitoringEnabled()
170-
&& Math.random() < configResolver.getSessionsSamplingRate();
158+
&& (Math.abs(this.sessionId.hashCode() % 100)
159+
< configResolver.getSessionsSamplingRate() * 100);
171160
}
172161

173162
/**
@@ -208,4 +197,16 @@ public PerfSession[] newArray(int size) {
208197
return new PerfSession[size];
209198
}
210199
};
200+
201+
/** Checks if the current {@link com.google.firebase.perf.v1.PerfSession} is verbose or not. */
202+
@VisibleForTesting
203+
static boolean isVerbose(@NonNull com.google.firebase.perf.v1.PerfSession perfSession) {
204+
for (SessionVerbosity sessionVerbosity : perfSession.getSessionVerbosityList()) {
205+
if (sessionVerbosity == SessionVerbosity.GAUGES_AND_SYSTEM_EVENTS) {
206+
return true;
207+
}
208+
}
209+
210+
return false;
211+
}
211212
}

0 commit comments

Comments
 (0)