Merge pull request #6884 from vector-im/feature/bma/sync_thread_investigation

Ensure sync thread is started
This commit is contained in:
Benoit Marty 2022-08-22 12:09:54 +02:00 committed by GitHub
commit e86058b299
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 135 additions and 33 deletions

1
changelog.d/6884.bugfix Normal file
View File

@ -0,0 +1 @@
Ensure SyncThread is started when the app is launched after a Push has been received.

1
changelog.d/6884.sdk Normal file
View File

@ -0,0 +1 @@
Rename `DebugService.logDbUsageInfo` (resp. `Session.logDbUsageInfo`) to `DebugService.getDbUsageInfo` (resp. `Session.getDbUsageInfo`) and return a String instead of logging. The caller may want to log the String.

View File

@ -28,7 +28,7 @@ interface DebugService {
fun getAllRealmConfigurations(): List<RealmConfiguration> fun getAllRealmConfigurations(): List<RealmConfiguration>
/** /**
* Prints out info on DB size to logcat. * Get info on DB size.
*/ */
fun logDbUsageInfo() fun getDbUsageInfo(): String
} }

View File

@ -323,9 +323,9 @@ interface Session {
fun getUiaSsoFallbackUrl(authenticationSessionId: String): String fun getUiaSsoFallbackUrl(authenticationSessionId: String): String
/** /**
* Debug API, will print out info on DB size to logcat. * Debug API, will return info about the DB.
*/ */
fun logDbUsageInfo() fun getDbUsageInfo(): String
/** /**
* Debug API, return the list of all RealmConfiguration used by this session. * Debug API, return the list of all RealmConfiguration used by this session.

View File

@ -53,6 +53,11 @@ interface SyncService {
*/ */
fun getSyncState(): SyncState fun getSyncState(): SyncState
/**
* This method returns true if the sync thread is alive, i.e. started.
*/
fun isSyncThreadAlive(): Boolean
/** /**
* This method allows to listen the sync state. * This method allows to listen the sync state.
* @return a [LiveData] of [SyncState]. * @return a [LiveData] of [SyncState].

View File

@ -38,7 +38,7 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val r
LiveEntityObserver, RealmChangeListener<RealmResults<T>> { LiveEntityObserver, RealmChangeListener<RealmResults<T>> {
private companion object { private companion object {
val BACKGROUND_HANDLER = createBackgroundHandler("LIVE_ENTITY_BACKGROUND") val BACKGROUND_HANDLER = createBackgroundHandler("Matrix-LIVE_ENTITY_BACKGROUND")
} }
protected val observerScope = CoroutineScope(SupervisorJob() + BACKGROUND_HANDLER.asCoroutineDispatcher()) protected val observerScope = CoroutineScope(SupervisorJob() + BACKGROUND_HANDLER.asCoroutineDispatcher())

View File

@ -19,16 +19,15 @@ package org.matrix.android.sdk.internal.database.tools
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.BuildConfig
import timber.log.Timber
internal class RealmDebugTools( internal class RealmDebugTools(
private val realmConfiguration: RealmConfiguration private val realmConfiguration: RealmConfiguration
) { ) {
/** /**
* Log info about the DB. * Get info about the DB.
*/ */
fun logInfo(baseName: String) { fun getInfo(baseName: String): String {
buildString { return buildString {
append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}") append("\n$baseName Realm located at : ${realmConfiguration.realmDirectory}/${realmConfiguration.realmFileName}")
if (BuildConfig.LOG_PRIVATE_DATA) { if (BuildConfig.LOG_PRIVATE_DATA) {
@ -54,7 +53,6 @@ internal class RealmDebugTools(
separator() separator()
} }
} }
.let { Timber.i(it) }
} }
private fun StringBuilder.separator() = append("\n==============================================") private fun StringBuilder.separator() = append("\n==============================================")

View File

@ -36,9 +36,9 @@ internal class DefaultDebugService @Inject constructor(
realmConfigurationGlobal realmConfigurationGlobal
} }
override fun logDbUsageInfo() { override fun getDbUsageInfo() = buildString {
RealmDebugTools(realmConfigurationAuth).logInfo("Auth") append(RealmDebugTools(realmConfigurationAuth).getInfo("Auth"))
RealmDebugTools(realmConfigurationGlobal).logInfo("Global") append(RealmDebugTools(realmConfigurationGlobal).getInfo("Global"))
sessionManager.getLastSession()?.logDbUsageInfo() append(sessionManager.getLastSession()?.getDbUsageInfo())
} }
} }

View File

@ -40,7 +40,7 @@ internal object MatrixModule {
io = Dispatchers.IO, io = Dispatchers.IO,
computation = Dispatchers.Default, computation = Dispatchers.Default,
main = Dispatchers.Main, main = Dispatchers.Main,
crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(), crypto = createBackgroundHandler("Matrix-Crypto_Thread").asCoroutineDispatcher(),
dmVerif = Executors.newSingleThreadExecutor().asCoroutineDispatcher() dmVerif = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
) )
} }

