Aggregate data outside of the RealmCryptoStore.

This commit is contained in:
Benoit Marty 2023-01-05 11:04:20 +01:00 committed by Benoit Marty
parent 30940cb937
commit 27d32188bf
8 changed files with 60 additions and 57 deletions

View File

@ -89,6 +89,7 @@ import org.matrix.android.sdk.internal.crypto.model.SessionInfo
import org.matrix.android.sdk.internal.crypto.model.toRest import org.matrix.android.sdk.internal.crypto.model.toRest
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
@ -192,21 +193,21 @@ internal class DefaultCryptoService @Inject constructor(
private val isStarting = AtomicBoolean(false) private val isStarting = AtomicBoolean(false)
private val isStarted = AtomicBoolean(false) private val isStarted = AtomicBoolean(false)
fun onStateEvent(roomId: String, event: Event) { fun onStateEvent(roomId: String, event: Event, cryptoStoreAggregator: CryptoStoreAggregator?) {
when (event.type) { when (event.type) {
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event, cryptoStoreAggregator)
} }
} }
fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean) { fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean, cryptoStoreAggregator: CryptoStoreAggregator?) {
// handle state events // handle state events
if (event.isStateEvent()) { if (event.isStateEvent()) {
when (event.type) { when (event.type) {
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event, cryptoStoreAggregator)
} }
} }
@ -384,7 +385,6 @@ internal class DefaultCryptoService @Inject constructor(
} }
} }
} }
cryptoStore.onSyncWillProcess()
} }
private fun internalStart() { private fun internalStart() {
@ -432,8 +432,8 @@ internal class DefaultCryptoService @Inject constructor(
* *
* @param syncResponse the syncResponse * @param syncResponse the syncResponse
*/ */
fun onSyncCompleted(syncResponse: SyncResponse) { fun onSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
cryptoStore.onSyncCompleted() cryptoStore.storeData(cryptoStoreAggregator)
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
runCatching { runCatching {
if (syncResponse.deviceLists != null) { if (syncResponse.deviceLists != null) {
@ -1000,15 +1000,26 @@ internal class DefaultCryptoService @Inject constructor(
} }
} }
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) { private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event, cryptoStoreAggregator: CryptoStoreAggregator?) {
if (!event.isStateEvent()) return if (!event.isStateEvent()) return
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>() val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()
val historyVisibility = eventContent?.historyVisibility val historyVisibility = eventContent?.historyVisibility
if (historyVisibility == null) { if (historyVisibility == null) {
cryptoStore.setShouldShareHistory(roomId, false) if (cryptoStoreAggregator != null) {
cryptoStoreAggregator.setShouldShareHistoryData[roomId] = false
} else {
// Store immediately
cryptoStore.setShouldShareHistory(roomId, false)
}
} else { } else {
cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED) if (cryptoStoreAggregator != null) {
cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory()) cryptoStoreAggregator.setShouldEncryptForInvitedMembersData[roomId] = historyVisibility != RoomHistoryVisibility.JOINED
cryptoStoreAggregator.setShouldShareHistoryData[roomId] = historyVisibility.shouldShareHistory()
} else {
// Store immediately
cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED)
cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory())
}
} }
} }

View File

