docs: Agent container emulator workflow
Document how the host emulator is driven over adb from the agent container: the start script now boots headless by default and trusts remote adb keys via ADB_VENDOR_KEYS at launch, since the TV system image is a user build that blocks pushing keys to adb_keys after boot. AGENTS.md points to the new doc and fixes the stale SDK path.
This commit is contained in:
parent
ed65b77e90
commit
40a9d1e2c6
3 changed files with 93 additions and 25 deletions
|
|
@ -5,7 +5,12 @@ for TV) that talks to a PeerTube instance over its REST API v1.
|
|||
|
||||
## Environment facts
|
||||
|
||||
- Host is Arch Linux with Android SDK at `~/Android/Sdk` (platforms 34/35/36, build-tools).
|
||||
- Host is Arch Linux. The Android SDK the build actually uses is `/opt/android-sdk`
|
||||
(`ANDROID_SDK_ROOT` — note `local.properties`' `sdk.dir` points to the outdated
|
||||
`~/Android/Sdk`, which doesn't exist; platforms 34/35/36, build-tools).
|
||||
- Emulator testing (host emulator + agent container over adb): see
|
||||
`docs/agent-container.md` — covers start script, ports, and what to reinstall
|
||||
after a container rebuild.
|
||||
- The Gradle wrapper is checked in (`gradlew` + `gradle/wrapper/`), so builds need only a
|
||||
JDK 17+ (`java`) on PATH. If `java` is missing, tell the user — do not install things on
|
||||
the host without asking.
|
||||
|
|
|
|||
60
docs/agent-container.md
Normal file
60
docs/agent-container.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# 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.
|
||||
- **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) and `/tmp/jtube-emu-run.log` (script).
|
||||
- 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`.
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# start-emulator.sh — boot the JTube TV test emulator on the HOST (not inside the
|
||||
# agent container), with GPU acceleration and a window. Use this when the app should
|
||||
# be tested over scrcpy (ATD/system quirks make scrcpy fail against headless
|
||||
# in-container emulators) or when you simply want to watch it.
|
||||
# agent container), with GPU acceleration, headless by default (drive it via
|
||||
# adb/scrcpy). JTUBE_EMU_MODE=windowed shows the Qt window.
|
||||
#
|
||||
# Boots on console :5600 (adbd :5601); the agent container bridges
|
||||
# rutherford:5556 -> 127.0.0.1:5601 with socat, so after this script the emulator is
|
||||
|
|
@ -54,22 +53,41 @@ for pid in $(ps aux | awk '/[q]emu-system-x86_64/ {print $2}' 2>/dev/null); do
|
|||
done
|
||||
sleep 1
|
||||
|
||||
ACCEL=()
|
||||
MODE="${JTUBE_EMU_MODE:-headless}" # headless (default) | windowed
|
||||
WINDOWED=1
|
||||
if [ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]; then
|
||||
echo "desktop session detected — emulator window + GPU host"
|
||||
ACCEL=()
|
||||
if [ "$MODE" = windowed ]; then
|
||||
if [ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]; then
|
||||
echo "windowed (JTUBE_EMU_MODE=windowed) — emulator window + GPU host"
|
||||
else
|
||||
echo "JTUBE_EMU_MODE=windowed but no display detected — falling back to headless"
|
||||
WINDOWED=0
|
||||
ACCEL+=(-no-window)
|
||||
fi
|
||||
else
|
||||
WINDOWED=0
|
||||
ACCEL+=(-no-window)
|
||||
echo "headless (no display) — running without a window, swiftshader rendering"
|
||||
echo "headless (default; JTUBE_EMU_MODE=windowed for a window) — no emulator window"
|
||||
fi
|
||||
if [ -e /dev/kvm ]; then
|
||||
[ $WINDOWED -eq 1 ] && ACCEL+=(-accel kvm)
|
||||
ACCEL+=(-accel on)
|
||||
echo "/dev/kvm found — hardware acceleration on"
|
||||
fi
|
||||
|
||||
# --- build combined adb vendor-keys file ------------------------------------
|
||||
# The TV system image is a user build: adb push to /data/misc/adb/adb_keys is
|
||||
# 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 <ctr> sh -c 'cat ~/.android/adbkey.pub' > /tmp/jtube-adbkeys/agent-container.pub
|
||||
VKEYS=/tmp/jtube-adbkeys-combined
|
||||
{
|
||||
cat "$HOME/.android/adbkey.pub"
|
||||
cat /tmp/jtube-adbkeys/*.pub 2>/dev/null
|
||||
} > "$VKEYS"
|
||||
chmod 600 "$VKEYS"
|
||||
|
||||
echo "Booting AVD '$AVD' …"
|
||||
setsid nohup "$EMU" -avd "$AVD" -port "$PORT" -gpu host "${ACCEL[@]:-}" \
|
||||
ADB_VENDOR_KEYS="$VKEYS" setsid nohup "$EMU" -avd "$AVD" -port "$PORT" -gpu host "${ACCEL[@]:-}" \
|
||||
-no-snapshot > /tmp/jtube-emu.log 2>&1 < /dev/null &
|
||||
echo "emulator PID $! — log: /tmp/jtube-emu.log"
|
||||
|
||||
|
|
@ -79,21 +97,6 @@ for i in $(seq 1 90); do
|
|||
sleep 5
|
||||
done
|
||||
|
||||
# --- authorize remote adb clients headlessly ---------------------------------
|
||||
# The host console transport is always trusted; use it to whitelist client keys
|
||||
# so `adb connect rutherford:5556` from other machines works without a popup.
|
||||
# Drop extra public keys into /tmp/jtube-adbkeys/ (one per file), e.g. from
|
||||
# Chester: cat ~/.android/adbkey.pub > /tmp/jtube-adbkeys/chester.pub
|
||||
"$ADB" -s "emulator-$PORT" root > /dev/null 2>&1 || true
|
||||
for key_file in "$HOME/.android/adbkey.pub" /tmp/jtube-adbkeys/*.pub; do
|
||||
[ -f "$key_file" ] || continue
|
||||
"$ADB" -s "emulator-$PORT" push "$key_file" "/data/misc/adb/adb_keys" > /dev/null 2>&1 || \
|
||||
"$ADB" -s "emulator-$PORT" shell "cat > /data/misc/adb/adb_keys" < "$key_file" || {
|
||||
echo "could not whitelist $key_file";
|
||||
}
|
||||
done
|
||||
"$ADB" -s "emulator-$PORT" shell "setprop service.adb.tcp.port 5601; stop adbd; start adbd" > /dev/null 2>&1 || true
|
||||
|
||||
# --- the bridge: advertise adbd on the LAN as :5556 ---------------------------
|
||||
if ! ss -tln 2>/dev/null | grep -q ":5556"; then
|
||||
if command -v socat > /dev/null; then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue