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.
126 lines
No EOL
4.5 KiB
Bash
Executable file
126 lines
No EOL
4.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# start-emulator.sh — boot the JTube TV test emulator on the HOST (not inside the
|
|
# 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
|
|
# reachable from anywhere as:
|
|
#
|
|
# adb connect rutherford:5556 && scrcpy -s rutherford:5556
|
|
#
|
|
# An RSA authorization popup appears on the emulator window on first connect —
|
|
# click "Always allow"/OK.
|
|
set -euo pipefail
|
|
|
|
SDK="${ANDROID_SDK_ROOT:-$HOME/Android/Sdk}"
|
|
EMU="$SDK/emulator/emulator"
|
|
ADB="$SDK/platform-tools/adb"
|
|
SDKM="$SDK/cmdline-tools/latest/bin/sdkmanager"
|
|
AVDM="$SDK/cmdline-tools/latest/bin/avdmanager"
|
|
AVD="${1:-jtubesc}"
|
|
PORT=5600
|
|
IMAGE="system-images;android-36;android-tv;x86_64"
|
|
|
|
[ -x "$EMU" ] || { echo "emulator not found at $EMU — install Android SDK cmdline-tools first"; exit 1; }
|
|
|
|
# --- bootstrap: java, system image, AVD -------------------------------------
|
|
if ! command -v java >/dev/null; then
|
|
echo "no java on PATH — required by sdkmanager/AVD tools"
|
|
echo " install it (Arch): sudo pacman -S --noconfirm jdk21-openjdk"
|
|
echo " then re-run this script"
|
|
exit 1
|
|
fi
|
|
|
|
if ! "$SDKM" --list_installed 2>/dev/null | grep -q "$IMAGE"; then
|
|
echo "installing $IMAGE (~1.5 GB, once)…"
|
|
yes | "$SDKM" "$IMAGE" > /dev/null
|
|
echo "installed"
|
|
fi
|
|
|
|
if [ ! -f "$HOME/.android/avd/$AVD.ini" ]; then
|
|
echo "creating AVD '$AVD'…"
|
|
echo no | "$AVDM" create avd -n "$AVD" -k "$IMAGE" -d tv_1080p > /dev/null
|
|
fi
|
|
|
|
# --- free stale emulator instances holding our port --------------------------
|
|
for pid in $(ps aux | awk '/[q]emu-system-x86_64/ {print $2}' 2>/dev/null); do
|
|
if tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null | grep -q "\-port $PORT"; then
|
|
echo "Killing stale emulator pid $pid"
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
fi
|
|
done
|
|
sleep 1
|
|
|
|
MODE="${JTUBE_EMU_MODE:-headless}" # headless (default) | windowed
|
|
WINDOWED=1
|
|
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 (default; JTUBE_EMU_MODE=windowed for a window) — no emulator window"
|
|
fi
|
|
if [ -e /dev/kvm ]; then
|
|
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' …"
|
|
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"
|
|
|
|
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; }
|
|
sleep 5
|
|
done
|
|
|
|
# --- 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
|
|
setsid nohup socat TCP-LISTEN:5556,bind=0.0.0.0,fork,reuseaddr TCP:127.0.0.1:$((PORT+1)) > /tmp/jtube-socat.log 2>&1 < /dev/null &
|
|
echo "socat bridge listening on :5556 (pid $!)"
|
|
else
|
|
echo "install socat for the remote bridge: sudo pacman -S --noconfirm socat"
|
|
fi
|
|
fi
|
|
|
|
# Keep the JTube TV app current + running so scrcpy lands on it.
|
|
APK="$HOME/Projects/jtube-tv/app/build/outputs/apk/debug/app-debug.apk"
|
|
if [ -f "$APK" ]; then
|
|
echo "Installing JTube TV…"
|
|
"$ADB" -s "emulator-$PORT" install -r "$APK" >/dev/null && echo "installed"
|
|
"$ADB" -s "emulator-$PORT" shell am start -n net.jeena.jtubetv/.MainActivity && echo "app started"
|
|
fi
|
|
|
|
cat <<EOF
|
|
|
|
Ready. From any machine that can reach rutherford:
|
|
|
|
adb connect rutherford:5556
|
|
scrcpy -s rutherford:5556
|
|
|
|
If scrcpy says "unauthorized", click the RSA dialog on the emulator window.
|
|
EOF |