-
Notifications
You must be signed in to change notification settings - Fork 764
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add debugger class that tracks animatedState lifecycles
Summary: # Context We are trying to resolve the crash associated to this task (T209041862) which happens due to an inconsistency between `initialStatesToRestore` and `animatedStates` in Litho's `TransitionManager`. Concretely, there is a missing `animatedState` for a given entry on `initialStatesToRestore`. # This diff In this diff we introduce this `AnimationInconsistencyDebugger`, which tracks whenever an `AnimatedState` is added or removed from `animatedStates`. Then on the custom exception we collect this data, so that we can try to understand when the missing `animatedState` was removed (if ever was removed). Below there is a high level overview of the points I identify that we add or remove (in red) animation states. Therefore, I believe that one of these flows is triggered somehow before the initial states are restored, and that is where the bug is (and hopefully I can identify a pattern after this is landed). {F1973763534} Reviewed By: zielinskimz Differential Revision: D67034475 fbshipit-source-id: 79ac843153d12cfa620c0329da3c3bc638533566
- Loading branch information
1 parent
7665163
commit c391c73
Showing
2 changed files
with
168 additions
and
9 deletions.
There are no files selected for viewing
117 changes: 117 additions & 0 deletions
117
...rendercore-transitions/src/main/java/com/facebook/litho/AnimationInconsistencyDebugger.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* 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 com.facebook.litho | ||
|
||
import com.facebook.litho.TransitionManager.AnimationCleanupTrigger | ||
import com.facebook.litho.TransitionManager.AnimationState | ||
import com.facebook.litho.TransitionManager.changeTypeToString | ||
|
||
/** | ||
* This class aids to collect information about which animation states were removed and where from. | ||
* The idea is that we can retrieve this information when the inconsistency crash happens and report | ||
* it in a custom exception. | ||
* | ||
* This debugger is disabled by default and to be enabled clients should use | ||
* [AnimationInconsistencyDebuggerConfig.isEnabled] and then get an instance of it. | ||
*/ | ||
internal class AnimationInconsistencyDebugger private constructor() { | ||
|
||
private val removedInfo = LinkedHashMap<TransitionId, RemovalInfo>() | ||
|
||
fun trackAnimationStateRemoved( | ||
transitionId: TransitionId, | ||
animationFinishTrigger: AnimationCleanupTrigger, | ||
animationState: AnimationState? | ||
) { | ||
removedInfo[transitionId] = RemovalInfo(transitionId, animationFinishTrigger, animationState) | ||
} | ||
|
||
fun trackAnimationStateCreated(transitionId: TransitionId) { | ||
removedInfo.remove(transitionId) | ||
} | ||
|
||
fun reset(transitionIdMap: TransitionIdMap<AnimationState>) { | ||
transitionIdMap.ids().forEach { id -> | ||
val animationState = transitionIdMap[id] | ||
removedInfo[id] = RemovalInfo(id, AnimationCleanupTrigger.RESET, animationState) | ||
} | ||
} | ||
|
||
fun getReadableStatus(): String { | ||
return removedInfo.entries.joinToString(separator = ",") { it.value.toString() } | ||
} | ||
|
||
class RemovalInfo( | ||
val transitionId: TransitionId, | ||
private val animationCleanupTrigger: AnimationCleanupTrigger, | ||
private val animationState: AnimationState? | ||
) { | ||
|
||
override fun toString(): String { | ||
return buildString { | ||
var currentIndent = 0 | ||
fun indentLine(value: String) { | ||
append(" ".repeat(currentIndent)).appendLine(value) | ||
} | ||
|
||
indentLine("[") | ||
currentIndent++ | ||
|
||
indentLine("transitionId=$transitionId") | ||
indentLine("animationCleanupTrigger=$animationCleanupTrigger") | ||
|
||
if (animationState != null) { | ||
indentLine("changeType=${changeTypeToString(animationState.changeType)}") | ||
indentLine( | ||
"shouldFinishUndeclaredAnimation=${animationState.shouldFinishUndeclaredAnimation}") | ||
indentLine("seenInLastTransition=${animationState.seenInLastTransition}") | ||
indentLine("hasDisappearingAnimation=${animationState.hasDisappearingAnimation}") | ||
if (animationState.propertyStates.isNotEmpty()) { | ||
indentLine("propertyStates:") | ||
currentIndent++ | ||
animationState.propertyStates.forEach { (property, state) -> | ||
indentLine("${property.getName()}:") | ||
currentIndent++ | ||
indentLine("targetValue=${state.targetValue}") | ||
indentLine("lastMountedValue=${state.lastMountedValue}") | ||
indentLine("numPendingAnimations=${state.numPendingAnimations}") | ||
currentIndent-- | ||
} | ||
} | ||
} | ||
indentLine("]") | ||
} | ||
} | ||
} | ||
|
||
companion object Factory { | ||
|
||
@JvmName("get") | ||
internal fun get(): AnimationInconsistencyDebugger? { | ||
return if (AnimationInconsistencyDebuggerConfig.isEnabled) { | ||
AnimationInconsistencyDebugger() | ||
} else { | ||
null | ||
} | ||
} | ||
} | ||
} | ||
|
||
object AnimationInconsistencyDebuggerConfig { | ||
|
||
@JvmField var isEnabled = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters