fix(open): boot a stopped Android AVD named by --device before claiming it

TH
44m ago
+454-126

Summary

open <app> --platform android --device <AVD> on a stopped AVD failed with DEVICE_NOT_FOUND, on main too. The maintainer's #4359 live runs found it. There were two causes:

  • open resolved devices running-only.
  • After a boot, open kept the AVD name as the device id.

The fix:

  • open admits stopped AVDs (androidAvdSelection: 'include-stopped') only when --device names a device. An unnamed open stays running-only, so a running phone still wins over a stopped AVD.
  • One owner, resolveOpenTargetDeviceOptions, feeds all four open resolution sites.
  • Install's boot-then-rebind step is now shared as bootStoppedLocalAndroidDevice. open runs it before the session claim and locks, so the session, claim and locks use the emulator-NNNN serial.
  • When open or install boots a stopped AVD, readiness receives the request's Android serial allowlist but not --serial: the resolved AVD is the boot target.
  • One daemon owner, core/device-readiness-input.ts, builds the sorted Android serial allowlist and the readiness input for boot, appstate, apps, doctor, the inventory request and the stopped-AVD boot. The per-file copies are deleted.
  • Behavior change, intended per maintainer review: install of a stopped AVD now honors the Android serial allowlist. Before, it booted the AVD regardless. An emulator that comes up outside the allowlist ends in boot_timeout, as boot does.
  • One --timeout startup deadline covers both the boot and open preparation. The superseded readyDeployAppUse is removed.

23 files. This is not an audit item; it is tracked alongside #4368.

Validation

  • Tested SHA 650c9bb.
  • Tests that fail without the fix:
    • Router: the open stopped-AVD selection case, the cold-AVD boot test, and unnamed open with a running phone plus a stopped AVD (selects the phone, no ensureReady).
    • Claims: rollback of the booted-serial claim; an allowlist that excludes the booted serial (no claim); and --serial naming another device (the resolved AVD still boots).
    • Router: open of a stopped AVD under an allowlist sends inventory both include-stopped and the allowlist, and boots within it. The real Android inventory keeping a stopped AVD under an allowlist is covered by platform-android/src/inventory.test.ts:25-66.
  • check:quick and check:fallow --base origin/main pass.
  • check:affected --run --head 650c9bb (exactCommit): format, lint, typecheck, layering, fallow and build pass. vitest-related fails only on 2 apple-runner chmod tests that fail when run as root (known baseline BASE-1). It selects them because a contracts comment changed, and that stops the gate before unit.
  • check:unit run directly at 650c9bb: all 17,968 vitest tests pass. The only failures are the 2 known smoke-daemon-clean tests, which fail because the container's PID 1 does not reap zombies.
  • Required live run, by the maintainer (not yet done). Use a cold AVD other than Pixel_7_CI:
    1. Confirm adb devices does not list the AVD.
    2. Run agent-device open com.android.settings --platform android --device <AVD> --json. Expect a boot, then Settings, with session device id emulator-NNNN.
    3. Run snapshot -i --json. Expect androidSnapshot.backend: android-helper.
    4. Run close --shutdown.
    5. With a phone or a running emulator attached and a stopped AVD present, run open com.android.settings --platform android without --device. Expect the running device to be selected and no emulator to boot.
    6. On a cold AVD, run install <apk> --device <AVD>.
  • Risk: device-facing. CI lanes own native coverage.

Generated by Claude Code


<a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1796964165&installation_model_id=447842&pr_number=4396&ref=codesmith_pr_footer&repository=callstack%2Fagent-device&return_to=https%3A%2F%2Fgithub.com%2Fcallstack%2Fagent-device%2Fpull%2F4396&signature=fc976f331a9a83ebca992aa23117721280d702cf34abf546af40d8e70be11624"&gt;&lt;picture&gt;&lt;source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"&gt;&lt;source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"&gt;&lt;img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png" width="190" height="28"&gt;
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

<a href="https://www.cubic.dev/action/auto-fix/pr/callstack/agent-device/4396?returnTo=https%3A%2F%2Fgithub.com%2Fcallstack%2Fagent-device%2Fpull%2F4396&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true">&lt;source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"&gt;&lt;source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"&gt;&lt;img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"&gt;


Generated by Claude Code