From c15b9edd371baf25d5d886570f1d16f71ba49cd4 Mon Sep 17 00:00:00 2001 From: Jake Wharton Date: Tue, 9 Apr 2024 18:04:08 -0400 Subject: [PATCH] Do not query guest version from UI thread (#1949) I'm not sure how I ended up committing the previous version as I was making changes specifically to avoid this, but I did. Instead, read the version once on startup when the app lifecycle is first bound and cache its value for later access on the UI thread. --- CHANGELOG.md | 1 + .../redwood/treehouse/ZiplineCodeSession.kt | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cad7824381..6106d3ad26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Changed: Fixed: - Work around a problem with our memory-leak fix where our old LazyList code would crash when its placeholders were unexpectedly removed. +- Avoid calling into the internal Zipline instance from the UI thread on startup. This would manifest as weird native crashes due to multiple threads mutating shared memory. ## [0.10.0] - 2024-04-05 diff --git a/redwood-treehouse-host/src/commonMain/kotlin/app/cash/redwood/treehouse/ZiplineCodeSession.kt b/redwood-treehouse-host/src/commonMain/kotlin/app/cash/redwood/treehouse/ZiplineCodeSession.kt index e81621b586..43b3f70e77 100644 --- a/redwood-treehouse-host/src/commonMain/kotlin/app/cash/redwood/treehouse/ZiplineCodeSession.kt +++ b/redwood-treehouse-host/src/commonMain/kotlin/app/cash/redwood/treehouse/ZiplineCodeSession.kt @@ -20,6 +20,7 @@ import app.cash.zipline.Zipline import app.cash.zipline.ZiplineApiMismatchException import app.cash.zipline.ZiplineScope import app.cash.zipline.withScope +import kotlin.concurrent.Volatile import kotlinx.coroutines.CoroutineScope import kotlinx.serialization.json.Json @@ -37,22 +38,26 @@ internal class ZiplineCodeSession( appService = appService, ) { private val ziplineScope = ZiplineScope() - private lateinit var appLifecycle: AppLifecycle override val json: Json get() = zipline.json - override val guestProtocolVersion: RedwoodVersion - get() { - return try { - appLifecycle.guestProtocolVersion - } catch (_: ZiplineApiMismatchException) { - RedwoodVersion.Unknown - } + @Volatile + private var _guestProtocolVersion: RedwoodVersion? = null + + override val guestProtocolVersion: RedwoodVersion get() = + checkNotNull(_guestProtocolVersion) { + "Cannot access guest version before ziplineStart" } override fun ziplineStart() { - appLifecycle = appService.withScope(ziplineScope).appLifecycle + val appLifecycle = appService.withScope(ziplineScope).appLifecycle + + _guestProtocolVersion = try { + appLifecycle.guestProtocolVersion + } catch (_: ZiplineApiMismatchException) { + RedwoodVersion.Unknown + } val host = RealAppLifecycleHost( appLifecycle = appLifecycle,