Skip to content

fix(android): speed up helper captures on animating apps and wait for the window list - #3611

Merged
thymikee merged 2 commits into
mainfrom
fix/android-helper-animated-app-capture-3558
Oct 14, 2026
Merged

thymikee merged 2 commits into
mainfrom
fix/android-helper-animated-app-capture-3558

Conversation

@thymikee

@thymikee thymikee commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Summary

Root cause of #3558: a looping animation keeps the app's main thread drawing every frame. Each accessibility read the helper makes that misses the cache waits for the current frame, so capture time is about (round trips × frame time). A Perfetto trace of the repro showed the main thread ~91% busy in doFrame. With the same tree and the same 1 Hz text tick but no animation, captures take 0.3–0.6 s. The tick is not the cause.

A second defect: a fresh UiAutomation connection turns on FLAG_RETRIEVE_INTERACTIVE_WINDOWS just before its first read, and the window list fills after that. The first read often listed only the SystemUI status bar (type 3). That matches the reporter's fallback log (helperWindowTypes: [3], content-poor-app-window).

  • perf: window roots and children are now read with uninterruptible depth-first prefetch (API 33+).
  • fix: when the helper turns the flag on, it waits up to 1 s for the list to name an active window.

Six helper files changed. Closes #3558

Validation

Head 86eb2d9780, base 562e798d1b. Repro: RN 0.86.3 release build with Reanimated 4.5.4 and a withRepeat opacity loop over 400 nodes. API 36 emulator with its CPUs saturated. Base and head APKs were installed alternately.

one-shot capture base head
traversal, mean of 12 7039 ms 3461 ms
app window listed, fresh connection, waitForIdleTimeoutMs=0 4/8 8/8

CLI, same conditions:

base head
snapshot 5.1–8.0 s 1.9–3.1 s
fresh-session wait 'id="row-5"' 15000 8.7–10.6 s 3.1–3.8 s

Other checks:

  • The helper JVM suite passes.
  • pnpm check:affected --run passes; its Android jobs run only on GitHub.
  • No unit tests were added: both changes call framework UiAutomation and AccessibilityNodeInfo APIs that the JVM suite cannot fake. The wait reuses the tested AccessibilityCaptureStabilizer.
  • Risk: on a fresh connection, a screen with no active window now waits 1 s before capture.

View guided diff Turn on auto-fix

Each accessibility read that misses the connection cache is served on the
app's main thread after the frame it is drawing. An app with a looping
animation draws back to back, so a 400-node traversal took 5-8 s. Reading
window roots and children with uninterruptible depth-first prefetch (API 33+)
measured about half the traversal time of the platform default.

Refs #3558
…dows

A fresh UiAutomation connection turns on FLAG_RETRIEVE_INTERACTIVE_WINDOWS
right before its first read, and the platform fills the window list after
that. The first capture often listed only the status bar, so a new helper
session or the one-shot fallback read as content-poor with no app window.
When the helper turns the flag on, wait up to 1 s for the list to name an
active window before capturing.

Refs #3558

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

View guided diff | Turn on auto-fix | Re-trigger cubic

@github-actions

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.21 MB 5.22 MB +4.1 kB
Package (unpacked) 5.21 MB 5.22 MB +4.1 kB
Package (download) 1.57 MB 1.57 MB +611 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.8 ms 27.3 ms -0.6 ms
CLI --help 79.1 ms 78.3 ms -0.8 ms

@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 86eb2d9. I read the diff and found nothing that needs a change. I did not run the helper JVM suite or any device, so the live numbers (7039 to 3461 ms) are from the PR body. CI is still running: Smoke Tests, Lint & Format, Bundle Size, Repo Guards, Compatibility & Provenance and Coverage are queued or in progress, and none has failed. The diff touches only the Android helper Java, so only the Android jobs such as Smoke Tests can exercise it. No conflicts. Not blocking, and you can take or leave these: the PR body shows elapsed time and window counts but not nodeCount, truncated or missingRootWindowTypes for base against head on the same animating screen, so please add that parity so we know the faster traversal drops no nodes (every element the base capture returns should appear in the head capture on a frame-stable screen); the removal of the unused GestureViewportReader.read() is unrelated to #3558 and could go in its own change or get a line in the body, and getRootInActiveWindow is still read outside AccessibilityNodeReads, so the Javadoc could say only window-list roots and children are covered; and the new wait sits in the shared enableInteractiveWindowRetrieval, so the gesture and viewport path can also pay up to 1 s on a fresh connection, which the risk note could state. Next, wait for CI to finish.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 14, 2026
@thymikee
thymikee merged commit d254cc5 into main Oct 14, 2026
18 checks passed
@thymikee
thymikee deleted the fix/android-helper-animated-app-capture-3558 branch October 14, 2026 15:23
@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-14 15:28 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android: snapshots take 2–22 s, and wait times out, while a Text ticks once a second inside a React Native sheet's dialog window

1 participant