Skip to content

Commit ba067b5

Browse files
authored
Handle corruption in DataStore Preferences gracefully (#5633)
Handle corruption in DataStore Preferences more gracefully. Tested manually by piping junk data into the datastore files. When the Settings data store preferences gets corrupt, it will be replaced by an empty preferences with all null values. This will cause settings to fall through to sdk defaults until the next settings fetch. If the Sessions data store preferences gets corrupt, it will lose the session id until the next session is generated on the next foreground. I could not force a session to upload will a null session id, but I expect it to be rare but possible with a multi-process app.
1 parent 31bce69 commit ba067b5

3 files changed

Lines changed: 28 additions & 3 deletions

File tree

firebase-sessions/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
* [fixed] Handle corruption in DataStore Preferences more gracefully.
4+
35
# 1.2.0
46

57
* [feature] Added support for accurate sessions on multi-process apps.
@@ -11,7 +13,7 @@
1113
# 1.0.1
1214

1315
* [fixed] Fixed NPE when no version name is
14-
set ([#5195](//github.com/firebase/firebase-android-sdk/issues/5195)).
16+
set ([#5195](https://github.com/firebase/firebase-android-sdk/issues/5195)).
1517
* [fixed] Populate DataCollectionStatus fields for Crashlytics and Perf.
1618

1719
# 1.0.0

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionDatastore.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ package com.google.firebase.sessions
1919
import android.content.Context
2020
import android.util.Log
2121
import androidx.datastore.core.DataStore
22+
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
2223
import androidx.datastore.preferences.core.Preferences
2324
import androidx.datastore.preferences.core.edit
2425
import androidx.datastore.preferences.core.emptyPreferences
2526
import androidx.datastore.preferences.core.stringPreferencesKey
2627
import androidx.datastore.preferences.preferencesDataStore
2728
import com.google.firebase.Firebase
2829
import com.google.firebase.app
30+
import com.google.firebase.sessions.ProcessDetailsProvider.getProcessName
2931
import java.util.concurrent.atomic.AtomicReference
3032
import kotlin.coroutines.CoroutineContext
3133
import kotlinx.coroutines.CoroutineScope
@@ -97,7 +99,15 @@ internal class SessionDatastoreImpl(
9799

98100
private companion object {
99101
private const val TAG = "FirebaseSessionsRepo"
102+
100103
private val Context.dataStore: DataStore<Preferences> by
101-
preferencesDataStore(name = SessionDataStoreConfigs.SESSIONS_CONFIG_NAME)
104+
preferencesDataStore(
105+
name = SessionDataStoreConfigs.SESSIONS_CONFIG_NAME,
106+
corruptionHandler =
107+
ReplaceFileCorruptionHandler { ex ->
108+
Log.w(TAG, "CorruptionException in sessions DataStore in ${getProcessName()}.", ex)
109+
emptyPreferences()
110+
},
111+
)
102112
}
103113
}

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/settings/SessionsSettings.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@
1717
package com.google.firebase.sessions.settings
1818

1919
import android.content.Context
20+
import android.util.Log
2021
import androidx.datastore.core.DataStore
22+
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
2123
import androidx.datastore.preferences.core.Preferences
24+
import androidx.datastore.preferences.core.emptyPreferences
2225
import androidx.datastore.preferences.preferencesDataStore
2326
import com.google.firebase.Firebase
2427
import com.google.firebase.FirebaseApp
2528
import com.google.firebase.app
2629
import com.google.firebase.installations.FirebaseInstallationsApi
2730
import com.google.firebase.sessions.ApplicationInfo
31+
import com.google.firebase.sessions.ProcessDetailsProvider.getProcessName
2832
import com.google.firebase.sessions.SessionDataStoreConfigs
2933
import com.google.firebase.sessions.SessionEvents
3034
import kotlin.coroutines.CoroutineContext
@@ -136,10 +140,19 @@ internal class SessionsSettings(
136140
}
137141

138142
internal companion object {
143+
private const val TAG = "SessionsSettings"
144+
139145
val instance: SessionsSettings
140146
get() = Firebase.app[SessionsSettings::class.java]
141147

142148
private val Context.dataStore: DataStore<Preferences> by
143-
preferencesDataStore(name = SessionDataStoreConfigs.SETTINGS_CONFIG_NAME)
149+
preferencesDataStore(
150+
name = SessionDataStoreConfigs.SETTINGS_CONFIG_NAME,
151+
corruptionHandler =
152+
ReplaceFileCorruptionHandler { ex ->
153+
Log.w(TAG, "CorruptionException in settings DataStore in ${getProcessName()}.", ex)
154+
emptyPreferences()
155+
},
156+
)
144157
}
145158
}

0 commit comments

Comments
 (0)