| name | adbharbor |
| description | Use when running adb commands, Android device automation, or app install/launch/test loops on this machine - adb is wrapped by AdbHarbor, which serializes device access between concurrent agents; explains waiting behavior, exit code 75, and how to pick a free device or run in parallel. |
AdbHarbor: adb is brokered on this machine
ALL device access on this machine goes through AdbHarbor, a lock broker
that gives each agent session exclusive access to one device at a time.
The harbor owns the ADB server port (5037), so every client is brokered —
adb at any path, Maestro, Android Studio, CI runners — not just shell
commands. You do not need to do anything special — run adb normally.
Read-only commands (getprop, dumpsys, pm list, settings get, ...)
are lease-exempt: they always run instantly, even on a busy device. Only
device-mutating commands (install, am/input, push, logcat, shell scripts)
take the lease.
What you'll observe
- Your commands never fight another agent. If another session holds the
device, your command prints
adbharbor: device X is busy (held by …) to
stderr and waits in a FIFO queue (default up to 10 minutes), then runs.
- Exit code 75 means "device busy, gave up waiting" — NOT an app or
device failure. Do not debug your app, do not kill other apps, do not
retry in a tight loop. Either wait and retry once later, or switch to a
free device.
- All commands from YOUR session share one lease: your install → launch →
test sequence cannot be interleaved by another agent. The lease lingers
~5 minutes after your last adb command, then the device passes to the
next session in the queue.
- Automation daemons (e.g. DroidRunner CI jobs) are brokered too: while a
job runs its device shows as held (session like
bun-...) and your
commands queue behind it — this is normal, wait or pick another device.
Commands
adbharbor devices
adbharbor who -s SERIAL
adbharbor status
adbharbor acquire -s SERIAL --ttl 30m
adbharbor release -s SERIAL
Rules
- Prefer a free device — atomically. Before a long task, run
S=$(adbharbor acquire --any --ttl 20m) — the broker picks a free
device, leases it to you, and prints its serial (stdout only). Pin every
command with adb -s $S … and adbharbor release -s $S when done.
Exit 75 = the whole fleet is busy. It's sticky: asking again returns
the device you already hold. (Manual alternative: adbharbor devices,
pick a free serial — but two agents can race; --any cannot.)
- Never
adbharbor release --force a device that another session
holds unless its holder is provably dead — force-release yanks the
device mid-command from the other agent. Crashed holders are reclaimed
automatically within ~1–2 minutes; you rarely need to intervene.
- For an exclusive multi-minute run (e.g. instrumented test suite), take
adbharbor acquire -s SERIAL --ttl 30m first and release when done —
this prevents your device from rotating away during quiet gaps longer
than the idle linger.
- If adb prints
running unlocked warnings, the broker is down —
locking is bypassed (fail-open). adbharbor doctor diagnoses.
- If
adbharbor cleanup reports ENABLED, apps you install are
auto-uninstalled when your session's lease ends — reinstall on the next
session instead of assuming state persists, and finish install→test
sequences without long idle gaps.