Skip to content

Merged sessions-sharedrepo into main #7039

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 26 commits into from
Jul 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6d4ee90
Use multi-process DataStore instead of Preferences DataStore (#6781)
mrober Mar 20, 2025
1d1b63b
Share settings cache between running processes (#6788)
mrober Mar 24, 2025
2ceec6c
Fix unit tests showing warning about datastore_shared_counter (#6830)
mrober Apr 2, 2025
9ec11cf
Create SharedSessionRepository and remove bound service (#6844)
mrober Apr 9, 2025
e6822ec
send session event based on data collection and setting config (#6852)
themiswang Apr 9, 2025
f28a5a2
Fix firelog send (#6855)
mrober Apr 9, 2025
3e5bc81
Implement fake datastore for unit tests (#6874)
mrober Apr 15, 2025
9222312
Fallback try catch block (#6873)
themiswang Apr 15, 2025
34d8b06
Add unit tests for session repo (#6878)
themiswang Apr 15, 2025
521422e
background time nullable (#6886)
themiswang Apr 16, 2025
d76faa7
Disable the activity lifecycle callbacks on app delete (#6877)
mrober Apr 16, 2025
02438e9
Implement new cold app start detection heuristic (#6950)
mrober May 9, 2025
b8f4a55
Implement ProcessDataManager (#6961)
mrober May 15, 2025
555aeaf
Implement cold start detection logic (#6975)
mrober May 20, 2025
84ce109
Add benchmark to measure startup time with cleared app data (#6985)
mrober May 23, 2025
d937ffe
Do not notify subscribers when session didn't change (#6988)
mrober May 26, 2025
fb3f49c
Fix the profile case with clear app data (#7000)
mrober May 30, 2025
9315ef0
Use the same tag for all logs in sessions (#7002)
mrober May 30, 2025
2dec910
Add more trace buttons to sessions test app (#7014)
mrober Jun 6, 2025
b286c3a
Allow Perf to use this version of AQS (#7041)
mrober Jun 17, 2025
8032306
Address feedback on sessions-sharedrepo (#7045)
mrober Jun 18, 2025
d889a39
Fix cold starts incorrectly using the previous firstSessionId (#7047)
mrober Jun 19, 2025
acd367c
Make the Sessions test app more convenient to test (#7054)
mrober Jun 20, 2025
d0b7357
Notify Sessions when a fatal crash occurs (#7074)
mrober Jun 26, 2025
0dd159c
Final cleanup before merging (#7112)
mrober Jul 8, 2025
5d0d9ec
Merge branch 'main' into sessions-sharedrepo
mrober Jul 8, 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
20 changes: 2 additions & 18 deletions firebase-sessions/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,20 @@
# Unreleased
* [changed] Added internal api for Crashlytics to notify Sessions of crash events
* [changed] Use multi-process DataStore instead of Preferences DataStore
* [changed] Update the heuristic to detect cold app starts

# 2.1.1
* [unchanged] Updated to keep SDK versions aligned.


## Kotlin
The Kotlin extensions library transitively includes the updated
`firebase-sessions` library. The Kotlin extensions library has no additional
updates.

# 2.1.0
* [changed] Add warning for known issue b/328687152
* [changed] Use Dagger for dependency injection
* [changed] Updated datastore dependency to v1.1.3 to
fix [CVE-2024-7254](https://github.com/advisories/GHSA-735f-pc8j-v9w8).


## Kotlin
The Kotlin extensions library transitively includes the updated
`firebase-sessions` library. The Kotlin extensions library has no additional
updates.

# 2.0.9
* [fixed] Make AQS resilient to background init in multi-process apps.


## Kotlin
The Kotlin extensions library transitively includes the updated
`firebase-sessions` library. The Kotlin extensions library has no additional
updates.

# 2.0.7
* [fixed] Removed extraneous logs that risk leaking internal identifiers.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import java.io.FileInputStream
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -31,12 +33,43 @@ class StartupBenchmark {
@Test
fun startup() =
benchmarkRule.measureRepeated(
packageName = "com.google.firebase.testing.sessions",
packageName = PACKAGE_NAME,
metrics = listOf(StartupTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD,
) {
pressHome()
startActivityAndWait()
}

@Test
fun startup_clearAppData() =
benchmarkRule.measureRepeated(
packageName = PACKAGE_NAME,
metrics = listOf(StartupTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD,
setupBlock = { clearAppData(packageName) },
) {
pressHome()
startActivityAndWait()
}

private fun clearAppData(packageName: String) {
val fileDescriptor =
InstrumentationRegistry.getInstrumentation()
.uiAutomation
.executeShellCommand("pm clear $packageName")
val fileInputStream = FileInputStream(fileDescriptor.fileDescriptor)
// Read the output to ensure the app data was cleared successfully
val result = fileInputStream.bufferedReader().use { it.readText().trim() }
fileDescriptor.close()
if (result != "Success") {
throw IllegalStateException("Unable to clear app data for $packageName - $result")
}
}

private companion object {
const val PACKAGE_NAME = "com.google.firebase.testing.sessions"
}
}
10 changes: 8 additions & 2 deletions firebase-sessions/firebase-sessions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,19 @@ plugins {
id("firebase-vendor")
id("kotlin-android")
id("kotlin-kapt")
id("kotlinx-serialization")
}

firebaseLibrary {
libraryGroup = "crashlytics"

testLab.enabled = true
publishJavadoc = false
releaseNotes { enabled.set(false) }

releaseNotes {
enabled = false
hasKTX = false
}
}

android {
Expand Down Expand Up @@ -76,7 +81,8 @@ dependencies {
implementation("com.google.android.datatransport:transport-api:3.2.0")
implementation(libs.javax.inject)
implementation(libs.androidx.annotation)
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.datastore)
implementation(libs.kotlinx.serialization.json)

vendor(libs.dagger.dagger) { exclude(group = "javax.inject", module = "javax.inject") }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.google.firebase.Firebase
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.initialize
import com.google.firebase.sessions.settings.SessionsSettings
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

Expand All @@ -36,23 +34,6 @@ import org.junit.runner.RunWith
*/
@RunWith(AndroidJUnit4::class)
class FirebaseSessionsTests {
@Before
fun setUp() {
Firebase.initialize(
ApplicationProvider.getApplicationContext(),
FirebaseOptions.Builder()
.setApplicationId(APP_ID)
.setApiKey(API_KEY)
.setProjectId(PROJECT_ID)
.build()
)
}

@After
fun cleanUp() {
FirebaseApp.clearInstancesForTest()
}

@Test
fun firebaseSessionsDoesInitialize() {
assertThat(FirebaseSessions.instance).isNotNull()
Expand All @@ -61,13 +42,25 @@ class FirebaseSessionsTests {
@Test
fun firebaseSessionsDependenciesDoInitialize() {
assertThat(SessionFirelogPublisher.instance).isNotNull()
assertThat(SessionGenerator.instance).isNotNull()
assertThat(SessionsSettings.instance).isNotNull()
}

companion object {
private const val APP_ID = "1:1:android:1a"
private const val API_KEY = "API-KEY-API-KEY-API-KEY-API-KEY-API-KEY"
private const val PROJECT_ID = "PROJECT-ID"

@BeforeClass
@JvmStatic
fun setUp() {
Firebase.initialize(
ApplicationProvider.getApplicationContext(),
FirebaseOptions.Builder()
.setApplicationId(APP_ID)
.setApiKey(API_KEY)
.setProjectId(PROJECT_ID)
.build(),
)
}
}
}

This file was deleted.

10 changes: 3 additions & 7 deletions firebase-sessions/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2023 Google LLC -->
<?xml version="1.0" encoding="utf-8"?><!-- Copyright 2023 Google LLC -->
<!-- -->
<!-- Licensed under the Apache License, Version 2.0 (the "License"); -->
<!-- you may not use this file except in compliance with the License. -->
Expand All @@ -19,11 +18,8 @@

<application>
<service
android:name="com.google.firebase.sessions.SessionLifecycleService"
android:enabled="true"
android:exported="false" />
<service android:name="com.google.firebase.components.ComponentDiscoveryService"
android:exported="false">
android:exported="false"
android:name="com.google.firebase.components.ComponentDiscoveryService">
<meta-data
android:name="com.google.firebase.components:com.google.firebase.sessions.FirebaseSessionsRegistrar"
android:value="com.google.firebase.components.ComponentRegistrar" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.google.android.datatransport.Encoding
import com.google.android.datatransport.Event
import com.google.android.datatransport.TransportFactory
import com.google.firebase.inject.Provider
import com.google.firebase.sessions.FirebaseSessions.Companion.TAG
import javax.inject.Inject
import javax.inject.Singleton

Expand Down Expand Up @@ -61,8 +62,6 @@ constructor(private val transportFactoryProvider: Provider<TransportFactory>) :
}

companion object {
private const val TAG = "EventGDTLogger"

private const val AQS_LOG_SOURCE = "FIREBASE_APPQUALITY_SESSION"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ constructor(
private val firebaseApp: FirebaseApp,
private val settings: SessionsSettings,
@Background backgroundDispatcher: CoroutineContext,
lifecycleServiceBinder: SessionLifecycleServiceBinder,
sessionsActivityLifecycleCallbacks: SessionsActivityLifecycleCallbacks,
) {

init {
Log.d(TAG, "Initializing Firebase Sessions SDK.")
Log.d(TAG, "Initializing Firebase Sessions ${BuildConfig.VERSION_NAME}.")
val appContext = firebaseApp.applicationContext.applicationContext
if (appContext is Application) {
appContext.registerActivityLifecycleCallbacks(SessionsActivityLifecycleCallbacks)
appContext.registerActivityLifecycleCallbacks(sessionsActivityLifecycleCallbacks)

CoroutineScope(backgroundDispatcher).launch {
val subscribers = FirebaseSessionsDependencies.getRegisteredSubscribers()
Expand All @@ -56,16 +56,12 @@ constructor(
if (!settings.sessionsEnabled) {
Log.d(TAG, "Sessions SDK disabled. Not listening to lifecycle events.")
} else {
val lifecycleClient = SessionLifecycleClient(backgroundDispatcher)
lifecycleClient.bindToService(lifecycleServiceBinder)
SessionsActivityLifecycleCallbacks.lifecycleClient = lifecycleClient

firebaseApp.addLifecycleEventListener { _, _ ->
Log.w(
TAG,
"FirebaseApp instance deleted. Sessions library will stop collecting data.",
)
SessionsActivityLifecycleCallbacks.lifecycleClient = null
sessionsActivityLifecycleCallbacks.onAppDelete()
}
}
}
Expand All @@ -79,7 +75,7 @@ constructor(
}

companion object {
private const val TAG = "FirebaseSessions"
internal const val TAG = "FirebaseSessions"

val instance: FirebaseSessions
get() = Firebase.app[FirebaseSessions::class.java]
Expand Down
Loading