@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
import org.matrix.olm.OlmAccount import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmOutboundGroupSession import org.matrix.olm.OlmOutboundGroupSession
@ -48,21 +49,6 @@ import org.matrix.olm.OlmOutboundGroupSession
*/ */
internal interface IMXCryptoStore { internal interface IMXCryptoStore {
/**
* Notify the store that a sync response treatment is starting.
* Impacted methods:
* - [setShouldShareHistory]
* - [setShouldEncryptForInvitedMembers]
* @See [onSyncCompleted] to notify that the treatment is over.
*/
fun onSyncWillProcess()
/**
* Notify the store that the sync treatment response is finished.
* The store will save all aggregated data.
*/
fun onSyncCompleted()
/** /**
* @return the device id * @return the device id
*/ */
@ -307,7 +293,11 @@ internal interface IMXCryptoStore {
fun shouldEncryptForInvitedMembers(roomId: String): Boolean fun shouldEncryptForInvitedMembers(roomId: String): Boolean
/** /**
* The data is not stored immediately, this MUST be call during a sync response treatment. * Sets a boolean flag that will determine whether or not this device should encrypt Events for
* invited members.
*
* @param roomId the room id
* @param shouldEncryptForInvitedMembers The boolean flag
*/ */
fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean)
@ -316,7 +306,6 @@ internal interface IMXCryptoStore {
/** /**
* Sets a boolean flag that will determine whether or not room history (existing inbound sessions) * Sets a boolean flag that will determine whether or not room history (existing inbound sessions)
* will be shared to new user invites. * will be shared to new user invites.
* The data is not stored immediately, this MUST be call during a sync response treatment.
* *
* @param roomId the room id * @param roomId the room id
* @param shouldShareHistory The boolean flag * @param shouldShareHistory The boolean flag
@ -601,6 +590,11 @@ internal interface IMXCryptoStore {
fun tidyUpDataBase() fun tidyUpDataBase()
fun getOutgoingRoomKeyRequests(inStates: Set<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest> fun getOutgoingRoomKeyRequests(inStates: Set<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest>
/**
* Store a bunch of data collected during a sync response treatment. @See [CryptoStoreAggregator].
*/
fun storeData(cryptoStoreAggregator: CryptoStoreAggregator)
/** /**
* Store a bunch of data related to the users. @See [UserDataToStore]. * Store a bunch of data related to the users. @See [UserDataToStore].
*/ */

View File

@ -719,13 +719,17 @@ internal class RealmCryptoStore @Inject constructor(
} }
override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) { override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) {
cryptoStoreAggregator?.setShouldEncryptForInvitedMembersData?.put(roomId, shouldEncryptForInvitedMembers) doRealmTransaction("setShouldEncryptForInvitedMembers", realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldEncryptForInvitedMembers = shouldEncryptForInvitedMembers
}
} }
override fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean) { override fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean) {
Timber.tag(loggerTag.value) Timber.tag(loggerTag.value)
.v("setShouldShareHistory for room $roomId is $shouldShareHistory") .v("setShouldShareHistory for room $roomId is $shouldShareHistory")
cryptoStoreAggregator?.setShouldShareHistoryData?.put(roomId, shouldShareHistory) doRealmTransaction("setShouldShareHistory", realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldShareHistory = shouldShareHistory
}
} }
override fun storeSession(olmSessionWrapper: OlmSessionWrapper, deviceKey: String) { override fun storeSession(olmSessionWrapper: OlmSessionWrapper, deviceKey: String) {
@ -1823,37 +1827,24 @@ internal class RealmCryptoStore @Inject constructor(
} }
} }
private var cryptoStoreAggregator: CryptoStoreAggregator? = null override fun storeData(cryptoStoreAggregator: CryptoStoreAggregator) {
override fun onSyncWillProcess() { if (cryptoStoreAggregator.isEmpty()) {
if (cryptoStoreAggregator != null) {
Timber.e("cryptoStoreAggregator is not null...")
}
cryptoStoreAggregator = CryptoStoreAggregator()
}
override fun onSyncCompleted() {
val aggregator = cryptoStoreAggregator ?: return Unit.also {
Timber.e("cryptoStoreAggregator is null...")
}
cryptoStoreAggregator = null
if (aggregator.isEmpty()) {
return return
} }
doRealmTransaction("onSyncCompleted", realmConfiguration) { realm -> doRealmTransaction("storeData - CryptoStoreAggregator", realmConfiguration) { realm ->
// setShouldShareHistory // setShouldShareHistory
aggregator.setShouldShareHistoryData.forEach { cryptoStoreAggregator.setShouldShareHistoryData.forEach {
CryptoRoomEntity.getOrCreate(realm, it.key).shouldShareHistory = it.value CryptoRoomEntity.getOrCreate(realm, it.key).shouldShareHistory = it.value
} }
// setShouldEncryptForInvitedMembers // setShouldEncryptForInvitedMembers
aggregator.setShouldEncryptForInvitedMembersData.forEach { cryptoStoreAggregator.setShouldEncryptForInvitedMembersData.forEach {
CryptoRoomEntity.getOrCreate(realm, it.key).shouldEncryptForInvitedMembers = it.value CryptoRoomEntity.getOrCreate(realm, it.key).shouldEncryptForInvitedMembers = it.value
} }
} }
} }
override fun storeData(userDataToStore: UserDataToStore) { override fun storeData(userDataToStore: UserDataToStore) {
doRealmTransaction("storeUserDataToStore", realmConfiguration) { realm -> doRealmTransaction("storeData - UserDataToStore", realmConfiguration) { realm ->
userDataToStore.userDevices.forEach { userDataToStore.userDevices.forEach {
storeUserDevices(realm, it.key, it.value) storeUserDevices(realm, it.key, it.value)
} }

View File

@ -176,7 +176,7 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
} }
// Give info to crypto module // Give info to crypto module
cryptoService.onStateEvent(roomId, event) cryptoService.onStateEvent(roomId, event, null)
} }
roomMemberContentsByUser.getOrPut(event.senderId) { roomMemberContentsByUser.getOrPut(event.senderId) {

View File

@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
import org.matrix.android.sdk.api.session.sync.model.SyncResponse import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.session.SessionListeners import org.matrix.android.sdk.internal.session.SessionListeners
@ -92,7 +93,7 @@ internal class SyncResponseHandler @Inject constructor(
postTreatmentSyncResponse(syncResponse, isInitialSync) postTreatmentSyncResponse(syncResponse, isInitialSync)
markCryptoSyncCompleted(syncResponse) markCryptoSyncCompleted(syncResponse, aggregator.cryptoStoreAggregator)
handlePostSync() handlePostSync()
@ -218,10 +219,10 @@ internal class SyncResponseHandler @Inject constructor(
} }
} }
private fun markCryptoSyncCompleted(syncResponse: SyncResponse) { private fun markCryptoSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
relevantPlugins.measureSpan("task", "crypto_sync_handler_onSyncCompleted") { relevantPlugins.measureSpan("task", "crypto_sync_handler_onSyncCompleted") {
measureTimeMillis { measureTimeMillis {
cryptoSyncHandler.onSyncCompleted(syncResponse) cryptoSyncHandler.onSyncCompleted(syncResponse, cryptoStoreAggregator)
}.also { }.also {
Timber.v("cryptoSyncHandler.onSyncCompleted took $it ms") Timber.v("cryptoSyncHandler.onSyncCompleted took $it ms")
} }

View File

@ -16,6 +16,8 @@
package org.matrix.android.sdk.internal.session.sync package org.matrix.android.sdk.internal.session.sync
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
internal class SyncResponsePostTreatmentAggregator { internal class SyncResponsePostTreatmentAggregator {
// List of RoomId // List of RoomId
val ephemeralFilesToDelete = mutableListOf<String>() val ephemeralFilesToDelete = mutableListOf<String>()
@ -28,4 +30,7 @@ internal class SyncResponsePostTreatmentAggregator {
// Set of users to call `crossSigningService.checkTrustAndAffectedRoomShields` once per sync // Set of users to call `crossSigningService.checkTrustAndAffectedRoomShields` once per sync
val userIdsForCheckingTrustAndAffectedRoomShields = mutableSetOf<String>() val userIdsForCheckingTrustAndAffectedRoomShields = mutableSetOf<String>()
// For the crypto store
val cryptoStoreAggregator = CryptoStoreAggregator()
} }

View File

@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.sync.model.SyncResponse import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
import org.matrix.android.sdk.internal.crypto.tasks.toDeviceTracingId import org.matrix.android.sdk.internal.crypto.tasks.toDeviceTracingId
import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
import org.matrix.android.sdk.internal.session.sync.ProgressReporter import org.matrix.android.sdk.internal.session.sync.ProgressReporter
@ -85,8 +86,8 @@ internal class CryptoSyncHandler @Inject constructor(
} }
} }
fun onSyncCompleted(syncResponse: SyncResponse) { fun onSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
cryptoService.onSyncCompleted(syncResponse) cryptoService.onSyncCompleted(syncResponse, cryptoStoreAggregator)
} }
/** /**

View File

@ -258,7 +258,7 @@ internal class RoomSyncHandler @Inject constructor(
root = eventEntity root = eventEntity
} }
// Give info to crypto module // Give info to crypto module
cryptoService.onStateEvent(roomId, event) cryptoService.onStateEvent(roomId, event, aggregator.cryptoStoreAggregator)
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync, aggregator) roomMemberEventHandler.handle(realm, roomId, event, isInitialSync, aggregator)
} }
} }
@ -495,7 +495,7 @@ internal class RoomSyncHandler @Inject constructor(
} }
} }
// Give info to crypto module // Give info to crypto module
cryptoService.onLiveEvent(roomEntity.roomId, event, isInitialSync) cryptoService.onLiveEvent(roomEntity.roomId, event, isInitialSync, aggregator.cryptoStoreAggregator)
// Try to remove local echo // Try to remove local echo
event.unsignedData?.transactionId?.also { txId -> event.unsignedData?.transactionId?.also { txId ->