Clear SDK cache properly (#4396)

* Use close() instead of destroy, because close() is synchronized.

* Use new method to clear the SDK cache.

* Format file.

* Remove the legacy way to clear the SDK cache.

* Remove unused import

* revert name change
This commit is contained in:
Benoit Marty 2025-03-20 14:33:59 +01:00 committed by GitHub
parent f85abe27fc
commit 93d27735e4
6 changed files with 41 additions and 33 deletions

View file

@ -8,7 +8,6 @@
package io.element.android.libraries.matrix.impl package io.element.android.libraries.matrix.impl
import io.element.android.libraries.androidutils.file.getSizeOfFiles import io.element.android.libraries.androidutils.file.getSizeOfFiles
import io.element.android.libraries.androidutils.file.safeDelete
import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.core.coroutine.childScope
@ -488,11 +487,11 @@ class RustMatrixClient(
verificationService.destroy() verificationService.destroy()
sessionDelegate.clearCurrentClient() sessionDelegate.clearCurrentClient()
innerRoomListService.destroy() innerRoomListService.close()
notificationService.destroy() notificationService.close()
notificationProcessSetup.destroy() notificationProcessSetup.destroy()
encryptionService.destroy() encryptionService.close()
innerClient.destroy() innerClient.close()
} }
override suspend fun getCacheSize(): Long { override suspend fun getCacheSize(): Long {
@ -500,8 +499,8 @@ class RustMatrixClient(
} }
override suspend fun clearCache() { override suspend fun clearCache() {
innerClient.clearCaches()
close() close()
deleteSessionDirectory(deleteCryptoDb = false)
} }
override suspend fun logout(userInitiated: Boolean, ignoreSdkError: Boolean) { override suspend fun logout(userInitiated: Boolean, ignoreSdkError: Boolean) {
@ -526,7 +525,7 @@ class RustMatrixClient(
} }
close() close()
deleteSessionDirectory(deleteCryptoDb = true) deleteSessionDirectory()
if (userInitiated) { if (userInitiated) {
sessionStore.removeSession(sessionId.value) sessionStore.removeSession(sessionId.value)
} }
@ -575,7 +574,7 @@ class RustMatrixClient(
} }
} }
close() close()
deleteSessionDirectory(deleteCryptoDb = true) deleteSessionDirectory()
sessionStore.removeSession(sessionId.value) sessionStore.removeSession(sessionId.value)
}.onFailure { }.onFailure {
Timber.e(it, "Failed to deactivate account") Timber.e(it, "Failed to deactivate account")
@ -663,25 +662,9 @@ class RustMatrixClient(
} }
} }
private suspend fun deleteSessionDirectory( private suspend fun deleteSessionDirectory() = withContext(sessionDispatcher) {
deleteCryptoDb: Boolean = false, // Delete all the files for this session
): Boolean = withContext(sessionDispatcher) { sessionPathsProvider.provides(sessionId)?.deleteRecursively()
val sessionPaths = sessionPathsProvider.provides(sessionId) ?: return@withContext false
// Always delete the cache directory
sessionPaths.cacheDirectory.deleteRecursively()
if (deleteCryptoDb) {
// Delete the folder and all its content
sessionPaths.fileDirectory.deleteRecursively()
} else {
// Do not delete the crypto database files.
sessionPaths.fileDirectory.listFiles().orEmpty()
.filterNot { it.name.contains("matrix-sdk-crypto") }
.forEach { file ->
Timber.w("Deleting file ${file.name}...")
file.safeDelete()
}
true
}
} }
} }

View file

@ -232,7 +232,7 @@ internal class RustEncryptionService(
) ?: error("User identity not found") ) ?: error("User identity not found")
} }
fun destroy() { fun close() {
service.destroy() service.close()
} }
} }

View file

@ -36,7 +36,7 @@ class RustNotificationService(
} }
} }
fun destroy() { fun close() {
notificationClient.destroy() notificationClient.close()
} }
} }

View file

@ -17,10 +17,12 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.api.SessionStore
import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
import org.matrix.rustcomponents.sdk.Client
import java.io.File import java.io.File
class RustMatrixClientTest { class RustMatrixClientTest {
@ -32,10 +34,27 @@ class RustMatrixClientTest {
} }
} }
@Test
fun `clear cache invokes the method clearCaches from the client and close it`() = runTest {
val clearCachesResult = lambdaRecorder<Unit> { }
val closeResult = lambdaRecorder<Unit> { }
createRustMatrixClient(
client = FakeRustClient(
clearCachesResult = clearCachesResult,
closeResult = closeResult,
)
).use { sut ->
sut.clearCache()
clearCachesResult.assertions().isCalledOnce()
closeResult.assertions().isCalledOnce()
}
}
private fun TestScope.createRustMatrixClient( private fun TestScope.createRustMatrixClient(
client: Client = FakeRustClient(),
sessionStore: SessionStore = InMemorySessionStore(), sessionStore: SessionStore = InMemorySessionStore(),
) = RustMatrixClient( ) = RustMatrixClient(
innerClient = FakeRustClient(), innerClient = client,
baseDirectory = File(""), baseDirectory = File(""),
sessionStore = sessionStore, sessionStore = sessionStore,
appCoroutineScope = backgroundScope, appCoroutineScope = backgroundScope,

View file

@ -10,6 +10,8 @@ package io.element.android.libraries.matrix.impl.fixtures.fakes
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSession import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSession
import io.element.android.libraries.matrix.test.A_DEVICE_ID import io.element.android.libraries.matrix.test.A_DEVICE_ID
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientDelegate import org.matrix.rustcomponents.sdk.ClientDelegate
import org.matrix.rustcomponents.sdk.Encryption import org.matrix.rustcomponents.sdk.Encryption
@ -31,6 +33,8 @@ class FakeRustClient(
private val notificationSettings: NotificationSettings = FakeRustNotificationSettings(), private val notificationSettings: NotificationSettings = FakeRustNotificationSettings(),
private val encryption: Encryption = FakeRustEncryption(), private val encryption: Encryption = FakeRustEncryption(),
private val session: Session = aRustSession(), private val session: Session = aRustSession(),
private val clearCachesResult: () -> Unit = { lambdaError() },
private val closeResult: () -> Unit = {},
) : Client(NoPointer) { ) : Client(NoPointer) {
override fun userId(): String = userId override fun userId(): String = userId
override fun deviceId(): String = deviceId override fun deviceId(): String = deviceId
@ -53,4 +57,6 @@ class FakeRustClient(
) = Unit ) = Unit
override suspend fun deletePusher(identifiers: PusherIdentifiers) = Unit override suspend fun deletePusher(identifiers: PusherIdentifiers) = Unit
override suspend fun clearCaches() = simulateLongTask { clearCachesResult() }
override fun close() = closeResult()
} }

View file

@ -167,7 +167,7 @@ class FakeMatrixClient(
return 0 return 0
} }
override suspend fun clearCache() { override suspend fun clearCache() = simulateLongTask {
clearCacheLambda() clearCacheLambda()
} }