Merge pull request #2755 from vector-im/feature/bma/big_e2e_rooms_2

Data for Worker overload (#2721)
This commit is contained in:
Benoit Marty 2021-02-02 13:04:33 +01:00 committed by GitHub
commit 67aa239398
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 13 deletions

View File

@ -14,6 +14,7 @@ Bugfix 🐛:
- When receiving a new pepper from identity server, use it on the next hash lookup (#2708) - When receiving a new pepper from identity server, use it on the next hash lookup (#2708)
- Crashes reported by PlayStore (new in 1.0.14) (#2707) - Crashes reported by PlayStore (new in 1.0.14) (#2707)
- Widgets: Support $matrix_widget_id parameter (#2748) - Widgets: Support $matrix_widget_id parameter (#2748)
- Data for Worker overload (#2721)
Translations 🗣: Translations 🗣:
- -

View File

@ -19,30 +19,30 @@ package org.matrix.android.sdk.internal.crypto.crosssigning
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.work.BackoffPolicy import androidx.work.BackoffPolicy
import androidx.work.ExistingWorkPolicy import androidx.work.ExistingWorkPolicy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder
import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.TaskThread import org.matrix.android.sdk.internal.task.TaskThread
import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.util.JsonCanonicalizer import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
import org.matrix.olm.OlmPkSigning import org.matrix.olm.OlmPkSigning
import org.matrix.olm.OlmUtility import org.matrix.olm.OlmUtility
@ -61,7 +61,10 @@ internal class DefaultCrossSigningService @Inject constructor(
private val taskExecutor: TaskExecutor, private val taskExecutor: TaskExecutor,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val cryptoCoroutineScope: CoroutineScope, private val cryptoCoroutineScope: CoroutineScope,
private val workManagerProvider: WorkManagerProvider) : CrossSigningService, DeviceListManager.UserDevicesUpdateListener { private val workManagerProvider: WorkManagerProvider,
private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
) : CrossSigningService,
DeviceListManager.UserDevicesUpdateListener {
private var olmUtility: OlmUtility? = null private var olmUtility: OlmUtility? = null
@ -689,7 +692,7 @@ internal class DefaultCrossSigningService @Inject constructor(
return DeviceTrustResult.Success(DeviceTrustLevel(crossSigningVerified = true, locallyVerified = locallyTrusted)) return DeviceTrustResult.Success(DeviceTrustLevel(crossSigningVerified = true, locallyVerified = locallyTrusted))
} }
fun checkDeviceTrust(myKeys: MXCrossSigningInfo?, otherKeys: MXCrossSigningInfo?, otherDevice: CryptoDeviceInfo) : DeviceTrustResult { fun checkDeviceTrust(myKeys: MXCrossSigningInfo?, otherKeys: MXCrossSigningInfo?, otherDevice: CryptoDeviceInfo): DeviceTrustResult {
val locallyTrusted = otherDevice.trustLevel?.isLocallyVerified() val locallyTrusted = otherDevice.trustLevel?.isLocallyVerified()
myKeys ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(userId)) myKeys ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(userId))
@ -747,8 +750,11 @@ internal class DefaultCrossSigningService @Inject constructor(
} }
override fun onUsersDeviceUpdate(userIds: List<String>) { override fun onUsersDeviceUpdate(userIds: List<String>) {
Timber.d("## CrossSigning - onUsersDeviceUpdate for $userIds") Timber.d("## CrossSigning - onUsersDeviceUpdate for ${userIds.size} users: $userIds")
val workerParams = UpdateTrustWorker.Params(sessionId = sessionId, updatedUserIds = userIds) val workerParams = UpdateTrustWorker.Params(
sessionId = sessionId,
filename = updateTrustWorkerDataRepository.createParam(userIds)
)
val workerData = WorkerParamsFactory.toData(workerParams) val workerData = WorkerParamsFactory.toData(workerParams)
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<UpdateTrustWorker>() val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<UpdateTrustWorker>()

View File

@ -55,7 +55,11 @@ internal class UpdateTrustWorker(context: Context,
internal data class Params( internal data class Params(
override val sessionId: String, override val sessionId: String,
override val lastFailureMessage: String? = null, override val lastFailureMessage: String? = null,
val updatedUserIds: List<String> // Kept for compatibility, but not used anymore (can be used for pending Worker)
val updatedUserIds: List<String>? = null,
// Passing a long list of userId can break the Work Manager due to data size limitation.
// so now we use a temporary file to store the data
val filename: String? = null
) : SessionWorkerParams ) : SessionWorkerParams
@Inject lateinit var crossSigningService: DefaultCrossSigningService @Inject lateinit var crossSigningService: DefaultCrossSigningService
@ -64,6 +68,7 @@ internal class UpdateTrustWorker(context: Context,
@CryptoDatabase @Inject lateinit var realmConfiguration: RealmConfiguration @CryptoDatabase @Inject lateinit var realmConfiguration: RealmConfiguration
@UserId @Inject lateinit var myUserId: String @UserId @Inject lateinit var myUserId: String
@Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper @Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper
@Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
@SessionDatabase @Inject lateinit var sessionRealmConfiguration: RealmConfiguration @SessionDatabase @Inject lateinit var sessionRealmConfiguration: RealmConfiguration
// @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater // @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater
@ -74,7 +79,17 @@ internal class UpdateTrustWorker(context: Context,
} }
override suspend fun doSafeWork(params: Params): Result { override suspend fun doSafeWork(params: Params): Result {
var userList = params.updatedUserIds var userList = params.filename
?.let { updateTrustWorkerDataRepository.getParam(it) }
?.userIds
?: params.updatedUserIds.orEmpty()
if (userList.isEmpty()) {
// This should not happen, but let's avoid go further in case of empty list
cleanup(params)
return Result.success()
}
// Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user, // Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user,
// or a new device?) So we check all again :/ // or a new device?) So we check all again :/
@ -213,9 +228,15 @@ internal class UpdateTrustWorker(context: Context,
} }
} }
cleanup(params)
return Result.success() return Result.success()
} }
private fun cleanup(params: Params) {
params.filename
?.let { updateTrustWorkerDataRepository.delete(it) }
}
private fun updateCrossSigningKeysTrust(realm: Realm, userId: String, verified: Boolean) { private fun updateCrossSigningKeysTrust(realm: Realm, userId: String, verified: Boolean) {
val xInfoEntity = realm.where(CrossSigningInfoEntity::class.java) val xInfoEntity = realm.where(CrossSigningInfoEntity::class.java)
.equalTo(CrossSigningInfoEntityFields.USER_ID, userId) .equalTo(CrossSigningInfoEntityFields.USER_ID, userId)

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.crypto.crosssigning
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
import java.io.File
import java.util.UUID
import javax.inject.Inject
@JsonClass(generateAdapter = true)
internal data class UpdateTrustWorkerData(
@Json(name = "userIds")
val userIds: List<String>
)
internal class UpdateTrustWorkerDataRepository @Inject constructor(
@SessionFilesDirectory parentDir: File
) {
private val workingDirectory = File(parentDir, "tw")
private val jsonAdapter = MoshiProvider.providesMoshi().adapter(UpdateTrustWorkerData::class.java)
// Return the path of the created file
fun createParam(userIds: List<String>): String {
val filename = "${UUID.randomUUID()}.json"
workingDirectory.mkdirs()
val file = File(workingDirectory, filename)
UpdateTrustWorkerData(userIds = userIds)
.let { jsonAdapter.toJson(it) }
.let { file.writeText(it) }
return filename
}
fun getParam(filename: String): UpdateTrustWorkerData? {
return File(workingDirectory, filename)
.takeIf { it.exists() }
?.readText()
?.let { jsonAdapter.fromJson(it) }
}
fun delete(filename: String) {
tryOrNull("Unable to delete $filename") {
File(workingDirectory, filename).delete()
}
}
}

View File

@ -140,14 +140,13 @@ internal class RoomSummaryUpdater @Inject constructor(
.queryActiveRoomMembersEvent() .queryActiveRoomMembersEvent()
.notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId) .notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
.findAll() .findAll()
.asSequence()
.map { it.userId } .map { it.userId }
roomSummaryEntity.otherMemberIds.clear() roomSummaryEntity.otherMemberIds.clear()
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
if (roomSummaryEntity.isEncrypted) { if (roomSummaryEntity.isEncrypted) {
// mmm maybe we could only refresh shield instead of checking trust also? // mmm maybe we could only refresh shield instead of checking trust also?
crossSigningService.onUsersDeviceUpdate(roomSummaryEntity.otherMemberIds.toList()) crossSigningService.onUsersDeviceUpdate(otherRoomMembers)
} }
} }
} }