From b5c6c1af0d32937a8167c5619afaf3d35cb9d4d3 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 30 Sep 2019 19:09:10 +0200 Subject: [PATCH 1/4] Realm: allow to clear corrupted session db --- .../SessionRealmConfigurationFactory.kt | 73 +++++++++++++++++++ .../android/internal/session/SessionModule.kt | 15 +--- 2 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt new file mode 100644 index 0000000000..e0e609c011 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2019 New Vector Ltd + * + * 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 im.vector.matrix.android.internal.database + +import android.content.Context +import im.vector.matrix.android.internal.database.model.SessionRealmModule +import im.vector.matrix.android.internal.session.SessionModule +import io.realm.Realm +import io.realm.RealmConfiguration +import timber.log.Timber +import java.io.File +import javax.inject.Inject + +private const val REALM_SHOULD_CLEAR_FLAG_ = "REALM_SHOULD_CLEAR_FLAG_" + +/** + * This class is handling creation of RealmConfiguration for a session. + * It will handle corrupted realm by clearing the db file. It allows to just clear cache without losing your crypto keys. + * It's clearly not perfect but there is no way to catch the native crash. + */ +internal class SessionRealmConfigurationFactory @Inject constructor(private val realmKeysUtils: RealmKeysUtils, + context: Context) { + + private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE) + + + fun create(directory: File, userMd5: String): RealmConfiguration { + val shouldClearRealm = sharedPreferences.getBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", false) + if (shouldClearRealm) { + directory.deleteRecursively() + } + sharedPreferences + .edit() + .putBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", true) + .apply() + + val realmConfiguration = RealmConfiguration.Builder() + .directory(directory) + .name("disk_store.realm") + .apply { + realmKeysUtils.configureEncryption(this, "${SessionModule.DB_ALIAS_PREFIX}$userMd5") + } + .modules(SessionRealmModule()) + .deleteRealmIfMigrationNeeded() + .build() + + // Try creating a realm instance and if it succeeds we can clear the flag + Realm.getInstance(realmConfiguration).use { + Timber.v("Successfully create realm instance") + sharedPreferences + .edit() + .putBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", false) + .apply() + } + return realmConfiguration + } + + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 7b655dd939..b3224ae0b3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -30,7 +30,7 @@ import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService import im.vector.matrix.android.api.session.securestorage.SecureStorageService import im.vector.matrix.android.internal.database.LiveEntityObserver -import im.vector.matrix.android.internal.database.RealmKeysUtils +import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory import im.vector.matrix.android.internal.database.model.SessionRealmModule import im.vector.matrix.android.internal.di.* import im.vector.matrix.android.internal.network.AccessTokenInterceptor @@ -54,6 +54,7 @@ internal abstract class SessionModule { @Module companion object { + internal const val DB_ALIAS_PREFIX = "session_db_" @JvmStatic @@ -94,18 +95,10 @@ internal abstract class SessionModule { @Provides @SessionDatabase @SessionScope - fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils, + fun providesRealmConfiguration(realmConfigurationFactory: SessionRealmConfigurationFactory, @UserCacheDirectory directory: File, @UserMd5 userMd5: String): RealmConfiguration { - return RealmConfiguration.Builder() - .directory(directory) - .name("disk_store.realm") - .apply { - realmKeysUtils.configureEncryption(this, "$DB_ALIAS_PREFIX$userMd5") - } - .modules(SessionRealmModule()) - .deleteRealmIfMigrationNeeded() - .build() + return realmConfigurationFactory.create(directory, userMd5) } @JvmStatic From abbc62dd35d9b64b6a0edddfc7ae628d4c9157ac Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 4 Oct 2019 19:42:27 +0200 Subject: [PATCH 2/4] Clear corrupted db: add some logs --- .../internal/database/SessionRealmConfigurationFactory.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt index e0e609c011..0c59b16268 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt @@ -41,6 +41,10 @@ internal class SessionRealmConfigurationFactory @Inject constructor(private val fun create(directory: File, userMd5: String): RealmConfiguration { val shouldClearRealm = sharedPreferences.getBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", false) if (shouldClearRealm) { + Timber.v("************************************************************") + Timber.v("The realm file session was corrupted and couldn't be loaded. ") + Timber.v("The file has been deleted to recover. ") + Timber.v("************************************************************") directory.deleteRecursively() } sharedPreferences From d2b9668d4e912d8a04e4ef3495e793cad14c17ea Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 7 Oct 2019 15:25:54 +0200 Subject: [PATCH 3/4] Inject element where they are used --- .../database/SessionRealmConfigurationFactory.kt | 10 +++++++--- .../matrix/android/internal/session/SessionModule.kt | 7 ++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt index 0c59b16268..6f44d1c490 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt @@ -18,6 +18,8 @@ package im.vector.matrix.android.internal.database import android.content.Context import im.vector.matrix.android.internal.database.model.SessionRealmModule +import im.vector.matrix.android.internal.di.UserCacheDirectory +import im.vector.matrix.android.internal.di.UserMd5 import im.vector.matrix.android.internal.session.SessionModule import io.realm.Realm import io.realm.RealmConfiguration @@ -33,17 +35,19 @@ private const val REALM_SHOULD_CLEAR_FLAG_ = "REALM_SHOULD_CLEAR_FLAG_" * It's clearly not perfect but there is no way to catch the native crash. */ internal class SessionRealmConfigurationFactory @Inject constructor(private val realmKeysUtils: RealmKeysUtils, + @UserCacheDirectory val directory: File, + @UserMd5 val userMd5: String, context: Context) { private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE) - fun create(directory: File, userMd5: String): RealmConfiguration { + fun create(): RealmConfiguration { val shouldClearRealm = sharedPreferences.getBoolean("$REALM_SHOULD_CLEAR_FLAG_$userMd5", false) if (shouldClearRealm) { Timber.v("************************************************************") - Timber.v("The realm file session was corrupted and couldn't be loaded. ") - Timber.v("The file has been deleted to recover. ") + Timber.v("The realm file session was corrupted and couldn't be loaded.") + Timber.v("The file has been deleted to recover.") Timber.v("************************************************************") directory.deleteRecursively() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index b3224ae0b3..4637b1428c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -31,7 +31,6 @@ import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesSer import im.vector.matrix.android.api.session.securestorage.SecureStorageService import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory -import im.vector.matrix.android.internal.database.model.SessionRealmModule import im.vector.matrix.android.internal.di.* import im.vector.matrix.android.internal.network.AccessTokenInterceptor import im.vector.matrix.android.internal.network.RetrofitFactory @@ -95,10 +94,8 @@ internal abstract class SessionModule { @Provides @SessionDatabase @SessionScope - fun providesRealmConfiguration(realmConfigurationFactory: SessionRealmConfigurationFactory, - @UserCacheDirectory directory: File, - @UserMd5 userMd5: String): RealmConfiguration { - return realmConfigurationFactory.create(directory, userMd5) + fun providesRealmConfiguration(realmConfigurationFactory: SessionRealmConfigurationFactory): RealmConfiguration { + return realmConfigurationFactory.create() } @JvmStatic From 979b42aa3033cf5b4670fc7739f31365eb451449 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 7 Oct 2019 16:07:57 +0200 Subject: [PATCH 4/4] Do not delete the crypto DB when deleting the session DB --- .../database/SessionRealmConfigurationFactory.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt index 6f44d1c490..d5a60e9d2b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/SessionRealmConfigurationFactory.kt @@ -28,6 +28,7 @@ import java.io.File import javax.inject.Inject private const val REALM_SHOULD_CLEAR_FLAG_ = "REALM_SHOULD_CLEAR_FLAG_" +private const val REALM_NAME = "disk_store.realm" /** * This class is handling creation of RealmConfiguration for a session. @@ -49,7 +50,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(private val Timber.v("The realm file session was corrupted and couldn't be loaded.") Timber.v("The file has been deleted to recover.") Timber.v("************************************************************") - directory.deleteRecursively() + deleteRealmFiles() } sharedPreferences .edit() @@ -58,7 +59,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(private val val realmConfiguration = RealmConfiguration.Builder() .directory(directory) - .name("disk_store.realm") + .name(REALM_NAME) .apply { realmKeysUtils.configureEncryption(this, "${SessionModule.DB_ALIAS_PREFIX}$userMd5") } @@ -77,5 +78,14 @@ internal class SessionRealmConfigurationFactory @Inject constructor(private val return realmConfiguration } - + // Delete all the realm files of the session + private fun deleteRealmFiles() { + listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file -> + try { + File(directory, file).deleteRecursively() + } catch (e: Exception) { + Timber.e(e, "Unable to move files") + } + } + } } \ No newline at end of file