1717package com.google.firebase.sessions.settings
1818
1919import android.util.Log
20+ import androidx.annotation.VisibleForTesting
2021import androidx.datastore.core.DataStore
22+ import com.google.firebase.annotations.concurrent.Background
2123import com.google.firebase.sessions.TimeProvider
2224import java.io.IOException
25+ import java.util.concurrent.atomic.AtomicReference
2326import javax.inject.Inject
2427import javax.inject.Singleton
28+ import kotlin.coroutines.CoroutineContext
29+ import kotlinx.coroutines.CoroutineScope
2530import kotlinx.coroutines.flow.first
31+ import kotlinx.coroutines.launch
2632import kotlinx.coroutines.runBlocking
2733
2834internal interface SettingsCache {
@@ -41,23 +47,38 @@ internal interface SettingsCache {
4147internal class SettingsCacheImpl
4248@Inject
4349constructor (
50+ @Background private val backgroundDispatcher: CoroutineContext ,
4451 private val timeProvider: TimeProvider ,
4552 private val sessionConfigsDataStore: DataStore <SessionConfigs >,
4653) : SettingsCache {
47- private var sessionConfigs: SessionConfigs
54+ private val sessionConfigsAtomicReference = AtomicReference <SessionConfigs >()
55+
56+ private val sessionConfigs: SessionConfigs
57+ get() {
58+ // Ensure configs are loaded from disk before the first access
59+ if (sessionConfigsAtomicReference.get() == null ) {
60+ // Double check to avoid the `runBlocking` unless necessary
61+ sessionConfigsAtomicReference.compareAndSet(
62+ null ,
63+ runBlocking { sessionConfigsDataStore.data.first() },
64+ )
65+ }
66+
67+ return sessionConfigsAtomicReference.get()
68+ }
4869
4970 init {
50- // Block until the cache is loaded from disk to ensure cache
51- // values are valid and readable from the main thread on init.
52- runBlocking { sessionConfigs = sessionConfigsDataStore.data.first() }
71+ CoroutineScope (backgroundDispatcher).launch {
72+ sessionConfigsDataStore.data.collect(sessionConfigsAtomicReference::set)
73+ }
5374 }
5475
5576 override fun hasCacheExpired (): Boolean {
56- val cacheUpdatedTimeMs = sessionConfigs.cacheUpdatedTimeMs
77+ val cacheUpdatedTimeSeconds = sessionConfigs.cacheUpdatedTimeSeconds
5778 val cacheDurationSeconds = sessionConfigs.cacheDurationSeconds
5879
59- if (cacheUpdatedTimeMs != null && cacheDurationSeconds != null ) {
60- val timeDifferenceSeconds = ( timeProvider.currentTime().ms - cacheUpdatedTimeMs) / 1000
80+ if (cacheUpdatedTimeSeconds != null && cacheDurationSeconds != null ) {
81+ val timeDifferenceSeconds = timeProvider.currentTime().seconds - cacheUpdatedTimeSeconds
6182 if (timeDifferenceSeconds < cacheDurationSeconds) {
6283 return false
6384 }
@@ -74,12 +95,12 @@ constructor(
7495 override suspend fun updateConfigs (sessionConfigs : SessionConfigs ) {
7596 try {
7697 sessionConfigsDataStore.updateData { sessionConfigs }
77- this .sessionConfigs = sessionConfigs
7898 } catch (ex: IOException ) {
7999 Log .w(TAG , " Failed to update config values: $ex " )
80100 }
81101 }
82102
103+ @VisibleForTesting
83104 internal suspend fun removeConfigs () =
84105 try {
85106 sessionConfigsDataStore.updateData { SessionConfigsSerializer .defaultValue }
0 commit comments