Skip to content

Commit ef2a3d4

Browse files
authored
Merge 4b978dc into af1fe93
2 parents af1fe93 + 4b978dc commit ef2a3d4

36 files changed

+693
-848
lines changed

firebase-perf/firebase-perf.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ dependencies {
118118
api("com.google.firebase:firebase-components:18.0.0")
119119
api("com.google.firebase:firebase-config:21.5.0")
120120
api("com.google.firebase:firebase-installations:17.2.0")
121-
api("com.google.firebase:firebase-sessions:2.0.7") {
121+
api(project(":firebase-sessions")) {
122122
exclude group: 'com.google.firebase', module: 'firebase-common'
123123
exclude group: 'com.google.firebase', module: 'firebase-common-ktx'
124124
exclude group: 'com.google.firebase', module: 'firebase-components'

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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@
3636
import com.google.firebase.perf.logging.ConsoleUrlGenerator;
3737
import com.google.firebase.perf.metrics.HttpMetric;
3838
import com.google.firebase.perf.metrics.Trace;
39+
import com.google.firebase.perf.session.FirebasePerformanceSessionSubscriber;
3940
import com.google.firebase.perf.session.SessionManager;
4041
import com.google.firebase.perf.transport.TransportManager;
4142
import com.google.firebase.perf.util.Constants;
4243
import com.google.firebase.perf.util.ImmutableBundle;
4344
import com.google.firebase.perf.util.Timer;
4445
import com.google.firebase.remoteconfig.RemoteConfigComponent;
46+
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
4547
import java.lang.annotation.Retention;
4648
import java.lang.annotation.RetentionPolicy;
4749
import java.net.URL;
@@ -136,11 +138,6 @@ public static FirebasePerformance getInstance() {
136138
// to false if it's been force disabled or it is set to null if neither.
137139
@Nullable private Boolean mPerformanceCollectionForceEnabledState = null;
138140

139-
private final FirebaseApp firebaseApp;
140-
private final Provider<RemoteConfigComponent> firebaseRemoteConfigProvider;
141-
private final FirebaseInstallationsApi firebaseInstallationsApi;
142-
private final Provider<TransportFactory> transportFactoryProvider;
143-
144141
/**
145142
* Constructs the FirebasePerformance class and allows injecting dependencies.
146143
*
@@ -166,11 +163,6 @@ public static FirebasePerformance getInstance() {
166163
ConfigResolver configResolver,
167164
SessionManager sessionManager) {
168165

169-
this.firebaseApp = firebaseApp;
170-
this.firebaseRemoteConfigProvider = firebaseRemoteConfigProvider;
171-
this.firebaseInstallationsApi = firebaseInstallationsApi;
172-
this.transportFactoryProvider = transportFactoryProvider;
173-
174166
if (firebaseApp == null) {
175167
this.mPerformanceCollectionForceEnabledState = false;
176168
this.configResolver = configResolver;
@@ -182,7 +174,6 @@ public static FirebasePerformance getInstance() {
182174
.initialize(firebaseApp, firebaseInstallationsApi, transportFactoryProvider);
183175

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

188179
remoteConfigManager.setFirebaseRemoteConfigProvider(firebaseRemoteConfigProvider);
@@ -192,6 +183,9 @@ public static FirebasePerformance getInstance() {
192183
sessionManager.setApplicationContext(appContext);
193184

194185
mPerformanceCollectionForceEnabledState = configResolver.getIsPerformanceCollectionEnabled();
186+
FirebaseSessionsDependencies.register(
187+
new FirebasePerformanceSessionSubscriber(isPerformanceCollectionEnabled()));
188+
195189
if (logger.isLogcatEnabled() && isPerformanceCollectionEnabled()) {
196190
logger.info(
197191
String.format(
@@ -282,7 +276,7 @@ public synchronized void setPerformanceCollectionEnabled(@Nullable Boolean enabl
282276
return;
283277
}
284278

285-
if (configResolver.getIsPerformanceCollectionDeactivated()) {
279+
if (Boolean.TRUE.equals(configResolver.getIsPerformanceCollectionDeactivated())) {
286280
logger.info("Firebase Performance is permanently disabled");
287281
return;
288282
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.session.gauges.GaugeManager
20+
import com.google.firebase.perf.v1.ApplicationProcessState
21+
import com.google.firebase.sessions.api.SessionSubscriber
22+
import java.util.UUID
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+
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)
42+
SessionManager.getInstance().updatePerfSession(updatedSession)
43+
GaugeManager.getInstance()
44+
.logGaugeMetadata(updatedSession.aqsSessionId(), ApplicationProcessState.FOREGROUND)
45+
}
46+
}

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
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;
2627
import java.util.List;
2728
import java.util.concurrent.TimeUnit;
2829

@@ -31,6 +32,7 @@ public class PerfSession implements Parcelable {
3132

3233
private final String sessionId;
3334
private final Timer creationTime;
35+
@Nullable private String aqsSessionId;
3436

3537
private boolean isGaugeAndEventCollectionEnabled = false;
3638

@@ -59,11 +61,24 @@ private PerfSession(@NonNull Parcel in) {
5961
creationTime = in.readParcelable(Timer.class.getClassLoader());
6062
}
6163

62-
/** Returns the sessionId of the object. */
64+
/** Returns the sessionId of the session. */
6365
public String sessionId() {
6466
return sessionId;
6567
}
6668

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+
6782
/**
6883
* Returns a timer object that has been seeded with the system time at which the session began.
6984
*/
@@ -113,6 +128,7 @@ public boolean isSessionRunningTooLong() {
113128

114129
/** Creates and returns the proto object for PerfSession object. */
115130
public com.google.firebase.perf.v1.PerfSession build() {
131+
// TODO(b/394127311): Switch to using AQS.
116132
com.google.firebase.perf.v1.PerfSession.Builder sessionMetric =
117133
com.google.firebase.perf.v1.PerfSession.newBuilder().setSessionId(sessionId);
118134

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

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,20 @@
1919
import androidx.annotation.Keep;
2020
import androidx.annotation.VisibleForTesting;
2121
import com.google.firebase.perf.application.AppStateMonitor;
22-
import com.google.firebase.perf.application.AppStateUpdateHandler;
2322
import com.google.firebase.perf.session.gauges.GaugeManager;
2423
import com.google.firebase.perf.v1.ApplicationProcessState;
2524
import com.google.firebase.perf.v1.GaugeMetadata;
2625
import com.google.firebase.perf.v1.GaugeMetric;
2726
import java.lang.ref.WeakReference;
2827
import java.util.HashSet;
2928
import java.util.Iterator;
29+
import java.util.Objects;
3030
import java.util.Set;
3131
import java.util.UUID;
32-
import java.util.concurrent.ExecutorService;
33-
import java.util.concurrent.Executors;
34-
import java.util.concurrent.Future;
3532

3633
/** Session manager to generate sessionIDs and broadcast to the application. */
3734
@Keep // Needed because of b/117526359.
38-
public class SessionManager extends AppStateUpdateHandler {
35+
public class SessionManager {
3936

4037
@SuppressLint("StaticFieldLeak")
4138
private static final SessionManager instance = new SessionManager();
@@ -45,7 +42,6 @@ public class SessionManager extends AppStateUpdateHandler {
4542
private final Set<WeakReference<SessionAwareObject>> clients = new HashSet<>();
4643

4744
private PerfSession perfSession;
48-
private Future syncInitFuture;
4945

5046
/** Returns the singleton instance of SessionManager. */
5147
public static SessionManager getInstance() {
@@ -71,57 +67,14 @@ public SessionManager(
7167
this.gaugeManager = gaugeManager;
7268
this.perfSession = perfSession;
7369
this.appStateMonitor = appStateMonitor;
74-
registerForAppState();
7570
}
7671

7772
/**
7873
* Finalizes gauge initialization during cold start. This must be called before app start finishes
7974
* (currently that is before onResume finishes) to ensure gauge collection starts on time.
8075
*/
8176
public void setApplicationContext(final Context appContext) {
82-
// Get PerfSession in main thread first, because it is possible that app changes fg/bg state
83-
// which creates a new perfSession, before the following is executed in background thread
84-
final PerfSession appStartSession = perfSession;
85-
// TODO(b/258263016): Migrate to go/firebase-android-executors
86-
@SuppressLint("ThreadPoolCreation")
87-
ExecutorService executorService = Executors.newSingleThreadExecutor();
88-
syncInitFuture =
89-
executorService.submit(
90-
() -> {
91-
gaugeManager.initializeGaugeMetadataManager(appContext);
92-
if (appStartSession.isGaugeAndEventCollectionEnabled()) {
93-
gaugeManager.logGaugeMetadata(
94-
appStartSession.sessionId(), ApplicationProcessState.FOREGROUND);
95-
}
96-
});
97-
}
98-
99-
@Override
100-
public void onUpdateAppState(ApplicationProcessState newAppState) {
101-
super.onUpdateAppState(newAppState);
102-
103-
if (appStateMonitor.isColdStart()) {
104-
// We want the Session to remain unchanged if this is a cold start of the app since we already
105-
// update the PerfSession in FirebasePerfProvider#onAttachInfo().
106-
return;
107-
}
108-
109-
if (newAppState == ApplicationProcessState.FOREGROUND) {
110-
// A new foregrounding of app will force a new sessionID generation.
111-
PerfSession session = PerfSession.createWithId(UUID.randomUUID().toString());
112-
updatePerfSession(session);
113-
} else {
114-
// If the session is running for too long, generate a new session and collect gauges as
115-
// necessary.
116-
if (perfSession.isSessionRunningTooLong()) {
117-
PerfSession session = PerfSession.createWithId(UUID.randomUUID().toString());
118-
updatePerfSession(session);
119-
} else {
120-
// For any other state change of the application, modify gauge collection state as
121-
// necessary.
122-
startOrStopCollectingGauges(newAppState);
123-
}
124-
}
77+
gaugeManager.initializeGaugeMetadataManager(appContext);
12578
}
12679

12780
/**
@@ -145,7 +98,7 @@ public void stopGaugeCollectionIfSessionRunningTooLong() {
14598
*/
14699
public void updatePerfSession(PerfSession perfSession) {
147100
// Do not update the perf session if it is the exact same sessionId.
148-
if (perfSession.sessionId() == this.perfSession.sessionId()) {
101+
if (Objects.equals(perfSession.sessionId(), this.perfSession.sessionId())) {
149102
return;
150103
}
151104

@@ -164,9 +117,6 @@ public void updatePerfSession(PerfSession perfSession) {
164117
}
165118
}
166119

167-
// Log the gauge metadata event if data collection is enabled.
168-
logGaugeMetadataIfCollectionEnabled(appStateMonitor.getAppState());
169-
170120
// Start of stop the gauge data collection.
171121
startOrStopCollectingGauges(appStateMonitor.getAppState());
172122
}
@@ -178,7 +128,6 @@ public void updatePerfSession(PerfSession perfSession) {
178128
* this does not reset the perfSession.
179129
*/
180130
public void initializeGaugeCollection() {
181-
logGaugeMetadataIfCollectionEnabled(ApplicationProcessState.FOREGROUND);
182131
startOrStopCollectingGauges(ApplicationProcessState.FOREGROUND);
183132
}
184133

@@ -206,12 +155,6 @@ public void unregisterForSessionUpdates(WeakReference<SessionAwareObject> client
206155
}
207156
}
208157

209-
private void logGaugeMetadataIfCollectionEnabled(ApplicationProcessState appState) {
210-
if (perfSession.isGaugeAndEventCollectionEnabled()) {
211-
gaugeManager.logGaugeMetadata(perfSession.sessionId(), appState);
212-
}
213-
}
214-
215158
private void startOrStopCollectingGauges(ApplicationProcessState appState) {
216159
if (perfSession.isGaugeAndEventCollectionEnabled()) {
217160
gaugeManager.startCollectingGauges(perfSession, appState);
@@ -224,9 +167,4 @@ private void startOrStopCollectingGauges(ApplicationProcessState appState) {
224167
public void setPerfSession(PerfSession perfSession) {
225168
this.perfSession = perfSession;
226169
}
227-
228-
@VisibleForTesting
229-
public Future getSyncInitFuture() {
230-
return this.syncInitFuture;
231-
}
232170
}

firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/CpuGaugeCollector.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
import static android.system.Os.sysconf;
1818

1919
import android.annotation.SuppressLint;
20-
import android.os.Build.VERSION;
21-
import android.os.Build.VERSION_CODES;
2220
import android.system.OsConstants;
2321
import androidx.annotation.Nullable;
2422
import androidx.annotation.VisibleForTesting;
@@ -163,7 +161,7 @@ private synchronized void scheduleCpuMetricCollectionWithRate(
163161
this.cpuMetricCollectionRateMs = cpuMetricCollectionRate;
164162
try {
165163
cpuMetricCollectorJob =
166-
cpuMetricCollectorExecutor.scheduleAtFixedRate(
164+
cpuMetricCollectorExecutor.scheduleWithFixedDelay(
167165
() -> {
168166
CpuMetricReading currCpuReading = syncCollectCpuMetric(referenceTime);
169167
if (currCpuReading != null) {
@@ -181,7 +179,7 @@ private synchronized void scheduleCpuMetricCollectionWithRate(
181179
private synchronized void scheduleCpuMetricCollectionOnce(Timer referenceTime) {
182180
try {
183181
@SuppressWarnings("FutureReturnValueIgnored")
184-
ScheduledFuture unusedFuture =
182+
ScheduledFuture<?> unusedFuture =
185183
cpuMetricCollectorExecutor.schedule(
186184
() -> {
187185
CpuMetricReading currCpuReading = syncCollectCpuMetric(referenceTime);
@@ -227,12 +225,7 @@ private CpuMetricReading syncCollectCpuMetric(Timer referenceTime) {
227225
}
228226

229227
private long getClockTicksPerSecond() {
230-
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
231-
return sysconf(OsConstants._SC_CLK_TCK);
232-
} else {
233-
// TODO(b/110779408): Figure out how to collect this info for Android API 20 and below.
234-
return INVALID_SC_PER_CPU_CLOCK_TICK;
235-
}
228+
return sysconf(OsConstants._SC_CLK_TCK);
236229
}
237230

238231
private long convertClockTicksToMicroseconds(long clockTicks) {

0 commit comments

Comments
 (0)