jtube-tv/docs/agent-container.md
Jeena a71de07969 emu: Stop silent early exits in the emulator start script
The script's set -euo pipefail made it die without any visible error in
two places: an empty /tmp/jtube-adbkeys/ failed the glob cat (the error
itself was discarded, so the output just stopped mid-script — this hits
any host after a reboot), and the boot-wait loop was killed on its first
iteration because adb exits non-zero while the device is still booting.
Both were swallowing the whole && chain (adb connect, scrcpy), making it
look like the emulator was broken when it was fine or about to be.

The stale bridge-emulator.sh duplicate (different port, broken vendor
keys path) is removed in the same spirit — keeping it invites running
the wrong script. Docs updated to match the one script.
2026-10-13 08:14:15 +09:00

67 lines
No EOL
3.4 KiB
Markdown

# Agent container ↔ host emulator setup
How the testing loop between the JTube TV agent container and the host
emulator works, and what needs to exist again after a rebuild.
## Topology
- **Emulator**: runs on the **host** (`/opt/android-sdk`, launched by
`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-<project>-<hash>`, launched with **`--network host`** — it shares the
host's network namespace. This is load-bearing: see below.
## Why host networking makes adb trivial
With `--network host`, the container's `localhost` *is* the host's localhost.
So inside the container:
- `adb connect 127.0.0.1:5556` → hits the host's socat bridge → emulator adbd.
- The adb **server** running on 127.0.0.1:5037 is also shared with the host,
so the container inherits whatever authorization the host adb server has.
No separate RSA handshake is needed. (Caveat: whoever's adb server grabs
port 5037 first owns it; all clients share it.)
## What must be (re)installed after a container rebuild
1. **`android-tools` in the container** (provides `adb`; installed into the
running container with `sudo pacman -S --noconfirm android-tools`, but that
is ephemeral). To make rebuilds self-sufficient, bake it into the
`agent-container` image at build time.
2. **Nothing else is needed for adb**: key handling is inherited from the
shared host adb server (see above). If the container is ever switched to
bridge networking, use `adb connect rutherford:5556` — remote keys are
handled by the emulator's `ADB_VENDOR_KEYS` (next section).
## Emulator-side facts (host)
- Ports: console `5600`, adbd `5601` (`-port 5600` ⇒ console+1), LAN bridge
`socat TCP-LISTEN:5556 → 127.0.0.1:5601` (0.0.0.0, so remote machines can
`adb connect rutherford:5556`).
- Remote key whitelisting: the TV system image is a user build — adb
`push`/`shell` writes to `/data/misc/adb/adb_keys` are blocked. The script
therefore builds `/tmp/jtube-adbkeys-combined` (host key + every
`/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), `/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`.
## Known quirks
- Emulator Qt toolbar (back/home buttons) is a detached XWayland window that
misbehaves on Hyprland — drive the emulator via scrcpy or adb instead.
- The TV image is a user build: no `adb root`.
- Under the Android TV AVD, keyboard input in the Qt window works, but the
reliable inputs are scrcpy (`b` = back, `h` = home) or
`adb shell input keyevent`.