ANR on Android
Description
Not sure if this is related to the other ANR issues I saw on the issues. happy if you can have a look. Running on react native 0.72.14, and my android app gets stuck (happens only on Android). This is the stack trace from Sentry: https://hibob.sentry.io/share/issue/65e71a32440241cc90397a2b9cb97c36/
Steps to reproduce
Not sure how to reproduce it. We have a floating button which appears right on the start of the app, which uses react-native-animated. When we‘re removing the usage of it – all seems to work well
Snack or a link to a repository
I don’t have, but if it a must, I will try to add one later
Reanimated version
3.15.1
React Native version
0.72.14
Platforms
Android
JavaScript runtime
Hermes
Workflow
React Native
Architecture
Paper (Old Architecture)
Build type
Release app & production bundle
Device
Real device
Device model
One Plus
Acknowledgements
Yes
Hey! 👋
The issue doesn't seem to contain a minimal reproduction.
Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?
We're getting these ANR issues too, both user reports and Sentry issues. Here's another stack trace, it's a bit different from what OP posted: https://rise-calendar.sentry.io/share/issue/2870f1735d574c08b5e4378ff096e410/
If it helps: users reported that the crashes happened while the app was in the background.
react-native: 0.75.4 react-native-reanimated: 3.15.4
We also run bridgeless / new architecture.
facing same issue. react-native: 0.74.1 react-native-reanimated: 3.11.0
Facing same issue react-native 0.76.3 react-native-reanimated 3.16.1
It presents in a couple different ways: https://chargefox.sentry.io/share/issue/b577493a3a89427eaba6ea0dfcdcf6f4/ (with a lot of ShareableObject::toJSValue) https://chargefox.sentry.io/share/issue/70d5600b92124594ba3f1ed8ac38ae26/ (with maybeFlushUIUpdatesQueue)
This might be related to this hermes issue that recently got resolved. We should see after the next hermes release.
@bartlomiejbloniarz so if I'm not wrong we should wait until Hermes new build is integrated into React Native and there is a new release?
In my case I'm getting ANR issue with: RN: 0.76.3 Reanimated: 3.17.0-rc.0
Here is what I receive from Sentry. I'm not sure if this is originated in the FastImage library which I understand it is using Reanimated.
Is there any way to "patch" code to try to fix this asap before waiting a new hermes release?
io.sentry.android.core.ApplicationNotResponding: ANR
atsyscall
at__futex_wait_ex
atNonPI::MutexLockWithTimeout
atpthread_mutex_lock
atoffset 1854000) (std::__ndk1::mutex::lock
atoffset 202c000) (facebook::react::Binding::schedulerDidFinishTransaction
atoffset 202c000) (facebook::react::Scheduler::uiManagerDidFinishTransaction
atoffset 202c000) (facebook::react::UIManager::shadowTreeDidFinishTransaction const
atoffset 202c000) (facebook::react::ShadowTree::mount const
atoffset 202c000) (facebook::react::ShadowTree::tryCommit const
atoffset 202c000) (facebook::react::ShadowTree::commit const
at
atoffset 202c000) (facebook::react::ShadowTreeRegistry::visit const
atoffset 2654000) (reanimated::NativeReanimatedModule::performOperations
atoffset 2654000) (facebook::jni::detail::MethodWrapper<void , &reanimated::NativeProxy::performOperations, reanimated::NativeProxy, void>::dispatch
atoffset 2654000) (facebook::jni::detail::FunctionWrapper<void , facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::NativeProxy, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject*, void>::call
at com.swmansion.reanimated.NativeProxy.performOperations
at com.swmansion.reanimated.NodesManager.performOperations(NodesManager.java:227)
at com.swmansion.reanimated.NodesManager.onEventDispatch(NodesManager.java:339)
at com.facebook.react.uimanager.events.FabricEventDispatcher.dispatchEvent(FabricEventDispatcher.java:71)
at com.facebook.react.internal.interop.InteropEventEmitter.receiveEvent(InteropEventEmitter.kt:39)
at com.dylanvann.fastimage.FastImageViewWithUrl.onAfterUpdate(FastImageViewWithUrl.java:127)
at com.dylanvann.fastimage.FastImageViewManager.onAfterUpdateTransaction(FastImageViewManager.java:181)
at com.dylanvann.fastimage.FastImageViewManager.onAfterUpdateTransaction(FastImageViewManager.java:33)
at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:95)
at com.facebook.react.uimanager.ViewManager.createViewInstance(ViewManager.java:195)
at com.facebook.react.uimanager.ViewManager.createView(ViewManager.java:122)
at com.facebook.react.fabric.mounting.SurfaceMountingManager.createViewUnsafe(SurfaceMountingManager.java:679)
at com.facebook.react.fabric.mounting.SurfaceMountingManager.preallocateView(SurfaceMountingManager.java:1086)
at com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem.execute(PreAllocateViewMountItem.java:63)
at com.facebook.react.fabric.mounting.MountItemDispatcher.executeOrEnqueue(MountItemDispatcher.java:387)
at com.facebook.react.fabric.mounting.MountItemDispatcher.dispatchMountItems(MountItemDispatcher.java:274)
at com.facebook.react.fabric.mounting.MountItemDispatcher.tryDispatchMountItems(MountItemDispatcher.java:126)
at com.facebook.react.fabric.FabricUIManager$3.runGuarded(FabricUIManager.java:831)
at com.facebook.react.bridge.GuardedRunnable.run(GuardedRunnable.java:29)
at com.facebook.react.fabric.FabricUIManager.scheduleMountItem(FabricUIManager.java:835)
at com.swmansion.reanimated.AndroidUIScheduler.triggerUI
at com.swmansion.reanimated.AndroidUIScheduler.lambda$new$0(AndroidUIScheduler.java:22)
at com.swmansion.reanimated.AndroidUIScheduler.$r8$lambda$iUspyirUxSIP7N2hKjm5b-wzLjg(unavailable:0)
at com.swmansion.reanimated.AndroidUIScheduler$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at com.swmansion.reanimated.AndroidUIScheduler$1.runGuarded(AndroidUIScheduler.java:40)
at com.facebook.react.bridge.GuardedRunnable.run(GuardedRunnable.java:29)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8762)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Hey @bartlomiejbloniarz how's it going? At Phantom, we also noticed a spike in ANRs, and it seems like we're having the same issue. Is the bug mentioned in Hermes thread already fixed in Reanimated? Did you check if the Hermes optimization Tzvetan Mikov made mitigates the issue? Kristen Hewell-Garett (my colleague) has a lot of details regarding this ANR issue, I will get them to chime in this thread as well.
So, I'm not sure how related our issue is exactly to this one because our stack traces are consistently during serialization/deserialization. Example:
"main" tid=1 Native
#00 pc 0x00000000000f021c /apex/com.android.runtime/lib64/bionic/libc.so (read+12)
#01 pc 0x00000000000fbd04 /apex/com.android.runtime/lib64/bionic/libc.so (__sread+48)
#02 pc 0x00000000000fbbf0 /apex/com.android.runtime/lib64/bionic/libc.so (__srefill+272)
#03 pc 0x00000000000fdf44 /apex/com.android.runtime/lib64/bionic/libc.so (fgets_unlocked+96)
#04 pc 0x00000000000fde9c /apex/com.android.runtime/lib64/bionic/libc.so (fgets+68)
#05 pc 0x0000000000103ba8 /apex/com.android.runtime/lib64/bionic/libc.so (pthread_getattr_np+388)
#06 pc 0x00000000002040b4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (BuildId: 7985320662426c272ad754fa16e4555334829826)
#07 pc 0x00000000000b7480 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (BuildId: 7985320662426c272ad754fa16e4555334829826)
#08 pc 0x00000000000b3948 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (BuildId: 7985320662426c272ad754fa16e4555334829826)
#09 pc 0x00000000000b36f4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (BuildId: 7985320662426c272ad754fa16e4555334829826)
#10 pc 0x0000000000050d0c /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (facebook::jsi::WithRuntimeDecorator<worklets::AroundLock, facebook::jsi::Runtime, facebook::jsi::Runtime>::call(facebook::jsi::Function const&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long)+108) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#11 pc 0x000000000003af70 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (facebook::jsi::Value facebook::jsi::Function::call<facebook::jsi::Value&, facebook::jsi::String>(facebook::jsi::Runtime&, facebook::jsi::Value&, facebook::jsi::String&&) const+140) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#12 pc 0x000000000003ae18 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+128) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#13 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#14 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#15 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#16 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#17 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#18 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#19 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#20 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#21 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#22 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#23 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#24 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#25 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#26 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#27 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#28 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#29 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#30 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#31 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#32 pc 0x0000000000039bac /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableArray::toJSValue(facebook::jsi::Runtime&)+144) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#33 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#34 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#35 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#36 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#37 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#38 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#39 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#40 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#41 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#42 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#43 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#44 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#45 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#46 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#47 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#48 pc 0x0000000000039bac /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableArray::toJSValue(facebook::jsi::Runtime&)+144) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#49 pc 0x0000000000039bac /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableArray::toJSValue(facebook::jsi::Runtime&)+144) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#50 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#51 pc 0x000000000003a828 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableObject::toJSValue(facebook::jsi::Runtime&)+208) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#52 pc 0x000000000003adc4 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::ShareableWorklet::toJSValue(facebook::jsi::Runtime&)+44) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#53 pc 0x0000000000069f64 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (std::__ndk1::__function::__func<reanimated::NativeReanimatedModule::scheduleOnUI(facebook::jsi::Runtime&, facebook::jsi::Value const&)::$_0, std::__ndk1::allocator<reanimated::NativeReanimatedModule::scheduleOnUI(facebook::jsi::Runtime&, facebook::jsi::Value const&)::$_0>, void ()>::operator()()+26148864) (BuildId: 4a76c13b9be79234db66bba565797a3d9048ab4c)
#54 pc 0x0000000000048128 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (worklets::UIScheduler::triggerUI()+184) (BuildId: 9dba5cf0d16bbecba49e2db594cb5f9c02265381)
#55 pc 0x00000000000794cc /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (facebook::jni::detail::MethodWrapper<void (reanimated::AndroidUIScheduler::*)(), &reanimated::AndroidUIScheduler::triggerUI(), reanimated::AndroidUIScheduler, void>::dispatch(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidUIScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject*>)+68) (BuildId: 4a76c13b9be79234db66bba565797a3d9048ab4c)
#56 pc 0x0000000000079410 /data/app/~~75Dyz7Trj2PPcahNES3lBg==/app.phantom-YZCLooH_l8ZqNekLU0lSMg==/split_config.arm64_v8a.apk (facebook::jni::detail::FunctionWrapper<void (*)(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidUIScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject*>), facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidUIScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject*, void>::call(_JNIEnv*, _jobject*, void (*)(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidUIScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject*>))+60) (BuildId: 4a76c13b9be79234db66bba565797a3d9048ab4c)
at com.swmansion.reanimated.AndroidUIScheduler.triggerUI (Native method)
at com.swmansion.reanimated.AndroidUIScheduler.lambda$new$0 (AndroidUIScheduler.java:22)
at com.swmansion.reanimated.AndroidUIScheduler.$r8$lambda$iUspyirUxSIP7N2hKjm5b-wzLjg (unavailable)
at com.swmansion.reanimated.AndroidUIScheduler$$ExternalSyntheticLambda0.run (D8$$SyntheticClass)
at com.swmansion.reanimated.AndroidUIScheduler$1.runGuarded (AndroidUIScheduler.java:40)
at com.facebook.react.bridge.GuardedRunnable.run (GuardedRunnable.java:29)
at android.os.Handler.handleCallback (Handler.java:958)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:257)
at android.os.Looper.loop (Looper.java:368)
at android.app.ActivityThread.main (ActivityThread.java:8839)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:572)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1049)
As you can see, we always end up failing somewhere in toJSValue. This is generally only on very low-end devices, and our app has a significant amount of memory overhead as it stands (something we're working on), so I could imagine that along with other CPU load we're experiencing, if we start paging out to memory, we could hit a long enough delay to start triggering ANRs. For reference, it seems like something like this:
useEffect(() => {
opacity.value = withRepeat(
withSequence(
withTiming(1, {
duration: tokens.time[500],
easing: tokens.ease.inOutSine
}),
withTiming(0.5, {
duration: tokens.time[500],
easing: tokens.ease.inOutSine
})
),
-1 // infinite repeats
);
}, [opacity]);
Would generate a 5-7kb payload that would need to be serialized and deserialized on either end per component instance. My gut feeling is that this is not a trivial amount of data to send I don't think, especially on low-end devices, but I also don't have a ton of experience here so feel free to correct me.
Some high level ideas for how the cross-thread serialization could be improved:
- Cache the string value of the function that's going to be eval'd directly in the thread, so that we don't have to pay the cost of serializing and deserializing it each time (if this is already done, please ignore this, I couldn't see it my own review but I may have missed it)
- For built-in animation functions like
withTimingandwithRepeat, we could potentially just load those directly into the UI thread on startup or first use or something, because we know they're not going to change. Then, the data structures that those generate on the JS thread could be much simpler and basically just call out to those functions with known values. This way the built-ins wouldn't even need to be eval'd each time. - We could also potentially make a way to define worklets such that if they're pure functions, we cache the eval'd value for those as well, and we only serialize the values of the arguments to those functions.
- We could also modify the Babel transform to turn worklets into pure functions (e.g. create more parameters for values captured in closure scope) so they don't need to be re-eval'd in general.
Happy to discuss any of these ideas, or take a stab at implementing them!
@pzuraq The issue mentioned above should be resolved from RN 0.78. Which version are you on? The trace looks like it should be the same issue, as it is calling the pthread_getattr_np function, that is really slow on the main thread, and without proper caching would snowball into an ANR.
We also added worklet caching in 3.17 to mitigate the serialization overhead. Which reanimated version are you using?
Thanks @bartlomiejbloniarz we're on [email protected] and Reanimated 3.16.7. We'll check the other versions and try to report back if the issue persists.
@bartlomiejbloniarz thanks for that clarification, that's good to know, we're definitely going to prioritize getting onto RN 0.78 then 😄
Re: caching, I did see that logic (I was mainly reviewing the main branch to see if it would get better as we upgraded), and I think there may still be some more work we can do here to make it more efficient. The issue is that we are not actually capturing the same functions over and over again. Consider this example:
useEffect(() => {
opacity.value = withRepeat(
withSequence(
withTiming(1, {
duration: tokens.time[500],
easing: tokens.ease.inOutSine
}),
withTiming(0.5, {
duration: tokens.time[500],
easing: tokens.ease.inOutSine
})
),
-1 // infinite repeats
);
}, [opacity]);
This is sending the animation object generated by withRepeat()/withSequence()/withTiming() over to the other thread, right? My understanding, reading the code, is that those functions will be returning new closures every time, which would mean that the shared pointers to those worklets would not be reused. The issue reproduction on #6758 is particularly worrying to me, it was this:
const onScroll = useAnimatedScrollHandler({
onBeginDrag: () => {
'worklet'
withSpring;
withClamp;
withDecay;
withDelay;
withTiming;
},
});
That example is referencing the exact same functions each time, not new closures/instances, so they would be properly cached in that case. But in my example, that would not be the case, unless worklets are not referencing the closure itself but referencing the function somehow. And if like that fix says we are in fact holding onto those worklet references forever, then it would be a bit more worrisome that this could progressively leak memory.
I think this issue is going to be at its worst for the top level worklet functions that get passed to useAnimated*, because every unique component/hook instance will be sending over a new closure instance, which will get fully serialized/deserialized, and cases like this where you're sending closure directly via shared objects. But I do think that the caching strategies I mentioned above could help in both cases.
cc @tjzel
I think the cleanest path forward that would allow us to reuse the same cached worklet functions everywhere would be:
- In the Babel transform, extract all worklet functions from their usage sites to module scope
- Parameterize all closure scoped variables passed to worklet functions
- Cache all worklet functions (now guaranteed to not be new closure instances ever) and pass parameterized closure values on either end
// before
const animatedStyles = useAnimatedStyle(() => {
return {
transform: [{ translateY: tabBarPositionOffsetSharedValue.value }],
};
});
// transfomed
// define function in module scope, add parameter for value that was previously
// captured in closure
const localWorkletFn = (translateY) => {
return {
transform: [{ translateY: translateY.value }],
};
};
// Pass the static function and the value that was previously captured in closure
const animatedStyles = useAnimatedStyle([localWorkletFn, tabBarPositionOffsetSharedValue]);
@pzuraq
- In the Babel transform, extract all worklet functions from their usage sites to module scope
- Parameterize all closure scoped variables passed to worklet functions
- Cache all worklet functions (now guaranteed to not be new closure instances ever) and pass parameterized closure values on either end
Unfortunately this approach won't work. You'd need to re-send the parameters of a worklets each time which is unnecessary and would lead to huge overhead, you'd also break semantics of the functions, breaking variadic arguments and arguments token usage.
Re: caching, I did see that logic (I was mainly reviewing the main branch to see if it would get better as we upgraded), and I think there may still be some more work we can do here to > make it more efficient. The issue is that we are not actually capturing the same functions over and over again. Consider this example:
useEffect(() => { opacity.value = withRepeat( withSequence( withTiming(1, { duration: tokens.time[500], easing: tokens.ease.inOutSine }), withTiming(0.5, { duration: tokens.time[500], easing: tokens.ease.inOutSine }) ), -1 // infinite repeats ); }, [opacity]);
The problem here is I think a lack of transparency of what's going on under the hood. withRepeat (and all animations) invocations actually return a function (a worklet) with a lot of other data. This data would be serialized/deserialized each time, because withRepeat won't return a stable reference - it returns a new animation. However, there's no need to create the animation one the RN Runtime and copy it to the UI Runtime.
You can apply the following optimization to avoid unnecessary copies - wrapping shared value assignment to runOnUI function:
useEffect(() => {
runOnUI(() => {
opacity.value = withRepeat(
withSequence(
withTiming(1, {
duration: tokens.time[500],
easing: tokens.ease.inOutSine,
}),
withTiming(0.5, {
duration: tokens.time[500],
easing: tokens.ease.inOutSine,
})
)
);
})(),
-1; // infinite repeats
}, [opacity]);
This way the only thing to memoize is the lambda inside runOnUI - the animation objects would actually be created on the UI runtime so it wouldn't be necessary to copy them. The closure of the worklet consists of stable withRepeat, withSequence etc.
While it's silly that these kinds of optimizations are necessary on the user side, we're actually overhauling the overall model of worklets and shareable memory in react-native-worklets and we aim to address these kinds of problems.