Skip to content

Commit abc49d4

Browse files
authored
Merge c9c0441 into 7d9c0bf
2 parents 7d9c0bf + c9c0441 commit abc49d4

18 files changed

+429
-430
lines changed

firebase-perf/firebase-perf.gradle

Lines changed: 3 additions & 0 deletions
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
@@ -138,4 +140,5 @@ dependencies {
138140
testImplementation libs.mockito.core
139141
testImplementation libs.mockito.mockito.inline
140142
testImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.6'
143+
testImplementation "androidx.arch.core:core-testing:2.1.0"
141144
}

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,10 @@ public FirebasePerfEarly(
5151
uiExecutor.execute(new AppStartTrace.StartFromBackgroundRunnable(appStartTrace));
5252
}
5353

54-
// TODO: Bring back Firebase Sessions dependency to watch for updates to sessions.
55-
5654
// In the case of cold start, we create a session and start collecting gauges as early as
5755
// possible.
58-
// There is code in SessionManager that prevents us from resetting the session twice in case
59-
// of app cold start.
56+
// Uploading the gauges however only starts once AQS is initialized.
57+
// TODO(b/394127311): Update this to use changes in AQS initialization,
6058
SessionManager.getInstance().initializeGaugeCollection();
6159
}
6260
}

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
import com.google.firebase.perf.util.ImmutableBundle;
4545
import com.google.firebase.perf.util.Timer;
4646
import com.google.firebase.remoteconfig.RemoteConfigComponent;
47-
import com.google.firebase.sessions.BuildConfig;
4847
import com.google.firebase.sessions.api.FirebaseSessionsDependencies;
48+
import com.google.firebase.sessions.api.SessionSubscriber;
4949
import java.lang.annotation.Retention;
5050
import java.lang.annotation.RetentionPolicy;
5151
import java.net.URL;
@@ -96,6 +96,8 @@ public class FirebasePerformance implements FirebasePerformanceAttributable {
9696
// once during initialization and cache it.
9797
private final ImmutableBundle mMetadataBundle;
9898

99+
private final SessionSubscriber sessionSubscriber;
100+
99101
/** Valid HttpMethods for manual network APIs */
100102
@StringDef({
101103
HttpMethod.GET,
@@ -169,9 +171,10 @@ public static FirebasePerformance getInstance() {
169171
this.mPerformanceCollectionForceEnabledState = false;
170172
this.configResolver = configResolver;
171173
this.mMetadataBundle = new ImmutableBundle(new Bundle());
174+
this.sessionSubscriber = new FirebasePerformanceSessionSubscriber(false);
172175
return;
173176
}
174-
DebugEnforcementCheck.setEnforcement(BuildConfig.DEBUG);
177+
DebugEnforcementCheck.setEnforcement(BuildConfig.ENFORCE_LEGACY_SESSIONS);
175178

176179
TransportManager.getInstance()
177180
.initialize(firebaseApp, firebaseInstallationsApi, transportFactoryProvider);
@@ -186,8 +189,8 @@ public static FirebasePerformance getInstance() {
186189
sessionManager.setApplicationContext(appContext);
187190

188191
mPerformanceCollectionForceEnabledState = configResolver.getIsPerformanceCollectionEnabled();
189-
FirebaseSessionsDependencies.register(
190-
new FirebasePerformanceSessionSubscriber(isPerformanceCollectionEnabled()));
192+
sessionSubscriber = new FirebasePerformanceSessionSubscriber(isPerformanceCollectionEnabled());
193+
FirebaseSessionsDependencies.register(sessionSubscriber);
191194

192195
if (logger.isLogcatEnabled() && isPerformanceCollectionEnabled()) {
193196
logger.info(
@@ -463,4 +466,9 @@ private static ImmutableBundle extractMetadata(Context appContext) {
463466
Boolean getPerformanceCollectionForceEnabledState() {
464467
return mPerformanceCollectionForceEnabledState;
465468
}
469+
470+
@VisibleForTesting
471+
SessionSubscriber getSessionSubscriber() {
472+
return sessionSubscriber;
473+
}
466474
}

firebase-perf/src/main/java/com/google/firebase/perf/logging/DebugEnforcementCheck.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,25 @@
1616

1717
package com.google.firebase.perf.logging
1818

19+
import com.google.firebase.perf.session.PerfSession
20+
import com.google.firebase.perf.session.isLegacy
21+
1922
class DebugEnforcementCheck {
2023
companion object {
2124
/** When enabled, failed preconditions will cause assertion errors for debugging. */
2225
@JvmStatic var enforcement: Boolean = false
2326
private var logger: AndroidLogger = AndroidLogger.getInstance()
2427

25-
public fun checkSession(isAqsAvailable: Boolean, failureMessage: String) {
26-
if (!isAqsAvailable) {
27-
Companion.logger.debug(failureMessage)
28+
fun checkSession(session: PerfSession, failureMessage: String) {
29+
if (session.isLegacy()) {
30+
logger.debug("legacy session ${session.sessionId()}: $failureMessage")
31+
assert(!enforcement) { failureMessage }
32+
}
33+
}
34+
35+
fun checkSession(sessionId: String, failureMessage: String) {
36+
if (sessionId.isLegacy()) {
37+
logger.debug("legacy session ${sessionId}: $failureMessage")
2838
assert(!enforcement) { failureMessage }
2939
}
3040
}

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
package com.google.firebase.perf.session
1818

19+
import com.google.firebase.perf.logging.DebugEnforcementCheck
1920
import com.google.firebase.perf.session.gauges.GaugeManager
2021
import com.google.firebase.perf.v1.ApplicationProcessState
2122
import com.google.firebase.sessions.api.SessionSubscriber
22-
import java.util.UUID
2323

2424
class FirebasePerformanceSessionSubscriber(override val isDataCollectionEnabled: Boolean) :
2525
SessionSubscriber {
@@ -28,15 +28,22 @@ class FirebasePerformanceSessionSubscriber(override val isDataCollectionEnabled:
2828

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

3233
// A [PerfSession] was created before a session was started.
33-
if (!currentPerfSession.isAqsReady) {
34+
// Since these were verbose gauge collection at app startup, it logs them to the updated session
35+
// ID.
36+
if (currentPerfSession.isLegacy() && currentPerfSession.isVerbose) {
3437
GaugeManager.getInstance()
35-
.logGaugeMetadata(currentPerfSession.sessionId(), ApplicationProcessState.FOREGROUND)
36-
return
38+
.logGaugeMetadata(sessionDetails.sessionId, ApplicationProcessState.FOREGROUND)
39+
GaugeManager.getInstance()
40+
.stopCollectingGaugesForLegacySession(
41+
sessionDetails.sessionId,
42+
ApplicationProcessState.FOREGROUND
43+
)
3744
}
3845

39-
val updatedSession = PerfSession.createWithId(UUID.randomUUID().toString())
46+
val updatedSession = PerfSession.createWithId(sessionDetails.sessionId)
4047
SessionManager.getInstance().updatePerfSession(updatedSession)
4148
GaugeManager.getInstance()
4249
.logGaugeMetadata(updatedSession.sessionId(), ApplicationProcessState.FOREGROUND)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.google.firebase.perf.session
2+
3+
import com.google.firebase.perf.util.Constants
4+
import java.util.UUID
5+
6+
/** Identifies whether the [PerfSession] is legacy or not. */
7+
fun PerfSession.isLegacy(): Boolean {
8+
return this.sessionId().isLegacy()
9+
}
10+
11+
/** Identifies whether the string is from a legacy [PerfSession]. */
12+
fun String.isLegacy(): Boolean {
13+
return this.startsWith(Constants.UNDEFINED_AQS_ID_PREFIX)
14+
}
15+
16+
/** Creates a valid session ID for [PerfSession] that can be predictably identified as legacy. */
17+
fun createLegacySessionId(): String {
18+
val uuid = UUID.randomUUID().toString().replace("-", "")
19+
return uuid.replaceRange(
20+
0,
21+
Constants.UNDEFINED_AQS_ID_PREFIX.length,
22+
Constants.UNDEFINED_AQS_ID_PREFIX
23+
)
24+
}

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

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,51 +24,43 @@
2424
import com.google.firebase.perf.util.Timer;
2525
import com.google.firebase.perf.v1.SessionVerbosity;
2626
import java.util.List;
27-
import java.util.UUID;
2827
import java.util.concurrent.TimeUnit;
2928

3029
/** Details of a session including a unique Id and related information. */
3130
public class PerfSession implements Parcelable {
3231
private final Timer creationTime;
3332
private final String sessionId;
3433
private boolean isGaugeAndEventCollectionEnabled = false;
35-
public final boolean isAqsReady;
3634

3735
/*
3836
* Creates a PerfSession object and decides what metrics to collect.
3937
*/
4038
public static PerfSession createWithId(@Nullable String aqsSessionId) {
41-
String sessionId;
42-
Boolean isAqsReady;
43-
if (aqsSessionId != null) {
44-
sessionId = aqsSessionId;
45-
isAqsReady = true;
46-
} else {
47-
sessionId = UUID.randomUUID().toString().replace("-", "");
48-
isAqsReady = false;
39+
String sessionId = aqsSessionId;
40+
if (sessionId == null) {
41+
sessionId = FirebaseSessionsHelperKt.createLegacySessionId();
4942
}
50-
PerfSession session = new PerfSession(sessionId, new Clock(), isAqsReady);
51-
session.setGaugeAndEventCollectionEnabled(shouldCollectGaugesAndEvents(sessionId));
43+
PerfSession session = new PerfSession(sessionId, new Clock());
44+
session.setGaugeAndEventCollectionEnabled(session.shouldCollectGaugesAndEvents());
5245
return session;
5346
}
5447

5548
/** Creates a PerfSession with the provided {@code sessionId} and {@code clock}. */
5649
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
57-
public PerfSession(String sessionId, Clock clock, boolean isAqsReady) {
50+
public PerfSession(String sessionId, Clock clock) {
5851
this.sessionId = sessionId;
59-
this.isAqsReady = isAqsReady;
6052
creationTime = clock.getTime();
6153
}
6254

6355
private PerfSession(@NonNull Parcel in) {
6456
super();
6557
sessionId = in.readString();
6658
isGaugeAndEventCollectionEnabled = in.readByte() != 0;
67-
isAqsReady = in.readByte() != 0;
6859
creationTime = in.readParcelable(Timer.class.getClassLoader());
6960
}
7061

7162
/** Returns the sessionId for the given session. */
63+
@NonNull
7264
public String sessionId() {
7365
return sessionId;
7466
}
@@ -160,10 +152,11 @@ public static com.google.firebase.perf.v1.PerfSession[] buildAndSort(
160152
}
161153

162154
/** If true, Session Gauge collection is enabled. */
163-
public static boolean shouldCollectGaugesAndEvents(String sessionId) {
155+
public boolean shouldCollectGaugesAndEvents() {
164156
ConfigResolver configResolver = ConfigResolver.getInstance();
165157
return configResolver.isPerformanceMonitoringEnabled()
166-
&& (Math.abs(sessionId.hashCode() % 100) < configResolver.getSessionsSamplingRate() * 100);
158+
&& (Math.abs(this.sessionId.hashCode() % 100)
159+
< configResolver.getSessionsSamplingRate() * 100);
167160
}
168161

169162
/**
@@ -187,7 +180,6 @@ public int describeContents() {
187180
public void writeToParcel(@NonNull Parcel out, int flags) {
188181
out.writeString(sessionId);
189182
out.writeByte((byte) (isGaugeAndEventCollectionEnabled ? 1 : 0));
190-
out.writeByte((byte) (isAqsReady ? 1 : 0));
191183
out.writeParcelable(creationTime, 0);
192184
}
193185

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

Lines changed: 29 additions & 17 deletions
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.application.AppStateUpdateHandler;
2223
import com.google.firebase.perf.logging.DebugEnforcementCheck;
2324
import com.google.firebase.perf.session.gauges.GaugeManager;
2425
import com.google.firebase.perf.v1.ApplicationProcessState;
@@ -32,7 +33,8 @@
3233

3334
/** Session manager to generate sessionIDs and broadcast to the application. */
3435
@Keep // Needed because of b/117526359.
35-
public class SessionManager {
36+
public class SessionManager extends AppStateUpdateHandler {
37+
3638
@SuppressLint("StaticFieldLeak")
3739
private static final SessionManager instance = new SessionManager();
3840

@@ -49,14 +51,12 @@ public static SessionManager getInstance() {
4951

5052
/** Returns the currently active PerfSession. */
5153
public final PerfSession perfSession() {
52-
DebugEnforcementCheck.Companion.checkSession(
53-
perfSession.isAqsReady, "Access perf session from manger without aqs ready");
54-
54+
DebugEnforcementCheck.Companion.checkSession(perfSession, "SessionManager.perfSession()");
5555
return perfSession;
5656
}
5757

5858
private SessionManager() {
59-
// session should quickly updated by session subscriber.
59+
// Generate a new sessionID for every cold start.
6060
this(GaugeManager.getInstance(), PerfSession.createWithId(null), AppStateMonitor.getInstance());
6161
}
6262

@@ -68,6 +68,20 @@ public SessionManager(
6868
this.appStateMonitor = appStateMonitor;
6969
}
7070

71+
@Override
72+
public void onUpdateAppState(ApplicationProcessState newAppState) {
73+
super.onUpdateAppState(newAppState);
74+
if (appStateMonitor.isColdStart()) {
75+
// Ignore the app state change if it's a cold start. [FirebasePerformanceSessionSubscriber]
76+
// handles any change that's needed.
77+
return;
78+
}
79+
80+
// While the change in app state doesn't start or stop gauge collection, it updates the upload
81+
// and gauge collection frequency.
82+
updateGaugeCollection(newAppState);
83+
}
84+
7185
/**
7286
* Finalizes gauge initialization during cold start. This must be called before app start finishes
7387
* (currently that is before onResume finishes) to ensure gauge collection starts on time.
@@ -82,10 +96,6 @@ public void setApplicationContext(final Context appContext) {
8296
* @see PerfSession#isSessionRunningTooLong()
8397
*/
8498
public void stopGaugeCollectionIfSessionRunningTooLong() {
85-
DebugEnforcementCheck.Companion.checkSession(
86-
perfSession.isAqsReady,
87-
"Session is not ready while trying to stopGaugeCollectionIfSessionRunningTooLong");
88-
8999
if (perfSession.isSessionRunningTooLong()) {
90100
gaugeManager.stopCollectingGauges();
91101
}
@@ -120,8 +130,9 @@ public void updatePerfSession(PerfSession perfSession) {
120130
}
121131
}
122132

123-
// Start of stop the gauge data collection.
124-
startOrStopCollectingGauges(appStateMonitor.getAppState());
133+
startOrStopCollectingGauges();
134+
// A session is *only* updated in Foreground.
135+
updateGaugeCollection(ApplicationProcessState.FOREGROUND);
125136
}
126137

127138
/**
@@ -131,7 +142,7 @@ public void updatePerfSession(PerfSession perfSession) {
131142
* this does not reset the perfSession.
132143
*/
133144
public void initializeGaugeCollection() {
134-
startOrStopCollectingGauges(ApplicationProcessState.FOREGROUND);
145+
startOrStopCollectingGauges();
135146
}
136147

137148
/**
@@ -158,17 +169,18 @@ public void unregisterForSessionUpdates(WeakReference<SessionAwareObject> client
158169
}
159170
}
160171

161-
private void startOrStopCollectingGauges(ApplicationProcessState appState) {
162-
DebugEnforcementCheck.Companion.checkSession(
163-
perfSession.isAqsReady, "Session is not ready while trying to startOrStopCollectingGauges");
164-
172+
private void startOrStopCollectingGauges() {
165173
if (perfSession.isGaugeAndEventCollectionEnabled()) {
166-
gaugeManager.startCollectingGauges(perfSession, appState);
174+
gaugeManager.startCollectingGaugeMetrics(perfSession);
167175
} else {
168176
gaugeManager.stopCollectingGauges();
169177
}
170178
}
171179

180+
private void updateGaugeCollection(ApplicationProcessState applicationProcessState) {
181+
gaugeManager.updateGaugeCollection(applicationProcessState);
182+
}
183+
172184
@VisibleForTesting
173185
public void setPerfSession(PerfSession perfSession) {
174186
this.perfSession = perfSession;

0 commit comments

Comments
 (0)