Repository navigation
fix(android): speed up helper captures on animating apps and wait for the window list - #3611
Conversation
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
Size Report
Startup median (7 runs, lower is better):
|
|
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. |
|
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_WINDOWSjust 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, base562e798d1b. Repro: RN 0.86.3 release build with Reanimated 4.5.4 and awithRepeatopacity loop over 400 nodes. API 36 emulator with its CPUs saturated. Base and head APKs were installed alternately.waitForIdleTimeoutMs=0CLI, same conditions:
snapshotwait 'id="row-5"' 15000Other checks:
pnpm check:affected --runpasses; its Android jobs run only on GitHub.UiAutomationandAccessibilityNodeInfoAPIs that the JVM suite cannot fake. The wait reuses the testedAccessibilityCaptureStabilizer.