From 67eff0583c90ec80a1a132ab2b2f776d6a1439a4 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 27 Sep 2020 08:57:32 +0200 Subject: [PATCH 01/19] Fix for vector-im#2100: Using Ringtone and RingtoneManager classes to control ringtones for incoming calls. Using systemwide setting for ringtone and volume. --- .../app/core/services/CallRingPlayer.kt | 27 ++++++++++++++++--- .../vector/app/core/services/CallService.kt | 22 +++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt index b14a097eb6..71733c7f07 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt @@ -17,6 +17,8 @@ package im.vector.app.core.services import android.content.Context +import android.media.Ringtone +import android.media.RingtoneManager import android.media.AudioAttributes import android.media.AudioManager import android.media.MediaPlayer @@ -25,7 +27,26 @@ import androidx.core.content.getSystemService import im.vector.app.R import timber.log.Timber -class CallRingPlayer( +class CallRingPlayerIncoming( + context: Context +) { + + private val applicationContext = context.applicationContext + private var r: Ringtone? = null + + fun start() { + val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) + r = RingtoneManager.getRingtone(applicationContext, notification) + Timber.v("## VOIP Starting ringing incomming") + r?.play() + } + + fun stop() { + r?.stop() + } +} + +class CallRingPlayerOutgoing( context: Context ) { @@ -44,12 +65,12 @@ class CallRingPlayer( try { if (player?.isPlaying == false) { player?.start() - Timber.v("## VOIP Starting ringing") + Timber.v("## VOIP Starting ringing outgoing") } else { Timber.v("## VOIP already playing") } } catch (failure: Throwable) { - Timber.e(failure, "## VOIP Failed to start ringing") + Timber.e(failure, "## VOIP Failed to start ringing outgoing") player = null } } else { diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index 1362c20be1..075b237be2 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -40,7 +40,8 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe private lateinit var notificationUtils: NotificationUtils private lateinit var webRtcPeerConnectionManager: WebRtcPeerConnectionManager - private var callRingPlayer: CallRingPlayer? = null + private var callRingPlayerIncoming: CallRingPlayerIncoming? = null + private var callRingPlayerOutgoing: CallRingPlayerOutgoing? = null private var wiredHeadsetStateReceiver: WiredHeadsetStateReceiver? = null private var bluetoothHeadsetStateReceiver: BluetoothHeadsetReceiver? = null @@ -63,14 +64,16 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe super.onCreate() notificationUtils = vectorComponent().notificationUtils() webRtcPeerConnectionManager = vectorComponent().webRtcPeerConnectionManager() - callRingPlayer = CallRingPlayer(applicationContext) + callRingPlayerIncoming = CallRingPlayerIncoming(applicationContext) + callRingPlayerOutgoing = CallRingPlayerOutgoing(applicationContext) wiredHeadsetStateReceiver = WiredHeadsetStateReceiver.createAndRegister(this, this) bluetoothHeadsetStateReceiver = BluetoothHeadsetReceiver.createAndRegister(this, this) } override fun onDestroy() { super.onDestroy() - callRingPlayer?.stop() + callRingPlayerIncoming?.stop() + callRingPlayerOutgoing?.stop() wiredHeadsetStateReceiver?.let { WiredHeadsetStateReceiver.unRegister(this, it) } wiredHeadsetStateReceiver = null bluetoothHeadsetStateReceiver?.let { BluetoothHeadsetReceiver.unRegister(this, it) } @@ -100,16 +103,17 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe when (intent.action) { ACTION_INCOMING_RINGING_CALL -> { mediaSession?.isActive = true - callRingPlayer?.start() + callRingPlayerIncoming?.start() displayIncomingCallNotification(intent) } ACTION_OUTGOING_RINGING_CALL -> { mediaSession?.isActive = true - callRingPlayer?.start() + callRingPlayerOutgoing?.start() displayOutgoingRingingCallNotification(intent) } ACTION_ONGOING_CALL -> { - callRingPlayer?.stop() + callRingPlayerIncoming?.stop() + callRingPlayerOutgoing?.stop() displayCallInProgressNotification(intent) } ACTION_NO_ACTIVE_CALL -> hideCallNotifications() @@ -117,7 +121,8 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe // lower notification priority displayCallInProgressNotification(intent) // stop ringing - callRingPlayer?.stop() + callRingPlayerIncoming?.stop() + callRingPlayerOutgoing?.stop() } ACTION_ONGOING_CALL_BG -> { // there is an ongoing call but call activity is in background @@ -125,7 +130,8 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe } else -> { // Should not happen - callRingPlayer?.stop() + callRingPlayerIncoming?.stop() + callRingPlayerOutgoing?.stop() myStopSelf() } } From a9f7fb46b346ca1719de61c42ab5f9a2b53c83ed Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 12 Oct 2020 15:06:49 +0200 Subject: [PATCH 02/19] Fix for ticket #2246: Ringtone volume cannot bechanged while ringing This fix delays the creation of the audioManager until the call is connected. This way the call feature does not takes the focus from the core service (where the ringtone is generated) until the call is esablished. This way the volume can be controled correctly while the phone is ringing (incoming and outgoing). --- .../main/java/im/vector/app/core/services/CallRingPlayer.kt | 2 +- .../java/im/vector/app/features/call/CallAudioManager.kt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt index 71733c7f07..d5d8bb14dd 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt @@ -95,7 +95,7 @@ class CallRingPlayerOutgoing( } else { mediaPlayer.setAudioAttributes(AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) - .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING) + .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) .build()) } return mediaPlayer diff --git a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt index 9b3c42ab5d..73d25662cd 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt @@ -93,6 +93,10 @@ class CallAudioManager( fun startForCall(mxCall: MxCall) { Timber.v("## VOIP: AudioManager startForCall ${mxCall.callId}") + } + + fun setupAudioManager(mxCall: MxCall) { + Timber.v("## VOIP: AudioManager setupAudioManager ${mxCall.callId}") val audioManager = audioManager ?: return savedIsSpeakerPhoneOn = audioManager.isSpeakerphoneOn savedIsMicrophoneMute = audioManager.isMicrophoneMute @@ -150,6 +154,7 @@ class CallAudioManager( fun onCallConnected(mxCall: MxCall) { Timber.v("##VOIP: AudioManager call answered, adjusting current sound device") + setupAudioManager(mxCall) adjustCurrentSoundDevice(mxCall) } From 33a962b72155cc433c9e2fc498b2b66d07cf8df4 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 4 Sep 2020 17:55:29 +0300 Subject: [PATCH 03/19] Start sync when receive m.call.invite. --- CHANGES.md | 1 + .../im/vector/app/features/call/WebRtcPeerConnectionManager.kt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f5a0d5dbb1..f276d12497 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ Improvements 🙌: Bugfix 🐛: - Messages encrypted with no way to decrypt after SDK update from 0.18 to 1.0.0 (#2252) + - Incoming call continues to ring if call is answered on another device (#1921) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index c70b52b09b..9f3e4cb910 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -702,6 +702,8 @@ class WebRtcPeerConnectionManager @Inject constructor( ) callContext.offerSdp = callInviteContent.offer + + currentSession?.startSync(true) } private fun createAnswer() { From 1de1ddd49631e1cc6dbf499d5c6bd17eb6be4314 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 30 Oct 2020 11:52:59 +0100 Subject: [PATCH 04/19] Fix / bg sync for received by other session + dismiss full screen intent --- .../java/im/vector/app/VectorApplication.kt | 3 ++ .../app/features/call/VectorCallViewModel.kt | 5 +++ .../call/WebRtcPeerConnectionManager.kt | 44 +++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 4f89763cda..5be313d719 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -42,6 +42,7 @@ import im.vector.app.core.di.HasVectorInjector import im.vector.app.core.di.VectorComponent import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.rx.RxConfig +import im.vector.app.features.call.WebRtcPeerConnectionManager import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks @@ -89,6 +90,7 @@ class VectorApplication : @Inject lateinit var rxConfig: RxConfig @Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var pinLocker: PinLocker + @Inject lateinit var webRtcPeerConnectionManager: WebRtcPeerConnectionManager lateinit var vectorComponent: VectorComponent @@ -173,6 +175,7 @@ class VectorApplication : }) ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler) ProcessLifecycleOwner.get().lifecycle.addObserver(pinLocker) + ProcessLifecycleOwner.get().lifecycle.addObserver(webRtcPeerConnectionManager) // This should be done as early as possible // initKnownEmojiHashSet(appContext) diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index edb75441c8..445f40e5b1 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -88,6 +88,11 @@ class VectorCallViewModel @AssistedInject constructor( private val currentCallListener = object : WebRtcPeerConnectionManager.CurrentCallListener { override fun onCurrentCallChange(call: MxCall?) { + // we need to check the state + if (call == null) { + // we should dismiss, e.g handled by other session? + _viewEvents.post(VectorCallViewEvents.DismissNoCall) + } } override fun onCaptureStateChanged() { diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index 9f3e4cb910..0b844f36d3 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -18,11 +18,16 @@ package im.vector.app.features.call import android.content.Context import android.hardware.camera2.CameraManager +import android.os.SystemClock import androidx.core.content.getSystemService +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent import im.vector.app.ActiveSessionDataSource import im.vector.app.core.services.BluetoothHeadsetReceiver import im.vector.app.core.services.CallService import im.vector.app.core.services.WiredHeadsetStateReceiver +import im.vector.app.push.fcm.FcmHelper import io.reactivex.disposables.Disposable import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.ReplaySubject @@ -71,8 +76,8 @@ import javax.inject.Singleton @Singleton class WebRtcPeerConnectionManager @Inject constructor( private val context: Context, - private val activeSessionDataSource: ActiveSessionDataSource -) : CallsListener { + private val activeSessionDataSource: ActiveSessionDataSource, +) : CallsListener, LifecycleObserver { private val currentSession: Session? get() = activeSessionDataSource.currentValue?.orNull() @@ -170,6 +175,8 @@ class WebRtcPeerConnectionManager @Inject constructor( private var currentCaptureMode: CaptureFormat = CaptureFormat.HD + private var isInBackground: Boolean = true + var capturerIsInError = false set(value) { field = value @@ -201,6 +208,17 @@ class WebRtcPeerConnectionManager @Inject constructor( } } + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + fun entersForeground() { + isInBackground = false + } + + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + fun entersBackground() { + isInBackground = true + } + + var currentCall: CallContext? = null set(value) { field = value @@ -703,7 +721,17 @@ class WebRtcPeerConnectionManager @Inject constructor( callContext.offerSdp = callInviteContent.offer - currentSession?.startSync(true) + // If this is received while in background, the app will not sync, + // and thus won't be able to received events. For example if the call is + // accepted on an other session this device will continue ringing + if (isInBackground) { + if (FcmHelper.isPushSupported()) { + // only for push version as fdroid version is already doing it? + currentSession?.startAutomaticBackgroundSync(30, 0) + } else { + // Maybe increase sync freq? but how to set back to default values? + } + } } private fun createAnswer() { @@ -851,6 +879,16 @@ class WebRtcPeerConnectionManager @Inject constructor( Timber.v("## VOIP onCallManagedByOtherSession: $callId") currentCall = null CallService.onNoActiveCall(context) + + // did we start background sync? so we should stop it + if (isInBackground) { + if (FcmHelper.isPushSupported()) { + currentSession?.stopAnyBackgroundSync() + } else { + // for fdroid we should not stop, it should continue syncing + // maybe we should restore default timeout/delay though? + } + } } private inner class StreamObserver(val callContext: CallContext) : PeerConnection.Observer { From 1fcbf7ed42c9c540b475672e334172abdc801a67 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 30 Oct 2020 14:16:04 +0100 Subject: [PATCH 05/19] Release backupOlmPkEncryption --- .../sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt index 3abbf9b16e..9f560bce2b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -1179,6 +1179,7 @@ internal class DefaultKeysBackupService @Inject constructor( cryptoStore.setKeyBackupVersion(null) cryptoStore.setKeysBackupData(null) + backupOlmPkEncryption?.releaseEncryption() backupOlmPkEncryption = null // Reset backup markers From 14e7e5e9fd45e537814dcb3cbd2350c89077d661 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 30 Oct 2020 14:29:44 +0100 Subject: [PATCH 06/19] Avoid usage of `!!` --- .../model/OlmInboundGroupSessionWrapper2.kt | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt index 478d55d077..8b00ed90d5 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt @@ -48,15 +48,12 @@ class OlmInboundGroupSessionWrapper2 : Serializable { */ val firstKnownIndex: Long? get() { - if (null != olmInboundGroupSession) { - try { - return olmInboundGroupSession!!.firstKnownIndex - } catch (e: Exception) { - Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") - } + return try { + return olmInboundGroupSession?.firstKnownIndex + } catch (e: Exception) { + Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") + null } - - return null } /** @@ -90,11 +87,13 @@ class OlmInboundGroupSessionWrapper2 : Serializable { @Throws(Exception::class) constructor(megolmSessionData: MegolmSessionData) { try { - olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!) - - if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) { - throw Exception("Mismatched group session Id") - } + val safeSessionKey = megolmSessionData.sessionKey ?: throw Exception("invalid data") + olmInboundGroupSession = OlmInboundGroupSession.importSession(safeSessionKey) + .also { + if (it.sessionIdentifier() != megolmSessionData.sessionId) { + throw Exception("Mismatched group session Id") + } + } senderKey = megolmSessionData.senderKey keysClaimed = megolmSessionData.senderClaimedKeys @@ -120,16 +119,18 @@ class OlmInboundGroupSessionWrapper2 : Serializable { return null } - val wantedIndex = index ?: olmInboundGroupSession!!.firstKnownIndex + val safeOlmInboundGroupSession = olmInboundGroupSession ?: return null + + val wantedIndex = index ?: safeOlmInboundGroupSession.firstKnownIndex MegolmSessionData( senderClaimedEd25519Key = keysClaimed?.get("ed25519"), - forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!), + forwardingCurve25519KeyChain = forwardingCurve25519KeyChain?.toList().orEmpty(), senderKey = senderKey, senderClaimedKeys = keysClaimed, roomId = roomId, - sessionId = olmInboundGroupSession!!.sessionIdentifier(), - sessionKey = olmInboundGroupSession!!.export(wantedIndex), + sessionId = safeOlmInboundGroupSession.sessionIdentifier(), + sessionKey = safeOlmInboundGroupSession.export(wantedIndex), algorithm = MXCRYPTO_ALGORITHM_MEGOLM ) } catch (e: Exception) { @@ -145,14 +146,11 @@ class OlmInboundGroupSessionWrapper2 : Serializable { * @return the exported data */ fun exportSession(messageIndex: Long): String? { - if (null != olmInboundGroupSession) { - try { - return olmInboundGroupSession!!.export(messageIndex) - } catch (e: Exception) { - Timber.e(e, "## exportSession() : export failed") - } + return try { + return olmInboundGroupSession?.export(messageIndex) + } catch (e: Exception) { + Timber.e(e, "## exportSession() : export failed") + null } - - return null } } From 0bcf42dbb8c6a035653f11d36dc06e30b2f710de Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 30 Oct 2020 16:14:33 +0100 Subject: [PATCH 07/19] KeysBackup: some API parameters are mandatory, so stop considering them as optional and avoid using `!!` Also fix an issue with Json name: `hash` -> `etag` Add some `internal` modifier (not as much as I would like to) var -> val Remove unused code --- .../android/sdk/common/CryptoTestHelper.kt | 3 +- .../crypto/keysbackup/KeysBackupTest.kt | 5 +- .../keysbackup/DefaultKeysBackupService.kt | 124 ++++++++---------- .../crypto/keysbackup/api/RoomKeysApi.kt | 2 +- .../keysbackup/model/MegolmBackupAuthData.kt | 37 ++++-- .../model/MegolmBackupCreationInfo.kt | 6 +- .../keysbackup/model/rest/BackupKeysResult.kt | 11 +- .../model/rest/CreateKeysBackupVersionBody.kt | 6 +- .../keysbackup/model/rest/KeyBackupData.kt | 17 +-- .../model/rest/KeysAlgorithmAndData.kt | 12 +- .../keysbackup/model/rest/KeysVersion.kt | 2 +- .../model/rest/KeysVersionResult.kt | 12 +- .../model/rest/UpdateKeysBackupVersionBody.kt | 8 +- .../recover/BootstrapSharedViewModel.kt | 2 +- 14 files changed, 122 insertions(+), 125 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt index b67172a908..1a9165ade4 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt @@ -245,7 +245,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo { return MegolmBackupCreationInfo( algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, - authData = createFakeMegolmBackupAuthData() + authData = createFakeMegolmBackupAuthData(), + recoveryKey = "fake" ) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt index ca8993fb00..8148d91e9c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt @@ -115,9 +115,8 @@ class KeysBackupTest : InstrumentedTest { } assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, megolmBackupCreationInfo.algorithm) - assertNotNull(megolmBackupCreationInfo.authData) - assertNotNull(megolmBackupCreationInfo.authData!!.publicKey) - assertNotNull(megolmBackupCreationInfo.authData!!.signatures) + assertNotNull(megolmBackupCreationInfo.authData.publicKey) + assertNotNull(megolmBackupCreationInfo.authData.signatures) assertNotNull(megolmBackupCreationInfo.recoveryKey) stateObserver.stopAndCheckStates(null) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt index 9f560bce2b..aaa6a1d4ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -30,7 +30,6 @@ import org.matrix.android.sdk.api.listeners.StepProgressListener import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener -import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.MegolmSessionData @@ -85,6 +84,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData import org.matrix.olm.OlmException import org.matrix.olm.OlmPkDecryption import org.matrix.olm.OlmPkEncryption @@ -170,7 +170,7 @@ internal class DefaultKeysBackupService @Inject constructor( runCatching { withContext(coroutineDispatchers.crypto) { val olmPkDecryption = OlmPkDecryption() - val megolmBackupAuthData = if (password != null) { + val signalableMegolmBackupAuthData = if (password != null) { // Generate a private key from the password val backgroundProgressListener = if (progressListener == null) { null @@ -189,7 +189,7 @@ internal class DefaultKeysBackupService @Inject constructor( } val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener) - MegolmBackupAuthData( + SignalableMegolmBackupAuthData( publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey), privateKeySalt = generatePrivateKeyResult.salt, privateKeyIterations = generatePrivateKeyResult.iterations @@ -197,14 +197,17 @@ internal class DefaultKeysBackupService @Inject constructor( } else { val publicKey = olmPkDecryption.generateKey() - MegolmBackupAuthData( + SignalableMegolmBackupAuthData( publicKey = publicKey ) } - val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary()) + val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary()) - val signedMegolmBackupAuthData = megolmBackupAuthData.copy( + val signedMegolmBackupAuthData = MegolmBackupAuthData( + publicKey = signalableMegolmBackupAuthData.publicKey, + privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt, + privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations, signatures = objectSigner.signObject(canonicalJson) ) @@ -223,8 +226,7 @@ internal class DefaultKeysBackupService @Inject constructor( @Suppress("UNCHECKED_CAST") val createKeysBackupVersionBody = CreateKeysBackupVersionBody( algorithm = keysBackupCreationInfo.algorithm, - authData = MoshiProvider.providesMoshi().adapter(Map::class.java) - .fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict? + authData = keysBackupCreationInfo.authData.toJsonDict() ) keysBackupStateManager.state = KeysBackupState.Enabling @@ -245,7 +247,7 @@ internal class DefaultKeysBackupService @Inject constructor( version = data.version, // We can consider that the server does not have keys yet count = 0, - hash = null + hash = "" ) enableKeysBackup(keyBackupVersion) @@ -267,7 +269,7 @@ internal class DefaultKeysBackupService @Inject constructor( withContext(coroutineDispatchers.crypto) { // If we're currently backing up to this backup... stop. // (We start using it automatically in createKeysBackupVersion so this is symmetrical). - if (keysBackupVersion != null && version == keysBackupVersion!!.version) { + if (keysBackupVersion != null && version == keysBackupVersion?.version) { resetKeysBackupData() keysBackupVersion = null keysBackupStateManager.state = KeysBackupState.Unknown @@ -408,10 +410,7 @@ internal class DefaultKeysBackupService @Inject constructor( val keysBackupVersionTrust = KeysBackupVersionTrust() val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData() - if (keysBackupVersion.algorithm == null - || authData == null - || authData.publicKey.isEmpty() - || authData.signatures.isNullOrEmpty()) { + if (authData == null || authData.publicKey.isEmpty() || authData.signatures.isEmpty()) { Timber.v("getKeysBackupTrust: Key backup is absent or missing required data") return keysBackupVersionTrust } @@ -479,7 +478,7 @@ internal class DefaultKeysBackupService @Inject constructor( cryptoCoroutineScope.launch(coroutineDispatchers.main) { val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) { // Get current signatures, or create an empty set - val myUserSignatures = authData.signatures?.get(userId)?.toMutableMap() ?: HashMap() + val myUserSignatures = authData.signatures[userId].orEmpty().toMutableMap() if (trust) { // Add current device signature @@ -498,26 +497,23 @@ internal class DefaultKeysBackupService @Inject constructor( // Create an updated version of KeysVersionResult val newMegolmBackupAuthData = authData.copy() - val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap() + val newSignatures = newMegolmBackupAuthData.signatures.toMutableMap() newSignatures[userId] = myUserSignatures val newMegolmBackupAuthDataWithNewSignature = newMegolmBackupAuthData.copy( signatures = newSignatures ) - val moshi = MoshiProvider.providesMoshi() - val adapter = moshi.adapter(Map::class.java) - @Suppress("UNCHECKED_CAST") UpdateKeysBackupVersionBody( algorithm = keysBackupVersion.algorithm, - authData = adapter.fromJson(newMegolmBackupAuthDataWithNewSignature.toJsonString()) as Map?, - version = keysBackupVersion.version!!) + authData = newMegolmBackupAuthDataWithNewSignature.toJsonDict(), + version = keysBackupVersion.version) } // And send it to the homeserver updateKeysBackupVersionTask - .configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version!!, updateKeysBackupVersionBody)) { + .configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version, updateKeysBackupVersionBody)) { this.callback = object : MatrixCallback { override fun onSuccess(data: Unit) { // Relaunch the state machine on this updated backup version @@ -688,7 +684,7 @@ internal class DefaultKeysBackupService @Inject constructor( stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey) // Get backed up keys from the homeserver - val data = getKeys(sessionId, roomId, keysVersionResult.version!!) + val data = getKeys(sessionId, roomId, keysVersionResult.version) withContext(coroutineDispatchers.computation) { val sessionsData = ArrayList() @@ -1023,19 +1019,10 @@ internal class DefaultKeysBackupService @Inject constructor( * @return the authentication if found and valid, null in other case */ private fun getMegolmBackupAuthData(keysBackupData: KeysVersionResult): MegolmBackupAuthData? { - if (keysBackupData.version.isNullOrBlank() - || keysBackupData.algorithm != MXCRYPTO_ALGORITHM_MEGOLM_BACKUP - || keysBackupData.authData == null) { - return null - } - - val authData = keysBackupData.getAuthDataAsMegolmBackupAuthData() - - if (authData?.signatures == null || authData.publicKey.isBlank()) { - return null - } - - return authData + return keysBackupData + .takeIf { it.version.isNotEmpty() && it.algorithm == MXCRYPTO_ALGORITHM_MEGOLM_BACKUP } + ?.getAuthDataAsMegolmBackupAuthData() + ?.takeIf { it.publicKey.isNotEmpty() } } /** @@ -1123,34 +1110,29 @@ internal class DefaultKeysBackupService @Inject constructor( * @param keysVersionResult backup information object as returned by [getCurrentVersion]. */ private fun enableKeysBackup(keysVersionResult: KeysVersionResult) { - if (keysVersionResult.authData != null) { - val retrievedMegolmBackupAuthData = keysVersionResult.getAuthDataAsMegolmBackupAuthData() + val retrievedMegolmBackupAuthData = keysVersionResult.getAuthDataAsMegolmBackupAuthData() - if (retrievedMegolmBackupAuthData != null) { - keysBackupVersion = keysVersionResult - cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { - cryptoStore.setKeyBackupVersion(keysVersionResult.version) - } - - onServerDataRetrieved(keysVersionResult.count, keysVersionResult.hash) - - try { - backupOlmPkEncryption = OlmPkEncryption().apply { - setRecipientKey(retrievedMegolmBackupAuthData.publicKey) - } - } catch (e: OlmException) { - Timber.e(e, "OlmException") - keysBackupStateManager.state = KeysBackupState.Disabled - return - } - - keysBackupStateManager.state = KeysBackupState.ReadyToBackUp - - maybeBackupKeys() - } else { - Timber.e("Invalid authentication data") - keysBackupStateManager.state = KeysBackupState.Disabled + if (retrievedMegolmBackupAuthData != null) { + keysBackupVersion = keysVersionResult + cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { + cryptoStore.setKeyBackupVersion(keysVersionResult.version) } + + onServerDataRetrieved(keysVersionResult.count, keysVersionResult.hash) + + try { + backupOlmPkEncryption = OlmPkEncryption().apply { + setRecipientKey(retrievedMegolmBackupAuthData.publicKey) + } + } catch (e: OlmException) { + Timber.e(e, "OlmException") + keysBackupStateManager.state = KeysBackupState.Disabled + return + } + + keysBackupStateManager.state = KeysBackupState.ReadyToBackUp + + maybeBackupKeys() } else { Timber.e("Invalid authentication data") keysBackupStateManager.state = KeysBackupState.Disabled @@ -1160,11 +1142,11 @@ internal class DefaultKeysBackupService @Inject constructor( /** * Update the DB with data fetch from the server */ - private fun onServerDataRetrieved(count: Int?, hash: String?) { + private fun onServerDataRetrieved(count: Int?, etag: String?) { cryptoStore.setKeysBackupData(KeysBackupDataEntity() .apply { backupLastServerNumberOfKeys = count - backupLastServerHash = hash + backupLastServerHash = etag } ) } @@ -1316,7 +1298,7 @@ internal class DefaultKeysBackupService @Inject constructor( // Make the request storeSessionDataTask - .configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData)) { + .configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version, keysBackupData)) { this.callback = sendingRequestCallback } .executeBy(taskExecutor) @@ -1337,8 +1319,7 @@ internal class DefaultKeysBackupService @Inject constructor( "algorithm" to sessionData!!.algorithm, "sender_key" to sessionData.senderKey, "sender_claimed_keys" to sessionData.senderClaimedKeys, - "forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain - ?: ArrayList()), + "forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()), "session_key" to sessionData.sessionKey) var encryptedSessionBackupData: OlmPkMessage? = null @@ -1379,9 +1360,9 @@ internal class DefaultKeysBackupService @Inject constructor( val jsonObject = keyBackupData.sessionData - val ciphertext = jsonObject?.get("ciphertext")?.toString() - val mac = jsonObject?.get("mac")?.toString() - val ephemeralKey = jsonObject?.get("ephemeral")?.toString() + val ciphertext = jsonObject["ciphertext"]?.toString() + val mac = jsonObject["mac"]?.toString() + val ephemeralKey = jsonObject["ephemeral"]?.toString() if (ciphertext != null && mac != null && ephemeralKey != null) { val encrypted = OlmPkMessage() @@ -1426,8 +1407,7 @@ internal class DefaultKeysBackupService @Inject constructor( @Suppress("UNCHECKED_CAST") val createKeysBackupVersionBody = CreateKeysBackupVersionBody( algorithm = keysBackupCreationInfo.algorithm, - authData = MoshiProvider.providesMoshi().adapter(Map::class.java) - .fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict? + authData = keysBackupCreationInfo.authData.toJsonDict() ) createKeysBackupVersionTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt index ed5383d6eb..3f8333528f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt @@ -35,7 +35,7 @@ import retrofit2.http.Path import retrofit2.http.Query /** - * Ref: https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md + * Ref: https://matrix.org/docs/spec/client_server/unstable#server-side-key-backups */ internal interface RoomKeysApi { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupAuthData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupAuthData.kt index 9df5f29294..54b92546e9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupAuthData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupAuthData.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.di.MoshiProvider /** @@ -30,7 +31,7 @@ data class MegolmBackupAuthData( * The curve25519 public key used to encrypt the backups. */ @Json(name = "public_key") - val publicKey: String = "", + val publicKey: String, /** * In case of a backup created from a password, the salt associated with the backup @@ -50,20 +51,38 @@ data class MegolmBackupAuthData( * userId -> (deviceSignKeyId -> signature) */ @Json(name = "signatures") - val signatures: Map>? = null + val signatures: Map> ) { - fun toJsonString(): String { - return MoshiProvider.providesMoshi() + fun toJsonDict(): JsonDict { + val moshi = MoshiProvider.providesMoshi() + val adapter = moshi.adapter(Map::class.java) + + return moshi .adapter(MegolmBackupAuthData::class.java) .toJson(this) + .let { + @Suppress("UNCHECKED_CAST") + adapter.fromJson(it) as JsonDict + } } - /** - * Same as the parent [MXJSONModel JSONDictionary] but return only - * data that must be signed. - */ - fun signalableJSONDictionary(): Map = HashMap().apply { + fun signalableJSONDictionary(): JsonDict { + return SignalableMegolmBackupAuthData( + publicKey = publicKey, + privateKeySalt = privateKeySalt, + privateKeyIterations = privateKeyIterations + ) + .signalableJSONDictionary() + } +} + +internal data class SignalableMegolmBackupAuthData( + val publicKey: String, + val privateKeySalt: String? = null, + val privateKeyIterations: Int? = null +) { + fun signalableJSONDictionary(): JsonDict = HashMap().apply { put("public_key", publicKey) privateKeySalt?.let { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt index 1414d0e0d7..c668e78a9e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/MegolmBackupCreationInfo.kt @@ -23,15 +23,15 @@ data class MegolmBackupCreationInfo( /** * The algorithm used for storing backups [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP]. */ - val algorithm: String = "", + val algorithm: String, /** * Authentication data. */ - val authData: MegolmBackupAuthData? = null, + val authData: MegolmBackupAuthData, /** * The Base58 recovery key. */ - val recoveryKey: String = "" + val recoveryKey: String ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/BackupKeysResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/BackupKeysResult.kt index a84ba7427b..3710a2d7d9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/BackupKeysResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/BackupKeysResult.kt @@ -16,15 +16,16 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest +import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class BackupKeysResult( - +internal data class BackupKeysResult( // The hash value which is an opaque string representing stored keys in the backup - var hash: String? = null, + @Json(name = "etag") + val hash: String, // The number of keys stored in the backup. - var count: Int? = null - + @Json(name = "count") + val count: Int ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt index a7831b38f1..a6bd8f8aaa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt @@ -21,17 +21,17 @@ import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.util.JsonDict @JsonClass(generateAdapter = true) -data class CreateKeysBackupVersionBody( +internal data class CreateKeysBackupVersionBody( /** * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined */ @Json(name = "algorithm") - override val algorithm: String? = null, + override val algorithm: String, /** * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" * see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData] */ @Json(name = "auth_data") - override val authData: JsonDict? = null + override val authData: JsonDict ) : KeysAlgorithmAndData diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt index 46eaa586a7..3f8129b8f6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeyBackupData.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.network.parsing.ForceToBoolean /** @@ -30,13 +30,13 @@ data class KeyBackupData( * Required. The index of the first message in the session that the key can decrypt. */ @Json(name = "first_message_index") - val firstMessageIndex: Long = 0, + val firstMessageIndex: Long, /** * Required. The number of times this key has been forwarded. */ @Json(name = "forwarded_count") - val forwardedCount: Int = 0, + val forwardedCount: Int, /** * Whether the device backing up the key has verified the device that the key is from. @@ -44,16 +44,11 @@ data class KeyBackupData( */ @ForceToBoolean @Json(name = "is_verified") - val isVerified: Boolean = false, + val isVerified: Boolean, /** * Algorithm-dependent data. */ @Json(name = "session_data") - val sessionData: Map? = null -) { - - fun toJsonString(): String { - return MoshiProvider.providesMoshi().adapter(KeyBackupData::class.java).toJson(this) - } -} + val sessionData: JsonDict +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt index 117d4dce70..e098aa0440 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData import org.matrix.android.sdk.internal.di.MoshiProvider @@ -37,24 +38,25 @@ import org.matrix.android.sdk.internal.di.MoshiProvider * } * */ -interface KeysAlgorithmAndData { +internal interface KeysAlgorithmAndData { /** * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined */ - val algorithm: String? + val algorithm: String /** * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData] */ - val authData: JsonDict? + val authData: JsonDict /** * Facility method to convert authData to a MegolmBackupAuthData object */ fun getAuthDataAsMegolmBackupAuthData(): MegolmBackupAuthData? { return MoshiProvider.providesMoshi() - .adapter(MegolmBackupAuthData::class.java) - .fromJsonValue(authData) + .takeIf { algorithm == MXCRYPTO_ALGORITHM_MEGOLM_BACKUP } + ?.adapter(MegolmBackupAuthData::class.java) + ?.fromJsonValue(authData) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersion.kt index 146c98b017..7a4c3415fc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersion.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersion.kt @@ -23,5 +23,5 @@ import com.squareup.moshi.JsonClass data class KeysVersion( // the keys backup version @Json(name = "version") - val version: String? = null + val version: String ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt index 0844c58d2e..485fd48a8c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysVersionResult.kt @@ -26,24 +26,24 @@ data class KeysVersionResult( * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined */ @Json(name = "algorithm") - override val algorithm: String? = null, + override val algorithm: String, /** * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" * see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData] */ @Json(name = "auth_data") - override val authData: JsonDict? = null, + override val authData: JsonDict, // the backup version @Json(name = "version") - val version: String? = null, + val version: String, // The hash value which is an opaque string representing stored keys in the backup - @Json(name = "hash") - val hash: String? = null, + @Json(name = "etag") + val hash: String, // The number of keys stored in the backup. @Json(name = "count") - val count: Int? = null + val count: Int ) : KeysAlgorithmAndData diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt index 65f0c1a845..4512ed7a55 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt @@ -26,16 +26,16 @@ data class UpdateKeysBackupVersionBody( * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined */ @Json(name = "algorithm") - override val algorithm: String? = null, + override val algorithm: String, /** * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" * see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData] */ @Json(name = "auth_data") - override val authData: JsonDict? = null, + override val authData: JsonDict, - // the backup version, mandatory + // Optional. The backup version. If present, must be the same as the path parameter. @Json(name = "version") - val version: String + val version: String? = null ) : KeysAlgorithmAndData diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index 72b767e12f..2e5097fdb7 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -103,7 +103,7 @@ class BootstrapSharedViewModel @AssistedInject constructor( } else { // we need to get existing backup passphrase/key and convert to SSSS val keyVersion = awaitCallback { - session.cryptoService().keysBackupService().getVersion(version.version ?: "", it) + session.cryptoService().keysBackupService().getVersion(version.version, it) } if (keyVersion == null) { // strange case... just finish? From fca0aa2cc4912502aedc1d84bad8b895d1a6a194 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 30 Oct 2020 17:10:59 +0100 Subject: [PATCH 08/19] KeysBackup: Avoid using `!!`, should fix #2262 --- CHANGES.md | 1 + .../crypto/keysbackup/KeysBackupTest.kt | 4 +- .../keysbackup/DefaultKeysBackupService.kt | 166 +++++++++--------- 3 files changed, 84 insertions(+), 87 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 56d38667fe..6f5081b86f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,6 +21,7 @@ Improvements 🙌: Bugfix 🐛: - Messages encrypted with no way to decrypt after SDK update from 0.18 to 1.0.0 (#2252) - Search Result | scroll jumps after pagination (#2238) + - KeysBackup: Avoid using `!!` (#2262) Translations 🗣: - diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt index 8148d91e9c..606f57b467 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt @@ -257,14 +257,14 @@ class KeysBackupTest : InstrumentedTest { // - Check encryptGroupSession() returns stg val keyBackupData = keysBackup.encryptGroupSession(session) assertNotNull(keyBackupData) - assertNotNull(keyBackupData.sessionData) + assertNotNull(keyBackupData!!.sessionData) // - Check pkDecryptionFromRecoveryKey() is able to create a OlmPkDecryption val decryption = keysBackup.pkDecryptionFromRecoveryKey(keyBackupCreationInfo.recoveryKey) assertNotNull(decryption) // - Check decryptKeyBackupData() returns stg val sessionData = keysBackup - .decryptKeyBackupData(keyBackupData, + .decryptKeyBackupData(keyBackupData!!, session.olmInboundGroupSession!!.sessionIdentifier(), cryptoTestData.roomId, decryption!!) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt index aaa6a1d4ca..fbcf5cfdeb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -1212,22 +1212,19 @@ internal class DefaultKeysBackupService @Inject constructor( // Gather data to send to the homeserver // roomId -> sessionId -> MXKeyBackupData - val keysBackupData = KeysBackupData( - roomIdToRoomKeysBackupData = HashMap() - ) + val keysBackupData = KeysBackupData() - for (olmInboundGroupSessionWrapper in olmInboundGroupSessionWrappers) { - val keyBackupData = encryptGroupSession(olmInboundGroupSessionWrapper) - if (keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId] == null) { - val roomKeysBackupData = RoomKeysBackupData( - sessionIdToKeyBackupData = HashMap() - ) - keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId!!] = roomKeysBackupData - } + olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper -> + val roomId = olmInboundGroupSessionWrapper.roomId ?: return@forEach + val olmInboundGroupSession = olmInboundGroupSessionWrapper.olmInboundGroupSession ?: return@forEach try { - keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId]!! - .sessionIdToKeyBackupData[olmInboundGroupSessionWrapper.olmInboundGroupSession!!.sessionIdentifier()] = keyBackupData + encryptGroupSession(olmInboundGroupSessionWrapper) + ?.let { + keysBackupData.roomIdToRoomKeysBackupData + .getOrPut(roomId) { RoomKeysBackupData() } + .sessionIdToKeyBackupData[olmInboundGroupSession.sessionIdentifier()] = it + } } catch (e: OlmException) { Timber.e(e, "OlmException") } @@ -1235,71 +1232,71 @@ internal class DefaultKeysBackupService @Inject constructor( Timber.v("backupKeys: 4 - Sending request") - val sendingRequestCallback = object : MatrixCallback { - override fun onSuccess(data: BackupKeysResult) { - uiHandler.post { - Timber.v("backupKeys: 5a - Request complete") + // Make the request + val version = keysBackupVersion?.version ?: return@withContext - // Mark keys as backed up - cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers) + storeSessionDataTask + .configureWith(StoreSessionsDataTask.Params(version, keysBackupData)) { + this.callback = object : MatrixCallback { + override fun onSuccess(data: BackupKeysResult) { + uiHandler.post { + Timber.v("backupKeys: 5a - Request complete") - if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) { - Timber.v("backupKeys: All keys have been backed up") - onServerDataRetrieved(data.count, data.hash) + // Mark keys as backed up + cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers) - // Note: Changing state will trigger the call to backupAllGroupSessionsCallback.onSuccess() - keysBackupStateManager.state = KeysBackupState.ReadyToBackUp - } else { - Timber.v("backupKeys: Continue to back up keys") - keysBackupStateManager.state = KeysBackupState.WillBackUp + if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) { + Timber.v("backupKeys: All keys have been backed up") + onServerDataRetrieved(data.count, data.hash) - backupKeys() - } - } - } + // Note: Changing state will trigger the call to backupAllGroupSessionsCallback.onSuccess() + keysBackupStateManager.state = KeysBackupState.ReadyToBackUp + } else { + Timber.v("backupKeys: Continue to back up keys") + keysBackupStateManager.state = KeysBackupState.WillBackUp - override fun onFailure(failure: Throwable) { - if (failure is Failure.ServerError) { - uiHandler.post { - Timber.e(failure, "backupKeys: backupKeys failed.") - - when (failure.error.code) { - MatrixError.M_NOT_FOUND, - MatrixError.M_WRONG_ROOM_KEYS_VERSION -> { - // Backup has been deleted on the server, or we are not using the last backup version - keysBackupStateManager.state = KeysBackupState.WrongBackUpVersion - backupAllGroupSessionsCallback?.onFailure(failure) - resetBackupAllGroupSessionsListeners() - resetKeysBackupData() - keysBackupVersion = null - - // Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver - checkAndStartKeysBackup() + backupKeys() + } + } + } + + override fun onFailure(failure: Throwable) { + if (failure is Failure.ServerError) { + uiHandler.post { + Timber.e(failure, "backupKeys: backupKeys failed.") + + when (failure.error.code) { + MatrixError.M_NOT_FOUND, + MatrixError.M_WRONG_ROOM_KEYS_VERSION -> { + // Backup has been deleted on the server, or we are not using the last backup version + keysBackupStateManager.state = KeysBackupState.WrongBackUpVersion + backupAllGroupSessionsCallback?.onFailure(failure) + resetBackupAllGroupSessionsListeners() + resetKeysBackupData() + keysBackupVersion = null + + // Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver + checkAndStartKeysBackup() + } + else -> + // Come back to the ready state so that we will retry on the next received key + keysBackupStateManager.state = KeysBackupState.ReadyToBackUp + } + } + } else { + uiHandler.post { + backupAllGroupSessionsCallback?.onFailure(failure) + resetBackupAllGroupSessionsListeners() + + Timber.e("backupKeys: backupKeys failed.") + + // Retry a bit later + keysBackupStateManager.state = KeysBackupState.ReadyToBackUp + maybeBackupKeys() + } } - else -> - // Come back to the ready state so that we will retry on the next received key - keysBackupStateManager.state = KeysBackupState.ReadyToBackUp } } - } else { - uiHandler.post { - backupAllGroupSessionsCallback?.onFailure(failure) - resetBackupAllGroupSessionsListeners() - - Timber.e("backupKeys: backupKeys failed.") - - // Retry a bit later - keysBackupStateManager.state = KeysBackupState.ReadyToBackUp - maybeBackupKeys() - } - } - } - } - - // Make the request - storeSessionDataTask - .configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version, keysBackupData)) { - this.callback = sendingRequestCallback } .executeBy(taskExecutor) } @@ -1308,46 +1305,45 @@ internal class DefaultKeysBackupService @Inject constructor( @VisibleForTesting @WorkerThread - fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData { + fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData? { // Gather information for each key - val device = cryptoStore.deviceWithIdentityKey(olmInboundGroupSessionWrapper.senderKey!!) + val device = olmInboundGroupSessionWrapper.senderKey?.let { cryptoStore.deviceWithIdentityKey(it) } // Build the m.megolm_backup.v1.curve25519-aes-sha2 data as defined at // https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md#mmegolm_backupv1curve25519-aes-sha2-key-format - val sessionData = olmInboundGroupSessionWrapper.exportKeys() + val sessionData = olmInboundGroupSessionWrapper.exportKeys() ?: return null val sessionBackupData = mapOf( - "algorithm" to sessionData!!.algorithm, + "algorithm" to sessionData.algorithm, "sender_key" to sessionData.senderKey, "sender_claimed_keys" to sessionData.senderClaimedKeys, "forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()), "session_key" to sessionData.sessionKey) - var encryptedSessionBackupData: OlmPkMessage? = null + val json = MoshiProvider.providesMoshi() + .adapter(Map::class.java) + .toJson(sessionBackupData) - val moshi = MoshiProvider.providesMoshi() - val adapter = moshi.adapter(Map::class.java) - - try { - val json = adapter.toJson(sessionBackupData) - - encryptedSessionBackupData = backupOlmPkEncryption?.encrypt(json) + val encryptedSessionBackupData = try { + backupOlmPkEncryption?.encrypt(json) } catch (e: OlmException) { Timber.e(e, "OlmException") + null } + ?: return null // Build backup data for that key return KeyBackupData( firstMessageIndex = try { - olmInboundGroupSessionWrapper.olmInboundGroupSession!!.firstKnownIndex + olmInboundGroupSessionWrapper.olmInboundGroupSession?.firstKnownIndex ?: 0 } catch (e: OlmException) { Timber.e(e, "OlmException") 0L }, - forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain!!.size, + forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain.orEmpty().size, isVerified = device?.isVerified == true, sessionData = mapOf( - "ciphertext" to encryptedSessionBackupData!!.mCipherText, + "ciphertext" to encryptedSessionBackupData.mCipherText, "mac" to encryptedSessionBackupData.mMac, "ephemeral" to encryptedSessionBackupData.mEphemeralKey) ) From 1db120a963e5b943dc85e25e63e45b7ef62b4624 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 30 Oct 2020 18:08:11 +0100 Subject: [PATCH 09/19] cleanup --- .../sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt index 8b00ed90d5..1dc27c75ca 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt @@ -49,7 +49,7 @@ class OlmInboundGroupSessionWrapper2 : Serializable { val firstKnownIndex: Long? get() { return try { - return olmInboundGroupSession?.firstKnownIndex + olmInboundGroupSession?.firstKnownIndex } catch (e: Exception) { Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") null From aa2a24e68a21f1f79732a22dbae6c9374753727a Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 31 Oct 2020 13:17:25 +0100 Subject: [PATCH 10/19] Changes requested by BillCarsonFs review. Thanks for the comments! --- .../main/java/im/vector/app/features/call/CallAudioManager.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt index 73d25662cd..3a24cf6d48 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt @@ -95,7 +95,7 @@ class CallAudioManager( Timber.v("## VOIP: AudioManager startForCall ${mxCall.callId}") } - fun setupAudioManager(mxCall: MxCall) { + private fun setupAudioManager(mxCall: MxCall) { Timber.v("## VOIP: AudioManager setupAudioManager ${mxCall.callId}") val audioManager = audioManager ?: return savedIsSpeakerPhoneOn = audioManager.isSpeakerphoneOn @@ -155,7 +155,6 @@ class CallAudioManager( fun onCallConnected(mxCall: MxCall) { Timber.v("##VOIP: AudioManager call answered, adjusting current sound device") setupAudioManager(mxCall) - adjustCurrentSoundDevice(mxCall) } fun getAvailableSoundDevices(): List { From 7a11ab5bcafd6871fbd2c3ba9ef8a958fa6bbec9 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 31 Oct 2020 13:48:53 +0100 Subject: [PATCH 11/19] Updated CHANGES.md --- CHANGES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 99058117b6..75ff66a35d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,12 @@ +Changes in Element 1.0.10 (xxxx-xx-xx) +=================================================== + +Features ✨: + - + +Bugfix 🐛: + - Fixed ringtone handling (#2100 & #2246) + Changes in Element 1.0.9 (2020-10-16) =================================================== From 3364dd3380b79a4ea7cc09da563137c06f0c0476 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 1 Nov 2020 10:13:27 +0100 Subject: [PATCH 12/19] Merged latest CHANGES.md --- CHANGES.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 75ff66a35d..9f7ce6d999 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,39 @@ -Changes in Element 1.0.10 (xxxx-xx-xx) +Changes in Element 1.0.10 (2020-XX-XX) =================================================== Features ✨: - + +Improvements 🙌: + - Rework sending Event management (#154) + - New room creation screen: set topic and avatar in the room creation form (#2078) + - Toggle Low priority tag (#1490) + - Add option to send with enter (#1195) + - Use Hardware keyboard enter to send message (use shift-enter for new line) (#1881, #1440) + - Edit and remove icons are now visible on image attachment preview screen (#2294) + - Room profile: BigImageViewerActivity now only display the image. Use the room setting to change or delete the room Avatar + - Better visibility of text reactions in dark theme (#1118) + - Room member profile: Add action to create (or open) a DM (#2310) + - Prepare changelog for F-Droid (#2296) + - Add graphic resources for F-Droid (#812, #2220) + - Highlight text in the body of the displayed result (#2200) Bugfix 🐛: - Fixed ringtone handling (#2100 & #2246) + - Messages encrypted with no way to decrypt after SDK update from 0.18 to 1.0.0 (#2252) + - Search Result | scroll jumps after pagination (#2238) + +Translations 🗣: + - + +SDK API changes ⚠️: + - + +Build 🧱: + - + +Other changes: + - Changes in Element 1.0.9 (2020-10-16) =================================================== From 9ff78051a913ab9689e734ee1622365087b3512e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Nov 2020 14:15:27 +0100 Subject: [PATCH 13/19] Cleanup --- .../vector/app/features/call/WebRtcPeerConnectionManager.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt index 0b844f36d3..86b38c1158 100644 --- a/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/WebRtcPeerConnectionManager.kt @@ -18,7 +18,6 @@ package im.vector.app.features.call import android.content.Context import android.hardware.camera2.CameraManager -import android.os.SystemClock import androidx.core.content.getSystemService import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver @@ -76,7 +75,7 @@ import javax.inject.Singleton @Singleton class WebRtcPeerConnectionManager @Inject constructor( private val context: Context, - private val activeSessionDataSource: ActiveSessionDataSource, + private val activeSessionDataSource: ActiveSessionDataSource ) : CallsListener, LifecycleObserver { private val currentSession: Session? @@ -218,7 +217,6 @@ class WebRtcPeerConnectionManager @Inject constructor( isInBackground = true } - var currentCall: CallContext? = null set(value) { field = value From c3b8ed223d22f0865104dec7adfae72048c097b9 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 2 Nov 2020 16:39:06 +0100 Subject: [PATCH 14/19] Increase log level of file logger --- .../java/im/vector/app/features/rageshake/VectorFileLogger.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/rageshake/VectorFileLogger.kt b/vector/src/main/java/im/vector/app/features/rageshake/VectorFileLogger.kt index f26ffdd700..a279c16cb1 100644 --- a/vector/src/main/java/im/vector/app/features/rageshake/VectorFileLogger.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/VectorFileLogger.kt @@ -102,8 +102,8 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec return if (vectorPreferences.labAllowedExtendedLogging()) { false } else { - // Exclude debug and verbose logs - priority <= Log.DEBUG + // Exclude verbose logs + priority < Log.DEBUG } } From 3c7f61e45c43389e9068fe631509cd51d7ff3b51 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 2 Nov 2020 16:41:30 +0100 Subject: [PATCH 15/19] Clean oldest gossiping entries on open Add a dump of DB size on bug report --- .../matrix/android/sdk/api/session/Session.kt | 5 ++ .../sdk/api/session/crypto/CryptoService.kt | 2 + .../internal/crypto/DefaultCryptoService.kt | 9 +++ .../internal/crypto/store/IMXCryptoStore.kt | 2 + .../crypto/store/db/RealmCryptoStore.kt | 58 +++++++++++++++++++ .../sdk/internal/session/DefaultSession.kt | 22 ++++++- .../app/features/rageshake/BugReporter.kt | 2 + 7 files changed, 99 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index f8dc906502..4cf46cbbc0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -238,4 +238,9 @@ interface Session : } val sharedSecretStorageService: SharedSecretStorageService + + /** + * Maintenance API, allows to print outs info on DB size to logcat + */ + fun dbgTraceDbInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 34be1b8d05..0eefca1b4c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -155,4 +155,6 @@ interface CryptoService { // For testing shared session fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? + + fun logDbUsageInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 326eac8f91..d3a3fd9fbd 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -314,6 +314,10 @@ internal class DefaultCryptoService @Inject constructor( } // Just update fetchDevicesList(NoOpMatrixCallback()) + + cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { + cryptoStore.tidyUpDataBase() + } } fun ensureDevice() { @@ -1291,6 +1295,11 @@ internal class DefaultCryptoService @Inject constructor( override fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? { return cryptoStore.getWithHeldMegolmSession(roomId, sessionId) } + + override fun logDbUsageInfo() { + cryptoStore.logDbUsageInfo() + } + /* ========================================================================================== * For test only * ========================================================================================== */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 72d541d4df..9a9f645b49 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -456,4 +456,6 @@ internal interface IMXCryptoStore { fun setDeviceKeysUploaded(uploaded: Boolean) fun getDeviceKeysUploaded(): Boolean + fun tidyUpDataBase() + fun logDbUsageInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 5d19e6d607..ec1a5d73a1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -95,6 +95,7 @@ import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.olm.OlmAccount import org.matrix.olm.OlmException import timber.log.Timber +import java.lang.StringBuilder import javax.inject.Inject import kotlin.collections.set @@ -1666,4 +1667,61 @@ internal class RealmCryptoStore @Inject constructor( result } } + + /** + * Some entries in the DB can get a bit out of control with time + * So we need to tidy up a bit + */ + override fun tidyUpDataBase() { + val prevWeekTs = System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1_000 + doRealmTransaction(realmConfiguration) { realm -> + + // Only keep one week history + realm.where() + .lessThan(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, prevWeekTs) + .findAll().let { + Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity") + it.deleteAllFromRealm() + } + + // Clean the cancelled ones? + realm.where() + .equalTo(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, OutgoingGossipingRequestState.CANCELLED.name) + .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name) + .findAll().let { + Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity") + it.deleteAllFromRealm() + } + + // Only keep one week history + realm.where() + .lessThan(GossipingEventEntityFields.AGE_LOCAL_TS, prevWeekTs) + .findAll().let { + Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields") + it.deleteAllFromRealm() + } + + // Can we do something for WithHeldSessionEntity? + } + } + + /** + * Prints out database info + */ + override fun logDbUsageInfo() { + Realm.getInstance(realmConfiguration).use { realm -> + val info = StringBuilder() + // Check if we have data + info.append("\n==============================================") + info.append("\n==============================================") + info.append("\nCrypto Realm is empty: ${realm.isEmpty}") + realmConfiguration.realmObjectClasses.forEach { modelClazz -> + val count = realm.where(modelClazz).count() + info.append("\nCrypto Realm - count ${modelClazz.simpleName}: $count") + } + info.append("\n==============================================") + info.append("\n==============================================") + Timber.i(info.toString()) + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 7e182525a9..3b1fc73bc9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -18,7 +18,9 @@ package org.matrix.android.sdk.internal.session import androidx.annotation.MainThread import dagger.Lazy +import io.realm.Realm import io.realm.RealmConfiguration +import io.realm.kotlin.where import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okhttp3.OkHttpClient @@ -197,7 +199,7 @@ internal class DefaultSession @Inject constructor( override fun close() { assert(isOpen) stopSync() - // timelineEventDecryptor.destroy() + // timelineEventDecryptor.destroy() uiHandler.post { lifecycleObservers.forEach { it.onStop() } } @@ -284,4 +286,22 @@ internal class DefaultSession @Inject constructor( override fun toString(): String { return "$myUserId - ${sessionParams.deviceId}" } + + override fun dbgTraceDbInfo() { + Realm.getInstance(realmConfiguration).use { realm -> + val info = StringBuilder() + + // Check if we have data + info.append("\n==============================================") + info.append("\n==============================================") + info.append("\nSession Realm is empty: ${realm.isEmpty}") + realmConfiguration.realmObjectClasses.forEach { modelClazz -> + val count = realm.where(modelClazz).count() + info.append("\nSession Realm - count ${modelClazz.simpleName}: $count") + } + info.append("\n==============================================") + info.append("\n==============================================") + Timber.i(info.toString()) + } + } } diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt index 95fe16ea51..4514c9ef80 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt @@ -446,6 +446,8 @@ class BugReporter @Inject constructor( */ fun openBugReportScreen(activity: FragmentActivity, forSuggestion: Boolean = false) { screenshot = takeScreenshot(activity) + activeSessionHolder.getSafeActiveSession()?.dbgTraceDbInfo() + activeSessionHolder.getSafeActiveSession()?.cryptoService()?.logDbUsageInfo() val intent = Intent(activity, BugReportActivity::class.java) intent.putExtra("FOR_SUGGESTION", forSuggestion) From d4963dfb31212b1e9354b0f6fbab7f098d6d3278 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Nov 2020 09:17:07 +0100 Subject: [PATCH 16/19] Use the same name for the 2 db log methods --- .../matrix/android/sdk/api/session/Session.kt | 2 +- .../sdk/internal/session/DefaultSession.kt | 2 +- .../app/features/rageshake/BugReporter.kt | 32 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index 4cf46cbbc0..56609610f1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -242,5 +242,5 @@ interface Session : /** * Maintenance API, allows to print outs info on DB size to logcat */ - fun dbgTraceDbInfo() + fun logDbUsageInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 3b1fc73bc9..2a6df81e72 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -287,7 +287,7 @@ internal class DefaultSession @Inject constructor( return "$myUserId - ${sessionParams.deviceId}" } - override fun dbgTraceDbInfo() { + override fun logDbUsageInfo() { Realm.getInstance(realmConfiguration).use { realm -> val info = StringBuilder() diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt index 4514c9ef80..96248187aa 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt @@ -212,20 +212,20 @@ class BugReporter @Inject constructor( } activeSessionHolder.getSafeActiveSession() - ?.takeIf { !mIsCancelled && withKeyRequestHistory } - ?.cryptoService() - ?.getGossipingEvents() - ?.let { GossipingEventsSerializer().serialize(it) } - ?.toByteArray() - ?.let { rawByteArray -> - File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) - .also { - it.outputStream() + ?.takeIf { !mIsCancelled && withKeyRequestHistory } + ?.cryptoService() + ?.getGossipingEvents() + ?.let { GossipingEventsSerializer().serialize(it) } + ?.toByteArray() + ?.let { rawByteArray -> + File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) + .also { + it.outputStream() .use { os -> os.write(rawByteArray) } - } - } - ?.let { compressFile(it) } - ?.let { gzippedFiles.add(it) } + } + } + ?.let { compressFile(it) } + ?.let { gzippedFiles.add(it) } var deviceId = "undefined" var userId = "undefined" @@ -446,8 +446,10 @@ class BugReporter @Inject constructor( */ fun openBugReportScreen(activity: FragmentActivity, forSuggestion: Boolean = false) { screenshot = takeScreenshot(activity) - activeSessionHolder.getSafeActiveSession()?.dbgTraceDbInfo() - activeSessionHolder.getSafeActiveSession()?.cryptoService()?.logDbUsageInfo() + activeSessionHolder.getSafeActiveSession()?.let { + it.logDbUsageInfo() + it.cryptoService().logDbUsageInfo() + } val intent = Intent(activity, BugReportActivity::class.java) intent.putExtra("FOR_SUGGESTION", forSuggestion) From 5eb2f143750233eb6377e3f37358ee3d34b13fa1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Nov 2020 09:20:24 +0100 Subject: [PATCH 17/19] Move RealmDebugTools and make it an internal class --- .../database/tools}/RealmDebugTools.kt | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) rename matrix-sdk-android/src/{debug/java/org/matrix/android/sdk/internal/database => main/java/org/matrix/android/sdk/internal/database/tools}/RealmDebugTools.kt (88%) diff --git a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/database/RealmDebugTools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt similarity index 88% rename from matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/database/RealmDebugTools.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt index e5f4af2377..4e37ab14a8 100644 --- a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/database/RealmDebugTools.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.database +package org.matrix.android.sdk.internal.database.tools import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity @@ -35,17 +35,19 @@ import io.realm.RealmConfiguration import io.realm.kotlin.where import timber.log.Timber -object RealmDebugTools { +internal class RealmDebugTools( + private val realmConfiguration: RealmConfiguration +) { /** - * Log info about the crypto DB + * Log info about the DB */ - fun dumpCryptoDb(realmConfiguration: RealmConfiguration) { + fun logInfo() { + Timber.d("Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}") + + val key = realmConfiguration.encryptionKey.joinToString("") { byte -> "%02x".format(byte) } + Timber.d("Realm encryption key : $key") + Realm.getInstance(realmConfiguration).use { - Timber.d("Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}") - - val key = realmConfiguration.encryptionKey.joinToString("") { byte -> "%02x".format(byte) } - Timber.d("Realm encryption key : $key") - // Check if we have data Timber.e("Realm is empty: ${it.isEmpty}") From a216f82b3584dfc390e137d96143204502d0a500 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Nov 2020 09:30:26 +0100 Subject: [PATCH 18/19] Avoid code duplication and log total count --- .../crypto/store/db/RealmCryptoStore.kt | 17 +---- .../database/tools/RealmDebugTools.kt | 64 ++++++++----------- .../sdk/internal/session/DefaultSession.kt | 19 +----- 3 files changed, 31 insertions(+), 69 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index ec1a5d73a1..72274aa70a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -87,6 +87,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.query.get import org.matrix.android.sdk.internal.crypto.store.db.query.getById import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate import org.matrix.android.sdk.internal.database.mapper.ContentMapper +import org.matrix.android.sdk.internal.database.tools.RealmDebugTools import org.matrix.android.sdk.internal.di.CryptoDatabase import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.MoshiProvider @@ -95,7 +96,6 @@ import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.olm.OlmAccount import org.matrix.olm.OlmException import timber.log.Timber -import java.lang.StringBuilder import javax.inject.Inject import kotlin.collections.set @@ -1709,19 +1709,6 @@ internal class RealmCryptoStore @Inject constructor( * Prints out database info */ override fun logDbUsageInfo() { - Realm.getInstance(realmConfiguration).use { realm -> - val info = StringBuilder() - // Check if we have data - info.append("\n==============================================") - info.append("\n==============================================") - info.append("\nCrypto Realm is empty: ${realm.isEmpty}") - realmConfiguration.realmObjectClasses.forEach { modelClazz -> - val count = realm.where(modelClazz).count() - info.append("\nCrypto Realm - count ${modelClazz.simpleName}: $count") - } - info.append("\n==============================================") - info.append("\n==============================================") - Timber.i(info.toString()) - } + RealmDebugTools(realmConfiguration).logInfo("Crypto") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt index 4e37ab14a8..ac60f88146 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt @@ -16,23 +16,9 @@ package org.matrix.android.sdk.internal.database.tools -import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity import io.realm.Realm import io.realm.RealmConfiguration -import io.realm.kotlin.where +import org.matrix.android.sdk.BuildConfig import timber.log.Timber internal class RealmDebugTools( @@ -41,30 +27,34 @@ internal class RealmDebugTools( /** * Log info about the DB */ - fun logInfo() { - Timber.d("Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}") + fun logInfo(baseName: String) { + buildString { + append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}") - val key = realmConfiguration.encryptionKey.joinToString("") { byte -> "%02x".format(byte) } - Timber.d("Realm encryption key : $key") + if (BuildConfig.LOG_PRIVATE_DATA) { + val key = realmConfiguration.encryptionKey.joinToString("") { byte -> "%02x".format(byte) } + append("\n$baseName Realm encryption key : $key") + } - Realm.getInstance(realmConfiguration).use { - // Check if we have data - Timber.e("Realm is empty: ${it.isEmpty}") - - Timber.d("Realm has CryptoMetadataEntity: ${it.where().count()}") - Timber.d("Realm has CryptoRoomEntity: ${it.where().count()}") - Timber.d("Realm has DeviceInfoEntity: ${it.where().count()}") - Timber.d("Realm has KeysBackupDataEntity: ${it.where().count()}") - Timber.d("Realm has OlmInboundGroupSessionEntity: ${it.where().count()}") - Timber.d("Realm has OlmSessionEntity: ${it.where().count()}") - Timber.d("Realm has UserEntity: ${it.where().count()}") - Timber.d("Realm has KeyInfoEntity: ${it.where().count()}") - Timber.d("Realm has CrossSigningInfoEntity: ${it.where().count()}") - Timber.d("Realm has TrustLevelEntity: ${it.where().count()}") - Timber.d("Realm has GossipingEventEntity: ${it.where().count()}") - Timber.d("Realm has IncomingGossipingRequestEntity: ${it.where().count()}") - Timber.d("Realm has OutgoingGossipingRequestEntity: ${it.where().count()}") - Timber.d("Realm has MyDeviceLastSeenInfoEntity: ${it.where().count()}") + Realm.getInstance(realmConfiguration).use { realm -> + // Check if we have data + separator() + separator() + append("\n$baseName Realm is empty: ${realm.isEmpty}") + var total = 0L + realmConfiguration.realmObjectClasses.forEach { modelClazz -> + val count = realm.where(modelClazz).count() + total += count + append("\n$baseName Realm - count ${modelClazz.simpleName}: $count") + } + separator() + append("\n$baseName Realm - total count: $total") + separator() + separator() + } } + .let { Timber.i(it) } } + + internal fun StringBuilder.separator() = append("\n==============================================") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 2a6df81e72..25345e953c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -18,9 +18,7 @@ package org.matrix.android.sdk.internal.session import androidx.annotation.MainThread import dagger.Lazy -import io.realm.Realm import io.realm.RealmConfiguration -import io.realm.kotlin.where import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okhttp3.OkHttpClient @@ -61,6 +59,7 @@ import org.matrix.android.sdk.api.session.user.UserService import org.matrix.android.sdk.api.session.widgets.WidgetService import org.matrix.android.sdk.internal.auth.SessionParamsStore import org.matrix.android.sdk.internal.crypto.DefaultCryptoService +import org.matrix.android.sdk.internal.database.tools.RealmDebugTools import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate @@ -288,20 +287,6 @@ internal class DefaultSession @Inject constructor( } override fun logDbUsageInfo() { - Realm.getInstance(realmConfiguration).use { realm -> - val info = StringBuilder() - - // Check if we have data - info.append("\n==============================================") - info.append("\n==============================================") - info.append("\nSession Realm is empty: ${realm.isEmpty}") - realmConfiguration.realmObjectClasses.forEach { modelClazz -> - val count = realm.where(modelClazz).count() - info.append("\nSession Realm - count ${modelClazz.simpleName}: $count") - } - info.append("\n==============================================") - info.append("\n==============================================") - Timber.i(info.toString()) - } + RealmDebugTools(realmConfiguration).logInfo("Session") } } From 997cd6834429022447601dbe17eae0b529f96664 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Nov 2020 09:57:34 +0100 Subject: [PATCH 19/19] Add some padding for easier readability --- .../android/sdk/internal/database/tools/RealmDebugTools.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt index ac60f88146..103e84dea6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt @@ -42,10 +42,11 @@ internal class RealmDebugTools( separator() append("\n$baseName Realm is empty: ${realm.isEmpty}") var total = 0L + val maxNameLength = realmConfiguration.realmObjectClasses.maxOf { it.simpleName.length } realmConfiguration.realmObjectClasses.forEach { modelClazz -> val count = realm.where(modelClazz).count() total += count - append("\n$baseName Realm - count ${modelClazz.simpleName}: $count") + append("\n$baseName Realm - count ${modelClazz.simpleName.padEnd(maxNameLength)} : $count") } separator() append("\n$baseName Realm - total count: $total") @@ -56,5 +57,5 @@ internal class RealmDebugTools( .let { Timber.i(it) } } - internal fun StringBuilder.separator() = append("\n==============================================") + private fun StringBuilder.separator() = append("\n==============================================") }