Skip to content

mobile: reads on a continuously updating Android screen take ~20–40 s each (no way to skip the settle wait for snapshots) #841

Closed

Description

@muhamedzeema

Summary

On Android, every expect(...) / locator action on a screen whose content keeps changing (a list of rows whose values update about once a second) takes ~20–40 s, while the same calls on a static screen take ~1 s. A test that spends a few minutes on such a screen runs into its timeout, and occasionally a single read hits the 30 s adb timeout:

ENGINE_FAILURE: snapshot failed: Android snapshot helper failed: adb timed out after 30000ms

iOS runs of the same test on the same screen are fast.

Environment

  • e2e 0.16.0, @e2e-dev/mobile 0.9.1, bundled agent-device 0.21.18
  • Android emulator, API 35, arm64, animations disabled (window/transition/animator scales 0)
  • React Native 0.86 debug build
  • macOS host

What we measured

From report.json step durations on the changing screen (one run, first steps):

1916 913 32036 22475 19637 20699 19937 21127 19214 23416   (ms)

The steps are ordinary expect(locator).toBeVisible(), locator.tap() and locator.fill() calls. The same kinds of steps on static screens in the same run take a few hundred ms. A plain agent-device snapshot against a static screen of the same app returns in ~1 s.

Disabling system animations only shaved a few seconds off (≈25–30 s → ≈20 s), so the delay looks tied to the content updating rather than to animations.

Expected

A way to read a screen that never becomes idle without paying a long wait per call — for example a per-engine (or per-call) option to skip or bound the wait for the UI to settle before a snapshot, similar to Maestro's waitToSettleTimeoutMs: 0. mobile({ settle }) only covers the wait after taps, fills and scrolls, not reads.

Repro shape

  1. A React Native screen with a FlatList of ~30 rows, each row showing a number that changes every second (any timer-driven value works).
  2. Android emulator, mobile({ platform: 'android' }).
  3. A test that does a handful of expect(screen.getByTestId(...)).toBeVisible() and tap() calls on that screen.
  4. Compare step durations with the timer stopped.

Related: #831 (a duration for path swipes) is the other thing we needed for this kind of screen — a fast fling did not register on a slide-to-confirm control.

Activity

  1. plousisalexis1-netizen commented on Oct 4, 2026

    @plousisalexis1-netizen
  2. muhamedzeema commented on Oct 4, 2026

    @muhamedzeema
    Author

    To clarify the error quoted above: it's the one from this issue's report, the same problem at its worst rather than a separate one. Here is where each part of it comes from:

    • ENGINE_FAILURE: snapshot failed: is e2e reporting that the mobile engine's snapshot call failed.
    • Android snapshot helper failed is raised by agent-device when the snapshot helper exits non-zero.
    • adb timed out after 30000ms is agent-device's adb command timeout (30 s).

    We ran bare agent-device snapshot calls (no e2e involved) on the same continuously updating screen. Same emulator and build, ~510 helper nodes, snapshot --json:

    per snapshot
    helper session reused (helperSessionReused: true) helper elapsedMs 2.4–3.5 s, wall 2.5–3.6 s (6 runs)
    separate CLI calls, mixed reuse wall 1.5–15.2 s; agent-device's own stats: p50 4.8 s, p95 11.6 s, max 15.1 s over 28 captures, with its "android snapshots are slow in this run" warning
    a static screen of the same app ~2 s

    So one snapshot of this screen is slow, at ~3 s and sometimes 10–15 s, but nowhere near 30 s. Yet a single expect(...).toBeVisible() / tap() / fill() step through e2e takes 20–40 s on that screen. That suggests each step takes several snapshots. Maybe it waits for two consecutive snapshots to match, or retries until the tree stops changing, and on a screen that never stops changing that runs until a limit. Once in a while one of those snapshots hits a 10–15 s outlier and runs past the adb timeout.

    A correction to our earlier guess: the helper's idle wait is only waitForIdleTimeoutMs: 500 / waitForIdleQuietMs: 100, so that isn't the cause.

    Two questions:

    1. Does a locator read or action take more than one snapshot per attempt (a stability check or similar)? If so, could that be switched off or bounded per engine or per call? That's the waitToSettleTimeoutMs: 0 style option we asked for above.
    2. Is the 2.5–3.5 s helper time for ~510 nodes expected, or is something about a constantly updating tree slowing the capture itself down?

    Environment unchanged: e2e 0.16.0, @e2e-dev/mobile 0.9.1, bundled agent-device 0.21.18, Android emulator API 35 arm64, animations off.

  3. plousisalexis1-netizen commented on Oct 4, 2026

    @plousisalexis1-netizen
  4. added
    P1Required for v0
    bugSomething isn't working
    driverdriver-1 SPI and reference web driver
    on Oct 13, 2026
  5. okwasniewski commented on Oct 19, 2026

    @okwasniewski
    Member

    Fixed upstream in agent-device and shipped in @e2e-dev/[email protected], which pins [email protected].

    To your two questions:

    1. One snapshot per attempt, no stability check across snapshots. The slow steps came from the snapshot helper. A persistent helper capture had a 5 s socket budget. Your ~500-node screen took 3-12 s per capture, so each one was treated as wedged: the helper was force-stopped, a one-shot am instrument capture ran (10-15 s), and the session restarted on the next read. That is how a 3 s capture became a 20-40 s step, and occasionally hit the 30 s adb timeout. fix(android): give a session capture the session's share of the helper budget callstack/agent-device#3568 gives a session capture the session's share of the helper budget.
    2. 2.5-3.5 s was not expected. A screen that redraws every frame makes each accessibility read wait for the current frame. fix(android): speed up helper captures on animating apps and wait for the window list callstack/agent-device#3611 cuts the round trips on animating apps and waits for the window list before the first read.

    Since the time was spent recovering a helper that wasn't wedged, not waiting for the screen to settle, we're not adding a skip-settle option for reads. If you still see slow reads on 0.12.3, please reopen with a --trace=on run.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Required for v0bugSomething isn't workingdriverdriver-1 SPI and reference web driver

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions