Add an internal option to skip Native Animated frames while inactive - #58295
Closed
zeyap wants to merge 1 commit into
Closed
Add an internal option to skip Native Animated frames while inactive#58295zeyap wants to merge 1 commit into
zeyap wants to merge 1 commit into
Conversation
|
@zeyap has exported this pull request. If you are a Meta employee, you can view the originating Diff in D118188111. |
Summary: This is to investigate a crash on ios in C++ Animated rollout. On iOS, Native Animated drives frames from a `CADisplayLink` on the main run loop. While the app is inactive — which includes the whole `UIApplicationWillEnterForeground` → `UIApplicationDidBecomeActive` transition — it is not presenting, so a frame rendered then is never seen. Its commit and synchronous per-view updates still run on the main thread though, competing with the work the app must complete to become responsive. Adds `initWithSkipFramesDuringForegroundTransition:` to `RCTAnimatedModuleProvider`, declared in a new `RCTAnimatedModuleProvider+Private.h`. When YES, `_onDisplayLinkTick` returns early while `applicationState == UIApplicationStateInactive`. **The public API is unchanged.** `RCTAnimatedModuleProvider.h` is untouched and the C++ API snapshots have no delta — `+Private.h` is in the ReactApple `exclude_patterns`. Plain `init` still exists and defaults to NO, so every existing caller is unaffected; only hosts that opt in via the private header see different behaviour. Two properties worth being explicit about: - **The clock is not stopped, only the frame is skipped.** `AnimationDriver` computes progress from a timestamp (`timeDeltaMs = frameTimeMs - startFrameTimeMs_`), so the first frame after activation resolves to the value the animation should have reached rather than resuming from where it was suspended. - **Frames are not skipped while backgrounded** — `Background` is not `Inactive`. Completion handlers, and any app logic they drive, are therefore delayed by at most the length of the transition, not by the time spent in the background. Reading `applicationState` rather than tracking lifecycle notifications also avoids a failure mode: a mirrored flag must be cleared on every path out of the transition, including an abandoned foregrounding (a `willEnterForeground` with no following `didBecomeActive`), or frames are skipped indefinitely. There is no such state to get stuck here. `UIApplicationStateInactive` also covers other non-presenting moments — Control Center, the app switcher, an incoming call banner. Skipping frames there is harmless for the same reason: the clock keeps running and the first frame after activation is correct. The check sits inside the file's existing `TARGET_OS_OSX` guard, since `UIApplication` is iOS-only and this translation unit also builds for macOS. Changelog: [Internal] Reviewed By: javache, christophpurrer Differential Revision: D118188111
zeyap
force-pushed
the
export-D118188111
branch
from
September 3, 2026 12:59
e2a7568 to
c29cfeb
Compare
|
This pull request has been merged in 3f9f385. |
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:
This is to investigate a crash on ios in C++ Animated rollout.
On iOS, Native Animated drives frames from a
CADisplayLinkon the main runloop. While the app is inactive — which includes the whole
UIApplicationWillEnterForeground→UIApplicationDidBecomeActivetransition— it is not presenting, so a frame rendered then is never seen. Its commit and
synchronous per-view updates still run on the main thread though, competing
with the work the app must complete to become responsive.
Adds
initWithSkipFramesDuringForegroundTransition:toRCTAnimatedModuleProvider, declared in a newRCTAnimatedModuleProvider+Private.h. When YES,_onDisplayLinkTickreturnsearly while
applicationState == UIApplicationStateInactive.The public API is unchanged.
RCTAnimatedModuleProvider.his untouched andthe C++ API snapshots have no delta —
+Private.his in the ReactAppleexclude_patterns. Plaininitstill exists and defaults to NO, so everyexisting caller is unaffected; only hosts that opt in via the private header see
different behaviour.
Two properties worth being explicit about:
AnimationDrivercomputes progress from a timestamp
(
timeDeltaMs = frameTimeMs - startFrameTimeMs_), so the first frame afteractivation resolves to the value the animation should have reached rather
than resuming from where it was suspended.
Backgroundis notInactive. Completion handlers, and any app logic they drive, are thereforedelayed by at most the length of the transition, not by the time spent in the
background.
Reading
applicationStaterather than tracking lifecycle notifications alsoavoids a failure mode: a mirrored flag must be cleared on every path out of the
transition, including an abandoned foregrounding (a
willEnterForegroundwithno following
didBecomeActive), or frames are skipped indefinitely. There is nosuch state to get stuck here.
UIApplicationStateInactivealso covers other non-presenting moments — ControlCenter, the app switcher, an incoming call banner. Skipping frames there is
harmless for the same reason: the clock keeps running and the first frame after
activation is correct.
The check sits inside the file's existing
TARGET_OS_OSXguard, sinceUIApplicationis iOS-only and this translation unit also builds for macOS.Changelog:
[Internal]
Reviewed By: javache, christophpurrer
Differential Revision: D118188111