Fixed
Status Update
Comments
ig...@jetbrains.com <ig...@jetbrains.com> #2
Project: platform/frameworks/support
Branch: androidx-main
commit 700259f0afe267dfe78b93db932a3cfd827a119d
Author: Sherry Hu <shuanghu@google.com>
Date: Mon May 10 14:23:09 2021
Add transition motion between fold and unfold.
Bug: 186211031
Test: manual
Change-Id: Id60f07311eca2d94ef91dc28ae45823a475160b4
M slidingpanelayout/slidingpanelayout/build.gradle
M slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/FoldTest.kt
M slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
https://android-review.googlesource.com/1702066
Branch: androidx-main
commit 700259f0afe267dfe78b93db932a3cfd827a119d
Author: Sherry Hu <shuanghu@google.com>
Date: Mon May 10 14:23:09 2021
Add transition motion between fold and unfold.
Bug: 186211031
Test: manual
Change-Id: Id60f07311eca2d94ef91dc28ae45823a475160b4
M slidingpanelayout/slidingpanelayout/build.gradle
M slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/FoldTest.kt
M slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
an...@google.com <an...@google.com>
ch...@google.com <ch...@google.com>
ap...@google.com <ap...@google.com> #3
Project: platform/frameworks/support
Branch: androidx-main
commit 600c482c16c5fe4897b83bdddf1b223e44327406
Author: Chuck Jazdzewski <chuckj@google.com>
Date: Wed Jul 07 13:29:00 2021
Fix race condition in SnapshotStateObserver
The fix to reset observers when rerunning the observer blocks (670ef938)
introduced a race condition causing spurratic NPEs when snapshots are
advanced or applied on a separate thread.
Fixes: 192677711
Test: ./gradlew :compose:r:r:tDUT
Change-Id: I79e80b1cd576bd57f26edf33cd0120b4b21e758d
M compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
M compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserverTests.kt
https://android-review.googlesource.com/1758105
Branch: androidx-main
commit 600c482c16c5fe4897b83bdddf1b223e44327406
Author: Chuck Jazdzewski <chuckj@google.com>
Date: Wed Jul 07 13:29:00 2021
Fix race condition in SnapshotStateObserver
The fix to reset observers when rerunning the observer blocks (670ef938)
introduced a race condition causing spurratic NPEs when snapshots are
advanced or applied on a separate thread.
Fixes: 192677711
Test: ./gradlew :compose:r:r:tDUT
Change-Id: I79e80b1cd576bd57f26edf33cd0120b4b21e758d
M compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
M compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserverTests.kt
ig...@jetbrains.com <ig...@jetbrains.com> #4
The example in the issue works now, but the example in the original issue still crashes in two threads:
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.platform.TestComposeWindow
fun main() {
for(i in 1..10000) {
TestComposeWindow(800, 800).setContent {
repeat(10) {
val state1 by remember { mutableStateOf(0) }
var state2 by remember { mutableStateOf(true) }
Box(Modifier.drawBehind {
state1
if (state2) {
state2 = false
}
})
}
}
}
}
Exceptions:
Exception in thread "main" java.lang.NullPointerException
at androidx.compose.runtime.collection.IdentityScopeMap.find(IdentityScopeMap.kt:319)
at androidx.compose.runtime.collection.IdentityScopeMap.getOrCreateIdentitySet(IdentityScopeMap.kt:102)
at androidx.compose.runtime.collection.IdentityScopeMap.add(IdentityScopeMap.kt:76)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ApplyMap.addValue(SnapshotStateObserver.kt:264)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$readObserver$1.invoke(SnapshotStateObserver.kt:56)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$readObserver$1.invoke(SnapshotStateObserver.kt:54)
at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1513)
at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1505)
at androidx.compose.runtime.SnapshotMutableStateImpl.getValue(SnapshotState.kt:143)
at androidx.compose.desktop.examples.example1.Main_jvmKt$main$1.invoke$lambda-6$lambda-3(Main.jvm.kt:66)
at androidx.compose.desktop.examples.example1.Main_jvmKt$main$1.access$invoke$lambda-6$lambda-3(Main.jvm.kt:29)
at androidx.compose.desktop.examples.example1.Main_jvmKt$main$1$1$1$1.invoke(Main.jvm.kt:35)
at androidx.compose.desktop.examples.example1.Main_jvmKt$main$1$1$1$1.invoke(Main.jvm.kt:33)
at androidx.compose.ui.draw.DrawBackgroundModifier.draw(DrawModifier.kt:101)
at androidx.compose.ui.node.ModifiedDrawNode.performDraw(ModifiedDrawNode.kt:102)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:259)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:258)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:1776)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:121)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:75)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:258)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:57)
at androidx.compose.ui.platform.SkijaLayer.performDrawLayer(SkijaLayer.desktop.kt:246)
at androidx.compose.ui.platform.SkijaLayer.drawLayer(SkijaLayer.desktop.kt:212)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:242)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:825)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:133)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:247)
at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:68)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:247)
at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:68)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:247)
at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:68)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:247)
at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:68)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:247)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:825)
at androidx.compose.ui.platform.DesktopOwner.draw(DesktopOwner.desktop.kt:318)
at androidx.compose.ui.platform.TestComposeWindow.setContent(TestComposeWindow.desktop.kt:115)
at androidx.compose.desktop.examples.example1.Main_jvmKt.main(Main.jvm.kt:29)
at androidx.compose.desktop.examples.example1.Main_jvmKt.main(Main.jvm.kt)
Exception in thread "AWT-EventQueue-0 @coroutine#3" java.lang.NullPointerException
at androidx.compose.runtime.collection.IdentityScopeMap.find(IdentityScopeMap.kt:319)
at androidx.compose.runtime.collection.IdentityScopeMap.access$find(IdentityScopeMap.kt:26)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$applyObserver$1.invoke(SnapshotStateObserver.kt:286)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$applyObserver$1.invoke(SnapshotStateObserver.kt:26)
at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot(Snapshot.kt:1440)
at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot(Snapshot.kt:1447)
at androidx.compose.runtime.snapshots.SnapshotKt.access$advanceGlobalSnapshot(Snapshot.kt:1)
at androidx.compose.runtime.snapshots.Snapshot$Companion.sendApplyNotifications(Snapshot.kt:462)
at androidx.compose.ui.platform.GlobalSnapshotManager$ensureStarted$1.invokeSuspend(GlobalSnapshotManager.desktop.kt:48)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
I will try to narrow it down.
ch...@google.com <ch...@google.com> #5
I am re-opening the bug as the above exception indicates that there is still a missing synchronize call.
If you can narrow it down I would really appreciate it!
ig...@jetbrains.com <ig...@jetbrains.com> #6
I reproduced the new exception with this code:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.snapshots.SnapshotStateObserver
import kotlin.concurrent.thread
fun main() {
println("START")
thread {
while (true) {
Snapshot.sendApplyNotifications()
}
}
for (i in 1..10000) {
val state1 by mutableStateOf(0)
var state2 by mutableStateOf(true)
val observer = SnapshotStateObserver({}).apply {
start()
}
observer.observeReads(Unit, {}) {
repeat(1000) {
state1
if (state2) {
state2 = false
}
}
}
}
}
Exception in thread "main" java.lang.NullPointerException: null cannot be cast to non-null type T of androidx.compose.runtime.collection.IdentityArraySet
at androidx.compose.runtime.collection.IdentityArraySet.get(IdentityArraySet.kt:44)
at androidx.compose.runtime.collection.IdentityArraySet.find(IdentityArraySet.kt:174)
at androidx.compose.runtime.collection.IdentityArraySet.add(IdentityArraySet.kt:53)
at androidx.compose.runtime.collection.IdentityScopeMap.add(IdentityScopeMap.kt:77)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ApplyMap.addValue(SnapshotStateObserver.kt:264)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$readObserver$1.invoke(SnapshotStateObserver.kt:56)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$readObserver$1.invoke(SnapshotStateObserver.kt:54)
at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1513)
at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1505)
at androidx.compose.runtime.SnapshotMutableStateImpl.getValue(SnapshotState.kt:143)
at androidx.compose.desktop.examples.example1.Main_jvmKt.main$lambda-1(Main.jvm.kt:51)
at androidx.compose.desktop.examples.example1.Main_jvmKt.access$main$lambda-1(Main.jvm.kt:1)
at androidx.compose.desktop.examples.example1.Main_jvmKt$main$3.invoke(Main.jvm.kt:43)
at androidx.compose.desktop.examples.example1.Main_jvmKt$main$3.invoke(Main.jvm.kt:40)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:1776)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:121)
at androidx.compose.desktop.examples.example1.Main_jvmKt.main(Main.jvm.kt:40)
at androidx.compose.desktop.examples.example1.Main_jvmKt.main(Main.jvm.kt)
Description
Component used: Snapshot, SnapshotStateObserver, mutableStateOf
Version used: a02b52bd (androidx-main, 01 Jul 2021)
There is a race condition when we apply snapshot in one thread and try to read the snapshot value in another.
This code:
crashes with exception:
The race condition is probably between
map.removeValueIf { scope -> scope in invalidated }
andcurrentMap!!.addValue(state)
in SnapshotStateObserver