Drive shared animation backend from Fabric frame callback (#57400)#57400
Open
bartlomiejbloniarz wants to merge 1 commit into
Open
Drive shared animation backend from Fabric frame callback (#57400)#57400bartlomiejbloniarz wants to merge 1 commit into
bartlomiejbloniarz wants to merge 1 commit into
Conversation
|
@bartlomiejbloniarz has exported this pull request. If you are a Meta employee, you can view the originating Diff in D110321362. |
7fef845 to
14a4667
Compare
meta-codesync Bot
pushed a commit
that referenced
this pull request
Jul 1, 2026
Summary: In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in `FabricUIManager`. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance. The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old `AnimationBackendChoreographer` owned a self-reposting callback that could keep driving `FabricUIManagerBinding.driveAnimationBackend` independently from Fabric's own lifecycle. During React instance teardown, `FabricUIManager.invalidate()` pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled. The shared animation backend is now driven from Fabric's existing `DISPATCH_UI` frame callback after mount items are dispatched. The Android `AnimationChoreographer` implementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend. Threading-wise: - If invalidation happens before a frame starts, `mDestroyed` makes the frame no-op. - If invalidation races with an already-running frame, `ReactChoreographer.removeFrameCallback` is serialized with callback execution via the `callbackQueues` monitor, so `onHostPause()` waits for the current `DISPATCH_UI` callback to finish before `unregister()` tears down the native binding. - If the frame reposts itself in `schedule()`, the blocked removal observes and removes that callback before teardown continues. Changelog: [Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown Differential Revision: D110321362
14a4667 to
2fb8422
Compare
meta-codesync Bot
pushed a commit
that referenced
this pull request
Jul 1, 2026
Summary: In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in `FabricUIManager`. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance. The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old `AnimationBackendChoreographer` owned a self-reposting callback that could keep driving `FabricUIManagerBinding.driveAnimationBackend` independently from Fabric's own lifecycle. During React instance teardown, `FabricUIManager.invalidate()` pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled. The shared animation backend is now driven from Fabric's existing `DISPATCH_UI` frame callback after mount items are dispatched. The Android `AnimationChoreographer` implementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend. Threading-wise: - If invalidation happens before a frame starts, `mDestroyed` makes the frame no-op. - If invalidation races with an already-running frame, `ReactChoreographer.removeFrameCallback` is serialized with callback execution via the `callbackQueues` monitor, so `onHostPause()` waits for the current `DISPATCH_UI` callback to finish before `unregister()` tears down the native binding. - If the frame reposts itself in `schedule()`, the blocked removal observes and removes that callback before teardown continues. Changelog: [Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown Reviewed By: zeyap Differential Revision: D110321362
2fb8422 to
37faa1b
Compare
Summary: In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in `FabricUIManager`. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance. The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old `AnimationBackendChoreographer` owned a self-reposting callback that could keep driving `FabricUIManagerBinding.driveAnimationBackend` independently from Fabric's own lifecycle. During React instance teardown, `FabricUIManager.invalidate()` pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled. The shared animation backend is now driven from Fabric's existing `DISPATCH_UI` frame callback after mount items are dispatched. The Android `AnimationChoreographer` implementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend. Threading-wise: - If invalidation happens before a frame starts, `mDestroyed` makes the frame no-op. - If invalidation races with an already-running frame, `ReactChoreographer.removeFrameCallback` is serialized with callback execution via the `callbackQueues` monitor, so `onHostPause()` waits for the current `DISPATCH_UI` callback to finish before `unregister()` tears down the native binding. - If the frame reposts itself in `schedule()`, the blocked removal observes and removes that callback before teardown continues. Changelog: [Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown Reviewed By: javache, zeyap Differential Revision: D110321362
meta-codesync Bot
pushed a commit
that referenced
this pull request
Jul 1, 2026
Summary: In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in `FabricUIManager`. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance. The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old `AnimationBackendChoreographer` owned a self-reposting callback that could keep driving `FabricUIManagerBinding.driveAnimationBackend` independently from Fabric's own lifecycle. During React instance teardown, `FabricUIManager.invalidate()` pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled. The shared animation backend is now driven from Fabric's existing `DISPATCH_UI` frame callback after mount items are dispatched. The Android `AnimationChoreographer` implementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend. Threading-wise: - If invalidation happens before a frame starts, `mDestroyed` makes the frame no-op. - If invalidation races with an already-running frame, `ReactChoreographer.removeFrameCallback` is serialized with callback execution via the `callbackQueues` monitor, so `onHostPause()` waits for the current `DISPATCH_UI` callback to finish before `unregister()` tears down the native binding. - If the frame reposts itself in `schedule()`, the blocked removal observes and removes that callback before teardown continues. Changelog: [Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown Reviewed By: javache, zeyap Differential Revision: D110321362
503a790 to
6450a73
Compare
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in
FabricUIManager. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance.The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old
AnimationBackendChoreographerowned a self-reposting callback that could keep drivingFabricUIManagerBinding.driveAnimationBackendindependently from Fabric's own lifecycle. During React instance teardown,FabricUIManager.invalidate()pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled.The shared animation backend is now driven from Fabric's existing
DISPATCH_UIframe callback after mount items are dispatched. The AndroidAnimationChoreographerimplementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend.Threading-wise:
mDestroyedmakes the frame no-op.ReactChoreographer.removeFrameCallbackis serialized with callback execution via thecallbackQueuesmonitor, soonHostPause()waits for the currentDISPATCH_UIcallback to finish beforeunregister()tears down the native binding.schedule(), the blocked removal observes and removes that callback before teardown continues.Changelog:
[Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown
Reviewed By: javache, zeyap
Differential Revision: D110321362