Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions firebase-crashlytics/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- [fixed] Made creating DataStore files more resilient [#7440]

# 20.0.2

- [changed] Bumped internal dependencies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.firebase.sessions

import android.content.Context
import android.os.Build
import android.util.Log
import androidx.datastore.core.DataMigration
import androidx.datastore.core.DataStore
Expand Down Expand Up @@ -48,6 +49,8 @@ import dagger.Component
import dagger.Module
import dagger.Provides
import java.io.File
import java.io.IOException
import java.nio.file.Files
import javax.inject.Qualifier
import javax.inject.Singleton
import kotlin.coroutines.CoroutineContext
Expand Down Expand Up @@ -146,7 +149,11 @@ internal interface FirebaseSessionsComponent {
SessionConfigsSerializer.defaultValue
},
scope = CoroutineScope(blockingDispatcher),
produceFile = { appContext.dataStoreFile("aqs/sessionConfigsDataStore.data") },
produceFile = {
prepDataStoreFile(
appContext.dataStoreFile("firebaseSessions/sessionConfigsDataStore.data")
)
},
)

@Provides
Expand All @@ -164,7 +171,9 @@ internal interface FirebaseSessionsComponent {
sessionDataSerializer.defaultValue
},
scope = CoroutineScope(blockingDispatcher),
produceFile = { appContext.dataStoreFile("aqs/sessionDataStore.data") },
produceFile = {
prepDataStoreFile(appContext.dataStoreFile("firebaseSessions/sessionDataStore.data"))
},
)

private fun <T> createDataStore(
Expand Down Expand Up @@ -197,6 +206,45 @@ internal interface FirebaseSessionsComponent {
} catch (_: SecurityException) {
false
}

/**
* Prepares the DataStore file by ensuring its parent directory exists. Throws [IOException]
* if the directory could not be created, or if a conflicting file could not be removed.
*/
private fun prepDataStoreFile(dataStoreFile: File): File {
val parentDir = dataStoreFile.parentFile ?: return dataStoreFile

// Check if something exists at the path, but isn't a directory
if (parentDir.exists() && !parentDir.isDirectory) {
// Only delete it if it's the specific file we know we can safely remove
if (parentDir.name == "firebaseSessions") {
if (!parentDir.delete()) {
throw IOException("Failed to delete conflicting file: $parentDir")
}
}
}

if (parentDir.isDirectory) {
return dataStoreFile
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Files.createDirectories(parentDir.toPath())
} catch (ex: Exception) {
throw IOException("Failed to create directory: $parentDir", ex)
}
} else {
if (!parentDir.mkdirs()) {
// It's possible another thread created it in the meantime, so we double-check
if (!parentDir.isDirectory) {
throw IOException("Failed to create directory: $parentDir")
}
}
}

return dataStoreFile
}
}
}
}