Skip to content

Commit 0057d69

Browse files
committed
Only ignore the already-booted error from simctl boot
simctl boot errors out (exit 149) when the device is already booted. Since the goal is simply for the device to be booted, treat that as a no-op -- but only after confirming via 'simctl list' that the device really is in the Booted state, mirroring the existing apple/testing/default_runner/simulator_creator.py helper. Exit 149 is not unique to already-booted (a device stuck 'Shutting Down' reports it too), so every other failure still propagates.
1 parent 530e052 commit 0057d69

1 file changed

Lines changed: 34 additions & 3 deletions

File tree

apple/internal/templates/apple_simulator.template.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,10 +466,41 @@ def boot_simulator(*, developer_path: str, simctl_path: str, udid: str) -> None:
466466

467467
# Boot the device explicitly via simctl. Historically the boot was a side
468468
# effect of launching Simulator.app with `-CurrentDeviceUDID`, but Simulator.app
469-
# was removed from the Xcode bundle in favor of DeviceHub.app (Xcode 26+), which
469+
# was removed from the Xcode bundle in favor of DeviceHub.app (Xcode 27), which
470470
# does not boot a device on launch. Booting via simctl works on every Xcode
471-
# version; an already-booted device exits non-zero, which we ignore.
472-
subprocess.run([simctl_path, "boot", udid], check=False)
471+
# version.
472+
try:
473+
subprocess.run([simctl_path, "boot", udid], check=True)
474+
except subprocess.CalledProcessError as e:
475+
# `simctl boot` errors out if the device is already booted, exiting 149
476+
# with "Unable to boot device in current state: Booted". Since our goal is
477+
# simply for the device to be booted, that case is already satisfied and we
478+
# can carry on. But 149 is not unique to "already booted" -- other states
479+
# like "Shutting Down" report it too -- so, as simulator_creator.py does, we
480+
# only ignore it after confirming via `simctl list` that the device really
481+
# is booted. Every other failure propagates.
482+
already_booted = False
483+
if e.returncode == 149:
484+
list_result = subprocess.run(
485+
[simctl_path, "list", "devices", "-j", udid],
486+
encoding="utf-8",
487+
stdout=subprocess.PIPE,
488+
check=True,
489+
)
490+
devices = json.loads(list_result.stdout)["devices"]
491+
device = next(
492+
(
493+
blob
494+
for devices_for_os in devices.values()
495+
for blob in devices_for_os
496+
if blob["udid"] == udid
497+
),
498+
None,
499+
)
500+
already_booted = bool(device) and device["state"].lower() == "booted"
501+
if not already_booted:
502+
raise
503+
logger.debug("Simulator %s is already booted", udid)
473504

474505
# Bring up a GUI window so the running app is visible. This is purely cosmetic
475506
# for `bazel run` -- the device is already booted above -- so it is best-effort:

0 commit comments

Comments
 (0)