Skip to content

Integrate Firebase Performance with Firebase Sessions. #5020

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

Merged
merged 18 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion firebase-perf/firebase-perf.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protobuf {
}

android {
compileSdkVersion project.targetSdkVersion
compileSdk 30

lintOptions {
abortOnError true
Expand Down Expand Up @@ -105,6 +105,7 @@ dependencies {
runtimeOnly project(':firebase-datatransport')
javadocClasspath 'com.google.auto.value:auto-value-annotations:1.6.6'
javadocClasspath 'com.google.code.findbugs:jsr305:3.0.2'
implementation project(':firebase-sessions')

// Google Deps
implementation "com.google.android.gms:play-services-tasks:18.0.1"
Expand Down
2 changes: 1 addition & 1 deletion firebase-perf/ktx/ktx.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ firebaseLibrary {
}

android {
compileSdkVersion project.targetSdkVersion
compileSdk 30
defaultConfig {
minSdkVersion 16
multiDexEnabled true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

package com.google.firebase.perf.ktx

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import com.google.firebase.FirebaseApp
Expand Down Expand Up @@ -49,15 +50,21 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations.initMocks
import org.robolectric.RobolectricTestRunner
import org.robolectric.Shadows

const val APP_ID = "APP_ID"
const val API_KEY = "API_KEY"
const val APP_ID = "1:149208680807:android:0000000000000000"
const val API_KEY = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

const val EXISTING_APP = "existing"

abstract class BaseTestCase {
@Before
open fun setUp() {
val context = ApplicationProvider.getApplicationContext<Context>()
val shadowPackageManager = Shadows.shadowOf(context.packageManager)
val packageInfo = shadowPackageManager.getInternalMutablePackageInfo(context.packageName)
packageInfo.versionName = "1.0.0"

Firebase.initialize(
ApplicationProvider.getApplicationContext(),
FirebaseOptions.Builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
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.FirebaseSessions;
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 +50,10 @@ public class FirebasePerfRegistrar implements ComponentRegistrar {
private static final String LIBRARY_NAME = "fire-perf";
private static final String EARLY_LIBRARY_NAME = "fire-perf-early";

static {
FirebaseSessionsDependencies.INSTANCE.addDependency(SessionSubscriber.Name.PERFORMANCE);
}

@Override
@Keep
public List<Component<?>> getComponents() {
Expand All @@ -58,6 +65,7 @@ public List<Component<?>> getComponents() {
.add(Dependency.requiredProvider(RemoteConfigComponent.class))
.add(Dependency.required(FirebaseInstallationsApi.class))
.add(Dependency.requiredProvider(TransportFactory.class))
.add(Dependency.required(FirebaseSessions.class))
.add(Dependency.required(FirebasePerfEarly.class))
.factory(FirebasePerfRegistrar::providesFirebasePerformance)
.build(),
Expand Down Expand Up @@ -94,7 +102,8 @@ private static FirebasePerformance providesFirebasePerformance(ComponentContaine
container.get(FirebaseApp.class),
container.get(FirebaseInstallationsApi.class),
container.getProvider(RemoteConfigComponent.class),
container.getProvider(TransportFactory.class)))
container.getProvider(TransportFactory.class),
container.get(FirebaseSessions.class)))
.build();

return component.getFirebasePerformance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
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.FirebaseSessions;
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 @@ -140,6 +142,7 @@ public static FirebasePerformance getInstance() {
private final Provider<RemoteConfigComponent> firebaseRemoteConfigProvider;
private final FirebaseInstallationsApi firebaseInstallationsApi;
private final Provider<TransportFactory> transportFactoryProvider;
private final FirebaseSessions firebaseSessions;

/**
* Constructs the FirebasePerformance class and allows injecting dependencies.
Expand All @@ -163,13 +166,15 @@ public static FirebasePerformance getInstance() {
FirebaseInstallationsApi firebaseInstallationsApi,
Provider<TransportFactory> transportFactoryProvider,
RemoteConfigManager remoteConfigManager,
FirebaseSessions firebaseSessions,
ConfigResolver configResolver,
SessionManager sessionManager) {

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

if (firebaseApp == null) {
this.mPerformanceCollectionForceEnabledState = false;
Expand Down Expand Up @@ -199,6 +204,26 @@ public static FirebasePerformance getInstance() {
ConsoleUrlGenerator.generateDashboardUrl(
firebaseApp.getOptions().getProjectId(), appContext.getPackageName())));
}

// Register with Firebase sessions to receive updates about session changes.
this.firebaseSessions.register(
new SessionSubscriber() {
@Override
public void onSessionChanged(@NonNull SessionDetails sessionDetails) {
// TODO(visum) Handle sessionID change by updating the sessionID in the sessionManager
}

@Override
public boolean isDataCollectionEnabled() {
return configResolver.isPerformanceMonitoringEnabled();
}

@NonNull
@Override
public Name getSessionSubscriberName() {
return SessionSubscriber.Name.PERFORMANCE;
}
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.firebase.perf.config.RemoteConfigManager;
import com.google.firebase.perf.session.SessionManager;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
import com.google.firebase.sessions.FirebaseSessions;
import dagger.Module;
import dagger.Provides;

Expand All @@ -34,16 +35,19 @@ public class FirebasePerformanceModule {
private final FirebaseInstallationsApi firebaseInstallations;
private final Provider<RemoteConfigComponent> remoteConfigComponentProvider;
private final Provider<TransportFactory> transportFactoryProvider;
private final FirebaseSessions firebaseSessions;

public FirebasePerformanceModule(
@NonNull FirebaseApp firebaseApp,
@NonNull FirebaseInstallationsApi firebaseInstallations,
@NonNull Provider<RemoteConfigComponent> remoteConfigComponentProvider,
@NonNull Provider<TransportFactory> transportFactoryProvider) {
@NonNull Provider<TransportFactory> transportFactoryProvider,
@NonNull FirebaseSessions firebaseSessions) {
this.firebaseApp = firebaseApp;
this.firebaseInstallations = firebaseInstallations;
this.remoteConfigComponentProvider = remoteConfigComponentProvider;
this.transportFactoryProvider = transportFactoryProvider;
this.firebaseSessions = firebaseSessions;
}

@Provides
Expand Down Expand Up @@ -80,4 +84,9 @@ ConfigResolver providesConfigResolver() {
SessionManager providesSessionManager() {
return SessionManager.getInstance();
}

@Provides
FirebaseSessions providesFirebaseSessions() {
return firebaseSessions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.firebase.components.Qualified;
import com.google.firebase.installations.FirebaseInstallationsApi;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
import com.google.firebase.sessions.FirebaseSessions;
import java.util.List;
import java.util.concurrent.Executor;
import org.junit.Test;
Expand All @@ -49,6 +50,7 @@ public void testGetComponents() {
Dependency.requiredProvider(RemoteConfigComponent.class),
Dependency.required(FirebaseInstallationsApi.class),
Dependency.requiredProvider(TransportFactory.class),
Dependency.required(FirebaseSessions.class),
Dependency.required(FirebasePerfEarly.class));

assertThat(firebasePerfComponent.isLazy()).isTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import androidx.annotation.Nullable;
Expand All @@ -39,6 +40,7 @@
import com.google.firebase.perf.util.Constants;
import com.google.firebase.perf.util.ImmutableBundle;
import com.google.firebase.remoteconfig.RemoteConfigComponent;
import com.google.firebase.sessions.FirebaseSessions;
import com.google.testing.timing.FakeDirectExecutorService;
import java.util.Map;
import org.junit.After;
Expand All @@ -50,6 +52,7 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowPackageManager;

/** Unit tests for {@link FirebasePerformance}. */
@RunWith(RobolectricTestRunner.class)
Expand Down Expand Up @@ -81,6 +84,14 @@ public void setUp() throws NameNotFoundException {
FirebaseApp.clearInstancesForTest();

Context context = ApplicationProvider.getApplicationContext();
ShadowPackageManager shadowPackageManager = shadowOf(context.getPackageManager());

PackageInfo packageInfo =
shadowPackageManager.getInternalMutablePackageInfo(context.getPackageName());
packageInfo.versionName = "1.0.0";

packageInfo.applicationInfo.metaData.clear();

FirebaseApp.initializeApp(context, options);
for (int i = 0; i <= Constants.MAX_TRACE_CUSTOM_ATTRIBUTES; i++) {
FirebasePerformance.getInstance().removeAttribute("dim" + i);
Expand All @@ -90,11 +101,6 @@ public void setUp() throws NameNotFoundException {
sharedPreferences.edit().clear().commit();
DeviceCacheManager.clearInstance();

shadowOf(context.getPackageManager())
.getInternalMutablePackageInfo(context.getPackageName())
.applicationInfo
.metaData
.clear();
spyRemoteConfigManager = spy(RemoteConfigManager.getInstance());
ConfigResolver.clearInstance();
spyConfigResolver = spy(ConfigResolver.getInstance());
Expand Down Expand Up @@ -544,8 +550,9 @@ private FirebasePerformance initializeFirebasePerformancePreferences(
Boolean sharedPreferencesEnabledDisabledKey,
Provider<RemoteConfigComponent> firebaseRemoteConfigProvider,
Provider<TransportFactory> transportFactoryProvider) {
Context context = ApplicationProvider.getApplicationContext();
DeviceCacheManager deviceCacheManager = new DeviceCacheManager(fakeDirectExecutorService);
deviceCacheManager.setContext(ApplicationProvider.getApplicationContext());
deviceCacheManager.setContext(context);
if (sharedPreferencesEnabledDisabledKey != null) {
deviceCacheManager.setValue(Constants.ENABLE_DISABLE, sharedPreferencesEnabledDisabledKey);
}
Expand All @@ -560,7 +567,6 @@ private FirebasePerformance initializeFirebasePerformancePreferences(
bundle.putBoolean(FIREPERF_FORCE_DEACTIVATED_KEY, metadataFireperfForceDeactivatedKey);
}

Context context = ApplicationProvider.getApplicationContext();
shadowOf(context.getPackageManager())
.getInternalMutablePackageInfo(context.getPackageName())
.applicationInfo
Expand All @@ -573,6 +579,7 @@ private FirebasePerformance initializeFirebasePerformancePreferences(
mock(FirebaseInstallationsApi.class),
transportFactoryProvider,
spyRemoteConfigManager,
mock(FirebaseSessions.class),
spyConfigResolver,
spySessionManager);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.robolectric.Shadows.shadowOf;

import android.content.Context;
import android.content.pm.PackageInfo;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.datatransport.TransportFactory;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.FirebaseApp;
Expand Down Expand Up @@ -64,6 +68,7 @@
import org.mockito.verification.VerificationMode;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;

/** Unit tests for {@link TransportManager}. */
@Config(shadows = ShadowPreconditions.class)
Expand Down Expand Up @@ -1393,6 +1398,16 @@ private void initializeTransport(boolean shouldInitialize) {
clearLastLoggedEvents();

if (shouldInitialize) {
// Set the version name since Firebase sessions needs it.
Context context = ApplicationProvider.getApplicationContext();
ShadowPackageManager shadowPackageManager = shadowOf(context.getPackageManager());

PackageInfo packageInfo =
shadowPackageManager.getInternalMutablePackageInfo(context.getPackageName());
packageInfo.versionName = "1.0.0";

packageInfo.applicationInfo.metaData.clear();

testTransportManager = TransportManager.getInstance();
testTransportManager.initializeForTest(
FirebaseApp.getInstance(),
Expand Down