Skip to content

Update GaugeManager to better support AQS #6693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 82 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
9c03b7b
Remove the logging of GaugeMetadata to allow using AQS (#6678)
tejasd Feb 7, 2025
134398c
Add a SessionSubscriber
tejasd Feb 7, 2025
99a541e
style
tejasd Feb 7, 2025
09a9dec
Remove app updates from session manager and add unit tests
tejasd Feb 7, 2025
f37408d
Fix unit test
tejasd Feb 10, 2025
7654251
Add license header
tejasd Feb 10, 2025
a0e9493
Revert changes in ConfigResolver
tejasd Feb 10, 2025
b3ba68d
Use AQS Session ID for building a perf session
tejasd Feb 10, 2025
5e5caf5
Update TODOs
tejasd Feb 10, 2025
eb9856e
More TODO
tejasd Feb 10, 2025
8efea1b
More TODO
tejasd Feb 10, 2025
8e510b1
More TODOs
tejasd Feb 10, 2025
3145a71
Revert adding AQS in traces
tejasd Feb 11, 2025
03e2b10
Allow using session subscriber for unit tests
tejasd Feb 11, 2025
3c3fab6
Remove TODO
tejasd Feb 11, 2025
d598282
Style
tejasd Feb 11, 2025
800b33b
Try and update test
tejasd Feb 11, 2025
afb0804
Address code review comments
tejasd Feb 11, 2025
a68fbfc
Merge branch 'td/aqs-subscriber' into td/aqs-usage
tejasd Feb 11, 2025
166ed7e
Update tests
tejasd Feb 11, 2025
030cd9a
style
tejasd Feb 11, 2025
a9a36d3
Switch to usage of AQS instead of sessions in most places
tejasd Feb 11, 2025
b9816ff
Implement a SessionSubscriber for Firebase Performance (#6683)
tejasd Feb 11, 2025
0841728
Merge branch 'fireperf-aqs' into td/aqs-usage
tejasd Feb 11, 2025
e5bc537
Add back Session Subscriber variable
tejasd Feb 11, 2025
2d357bc
Upload some changes for gauge manager changes
tejasd Feb 11, 2025
f379bc0
More changes
tejasd Feb 11, 2025
fc403c0
Revert initializing gauge collection in FirebasePerfEarly
tejasd Feb 11, 2025
20fb963
style changes
tejasd Feb 11, 2025
f692e14
comment changes
tejasd Feb 11, 2025
6ee06c5
Update comment
tejasd Feb 25, 2025
49f0008
Remove the logging of GaugeMetadata to allow using AQS (#6678)
tejasd Feb 7, 2025
c5e9b9b
Implement a SessionSubscriber for Firebase Performance (#6683)
tejasd Feb 11, 2025
c71fd96
Use multi-process DataStore instead of Preferences DataStore (#6781)
mrober Mar 20, 2025
fcd270c
Share settings cache between running processes (#6788)
mrober Mar 24, 2025
51f5648
Merge branch 'fireperf-aqs' into td/aqs-usage
tejasd Apr 1, 2025
45f6252
Switch AQS ID to an always known ID
tejasd Apr 1, 2025
d307f57
More changes
tejasd Apr 1, 2025
54f5602
Fix unit tests showing warning about datastore_shared_counter (#6830)
mrober Apr 2, 2025
e0eb4c9
Fix unit tests showing warning about datastore_shared_counter (#6830)
mrober Apr 2, 2025
b453f98
Remove the logging of GaugeMetadata to allow using AQS (#6678)
tejasd Feb 7, 2025
50f8ba0
Add a SessionSubscriber
tejasd Feb 7, 2025
d1588c9
Remove app updates from session manager and add unit tests
tejasd Feb 7, 2025
7718f95
Implement a SessionSubscriber for Firebase Performance (#6683)
tejasd Feb 11, 2025
e91e147
Revert initializing gauge collection in FirebasePerfEarly
tejasd Feb 11, 2025
29cffc6
Switch AQS ID to an always known ID
tejasd Apr 1, 2025
7dfdc76
Update unit tests
tejasd Apr 3, 2025
1793cda
Add a better explanation in SessionSubscriber
tejasd Apr 3, 2025
57c9eb7
Merge branch 'fireperf-aqs' into td/aqs-usage
tejasd Apr 4, 2025
c22a3eb
Attempt at updating the GaugeManagerTests
tejasd Apr 4, 2025
fa39f77
More tests
tejasd Apr 4, 2025
639c85e
Revert no-op change
tejasd Apr 4, 2025
63d7959
API change
tejasd Apr 4, 2025
4574165
Fix API change
tejasd Apr 4, 2025
955c5f9
Add test rule which might fix github action unit test failure
tejasd Apr 4, 2025
2026636
style
tejasd Apr 4, 2025
3986c22
update comment
tejasd Apr 4, 2025
9385461
nit
tejasd Apr 4, 2025
c01019d
Update test and add a TODO
tejasd Apr 4, 2025
775682c
Add logging in syncFlush
tejasd Apr 4, 2025
13ce733
style + logs change
tejasd Apr 4, 2025
da8acfa
Update comment in updateAppState
tejasd Apr 7, 2025
1e8b629
convert perf session to use aqs support session id (#6832)
themiswang Apr 7, 2025
3f2b6e7
Merge branch 'fireperf-aqs' into td/aqs-usage
tejasd Apr 7, 2025
10369d0
Remove the logging of GaugeMetadata to allow using AQS (#6678)
tejasd Feb 7, 2025
a9f47b4
Implement a SessionSubscriber for Firebase Performance (#6683)
tejasd Feb 11, 2025
7d9c0bf
convert perf session to use aqs support session id (#6832)
themiswang Apr 7, 2025
d75b095
Merge branch 'fireperf-aqs' into td/aqs-usage
tejasd Apr 7, 2025
c933078
Revert changes in sessions to fireperf-aqs
tejasd Apr 7, 2025
7fb534d
Revert additional changes from sessions
tejasd Apr 7, 2025
73a04e7
Revert libs change
tejasd Apr 7, 2025
a0ee2b2
More changes
tejasd Apr 8, 2025
97bc643
Fix tests
tejasd Apr 8, 2025
8377e8c
Revert usage of mockClock
tejasd Apr 8, 2025
f2a4728
Re-introduce gauge collection for app start
tejasd Apr 8, 2025
78d4524
Add verbose check
tejasd Apr 8, 2025
ebb5325
style
tejasd Apr 8, 2025
281e7b1
Try simplifying logging
tejasd Apr 8, 2025
f5a494e
style
tejasd Apr 8, 2025
a2d6ed2
Add a legacy sessions build config
tejasd Apr 8, 2025
3f8c550
Fix unit tests
tejasd Apr 9, 2025
c9c0441
unused log
tejasd Apr 9, 2025
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
5 changes: 4 additions & 1 deletion firebase-perf/firebase-perf.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,15 @@ android {
buildConfigField("String", "TRANSPORT_LOG_SRC", "String.valueOf(\"FIREPERF\")")
buildConfigField("Boolean", "ENFORCE_DEFAULT_LOG_SRC", "Boolean.valueOf(false)")
buildConfigField("String", "FIREPERF_VERSION_NAME", "String.valueOf(\"" + property("version") + "\")")
buildConfigField("Boolean", "ENFORCE_LEGACY_SESSIONS", "Boolean.valueOf(false)")

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

minSdkVersion project.minSdkVersion
Expand Down Expand Up @@ -118,7 +120,7 @@ dependencies {
api("com.google.firebase:firebase-components:18.0.0")
api("com.google.firebase:firebase-config:21.5.0")
api("com.google.firebase:firebase-installations:17.2.0")
api("com.google.firebase:firebase-sessions:2.0.7") {
api(project(":firebase-sessions")) {
exclude group: 'com.google.firebase', module: 'firebase-common'
exclude group: 'com.google.firebase', module: 'firebase-common-ktx'
exclude group: 'com.google.firebase', module: 'firebase-components'
Expand All @@ -138,4 +140,5 @@ dependencies {
testImplementation libs.mockito.core
testImplementation libs.mockito.mockito.inline
testImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.6'
testImplementation "androidx.arch.core:core-testing:2.1.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ public FirebasePerfEarly(
uiExecutor.execute(new AppStartTrace.StartFromBackgroundRunnable(appStartTrace));
}

// TODO: Bring back Firebase Sessions dependency to watch for updates to sessions.

// 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.
// Uploading the gauges however only starts once AQS is initialized.
// TODO(b/394127311): Update this to use changes in AQS initialization,
SessionManager.getInstance().initializeGaugeCollection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import com.google.firebase.perf.injection.modules.FirebasePerformanceModule;
import com.google.firebase.platforminfo.LibraryVersionComponent;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
import com.google.firebase.sessions.api.SessionSubscriber;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
Expand All @@ -47,6 +49,11 @@ public class FirebasePerfRegistrar implements ComponentRegistrar {
private static final String LIBRARY_NAME = "fire-perf";
private static final String EARLY_LIBRARY_NAME = "fire-perf-early";

static {
// Add Firebase Performance as a dependency of Sessions when this class is loaded into memory.
FirebaseSessionsDependencies.addDependency(SessionSubscriber.Name.PERFORMANCE);
}

@Override
@Keep
public List<Component<?>> getComponents() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@
import com.google.firebase.perf.config.RemoteConfigManager;
import com.google.firebase.perf.logging.AndroidLogger;
import com.google.firebase.perf.logging.ConsoleUrlGenerator;
import com.google.firebase.perf.logging.DebugEnforcementCheck;
import com.google.firebase.perf.metrics.HttpMetric;
import com.google.firebase.perf.metrics.Trace;
import com.google.firebase.perf.session.FirebasePerformanceSessionSubscriber;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.transport.TransportManager;
import com.google.firebase.perf.util.Constants;
import com.google.firebase.perf.util.ImmutableBundle;
import com.google.firebase.perf.util.Timer;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
import com.google.firebase.sessions.api.SessionSubscriber;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.URL;
Expand Down Expand Up @@ -92,6 +96,8 @@ public class FirebasePerformance implements FirebasePerformanceAttributable {
// once during initialization and cache it.
private final ImmutableBundle mMetadataBundle;

private final SessionSubscriber sessionSubscriber;

/** Valid HttpMethods for manual network APIs */
@StringDef({
HttpMethod.GET,
Expand Down Expand Up @@ -136,11 +142,6 @@ public static FirebasePerformance getInstance() {
// to false if it's been force disabled or it is set to null if neither.
@Nullable private Boolean mPerformanceCollectionForceEnabledState = null;

private final FirebaseApp firebaseApp;
private final Provider<RemoteConfigComponent> firebaseRemoteConfigProvider;
private final FirebaseInstallationsApi firebaseInstallationsApi;
private final Provider<TransportFactory> transportFactoryProvider;

/**
* Constructs the FirebasePerformance class and allows injecting dependencies.
*
Expand All @@ -166,23 +167,19 @@ public static FirebasePerformance getInstance() {
ConfigResolver configResolver,
SessionManager sessionManager) {

this.firebaseApp = firebaseApp;
this.firebaseRemoteConfigProvider = firebaseRemoteConfigProvider;
this.firebaseInstallationsApi = firebaseInstallationsApi;
this.transportFactoryProvider = transportFactoryProvider;

if (firebaseApp == null) {
this.mPerformanceCollectionForceEnabledState = false;
this.configResolver = configResolver;
this.mMetadataBundle = new ImmutableBundle(new Bundle());
this.sessionSubscriber = new FirebasePerformanceSessionSubscriber(false);
return;
}
DebugEnforcementCheck.setEnforcement(BuildConfig.ENFORCE_LEGACY_SESSIONS);

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

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

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

mPerformanceCollectionForceEnabledState = configResolver.getIsPerformanceCollectionEnabled();
sessionSubscriber = new FirebasePerformanceSessionSubscriber(isPerformanceCollectionEnabled());
FirebaseSessionsDependencies.register(sessionSubscriber);

if (logger.isLogcatEnabled() && isPerformanceCollectionEnabled()) {
logger.info(
String.format(
Expand Down Expand Up @@ -282,7 +282,7 @@ public synchronized void setPerformanceCollectionEnabled(@Nullable Boolean enabl
return;
}

if (configResolver.getIsPerformanceCollectionDeactivated()) {
if (Boolean.TRUE.equals(configResolver.getIsPerformanceCollectionDeactivated())) {
logger.info("Firebase Performance is permanently disabled");
return;
}
Expand Down Expand Up @@ -466,4 +466,9 @@ private static ImmutableBundle extractMetadata(Context appContext) {
Boolean getPerformanceCollectionForceEnabledState() {
return mPerformanceCollectionForceEnabledState;
}

@VisibleForTesting
SessionSubscriber getSessionSubscriber() {
return sessionSubscriber;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.perf.logging

import com.google.firebase.perf.session.PerfSession
import com.google.firebase.perf.session.isLegacy

class DebugEnforcementCheck {
companion object {
/** When enabled, failed preconditions will cause assertion errors for debugging. */
@JvmStatic var enforcement: Boolean = false
private var logger: AndroidLogger = AndroidLogger.getInstance()

fun checkSession(session: PerfSession, failureMessage: String) {
if (session.isLegacy()) {
logger.debug("legacy session ${session.sessionId()}: $failureMessage")
assert(!enforcement) { failureMessage }
}
}

fun checkSession(sessionId: String, failureMessage: String) {
if (sessionId.isLegacy()) {
logger.debug("legacy session ${sessionId}: $failureMessage")
assert(!enforcement) { failureMessage }
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.perf.session

import com.google.firebase.perf.logging.DebugEnforcementCheck
import com.google.firebase.perf.session.gauges.GaugeManager
import com.google.firebase.perf.v1.ApplicationProcessState
import com.google.firebase.sessions.api.SessionSubscriber

class FirebasePerformanceSessionSubscriber(override val isDataCollectionEnabled: Boolean) :
SessionSubscriber {

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

override fun onSessionChanged(sessionDetails: SessionSubscriber.SessionDetails) {
val currentPerfSession = SessionManager.getInstance().perfSession()
DebugEnforcementCheck.checkSession(currentPerfSession, "onSessionChanged")

// A [PerfSession] was created before a session was started.
// Since these were verbose gauge collection at app startup, it logs them to the updated session
// ID.
if (currentPerfSession.isLegacy() && currentPerfSession.isVerbose) {
GaugeManager.getInstance()
.logGaugeMetadata(sessionDetails.sessionId, ApplicationProcessState.FOREGROUND)
GaugeManager.getInstance()
.stopCollectingGaugesForLegacySession(
sessionDetails.sessionId,
ApplicationProcessState.FOREGROUND
)
}

val updatedSession = PerfSession.createWithId(sessionDetails.sessionId)
SessionManager.getInstance().updatePerfSession(updatedSession)
GaugeManager.getInstance()
.logGaugeMetadata(updatedSession.sessionId(), ApplicationProcessState.FOREGROUND)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.google.firebase.perf.session

import com.google.firebase.perf.util.Constants
import java.util.UUID

/** Identifies whether the [PerfSession] is legacy or not. */
fun PerfSession.isLegacy(): Boolean {
return this.sessionId().isLegacy()
}

/** Identifies whether the string is from a legacy [PerfSession]. */
fun String.isLegacy(): Boolean {
return this.startsWith(Constants.UNDEFINED_AQS_ID_PREFIX)
}

/** Creates a valid session ID for [PerfSession] that can be predictably identified as legacy. */
fun createLegacySessionId(): String {
val uuid = UUID.randomUUID().toString().replace("-", "")
return uuid.replaceRange(
0,
Constants.UNDEFINED_AQS_ID_PREFIX.length,
Constants.UNDEFINED_AQS_ID_PREFIX
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@

/** Details of a session including a unique Id and related information. */
public class PerfSession implements Parcelable {

private final String sessionId;
private final Timer creationTime;

private final String sessionId;
private boolean isGaugeAndEventCollectionEnabled = false;

/*
* Creates a PerfSession object and decides what metrics to collect.
*/
public static PerfSession createWithId(@NonNull String sessionId) {
String prunedSessionId = sessionId.replace("-", "");
PerfSession session = new PerfSession(prunedSessionId, new Clock());
session.setGaugeAndEventCollectionEnabled(shouldCollectGaugesAndEvents());

public static PerfSession createWithId(@Nullable String aqsSessionId) {
String sessionId = aqsSessionId;
if (sessionId == null) {
sessionId = FirebaseSessionsHelperKt.createLegacySessionId();
}
PerfSession session = new PerfSession(sessionId, new Clock());
session.setGaugeAndEventCollectionEnabled(session.shouldCollectGaugesAndEvents());
return session;
}

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

/** Returns the sessionId of the object. */
/** Returns the sessionId for the given session. */
@NonNull
public String sessionId() {
return sessionId;
}
Expand Down Expand Up @@ -90,18 +91,6 @@ public boolean isVerbose() {
return isGaugeAndEventCollectionEnabled;
}

/** Checks if the current {@link com.google.firebase.perf.v1.PerfSession} is verbose or not. */
@VisibleForTesting
static boolean isVerbose(@NonNull com.google.firebase.perf.v1.PerfSession perfSession) {
for (SessionVerbosity sessionVerbosity : perfSession.getSessionVerbosityList()) {
if (sessionVerbosity == SessionVerbosity.GAUGES_AND_SYSTEM_EVENTS) {
return true;
}
}

return false;
}

/**
* Checks if it has been more than {@link ConfigResolver#getSessionsMaxDurationMinutes()} time
* since the creation time of the current session.
Expand Down Expand Up @@ -163,11 +152,11 @@ public static com.google.firebase.perf.v1.PerfSession[] buildAndSort(
}

/** If true, Session Gauge collection is enabled. */
public static boolean shouldCollectGaugesAndEvents() {
public boolean shouldCollectGaugesAndEvents() {
ConfigResolver configResolver = ConfigResolver.getInstance();

return configResolver.isPerformanceMonitoringEnabled()
&& Math.random() < configResolver.getSessionsSamplingRate();
&& (Math.abs(this.sessionId.hashCode() % 100)
< configResolver.getSessionsSamplingRate() * 100);
}

/**
Expand Down Expand Up @@ -208,4 +197,16 @@ public PerfSession[] newArray(int size) {
return new PerfSession[size];
}
};

/** Checks if the current {@link com.google.firebase.perf.v1.PerfSession} is verbose or not. */
@VisibleForTesting
static boolean isVerbose(@NonNull com.google.firebase.perf.v1.PerfSession perfSession) {
for (SessionVerbosity sessionVerbosity : perfSession.getSessionVerbosityList()) {
if (sessionVerbosity == SessionVerbosity.GAUGES_AND_SYSTEM_EVENTS) {
return true;
}
}

return false;
}
}
Loading
Loading