From 9901a43dc10ceb25663b69472fae81390a1360fb Mon Sep 17 00:00:00 2001
From: Maxime NATUREL <maxime.naturel@niji.fr>
Date: Thu, 17 Nov 2022 17:06:44 +0100
Subject: [PATCH 1/2] Add changelog entry

---
 changelog.d/7604.bugfix | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/7604.bugfix

diff --git a/changelog.d/7604.bugfix b/changelog.d/7604.bugfix
new file mode 100644
index 0000000000..0fbee55bce
--- /dev/null
+++ b/changelog.d/7604.bugfix
@@ -0,0 +1 @@
+ANR on session start when sending client info is enabled

From 74c945b7f0f338340a06f160476b0c779dc61821 Mon Sep 17 00:00:00 2001
From: Maxime NATUREL <maxime.naturel@niji.fr>
Date: Thu, 17 Nov 2022 17:11:16 +0100
Subject: [PATCH 2/2] Launching the sending of the client info in a dedicated
 coroutine to avoid ANR on application start

---
 .../java/im/vector/app/core/di/ActiveSessionHolder.kt  |  4 +---
 .../core/session/ConfigureAndStartSessionUseCase.kt    | 10 +++++++---
 .../session/ConfigureAndStartSessionUseCaseTest.kt     |  9 +++++++++
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
index 7e4f73e7a5..f1863cfa23 100644
--- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
@@ -111,9 +111,7 @@ class ActiveSessionHolder @Inject constructor(
                 }
                 ?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
                     setActiveSession(session)
-                    runBlocking {
-                        configureAndStartSessionUseCase.execute(session, startSyncing = startSync)
-                    }
+                    configureAndStartSessionUseCase.execute(session, startSyncing = startSync)
                 }
     }
 
diff --git a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt
index 71863b8642..c47769052c 100644
--- a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt
+++ b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt
@@ -22,7 +22,9 @@ import im.vector.app.core.extensions.startSyncing
 import im.vector.app.core.notification.EnableNotificationsSettingUpdater
 import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
 import im.vector.app.features.call.webrtc.WebRtcCallManager
+import im.vector.app.features.session.coroutineScope
 import im.vector.app.features.settings.VectorPreferences
+import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.sync.FilterService
 import timber.log.Timber
@@ -36,7 +38,7 @@ class ConfigureAndStartSessionUseCase @Inject constructor(
         private val enableNotificationsSettingUpdater: EnableNotificationsSettingUpdater,
 ) {
 
-    suspend fun execute(session: Session, startSyncing: Boolean = true) {
+    fun execute(session: Session, startSyncing: Boolean = true) {
         Timber.i("Configure and start session for ${session.myUserId}. startSyncing: $startSyncing")
         session.open()
         session.filterService().setFilter(FilterService.FilterPreset.ElementFilter)
@@ -45,8 +47,10 @@ class ConfigureAndStartSessionUseCase @Inject constructor(
         }
         session.pushersService().refreshPushers()
         webRtcCallManager.checkForProtocolsSupportIfNeeded()
-        if (vectorPreferences.isClientInfoRecordingEnabled()) {
-            updateMatrixClientInfoUseCase.execute(session)
+        session.coroutineScope.launch {
+            if (vectorPreferences.isClientInfoRecordingEnabled()) {
+                updateMatrixClientInfoUseCase.execute(session)
+            }
         }
         enableNotificationsSettingUpdater.onSessionsStarted(session)
     }
diff --git a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt
index 861e59e0f1..760879b69d 100644
--- a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt
+++ b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt
@@ -18,6 +18,7 @@ package im.vector.app.core.session
 
 import im.vector.app.core.extensions.startSyncing
 import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
+import im.vector.app.features.session.coroutineScope
 import im.vector.app.test.fakes.FakeContext
 import im.vector.app.test.fakes.FakeEnableNotificationsSettingUpdater
 import im.vector.app.test.fakes.FakeSession
@@ -32,6 +33,7 @@ import io.mockk.mockkStatic
 import io.mockk.runs
 import io.mockk.unmockkAll
 import io.mockk.verify
+import kotlinx.coroutines.test.advanceUntilIdle
 import kotlinx.coroutines.test.runTest
 import org.junit.After
 import org.junit.Before
@@ -57,6 +59,7 @@ class ConfigureAndStartSessionUseCaseTest {
     @Before
     fun setup() {
         mockkStatic("im.vector.app.core.extensions.SessionKt")
+        mockkStatic("im.vector.app.features.session.SessionCoroutineScopesKt")
     }
 
     @After
@@ -68,6 +71,7 @@ class ConfigureAndStartSessionUseCaseTest {
     fun `given start sync needed and client info recording enabled when execute then it should be configured properly`() = runTest {
         // Given
         val fakeSession = givenASession()
+        every { fakeSession.coroutineScope } returns this
         fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
         coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
         fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true)
@@ -75,6 +79,7 @@ class ConfigureAndStartSessionUseCaseTest {
 
         // When
         configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true)
+        advanceUntilIdle()
 
         // Then
         verify { fakeSession.startSyncing(fakeContext.instance) }
@@ -88,6 +93,7 @@ class ConfigureAndStartSessionUseCaseTest {
     fun `given start sync needed and client info recording disabled when execute then it should be configured properly`() = runTest {
         // Given
         val fakeSession = givenASession()
+        every { fakeSession.coroutineScope } returns this
         fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
         coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
         fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false)
@@ -95,6 +101,7 @@ class ConfigureAndStartSessionUseCaseTest {
 
         // When
         configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true)
+        advanceUntilIdle()
 
         // Then
         verify { fakeSession.startSyncing(fakeContext.instance) }
@@ -108,6 +115,7 @@ class ConfigureAndStartSessionUseCaseTest {
     fun `given a session and no start sync needed when execute then it should be configured properly`() = runTest {
         // Given
         val fakeSession = givenASession()
+        every { fakeSession.coroutineScope } returns this
         fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
         coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
         fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true)
@@ -115,6 +123,7 @@ class ConfigureAndStartSessionUseCaseTest {
 
         // When
         configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false)
+        advanceUntilIdle()
 
         // Then
         verify(inverse = true) { fakeSession.startSyncing(fakeContext.instance) }