View File

@ -263,11 +263,11 @@ internal class DefaultSession @Inject constructor(
} }
} }
override fun logDbUsageInfo() { override fun getDbUsageInfo() = buildString {
RealmDebugTools(realmConfiguration).logInfo("Session") append(RealmDebugTools(realmConfiguration).getInfo("Session"))
RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto") append(RealmDebugTools(realmConfigurationCrypto).getInfo("Crypto"))
RealmDebugTools(realmConfigurationIdentity).logInfo("Identity") append(RealmDebugTools(realmConfigurationIdentity).getInfo("Identity"))
RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner") append(RealmDebugTools(realmConfigurationContentScanner).getInfo("ContentScanner"))
} }
override fun getRealmConfigurations(): List<RealmConfiguration> { override fun getRealmConfigurations(): List<RealmConfiguration> {

View File

@ -55,7 +55,7 @@ internal class EventSenderProcessorThread @Inject constructor(
private val queuedTaskFactory: QueuedTaskFactory, private val queuedTaskFactory: QueuedTaskFactory,
private val taskExecutor: TaskExecutor, private val taskExecutor: TaskExecutor,
private val memento: QueueMemento private val memento: QueueMemento
) : Thread("SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor { ) : Thread("Matrix-SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor {
private fun markAsManaged(task: QueuedTask) { private fun markAsManaged(task: QueuedTask) {
memento.track(task) memento.track(task)

View File

@ -76,7 +76,7 @@ internal class DefaultTimeline(
) : Timeline { ) : Timeline {
companion object { companion object {
val BACKGROUND_HANDLER = createBackgroundHandler("DefaultTimeline_Thread") val BACKGROUND_HANDLER = createBackgroundHandler("Matrix-DefaultTimeline_Thread")
} }
override val timelineID = UUID.randomUUID().toString() override val timelineID = UUID.randomUUID().toString()

View File

@ -73,6 +73,8 @@ internal class DefaultSyncService @Inject constructor(
override fun getSyncState() = getSyncThread().currentState() override fun getSyncState() = getSyncThread().currentState()
override fun isSyncThreadAlive() = getSyncThread().isAlive
override fun getSyncRequestStateFlow() = syncRequestStateTracker.syncRequestState override fun getSyncRequestStateFlow() = syncRequestStateTracker.syncRequestState
override fun hasAlreadySynced(): Boolean { override fun hasAlreadySynced(): Boolean {

View File

@ -62,7 +62,7 @@ internal class SyncThread @Inject constructor(
private val backgroundDetectionObserver: BackgroundDetectionObserver, private val backgroundDetectionObserver: BackgroundDetectionObserver,
private val activeCallHandler: ActiveCallHandler, private val activeCallHandler: ActiveCallHandler,
private val lightweightSettingsStorage: DefaultLightweightSettingsStorage private val lightweightSettingsStorage: DefaultLightweightSettingsStorage
) : Thread("SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { ) : Thread("Matrix-SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
private var state: SyncState = SyncState.Idle private var state: SyncState = SyncState.Idle
private var liveState = MutableLiveData(state) private var liveState = MutableLiveData(state)

View File

@ -49,13 +49,13 @@ internal class DefaultBackgroundDetectionObserver : BackgroundDetectionObserver
} }
override fun onStart(owner: LifecycleOwner) { override fun onStart(owner: LifecycleOwner) {
Timber.v("App returning to foreground…") Timber.d("App returning to foreground…")
isInBackground = false isInBackground = false
listeners.forEach { it.onMoveToForeground() } listeners.forEach { it.onMoveToForeground() }
} }
override fun onStop(owner: LifecycleOwner) { override fun onStop(owner: LifecycleOwner) {
Timber.v("App going to background…") Timber.d("App going to background…")
isInBackground = true isInBackground = true
listeners.forEach { it.onMoveToBackground() } listeners.forEach { it.onMoveToBackground() }
} }

View File

@ -266,7 +266,7 @@ class VectorApplication :
} }
private fun createFontThreadHandler(): Handler { private fun createFontThreadHandler(): Handler {
val handlerThread = HandlerThread("fonts") val handlerThread = HandlerThread("Vector-fonts")
handlerThread.start() handlerThread.start()
return Handler(handlerThread.looper) return Handler(handlerThread.looper)
} }

View File

@ -20,6 +20,7 @@ import android.content.Context
import arrow.core.Option import arrow.core.Option
import im.vector.app.ActiveSessionDataSource import im.vector.app.ActiveSessionDataSource
import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.extensions.configureAndStart
import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.pushers.UnifiedPushHelper
import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
@ -100,7 +101,13 @@ class ActiveSessionHolder @Inject constructor(
} }
suspend fun getOrInitializeSession(startSync: Boolean): Session? { suspend fun getOrInitializeSession(startSync: Boolean): Session? {
return activeSessionReference.get() ?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session -> return activeSessionReference.get()
?.also {
if (startSync && !it.syncService().isSyncThreadAlive()) {
it.startSyncing(applicationContext)
}
}
?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
setActiveSession(session) setActiveSession(session)
session.configureAndStart(applicationContext, startSyncing = startSync) session.configureAndStart(applicationContext, startSyncing = startSync)
} }

View File

@ -28,7 +28,7 @@ import org.matrix.android.sdk.api.session.sync.FilterService
import timber.log.Timber import timber.log.Timber
fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) { fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) {
Timber.i("Configure and start session for $myUserId") Timber.i("Configure and start session for $myUserId. startSyncing: $startSyncing")
open() open()
filterService().setFilter(FilterService.FilterPreset.ElementFilter) filterService().setFilter(FilterService.FilterPreset.ElementFilter)
if (startSyncing) { if (startSyncing) {

View File

@ -19,7 +19,7 @@ package im.vector.app.features.home.room.detail.timeline.helper
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
private const val THREAD_NAME = "Timeline_Building_Thread" private const val THREAD_NAME = "Vector-Timeline_Building_Thread"
object TimelineAsyncHelper { object TimelineAsyncHelper {

View File

@ -78,6 +78,7 @@ class BugReporter @Inject constructor(
private val systemLocaleProvider: SystemLocaleProvider, private val systemLocaleProvider: SystemLocaleProvider,
private val matrix: Matrix, private val matrix: Matrix,
private val buildMeta: BuildMeta, private val buildMeta: BuildMeta,
private val processInfo: ProcessInfo,
private val sdkIntProvider: BuildVersionSdkIntProvider, private val sdkIntProvider: BuildVersionSdkIntProvider,
) { ) {
var inMultiWindowMode = false var inMultiWindowMode = false
@ -499,10 +500,26 @@ class BugReporter @Inject constructor(
*/ */
fun openBugReportScreen(activity: FragmentActivity, reportType: ReportType = ReportType.BUG_REPORT) { fun openBugReportScreen(activity: FragmentActivity, reportType: ReportType = ReportType.BUG_REPORT) {
screenshot = takeScreenshot(activity) screenshot = takeScreenshot(activity)
matrix.debugService().logDbUsageInfo() logDbInfo()
logProcessInfo()
logOtherInfo()
activity.startActivity(BugReportActivity.intent(activity, reportType)) activity.startActivity(BugReportActivity.intent(activity, reportType))
} }
private fun logOtherInfo() {
Timber.i("SyncThread state: " + activeSessionHolder.getSafeActiveSession()?.syncService()?.getSyncState())
}
private fun logDbInfo() {
val dbInfo = matrix.debugService().getDbUsageInfo()
Timber.i(dbInfo)
}
private fun logProcessInfo() {
val pInfo = processInfo.getInfo()
Timber.i(pInfo)
}
private fun rageShakeAppNameForReport(reportType: ReportType): String { private fun rageShakeAppNameForReport(reportType: ReportType): String {
// As per https://github.com/matrix-org/rageshake // As per https://github.com/matrix-org/rageshake
// app: Identifier for the application (eg 'riot-web'). // app: Identifier for the application (eg 'riot-web').

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.rageshake
import android.annotation.SuppressLint
import android.app.Application
import android.os.Build
import android.os.Process
import java.lang.reflect.Method
import javax.inject.Inject
class ProcessInfo @Inject constructor() {
fun getInfo() = buildString {
append("===========================================\n")
append("* PROCESS INFO *\n")
append("===========================================\n")
val processId = Process.myPid()
append("ProcessId: $processId\n")
append("ProcessName: ${getProcessName()}\n")
append(getThreadInfo())
append("===========================================\n")
}
@SuppressLint("PrivateApi")
private fun getProcessName(): String? {
return if (Build.VERSION.SDK_INT >= 28) {
Application.getProcessName()
} else {
try {
val activityThread = Class.forName("android.app.ActivityThread")
val getProcessName: Method = activityThread.getDeclaredMethod("currentProcessName")
getProcessName.invoke(null) as? String
} catch (t: Throwable) {
null
}
}
}
private fun getThreadInfo() = buildString {
append("Thread activeCount: ${Thread.activeCount()}\n")
Thread.getAllStackTraces().keys
.sortedBy { it.name }
.forEach { thread -> append(thread.getInfo()) }
}
}
private fun Thread.getInfo() = buildString {
append("Thread '$name':")
append(" id: $id")
append(" priority: $priority")
append(" group name: ${threadGroup?.name ?: "null"}")
append(" state: $state")
append(" isAlive: $isAlive")
append(" isDaemon: $isDaemon")
append(" isInterrupted: $isInterrupted")
append("\n")
}