Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
94bf1b4
Remove the logging of GaugeMetadata to allow using AQS (#6678)
tejasd Feb 7, 2025
6624a4e
Implement a SessionSubscriber for Firebase Performance (#6683)
tejasd Feb 11, 2025
7914326
convert perf session to use aqs support session id (#6832)
themiswang Apr 7, 2025
c95d813
Update PerfSession and SessionManager to identify Legacy sessions. (#…
tejasd Apr 14, 2025
cbc5130
Add process name to application info (#6890)
themiswang Apr 17, 2025
b9e5efb
Update GaugeManager for AQS (#6938)
tejasd May 7, 2025
e4dc71d
Add unit tests for new logging in GaugeManager using GaugeCounter. (#…
tejasd May 15, 2025
35767db
Refactor usage of ProcessName in Fireperf. (#6963)
tejasd May 16, 2025
591db10
Add missing `GaugeCounter` increment. (#6966)
tejasd May 16, 2025
5ee6df3
Add gauge counter to collector tests (#6991)
tejasd May 26, 2025
3d97050
Update Gauge logging to better match the implementation on main (#6992)
tejasd May 27, 2025
d8cab85
Make the AQS Test App behave more typically for Perf start up (#7158)
mrober Jul 16, 2025
76c322e
Update the behaviour of the FirebasePerformanceSessionSubcriber to be…
tejasd Jul 25, 2025
db794e1
Add more legacy session verification, move up gauge collection, and u…
tejasd Jul 30, 2025
22ec9a5
Update the version dependency of firebase sessions (#7201)
tejasd Jul 30, 2025
917fa58
Update legacy session enforcement and debugging logic (#7244)
tejasd Aug 13, 2025
91fea97
Update legacy session logs to include trace names. (#7258)
tejasd Aug 14, 2025
cc777ce
Merge branch 'main' into fireperf-aqs
tejasd Jan 8, 2026
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
4 changes: 3 additions & 1 deletion firebase-perf/firebase-perf.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,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 @@ -124,7 +126,7 @@ dependencies {
api("com.google.firebase:firebase-installations:18.0.0") {
exclude group: 'com.google.firebase', module: 'firebase-common-ktx'
}
api("com.google.firebase:firebase-sessions:2.0.7") {
api("com.google.firebase:firebase-sessions:3.0.0") {
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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import com.google.firebase.perf.application.AppStateMonitor;
import com.google.firebase.perf.config.ConfigResolver;
import com.google.firebase.perf.metrics.AppStartTrace;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.perf.session.FirebasePerformanceSessionSubscriber;
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
import java.util.concurrent.Executor;

/**
Expand All @@ -41,6 +42,10 @@ public FirebasePerfEarly(
ConfigResolver configResolver = ConfigResolver.getInstance();
configResolver.setApplicationContext(context);

// Register FirebasePerformance as a subscriber ASAP - which will start collecting gauges if the
// FirebaseSession is verbose.
FirebaseSessionsDependencies.register(new FirebasePerformanceSessionSubscriber(configResolver));

AppStateMonitor appStateMonitor = AppStateMonitor.getInstance();
appStateMonitor.registerActivityLifecycleCallbacks(context);
appStateMonitor.registerForAppColdStart(new FirebasePerformanceInitializer());
Expand All @@ -50,13 +55,5 @@ public FirebasePerfEarly(
appStartTrace.registerActivityLifecycleCallbacks(context);
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.
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,6 +34,7 @@
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.FirebaseSessionsEnforcementCheck;
import com.google.firebase.perf.metrics.HttpMetric;
import com.google.firebase.perf.metrics.Trace;
import com.google.firebase.perf.session.SessionManager;
Expand Down Expand Up @@ -136,11 +137,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 +162,18 @@ 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());
return;
}
FirebaseSessionsEnforcementCheck.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 +183,7 @@ public static FirebasePerformance getInstance() {
sessionManager.setApplicationContext(appContext);

mPerformanceCollectionForceEnabledState = configResolver.getIsPerformanceCollectionEnabled();

if (logger.isLogcatEnabled() && isPerformanceCollectionEnabled()) {
logger.info(
String.format(
Expand Down Expand Up @@ -282,7 +274,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
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.isLegacy
import com.google.firebase.perf.v1.PerfSession as ProtoPerfSession

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

@JvmStatic
fun checkSessionsList(sessions: List<ProtoPerfSession>, failureMessage: String) {
if (sessions.count { it.sessionId.isLegacy() } == sessions.size) {
sessions.forEach { checkSession(it.sessionId, failureMessage) }
}
}

@JvmStatic
fun checkSession(sessionId: String, failureMessage: String) {
if (sessionId.isLegacy()) {
logger.verbose("Contains Legacy Session ${sessionId}: $failureMessage")
assert(!enforcement) { failureMessage }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package com.google.firebase.perf.metrics;

import static com.google.firebase.perf.util.AppProcessesProvider.getAppProcesses;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
Expand Down Expand Up @@ -552,11 +554,8 @@ public static boolean isAnyAppProcessInForeground(Context appContext) {
if (activityManager == null) {
return true;
}
List<ActivityManager.RunningAppProcessInfo> appProcesses =
activityManager.getRunningAppProcesses();
if (appProcesses != null) {
String appProcessName = appContext.getPackageName();
String allowedAppProcessNamePrefix = appProcessName + ":";
List<ActivityManager.RunningAppProcessInfo> appProcesses = getAppProcesses(appContext);
if (!appProcesses.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public NetworkRequestMetricBuilder setCustomAttributes(Map<String, String> attri
* point depending upon the current {@link PerfSession} verbosity.
*
* @see GaugeManager#collectGaugeMetricOnce(Timer)
* @see PerfSession#isGaugeAndEventCollectionEnabled()
* @see PerfSession#isVerbose()
*/
public NetworkRequestMetricBuilder setRequestStartTimeMicros(long time) {
SessionManager sessionManager = SessionManager.getInstance();
Expand All @@ -234,7 +234,7 @@ public NetworkRequestMetricBuilder setRequestStartTimeMicros(long time) {
builder.setClientStartTimeUs(time);
updateSession(perfSession);

if (perfSession.isGaugeAndEventCollectionEnabled()) {
if (perfSession.isVerbose()) {
gaugeManager.collectGaugeMetricOnce(perfSession.getTimer());
}

Expand Down Expand Up @@ -265,12 +265,12 @@ public long getTimeToResponseInitiatedMicros() {
* point depending upon the current {@link PerfSession} Verbosity.
*
* @see GaugeManager#collectGaugeMetricOnce(Timer)
* @see PerfSession#isGaugeAndEventCollectionEnabled()
* @see PerfSession#isVerbose()
*/
public NetworkRequestMetricBuilder setTimeToResponseCompletedMicros(long time) {
builder.setTimeToResponseCompletedUs(time);

if (SessionManager.getInstance().perfSession().isGaugeAndEventCollectionEnabled()) {
if (SessionManager.getInstance().perfSession().isVerbose()) {
gaugeManager.collectGaugeMetricOnce(SessionManager.getInstance().perfSession().getTimer());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public void start() {

updateSession(perfSession);

if (perfSession.isGaugeAndEventCollectionEnabled()) {
if (perfSession.isVerbose()) {
gaugeManager.collectGaugeMetricOnce(perfSession.getTimer());
}
}
Expand All @@ -259,7 +259,7 @@ public void stop() {
if (!name.isEmpty()) {
transportManager.log(new TraceMetricBuilder(this).build(), getAppState());

if (SessionManager.getInstance().perfSession().isGaugeAndEventCollectionEnabled()) {
if (SessionManager.getInstance().perfSession().isVerbose()) {
gaugeManager.collectGaugeMetricOnce(
SessionManager.getInstance().perfSession().getTimer());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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.config.ConfigResolver
import com.google.firebase.perf.logging.FirebaseSessionsEnforcementCheck.Companion.checkSession
import com.google.firebase.sessions.api.SessionSubscriber

class FirebasePerformanceSessionSubscriber(val configResolver: ConfigResolver) : SessionSubscriber {

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

override val isDataCollectionEnabled: Boolean
get() = configResolver.isPerformanceCollectionEnabled ?: false

override fun onSessionChanged(sessionDetails: SessionSubscriber.SessionDetails) {
val currentPerfSession = SessionManager.getInstance().perfSession()
// TODO(b/394127311): Add logic to deal with app start gauges if necessary.
checkSession(currentPerfSession.sessionId(), "Existing session in onSessionChanged().")

val updatedSession = PerfSession.createWithId(sessionDetails.sessionId)
SessionManager.getInstance().updatePerfSession(updatedSession)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.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
)
}
Loading
Loading