Skip to content

Create SharedSessionRepository and remove bound service #6844

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 2 commits into from
Apr 9, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class FirebaseSessionsTests {
@Test
fun firebaseSessionsDependenciesDoInitialize() {
assertThat(SessionFirelogPublisher.instance).isNotNull()
assertThat(SessionGenerator.instance).isNotNull()
assertThat(SessionsSettings.instance).isNotNull()
}

Expand Down

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 @@ -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
// Log.w(
// TAG,
// "FirebaseApp instance deleted. Sessions library will stop collecting data.",
// )
// TODO(mrober): Clean up on firebase app delete
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ import kotlinx.coroutines.CoroutineScope
internal interface FirebaseSessionsComponent {
val firebaseSessions: FirebaseSessions

val sessionDatastore: SessionDatastore
val sessionFirelogPublisher: SessionFirelogPublisher
val sessionGenerator: SessionGenerator
val sessionsSettings: SessionsSettings
Expand Down Expand Up @@ -95,18 +94,10 @@ internal interface FirebaseSessionsComponent {
interface MainModule {
@Binds @Singleton fun eventGDTLoggerInterface(impl: EventGDTLogger): EventGDTLoggerInterface

@Binds @Singleton fun sessionDatastore(impl: SessionDatastoreImpl): SessionDatastore

@Binds
@Singleton
fun sessionFirelogPublisher(impl: SessionFirelogPublisherImpl): SessionFirelogPublisher

@Binds
@Singleton
fun sessionLifecycleServiceBinder(
impl: SessionLifecycleServiceBinderImpl
): SessionLifecycleServiceBinder

@Binds
@Singleton
fun crashlyticsSettingsFetcher(impl: RemoteSettingsFetcher): CrashlyticsSettingsFetcher
Expand All @@ -123,6 +114,10 @@ internal interface FirebaseSessionsComponent {

@Binds @Singleton fun settingsCache(impl: SettingsCacheImpl): SettingsCache

@Binds
@Singleton
fun sharedSessionRepository(impl: SharedSessionRepositoryImpl): SharedSessionRepository

companion object {
private const val TAG = "FirebaseSessions"

Expand Down Expand Up @@ -157,13 +152,14 @@ internal interface FirebaseSessionsComponent {
fun sessionDataStore(
appContext: Context,
@Blocking blockingDispatcher: CoroutineContext,
sessionDataSerializer: SessionDataSerializer,
): DataStore<SessionData> =
createDataStore(
serializer = SessionDataSerializer,
serializer = sessionDataSerializer,
corruptionHandler =
ReplaceFileCorruptionHandler { ex ->
Log.w(TAG, "CorruptionException in session data DataStore", ex)
SessionDataSerializer.defaultValue
sessionDataSerializer.defaultValue
},
scope = CoroutineScope(blockingDispatcher),
produceFile = { appContext.dataStoreFile("aqs/sessionDataStore.data") },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.sessions

import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import java.io.InputStream
import java.io.OutputStream
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

/** Session data to be persisted. */
@Serializable
internal data class SessionData(val sessionDetails: SessionDetails, val backgroundTime: Time)

/** DataStore json [Serializer] for [SessionData]. */
@Singleton
internal class SessionDataSerializer
@Inject
constructor(
private val sessionGenerator: SessionGenerator,
private val timeProvider: TimeProvider,
) : Serializer<SessionData> {
override val defaultValue: SessionData
get() =
SessionData(
sessionDetails = sessionGenerator.generateNewSession(currentSession = null),
backgroundTime = timeProvider.currentTime(),
)

override suspend fun readFrom(input: InputStream): SessionData =
try {
Json.decodeFromString<SessionData>(input.readBytes().decodeToString())
} catch (ex: Exception) {
throw CorruptionException("Cannot parse session data", ex)
}

override suspend fun writeTo(t: SessionData, output: OutputStream) {
@Suppress("BlockingMethodInNonBlockingContext") // blockingDispatcher is safe for blocking calls
output.write(Json.encodeToString(SessionData.serializer(), t).encodeToByteArray())
}
}

This file was deleted.

Loading
Loading