Skip to content

iOS system-alert snapshot probe can bypass capture timeout and stall for 30–39 seconds #1244

Description

@dallasnorton

Summary

On an iOS Simulator, snapshot -i can take 30–39 seconds when a SpringBoard-owned system alert is visible, even though ordinary app snapshots are fast. The system-modal probe runs before the bounded snapshot capture plan, so the existing plan deadline and XCTest recovery protections do not bound this path.

Observed with agent-device 0.19.1, which is also the latest release at the time of this report.

Observed behavior

From 68 recorded iOS snapshot operations in one investigation:

  • median: 330 ms
  • p90: 5,032 ms
  • p95: 29,962 ms
  • maximum: 39,208 ms
  • 10 exceeded 1 second
  • 8 exceeded 5 seconds
  • 6 exceeded 20 seconds

Every 30–39 second outlier occurred while a SpringBoard system alert was displayed. Two repeatable examples were:

  1. An ASWebAuthenticationSession consent prompt of the form “App Wants to Use example.com to Sign In”.
  2. The standard notification permission prompt of the form “App Would Like to Send You Notifications”.

The command eventually returned the alert's semantic nodes, but only after the long stall. Ordinary app-owned snapshots in the same environment generally returned in hundreds of milliseconds.

Reproduction shape

  1. Boot an iOS Simulator and open an app that presents one of the system dialogs above.
  2. While the dialog is visible, run:
agent-device snapshot -i --platform ios --session <session>
  1. Observe that the command may take roughly 30–39 seconds before returning the alert tree.

The issue was seen with both the authentication consent dialog and notification permission dialog, so it does not appear specific to one alert's contents.

Source-path analysis

Both snapshotFast and snapshotRaw call blockingSystemAlertSnapshot() before calling runSnapshotCapturePlan(...).

blockingSystemAlertSnapshot() performs SpringBoard alert/sheet enumeration and descendant queries through safeElementsQuery. That helper delegates to safely, which catches Objective-C exceptions but does not impose a time limit.

As a result:

  • the 20-second snapshotPlanBudget has not started yet;
  • the bounded XCTest tree-capture slices do not apply;
  • a slow springboard.alerts.allElementsBoundByIndex, sheet query, or descendant query can block the request outside the normal capture/recovery envelope.

Relevant files on current main:

  • apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift
  • apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift
  • apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift
  • apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift

The recent bounded iOS capture work in #1107, #1144, and #1158 protects the normal capture plan, but this pre-plan system-modal path bypasses those protections.

This also appears distinct from #1231 / #1232, which concern remote-hosted AccessorySetupKit UI on physical iOS and missing/flaky modal detection rather than long-running SpringBoard queries on a simulator.

Expected behavior

  • System-modal detection is included in a bounded request/capture budget.
  • A normal SpringBoard alert returns its actionable semantic nodes promptly.
  • If the modal query exceeds its budget, the command fails or falls back with an explicit, actionable degraded-state result rather than blocking for 30–39 seconds.
  • A slow modal query does not wedge the runner, destroy the daemon, or invalidate unrelated sessions.
  • Diagnostics identify which system-modal probe timed out and how long it ran.

Possible direction

Treat system-modal detection as a bounded capture tier rather than an unbounded preflight. For example, run the SpringBoard query through the same bounded main-thread work/watchdog mechanism and share the overall capture deadline, stopping remaining alert/sheet/descendant queries once the deadline is exhausted.

The exact implementation is best left to the maintainers; the important contract is that the special system-modal path cannot bypass the snapshot command's timeout and recovery guarantees.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions