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

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f5fd0c7
Use multi-process DataStore instead of Preferences DataStore (#6781)
mrober Mar 20, 2025
0169aee
Share settings cache between running processes (#6788)
mrober Mar 24, 2025
533e20c
Fix unit tests showing warning about datastore_shared_counter (#6830)
mrober Apr 2, 2025
60e0965
Create SharedSessionRepository and remove bound service (#6844)
mrober Apr 9, 2025
fa6809a
send session event based on data collection and setting config (#6852)
themiswang Apr 9, 2025
4aedcbf
Fix firelog send (#6855)
mrober Apr 9, 2025
be16ffb
Implement fake datastore for unit tests (#6874)
mrober Apr 15, 2025
99b1532
Fallback try catch block (#6873)
themiswang Apr 15, 2025
a9daf57
Add unit tests for session repo (#6878)
themiswang Apr 15, 2025
12b0596
background time nullable (#6886)
themiswang Apr 16, 2025
3c0aa0d
Disable the activity lifecycle callbacks on app delete (#6877)
mrober Apr 16, 2025
1da2b77
Implement new cold app start detection heuristic (#6950)
mrober May 9, 2025
bd3217d
Implement ProcessDataManager (#6961)
mrober May 15, 2025
3bd7132
Implement cold start detection logic (#6975)
mrober May 20, 2025
e6e6006
Add benchmark to measure startup time with cleared app data (#6985)
mrober May 23, 2025
66b7f0f
Do not notify subscribers when session didn't change (#6988)
mrober May 26, 2025
eec26a9
Fix the profile case with clear app data (#7000)
mrober May 30, 2025
8a61cbc
Use the same tag for all logs in sessions (#7002)
mrober May 30, 2025
ada72e1
Add more trace buttons to sessions test app (#7014)
mrober Jun 6, 2025
009307f
Allow Perf to use this version of AQS (#7041)
mrober Jun 17, 2025
21215eb
Address feedback on sessions-sharedrepo (#7045)
mrober Jun 18, 2025
0aae9f1
Fix cold starts incorrectly using the previous firstSessionId (#7047)
mrober Jun 19, 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
21 changes: 2 additions & 19 deletions firebase-sessions/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
# Unreleased

* [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.")
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
Loading