[cherry-pick][4.1] Fix commits during the Android draw pass#9124
Open
bartlomiejbloniarz wants to merge 2 commits into4.1-stablefrom
Open
[cherry-pick][4.1] Fix commits during the Android draw pass#9124bartlomiejbloniarz wants to merge 2 commits into4.1-stablefrom
bartlomiejbloniarz wants to merge 2 commits into4.1-stablefrom
Conversation
Separates the synchronous UI props update logic into its own `applySynchronousUpdates` method. Adds `partitionUpdates` and `shouldUseSynchronousUpdatesInPerformOperations` helpers to support the extracted method.
This PR intends to solve the most annoying crash that we currently face on Android. The crash is caused by Reanimated calling `ShadowTree::commit` when handling events that were emitted while in the Android drawing pass. Performing a commit can cause other changes queued by React Native to also get applied. This can lead to the view hierarchy being modified, which is not allowed while in the draw pass. To fix this, we have a workaround where if we are in the draw pass, we instead only apply non-layout changes (that can be applied without a ShadowTree commit), and schedule the layout changes to happen when we are outside of the draw call. We want to apply the non-layout updates there to maintain things like transform driven sticky headers. closes #8422 🤞 I added a new Android Draw Pass example, it would also make sense to test the sticky header and other event related examples
There was a problem hiding this comment.
Pull request overview
Cherry-picks upstream fixes to prevent Reanimated/Fabric commits from occurring during the Android draw pass (a common crash source), by detecting draw-pass execution and applying only “safe” non-layout/synchronous UI prop updates while deferring layout-affecting commits to the next frame.
Changes:
- Add Android draw-pass detection (
DrawPassDetector) and route event-driven updates through a draw-pass-aware operations path. - Introduce “non-layout” operations path end-to-end (Java → JNI → C++), and extract synchronous UI-props logic into
applySynchronousUpdates. - Add
getPendingUpdates()and a new example screen to reproduce/validate the Android crash scenario.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NodesManager.java | Adds draw-pass-aware execution path and non-layout operations call during draw. |
| packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NativeProxy.java | Exposes new JNI method and uses draw-pass-aware operations when flushing. |
| packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/DrawPassDetector.java | New helper to detect whether current UI-thread turn is in a draw pass. |
| packages/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h | Declares performNonLayoutOperations on the JNI proxy. |
| packages/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp | Implements and registers the new JNI method. |
| packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h | Adds performNonLayoutOperations and extracted applySynchronousUpdates declaration. |
| packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp | Refactors synchronous updates, partitions updates, and adds non-layout operations path. |
| packages/react-native-reanimated/Common/cpp/reanimated/Fabric/updates/UpdatesRegistry.h | Adds getPendingUpdates() API. |
| packages/react-native-reanimated/Common/cpp/reanimated/Fabric/updates/UpdatesRegistry.cpp | Implements getPendingUpdates() to snapshot pending updates without committing. |
| apps/common-app/src/apps/reanimated/examples/index.ts | Registers the new Android draw-pass example. |
| apps/common-app/src/apps/reanimated/examples/StickyHeaderExample.tsx | Tweaks animated style to include a layout-affecting prop (width) for testing. |
| apps/common-app/src/apps/reanimated/examples/AndroidDrawPassExample.tsx | New repro example for the Android draw-pass crash/fix behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Comment on lines
+801
to
+808
| void ReanimatedModuleProxy::performNonLayoutOperations() { | ||
| ReanimatedSystraceSection s( | ||
| "ReanimatedModuleProxy::performNonLayoutOperations"); | ||
|
|
||
| UpdatesBatch updatesBatch = animatedPropsRegistry_->getPendingUpdates(); | ||
|
|
||
| applySynchronousUpdates(updatesBatch, true); | ||
| } |
| "[Reanimated] Border radius string must be a percentage"); | ||
| } | ||
| intBuffer.push_back(CMD_UNIT_PERCENT); | ||
| doubleBuffer.push_back(std::stof(valueStr.substr(0, -1))); |
Comment on lines
+136
to
+145
| void performOperationsRespectingDrawPass() { | ||
| mDrawPassDetector.initialize(); | ||
| if (isInDrawPass()) { | ||
| performNonLayoutOperations(); | ||
| startUpdatingOnAnimationFrame(); | ||
| return; | ||
| } | ||
|
|
||
| performOperations(); | ||
| } |
Comment on lines
+30
to
+38
| void initialize() { | ||
| Activity activity = mContext.getCurrentActivity(); | ||
| if (activity == null) { | ||
| return; | ||
| } | ||
|
|
||
| View decorView = activity.getWindow().getDecorView(); | ||
| if (decorView == mDecorView) { | ||
| return; |
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.
Cherry picks #9078 and #9072