diff --git a/docs/agent-container.md b/docs/agent-container.md index 48a15d2..5d6b66f 100644 --- a/docs/agent-container.md +++ b/docs/agent-container.md @@ -9,6 +9,12 @@ emulator works, and what needs to exist again after a rebuild. `scripts/start-emulator.sh`). **Headless is the default**; set `JTUBE_EMU_MODE=windowed` if you want the Qt window (e.g. for desktop interaction testing). View it via scrcpy either way. +- **Only the host can start the emulator** (by design — no SSH from the + container to the host, no SDK/KVM inside the container). If the agent + finds no emulator, it should tell the user to run + `./scripts/start-emulator.sh` on the host rather than try to work around + it. Reachability check: `adb connect rutherford:5556` then + `adb -s rutherford:5556 shell getprop sys.boot_completed` → `1`. - **Agent container**: image `agent-container:latest`, container name pattern `ac--`, launched with **`--network host`** — it shares the host's network namespace. This is load-bearing: see below. @@ -46,7 +52,8 @@ So inside the container: `/tmp/jtube-adbkeys/*.pub`) and launches the emulator with `ADB_VENDOR_KEYS` pointing at it. To trust a new client: put its `~/.android/adbkey.pub` into `/tmp/jtube-adbkeys/` **before** launching. -- Logs: `/tmp/jtube-emu.log` (QEMU) and `/tmp/jtube-emu-run.log` (script). +- Logs: `/tmp/jtube-emu.log` (QEMU), `/tmp/jtube-socat.log` (bridge), + `/tmp/jtube-adbkeys-combined` (rebuilt each launch). - Viewing: `scrcpy -s emulator-5600` on the host, or from any LAN machine: `adb connect rutherford:5556 && scrcpy -s 127.0.0.1:5556`. diff --git a/scripts/bridge-emulator.sh b/scripts/bridge-emulator.sh deleted file mode 100755 index 5fc8ed2..0000000 --- a/scripts/bridge-emulator.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -# -# bridge-emulator.sh — (host-side) expose the emulator's adbd to the LAN so agents -# inside the container/other machines can use it: binds :5557 -> 127.0.0.1:5601. -# The emulator console transport (emulator-5600) stays local-only; this bridges the -# adbd TCP port 5601. -set -euo pipefail -ADBD_PORT=5601 -BRIDGE_PORT=5557 - -# start emulator if not running -ADB="${ANDROID_SDK_ROOT:-$HOME/Android/Sdk}/platform-tools/adb" -if ! "$ADB" devices | grep -q "emulator-5600.*device"; then - echo "emulator-5600 not running — starting it…" - ADB_VENDOR_KEYS="$HOME/.android/adbkey" setsid nohup \ - "${ANDROID_SDK_ROOT:-$HOME/Android/Sdk}/emulator/emulator" -avd jtubesc -port 5600 \ - -no-window -gpu swiftshader_indirect -no-snapshot -no-audio -no-boot-anim \ - > /tmp/jtube-emu.log 2>&1 < /dev/null & - echo "waiting for boot (log: /tmp/jtube-emu.log)…" - for i in $(seq 1 60); do - ok=$("$ADB" -s emulator-5600 shell getprop sys.boot_completed 2>/dev/null | tr -d '\r') - [ "$ok" = "1" ] && { echo "BOOTED"; break; } - sleep 5 - done -fi - -# keep JTube TV installed + running -APK="$HOME/Projects/jtube-tv/app/build/outputs/apk/debug/app-debug.apk" -if [ -f "$APK" ]; then - "$ADB" -s emulator-5600 install -r "$APK" >/dev/null && echo "JTube TV installed" - "$ADB" -s emulator-5600 shell am start -n net.jeena.jtubetv/.MainActivity && echo "app started" -fi - -# the bridge (bind all LAN addresses) -if ! ss -tln 2>/dev/null | grep -q ":$BRIDGE_PORT"; then - setsid nohup socat TCP-LISTEN:$BRIDGE_PORT,bind=0.0.0.0,fork,reuseaddr \ - TCP:127.0.0.1:$ADBD_PORT > /tmp/jtube-bridge.log 2>&1 < /dev/null & - echo "bridge: :$BRIDGE_PORT -> 127.0.0.1:$ADBD_PORT (pid $!)" -fi - -echo "From this host: adb connect localhost:$BRIDGE_PORT" -echo "From other machines: adb connect rutherford:$BRIDGE_PORT" \ No newline at end of file diff --git a/scripts/start-emulator.sh b/scripts/start-emulator.sh index 5995100..fdb9af7 100755 --- a/scripts/start-emulator.sh +++ b/scripts/start-emulator.sh @@ -62,11 +62,13 @@ if [ "$MODE" = windowed ]; then else echo "JTUBE_EMU_MODE=windowed but no display detected — falling back to headless" WINDOWED=0 - ACCEL+=(-no-window) + ACCEL+=(-no-window -gpu swiftshader_indirect) fi else WINDOWED=0 - ACCEL+=(-no-window) + # Headless has no X display, so -gpu host/GLX can't init EGL ("Failed to get EGL + # display") and the emulator dies on launch — fall back to software rendering. + ACCEL+=(-no-window -gpu swiftshader_indirect) echo "headless (default; JTUBE_EMU_MODE=windowed for a window) — no emulator window" fi if [ -e /dev/kvm ]; then @@ -79,21 +81,27 @@ fi # blocked, so remote keys are trusted via ADB_VENDOR_KEYS at launch instead. # Drop extra public keys into /tmp/jtube-adbkeys/ (one per file), e.g. from the # agent container: docker exec sh -c 'cat ~/.android/adbkey.pub' > /tmp/jtube-adbkeys/agent-container.pub +mkdir -p /tmp/jtube-adbkeys VKEYS=/tmp/jtube-adbkeys-combined { cat "$HOME/.android/adbkey.pub" - cat /tmp/jtube-adbkeys/*.pub 2>/dev/null + # Optional extra keys — must not fail the script under `set -e` when absent. + shopt -s nullglob + for k in /tmp/jtube-adbkeys/*.pub; do cat "$k"; done + shopt -u nullglob } > "$VKEYS" chmod 600 "$VKEYS" echo "Booting AVD '$AVD' …" -ADB_VENDOR_KEYS="$VKEYS" setsid nohup "$EMU" -avd "$AVD" -port "$PORT" -gpu host "${ACCEL[@]:-}" \ +ADB_VENDOR_KEYS="$VKEYS" setsid nohup "$EMU" -avd "$AVD" -port "$PORT" "${ACCEL[@]:-}" \ -no-snapshot > /tmp/jtube-emu.log 2>&1 < /dev/null & echo "emulator PID $! — log: /tmp/jtube-emu.log" for i in $(seq 1 90); do - ok=$("$ADB" -s "emulator-$PORT" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r') - [ "$ok" = "1" ] && { echo "BOOTED"; break; } + # adb exits non-zero while the device is still booting — don't let + # pipefail+set -e kill the wait loop. + ok=$( ("$ADB" -s "emulator-$PORT" shell getprop sys.boot_completed 2>/dev/null || true) | tr -d '\r') + if [ "$ok" = "1" ]; then echo "BOOTED"; break; fi sleep 5 done