Managing multiple Android devices over ADB: a practical reference

Managing multiple Android devices over ADB comes down to three habits: check what is connected with adb devices -l, address every command to one device with -s <serial> or ANDROID_SERIAL, and wrap repeated actions in a loop over all serials. This reference collects the commands, flags and fixes for that workflow.

Getting started with ADB

ADB (Android Debug Bridge) connects a host to the adbd daemon on each device through a local server. Multi-device commands are needed for testing one build on several models, debugging device-specific crashes and batch installs.

Prerequisites:

  • Platform-Tools installed and on PATH
  • USB debugging enabled
  • The host’s RSA key authorized on the device

adb version        # client and platform-tools version

adb start-server   # start the server on port 5037

adb kill-server    # stop it after updates or hangs

 

Listing and identifying devices

adb devices        # serial and state of every device

adb devices -l     # adds product, model, device and transport_id

 

The -l output helps tell identical phones apart in a long list.

State Meaning Action
device Connected and authorized Ready for commands
unauthorized RSA key not accepted Unlock the phone and accept the prompt
offline Connected, but adbd not responding Replug or restart the server
no permissions Host can’t access the USB device (Linux) Add a udev rule and replug

 

adb -d get-serialno                                      # serial of the single USB device

adb -s <serial> shell getprop ro.product.model           # model name

adb -s <serial> shell getprop ro.build.version.release   # Android version

 

Model and Android version are useful labels when results from several phones go into one report.

Targeting a specific device

Target flags go before the subcommand:

adb -s R58M12ABCDE shell     # by serial (USB, emulator or ip:port)

adb -d install app.apk       # the only device on USB

adb -e logcat                # the only emulator or TCP/IP device

adb -t 3 reboot              # by transport_id from adb devices -l

 

-t helps when two low-cost devices report the same serial, such as 0123456789ABCDEF, because the transport ID is always unique.

For a session or script that works with one device, set the serial once:

export ANDROID_SERIAL=R58M12ABCDE

adb shell getprop ro.product.model   # goes to R58M12ABCDE

unset ANDROID_SERIAL                 # back to default targeting

 

Common error:

adb: more than one device/emulator

 

ADB refuses to guess a target when several devices are attached and none is specified. The error often comes from a forgotten emulator still running. Add -s <serial>, export ANDROID_SERIAL, or use -d / -e when only one device of that type is connected. An explicit -s overrides ANDROID_SERIAL.

Running commands on all devices

Loop over every serial in the device state:

for s in $(adb devices | awk ‘NR>1 && $2==”device” {print $1}’); do

  echo “== s”adb-s”s” shell getprop ro.product.model

done

 

awk skips the header line and ignores unauthorized or offline phones.

Run slow jobs in parallel with xargs -P:

adb devices | awk ‘NR>1 && $2==”device” {print $1}’ \

  | xargs -P 4 -I{} adb -s {} install -r app-release.apk

 

-P 4 processes four devices at a time; -I{} inserts each serial.

Batch jobs for the loop body:

  • Install a build: adb -s “$s” install -r app.apk
  • Clear app data: adb -s “$s” shell pm clear com.example.app
  • Take a screenshot: adb -s “s”exec-outscreencap-p>”s.png”
  • Pull logs: adb -s “s”logcat-d>”s.log”

With xargs, wrap redirections in sh -c ‘…’ so each device writes its own file.

Wireless and network connections

TCP/IP mode, starting from a USB connection:

adb -s <serial> tcpip 5555         # restart adbd listening on TCP 5555

adb connect 192.168.1.42:5555      # connect over Wi-Fi

adb disconnect 192.168.1.42:5555   # drop one; plain adb disconnect drops all

 

tcpip mode stays active until the device reboots; after that, USB is needed again.

Android 11+ Wireless debugging needs no cable. Open Developer options → Wireless debugging → Pair device with pairing code:

adb pair 192.168.1.42:37099        # enter the six-digit code

adb connect 192.168.1.42:41235     # port shown on the Wireless debugging screen

 

Network serials look like 192.168.1.42:5555 and work with -s like any other serial.

Method Speed Stability Setup
USB Fastest, no network overhead Most stable Cable and driver
Wi-Fi (tcpip) Network-bound Lost after reboot USB cable once per boot
Pairing (adb pair) Network-bound Port changes on reconnect Android 11+, one-time pairing

Working with devices you don’t physically have

Emulators handle basic checks across API levels and appear as emulator-5554, but bugs tied to vendor skins, cameras or chipsets need real hardware. When a bug only reproduces on a model nobody on the team owns, renting a remote phone farm online gives access to real hardware without buying it. Such services keep physical handsets connected and let you control them from a browser, so you can install the build and reproduce the issue on the exact model. 

When a remote host exposes a device’s ADB port on its localhost, forward it over SSH:

ssh -N -L 5555:localhost:5555 user@remote-host

adb connect localhost:5555

 

Security note: never expose port 5555 to the open internet. ADB in tcpip mode is unencrypted and grants shell access.

App and file management across devices

adb -s <serial> install -r app.apk

adb -s <serial> install-multiple base.apk split_config.arm64_v8a.apk

adb -s <serial> uninstall com.example.app

adb -s <serial> shell pm list packages | grep example

adb -s <serial> push config.json /sdcard/Download/

adb -s <serial> pull /sdcard/Download/report.txt ./

adb -s <serial> shell am start -n com.example.app/.MainActivity

adb -s <serial> shell am force-stop com.example.app

adb -s <serial> shell pm clear com.example.app

 

-r keeps app data on reinstall; install-multiple installs split APKs from an App Bundle in one session. push and pull copy files to and from shared storage. am start launches an activity by component name, force-stop kills the process, and pm clear resets the app to first launch.

Logs, screenshots and debugging

adb -s <serial> logcat -c                        # clear the buffer

adb -s <serial> logcat -s MyAppTag               # one tag, silence the rest

adb -s <serial> logcat ‘*:E’                     # errors and above

adb -s <serial> logcat MyAppTag:D ‘*:S’          # tag at debug level

adb -s <serial> exec-out screencap -p > screen.png

adb -s <serial> shell screenrecord /sdcard/demo.mp4   # Ctrl+C to stop, 3 min by default

adb -s <serial> pull /sdcard/demo.mp4

adb -s <serial> bugreport bugreport.zip

 

exec-out streams binary data unaltered, so the PNG isn’t corrupted. Clear logcat before reproducing a bug to keep the capture short.

Troubleshooting

Problem Cause Fix
unauthorized RSA key not accepted Accept the prompt or revoke authorizations
offline Stale connection Replug, restart the server
Port 5037 in use Second ADB server Keep one Platform-Tools on PATH
Device not listed Driver or charge-only cable Install the driver, use a data cable

Running adb devices -l before every batch job catches all four early.

Leave a Reply

Your email address will not be published. Required fields are marked *