Merge pull request #4193 from vector-im/feature/bma/fix_logout_crash
Try to fix #4007
This commit is contained in:
commit
7338982030
|
@ -0,0 +1 @@
|
|||
Fix random crash when user logs out just after the log in.
|
|
@ -379,7 +379,8 @@ internal interface IMXCryptoStore {
|
|||
|
||||
fun getOrAddOutgoingSecretShareRequest(secretName: String, recipients: Map<String, List<String>>): OutgoingSecretRequest?
|
||||
|
||||
fun saveGossipingEvent(event: Event)
|
||||
fun saveGossipingEvent(event: Event) = saveGossipingEvents(listOf(event))
|
||||
|
||||
fun saveGossipingEvents(events: List<Event>)
|
||||
|
||||
fun updateGossipingRequestState(request: IncomingShareRequestCommon, state: GossipingRequestState) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import io.realm.Realm
|
|||
import io.realm.RealmConfiguration
|
||||
import io.realm.Sort
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
|
@ -100,6 +101,8 @@ import org.matrix.olm.OlmAccount
|
|||
import org.matrix.olm.OlmException
|
||||
import org.matrix.olm.OlmOutboundGroupSession
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.set
|
||||
|
||||
|
@ -137,8 +140,11 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
newSessionListeners.remove(listener)
|
||||
}
|
||||
|
||||
private val monarchyWriteAsyncExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
private val monarchy = Monarchy.Builder()
|
||||
.setRealmConfiguration(realmConfiguration)
|
||||
.setWriteAsyncExecutor(monarchyWriteAsyncExecutor)
|
||||
.build()
|
||||
|
||||
init {
|
||||
|
@ -199,6 +205,14 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
|
||||
override fun close() {
|
||||
// Ensure no async request will be run later
|
||||
val tasks = monarchyWriteAsyncExecutor.shutdownNow()
|
||||
Timber.w("Closing RealmCryptoStore, ${tasks.size} async task(s) cancelled")
|
||||
tryOrNull("Interrupted") {
|
||||
// Wait 1 minute max
|
||||
monarchyWriteAsyncExecutor.awaitTermination(1, TimeUnit.MINUTES)
|
||||
}
|
||||
|
||||
olmSessionsToRelease.forEach {
|
||||
it.value.olmSession.releaseSession()
|
||||
}
|
||||
|
@ -1163,8 +1177,8 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
|
||||
override fun saveGossipingEvents(events: List<Event>) {
|
||||
val now = System.currentTimeMillis()
|
||||
monarchy.writeAsync { realm ->
|
||||
val now = System.currentTimeMillis()
|
||||
events.forEach { event ->
|
||||
val ageLocalTs = event.unsignedData?.age?.let { now - it } ?: now
|
||||
val entity = GossipingEventEntity(
|
||||
|
@ -1182,23 +1196,6 @@ internal class RealmCryptoStore @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun saveGossipingEvent(event: Event) {
|
||||
monarchy.writeAsync { realm ->
|
||||
val now = System.currentTimeMillis()
|
||||
val ageLocalTs = event.unsignedData?.age?.let { now - it } ?: now
|
||||
val entity = GossipingEventEntity(
|
||||
type = event.type,
|
||||
sender = event.senderId,
|
||||
ageLocalTs = ageLocalTs,
|
||||
content = ContentMapper.map(event.content)
|
||||
).apply {
|
||||
sendState = SendState.SYNCED
|
||||
decryptionResultJson = MoshiProvider.providesMoshi().adapter(OlmDecryptionResult::class.java).toJson(event.mxDecryptionResult)
|
||||
decryptionErrorCode = event.mCryptoError?.name
|
||||
}
|
||||
realm.insertOrUpdate(entity)
|
||||
}
|
||||
}
|
||||
// override fun getOutgoingRoomKeyRequestByState(states: Set<ShareRequestState>): OutgoingRoomKeyRequest? {
|
||||
// val statesIndex = states.map { it.ordinal }.toTypedArray()
|
||||
// return doRealmQueryAndCopy(realmConfiguration) { realm ->
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.cleanup
|
|||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import kotlinx.coroutines.delay
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.auth.SessionParamsStore
|
||||
import org.matrix.android.sdk.internal.crypto.CryptoModule
|
||||
|
@ -51,37 +51,56 @@ internal class CleanupSession @Inject constructor(
|
|||
@UserMd5 private val userMd5: String
|
||||
) {
|
||||
suspend fun handle() {
|
||||
val sessionRealmCount = Realm.getGlobalInstanceCount(realmSessionConfiguration)
|
||||
val cryptoRealmCount = Realm.getGlobalInstanceCount(realmCryptoConfiguration)
|
||||
Timber.d("Realm instance ($sessionRealmCount - $cryptoRealmCount)")
|
||||
|
||||
Timber.d("Cleanup: delete session params...")
|
||||
sessionParamsStore.delete(sessionId)
|
||||
|
||||
Timber.d("Cleanup: cancel pending works...")
|
||||
workManagerProvider.cancelAllWorks()
|
||||
|
||||
Timber.d("Cleanup: release session...")
|
||||
sessionManager.releaseSession(sessionId)
|
||||
|
||||
Timber.d("Cleanup: clear session data...")
|
||||
clearSessionDataTask.execute(Unit)
|
||||
|
||||
Timber.d("Cleanup: clear crypto data...")
|
||||
clearCryptoDataTask.execute(Unit)
|
||||
|
||||
Timber.d("Cleanup: clear file system")
|
||||
sessionFiles.deleteRecursively()
|
||||
sessionCache.deleteRecursively()
|
||||
|
||||
Timber.d("Cleanup: clear the database keys")
|
||||
realmKeysUtils.clear(SessionModule.getKeyAlias(userMd5))
|
||||
realmKeysUtils.clear(CryptoModule.getKeyAlias(userMd5))
|
||||
|
||||
Timber.d("Cleanup: release session...")
|
||||
sessionManager.releaseSession(sessionId)
|
||||
// Wait for all the Realm instance to be released properly. Closing Realm instance is async.
|
||||
// After that we can safely delete the Realm files
|
||||
waitRealmRelease()
|
||||
|
||||
// Sanity check
|
||||
if (BuildConfig.DEBUG) {
|
||||
Realm.getGlobalInstanceCount(realmSessionConfiguration)
|
||||
.takeIf { it > 0 }
|
||||
?.let { Timber.e("All realm instance for session has not been closed ($it)") }
|
||||
Realm.getGlobalInstanceCount(realmCryptoConfiguration)
|
||||
.takeIf { it > 0 }
|
||||
?.let { Timber.e("All realm instance for crypto has not been closed ($it)") }
|
||||
Timber.d("Cleanup: clear file system")
|
||||
sessionFiles.deleteRecursively()
|
||||
sessionCache.deleteRecursively()
|
||||
}
|
||||
|
||||
private suspend fun waitRealmRelease() {
|
||||
var timeToWaitMillis = MAX_TIME_TO_WAIT_MILLIS
|
||||
do {
|
||||
val sessionRealmCount = Realm.getGlobalInstanceCount(realmSessionConfiguration)
|
||||
val cryptoRealmCount = Realm.getGlobalInstanceCount(realmCryptoConfiguration)
|
||||
Timber.d("Wait for all Realm instance to be closed ($sessionRealmCount - $cryptoRealmCount)")
|
||||
if (sessionRealmCount > 0 || cryptoRealmCount > 0) {
|
||||
Timber.d("Waiting ${TIME_TO_WAIT_MILLIS}ms")
|
||||
delay(TIME_TO_WAIT_MILLIS)
|
||||
timeToWaitMillis -= TIME_TO_WAIT_MILLIS
|
||||
} else {
|
||||
timeToWaitMillis = 0
|
||||
}
|
||||
} while (timeToWaitMillis > 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_TIME_TO_WAIT_MILLIS = 10_000L
|
||||
private const val TIME_TO_WAIT_MILLIS = 10L
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue