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

Merged
TH
6d ago
+81-12

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 capturebasehead
traversal, mean of 127039 ms3461 ms
app window listed, fresh connection, waitForIdleTimeoutMs=04/88/8

CLI, same conditions:

basehead
snapshot5.1–8.0 s1.9–3.1 s
fresh-session wait 'id="row-5"' 150008.7–10.6 s3.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.