Skip to content

Phone Farm

DroidBot supports multiple physical Android devices simultaneously. Each phone gets its own job queue, its own scheduler entries, and its own live stream. This guide covers hardware setup, multi-device configuration, and per-phone scheduling.

ComponentRecommendationNotes
USB hubPowered 7+ port hubMust be powered — phones draw significant current
USB cablesData-capable cablesCharge-only cables do not work with ADB
PhonesAny Android 5.0+Higher-end devices are faster (XML dumps, app transitions)
Host machineLinux recommendedADB is most stable on Linux; macOS works too
  1. Plug all phones into the powered USB hub
  2. Enable USB debugging on each phone (see Connect Phone)
  3. Authorize each phone (accept the USB debugging prompt on each device)
  4. Verify all devices are visible:
Terminal window
adb devices
# L9AIB7603188953 device (ASUS ROG Phone II)
# RZCX125RE5L device (Samsung Galaxy A15)
# EMULATOR_SERIAL device (optional: emulator)

Navigate to the Phone Admin tab to see all connected devices:

  • Device serial, model, and nickname
  • Online/offline status
  • Live WebRTC stream per device
  • Tap/type/back controls for remote interaction

Each device appears as a selectable option throughout the dashboard — the Skill Hub, Bot tab, Scheduler, and Skill Creator all have device selector dropdowns.

The scheduler enforces one active job per phone. Each device has its own queue, and jobs are processed independently.

Terminal window
# Phone 1: crawl every 4 hours
curl -X POST http://localhost:5055/api/schedules \
-H "Content-Type: application/json" \
-d '{
"name": "Phone 1 crawl",
"job_type": "crawl",
"device": "L9AIB7603188953",
"interval_minutes": 240,
"params": {"query": "#Cat", "passes": 5},
"max_duration_minutes": 30,
"priority": 5
}'
# Phone 2: outreach every 6 hours
curl -X POST http://localhost:5055/api/schedules \
-H "Content-Type: application/json" \
-d '{
"name": "Phone 2 outreach",
"job_type": "outreach",
"device": "RZCX125RE5L",
"interval_minutes": 360,
"params": {"strategy_id": 1, "limit": 15},
"max_duration_minutes": 30,
"priority": 3
}'

Jobs have priority 1 (highest) through 5 (lowest). When a higher-priority job is pending and the current job has been running for over 90 seconds (grace period), the scheduler preempts the running job.

Protected jobs: post and publish_draft are never preempted (interrupting would corrupt the upload state).

The scheduler runs on a 30-second tick cycle:

  1. Clean orphaned jobs (dead PIDs)
  2. Enqueue due scheduled jobs
  3. Process each phone’s queue (launch, detect completion, preempt)
  4. Check for timeouts (SIGTERM -> 5s -> SIGKILL)
  5. Run content plan pipeline tick
Terminal window
# Run full test suite on Phone 1
DEVICE=L9AIB7603188953 python3 -m pytest tests/ -v --tb=short
# Run specific test on Phone 2
DEVICE=RZCX125RE5L python3 -m pytest tests/test_04_crawl.py -v

The Tests tab in the dashboard also has a device selector for running pytest with screen recordings.

Phone 1 (ASUS, fast): crawl + upload + publish
Phone 2 (Samsung, steady): outreach + inbox scan + engage
Phone 1: TikTok account A -> target audience X
Phone 2: TikTok account B -> target audience Y

Use the scheduler’s daily_times feature to stagger work:

Terminal window
# Phone 1: morning crawl + evening publish
# Phone 2: afternoon outreach + night engagement

The Scheduler tab provides a 24-hour visual timeline showing all jobs across all phones. Color-coded bars indicate job type, and you can see which phone is running what at a glance.

Per-phone queue status is available via the API:

Terminal window
curl -s http://localhost:5055/api/scheduler/queue | python3 -m json.tool

Emulators appear as regular ADB devices and work with the same scheduling and job system. The EmulatorManager service provides lifecycle management (create, start, stop, delete AVDs) from the dashboard and API.

See Emulator Support for details on the EmulatorPool for parallel headless emulators.

Terminal window
adb kill-server && adb start-server && adb devices

If a specific device goes offline, unplug and replug its USB cable. Some phones need USB mode set to “File transfer” mode.

If devices keep disconnecting, the USB hub may not supply enough power. Use a hub with external power supply rated for at least 2A per port.

The scheduler’s _phone_procs dict is in-memory. After a server restart, orphaned jobs are cleaned up on the next scheduler tick (within 30 seconds).