android-test: headless emulator default for GUI smokes
Default EMULATOR_HEADLESS=1 (-no-window, QT offscreen) while guest GLES still runs via SwiftShader. Auto-start AVD when no adb device; WINDOWED=1 for a host window on laptops.
This commit is contained in:
parent
4b729663b3
commit
0c3019822f
8 changed files with 320 additions and 59 deletions
|
|
@ -156,12 +156,12 @@ STACK=stage ./android-test/run-android-pay-smoke.sh
|
||||||
**User-local emulator (no apt root if SDK already under `$HOME/Android/Sdk`):**
|
**User-local emulator (no apt root if SDK already under `$HOME/Android/Sdk`):**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export ANDROID_HOME=$HOME/Android/Sdk
|
# Default = headless (no host window); guest GLES via SwiftShader.
|
||||||
export PATH=$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools:$PATH
|
# Prefer the helper — same flags smokes use:
|
||||||
# AVD e.g. TalerWallet34 (google_apis x86_64)
|
./android-test/start-android-emulator.sh --wait
|
||||||
emulator -avd TalerWallet34 -no-window -gpu swiftshader_indirect -memory 1536 &
|
|
||||||
adb wait-for-device
|
|
||||||
./android-test/run-android-pay-smoke.sh
|
./android-test/run-android-pay-smoke.sh
|
||||||
|
# Or let smoke auto-start the AVD (AUTO_START_EMULATOR=1).
|
||||||
|
# Windowed laptop: WINDOWED=1 ./android-test/start-android-emulator.sh --wait
|
||||||
```
|
```
|
||||||
|
|
||||||
**Limits (clementine 2026-07-17):** host RAM ~3.7 GiB → emulator often ANRs System UI;
|
**Limits (clementine 2026-07-17):** host RAM ~3.7 GiB → emulator often ANRs System UI;
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,39 @@ Automation can run on hosts that support **Android only**, **GUI tooling only**
|
||||||
| `AUTO_ANDROID` | `0` / `1` | Run Android wallet automation (adb, APK, emulator/device) |
|
| `AUTO_ANDROID` | `0` / `1` | Run Android wallet automation (adb, APK, emulator/device) |
|
||||||
| `AUTO_GUI` | `0` / `1` | Drive **graphical** UI (uiautomator taps, multi-round). If `0`, deep-link/CLI-only install smoke. |
|
| `AUTO_GUI` | `0` / `1` | Drive **graphical** UI (uiautomator taps, multi-round). If `0`, deep-link/CLI-only install smoke. |
|
||||||
| `AUTO_PLATFORM` | `auto` / `linux` / `macos` / `ios` | Host family (optional override) |
|
| `AUTO_PLATFORM` | `auto` / `linux` / `macos` / `ios` | Host family (optional override) |
|
||||||
|
| `EMULATOR_HEADLESS` | **`1` (default)** / `0` | No host window (`-no-window`). Server/CI-safe. |
|
||||||
|
| `WINDOWED` | `0` / `1` | Shortcut: `WINDOWED=1` ⇒ show emulator window (`EMULATOR_HEADLESS=0`) |
|
||||||
|
| `EMULATOR_GPU` | default **`swiftshader_indirect`** | Guest GLES still runs headless (layout/taps/screenshots). Override `host` only if windowed + real GPU. |
|
||||||
|
| `AUTO_START_EMULATOR` | **`1` (default)** / `0` | If no adb device, start AVD via `start-android-emulator.sh --wait` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Headless mode (default)
|
||||||
|
|
||||||
|
**Default for all GUI / pay smokes:** no window on the host. Opening an emulator
|
||||||
|
GUI on servers (or headless CI) is wrong; these scripts therefore start the AVD
|
||||||
|
with **`-no-window`** and still keep **graphics logic** in the guest:
|
||||||
|
|
||||||
|
| Piece | Headless default |
|
||||||
|
|-------|------------------|
|
||||||
|
| Host window | **off** (`-no-window`, `QT_QPA_PLATFORM=offscreen`, no `DISPLAY`) |
|
||||||
|
| Guest GLES | **on** via **SwiftShader** (`-gpu swiftshader_indirect`) |
|
||||||
|
| UI automation | **on** — `uiautomator` dump/tap + `screencap` (no X11 needed) |
|
||||||
|
| Audio / boot anim | off (`-no-audio -no-boot-anim`) |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# explicit (same as default)
|
||||||
|
./start-android-emulator.sh --wait
|
||||||
|
|
||||||
|
# or let smoke auto-start headless AVD when no phone is plugged in
|
||||||
|
STACK=goa ./run-android-gui-smoke.sh
|
||||||
|
|
||||||
|
# laptop: show the emulator window
|
||||||
|
WINDOWED=1 ./start-android-emulator.sh --wait
|
||||||
|
# or: EMULATOR_HEADLESS=0 EMULATOR_GPU=host ./start-android-emulator.sh --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
Shared code: `lib_android_env.sh` + `start-android-emulator.sh`.
|
||||||
|
|
||||||
**Semantics:**
|
**Semantics:**
|
||||||
|
|
||||||
|
|
@ -203,6 +236,8 @@ Scripts **today** implement Android only; they should honour:
|
||||||
| `run-android-gui-smoke.sh` | Multi-round GUI drive |
|
| `run-android-gui-smoke.sh` | Multi-round GUI drive |
|
||||||
| `run-goa-gui-chain.sh` | Multi mint/withdraw/pay (gui-workflows port) |
|
| `run-goa-gui-chain.sh` | Multi mint/withdraw/pay (gui-workflows port) |
|
||||||
| `run-android-build-and-smoke.sh` | Build inference fix branch + smoke (`GUI=1` optional) |
|
| `run-android-build-and-smoke.sh` | Build inference fix branch + smoke (`GUI=1` optional) |
|
||||||
|
| `start-android-emulator.sh` | Start AVD (**headless default**, SwiftShader) |
|
||||||
|
| `lib_android_env.sh` | Flags, PATH, `android_ensure_device` |
|
||||||
| `lib_ui.py` | Dump/tap/ANR helpers |
|
| `lib_ui.py` | Dump/tap/ANR helpers |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -233,6 +268,7 @@ Scripts **today** implement Android only; they should honour:
|
||||||
- [x] Minimalvariante: was geht / was nicht (Beschränkungen)
|
- [x] Minimalvariante: was geht / was nicht (Beschränkungen)
|
||||||
- [x] Two stacks (goa / stage)
|
- [x] Two stacks (goa / stage)
|
||||||
- [x] Flags design (`AUTO_ANDROID` / `AUTO_GUI` / platform defaults)
|
- [x] Flags design (`AUTO_ANDROID` / `AUTO_GUI` / platform defaults)
|
||||||
|
- [x] **Headless emulator default** (`EMULATOR_HEADLESS=1`, SwiftShader)
|
||||||
- [x] Linux default = Android suite only
|
- [x] Linux default = Android suite only
|
||||||
- [x] Inference-branch policy
|
- [x] Inference-branch policy
|
||||||
- [ ] Wrapper enforces flags in every entry script (incremental)
|
- [ ] Wrapper enforces flags in every entry script (incremental)
|
||||||
|
|
|
||||||
|
|
@ -59,5 +59,16 @@ Canonical notes (minimal variant, **flags**, Linux defaults):
|
||||||
| `AUTO_ANDROID` | `1` | Run Android adb/APK automation |
|
| `AUTO_ANDROID` | `1` | Run Android adb/APK automation |
|
||||||
| `AUTO_GUI` | `1` | Graphical uiautomator drive (else deep-link only) |
|
| `AUTO_GUI` | `1` | Graphical uiautomator drive (else deep-link only) |
|
||||||
| `AUTO_PLATFORM` | `auto` → `linux` | Host family; macOS can later pair with iOS out of tree |
|
| `AUTO_PLATFORM` | `auto` → `linux` | Host family; macOS can later pair with iOS out of tree |
|
||||||
|
| **`EMULATOR_HEADLESS`** | **`1`** | **No host window** (`-no-window`). Server-safe. |
|
||||||
|
| `EMULATOR_GPU` | `swiftshader_indirect` | Guest GLES still active for UI/taps/screenshots |
|
||||||
|
| `AUTO_START_EMULATOR` | `1` | Auto-start headless AVD if no adb device |
|
||||||
|
| `WINDOWED` | `0` | `WINDOWED=1` → show emulator window |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# headless AVD only (default path for servers)
|
||||||
|
./start-android-emulator.sh --wait
|
||||||
|
# windowed (laptops)
|
||||||
|
WINDOWED=1 ./start-android-emulator.sh --wait
|
||||||
|
```
|
||||||
|
|
||||||
See also parent [GIT-AUTOMATION-NOTES.md](../GIT-AUTOMATION-NOTES.md).
|
See also parent [GIT-AUTOMATION-NOTES.md](../GIT-AUTOMATION-NOTES.md).
|
||||||
|
|
|
||||||
153
scripts/taler-monitoring/android-test/lib_android_env.sh
Normal file
153
scripts/taler-monitoring/android-test/lib_android_env.sh
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
# shellcheck shell=bash
|
||||||
|
# Shared Android env for GUI / adb smokes.
|
||||||
|
# Source: . "$ROOT/lib_android_env.sh"
|
||||||
|
#
|
||||||
|
# Defaults favour **servers / CI**: no host window (headless emulator), while the
|
||||||
|
# guest still runs GLES via SwiftShader so UI layout / uiautomator work.
|
||||||
|
#
|
||||||
|
# See GUI-AUTOMATION-NOTES.md → Headless mode
|
||||||
|
|
||||||
|
# --- SDK / PATH ---------------------------------------------------------------
|
||||||
|
export ANDROID_HOME="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$HOME/Android/Sdk}}"
|
||||||
|
export ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$ANDROID_HOME}"
|
||||||
|
for d in \
|
||||||
|
"$ANDROID_HOME/platform-tools" \
|
||||||
|
"$ANDROID_HOME/emulator" \
|
||||||
|
"$ANDROID_HOME/cmdline-tools/latest/bin"
|
||||||
|
do
|
||||||
|
[ -d "$d" ] && case ":$PATH:" in *":$d:"*) ;; *) PATH="$d:$PATH" ;; esac
|
||||||
|
done
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
# AVD path (some hosts keep AVDs under ~/.config/.android)
|
||||||
|
if [ -z "${ANDROID_AVD_HOME:-}" ]; then
|
||||||
|
if [ -d "$HOME/.android/avd" ]; then
|
||||||
|
export ANDROID_AVD_HOME="$HOME/.android/avd"
|
||||||
|
elif [ -d "$HOME/.config/.android/avd" ]; then
|
||||||
|
export ANDROID_AVD_HOME="$HOME/.config/.android/avd"
|
||||||
|
# emulator also looks at ~/.android/avd — soft-link if missing
|
||||||
|
if [ ! -e "$HOME/.android/avd" ]; then
|
||||||
|
mkdir -p "$HOME/.android"
|
||||||
|
ln -sfn "$HOME/.config/.android/avd" "$HOME/.android/avd" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Platform / feature flags -------------------------------------------------
|
||||||
|
os=$(uname -s)
|
||||||
|
case "${AUTO_PLATFORM:-auto}" in
|
||||||
|
auto)
|
||||||
|
case "$os" in
|
||||||
|
Linux) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
||||||
|
Darwin) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
||||||
|
*) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
linux|macos) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
||||||
|
*) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Headless = default (no X11/Wayland window on host). GUI *logic* still runs in
|
||||||
|
# the guest via software GPU. Set EMULATOR_HEADLESS=0 or WINDOWED=1 for a window.
|
||||||
|
: "${EMULATOR_HEADLESS:=1}"
|
||||||
|
if [ "${WINDOWED:-0}" = "1" ]; then
|
||||||
|
EMULATOR_HEADLESS=0
|
||||||
|
fi
|
||||||
|
export EMULATOR_HEADLESS
|
||||||
|
|
||||||
|
# Soft GLES for headless; windowed may override to host/auto if set by user.
|
||||||
|
if [ "${EMULATOR_HEADLESS}" = "1" ]; then
|
||||||
|
: "${EMULATOR_GPU:=swiftshader_indirect}"
|
||||||
|
else
|
||||||
|
: "${EMULATOR_GPU:=swiftshader_indirect}" # still safe default; host GPU: EMULATOR_GPU=host
|
||||||
|
fi
|
||||||
|
export EMULATOR_GPU
|
||||||
|
|
||||||
|
: "${EMULATOR_AVD:=TalerWallet34}"
|
||||||
|
: "${EMULATOR_MEMORY:=1536}"
|
||||||
|
: "${EMULATOR_CORES:=2}"
|
||||||
|
# If no adb device: start headless AVD (0 = require phone/manual emulator)
|
||||||
|
: "${AUTO_START_EMULATOR:=1}"
|
||||||
|
: "${EMULATOR_BOOT_TIMEOUT:=180}"
|
||||||
|
: "${EMULATOR_LOG:=/tmp/taler-android-emulator.log}"
|
||||||
|
|
||||||
|
android_adb_serial() {
|
||||||
|
adb devices 2>/dev/null | awk '/\tdevice$/{print $1; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
android_has_device() {
|
||||||
|
[ -n "$(android_adb_serial)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build emulator argv for current headless/windowed mode.
|
||||||
|
# Prints args; caller exec/nohup.
|
||||||
|
android_emulator_args() {
|
||||||
|
local avd="${1:-$EMULATOR_AVD}"
|
||||||
|
local args=( -avd "$avd" -gpu "$EMULATOR_GPU" -no-audio -no-boot-anim )
|
||||||
|
if [ "${EMULATOR_HEADLESS}" = "1" ]; then
|
||||||
|
args+=( -no-window )
|
||||||
|
# Avoid Qt trying to open a display on servers
|
||||||
|
export QT_QPA_PLATFORM="${QT_QPA_PLATFORM:-offscreen}"
|
||||||
|
fi
|
||||||
|
if [ -n "${EMULATOR_MEMORY:-}" ]; then
|
||||||
|
args+=( -memory "$EMULATOR_MEMORY" )
|
||||||
|
fi
|
||||||
|
if [ -n "${EMULATOR_CORES:-}" ]; then
|
||||||
|
args+=( -cores "$EMULATOR_CORES" )
|
||||||
|
fi
|
||||||
|
# extra user flags
|
||||||
|
# shellcheck disable=SC2206
|
||||||
|
if [ -n "${EMULATOR_EXTRA_ARGS:-}" ]; then
|
||||||
|
# intentional word-split for extra flags
|
||||||
|
args+=( ${EMULATOR_EXTRA_ARGS} )
|
||||||
|
fi
|
||||||
|
printf '%s\n' "${args[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure an adb "device" is online. Optionally start headless emulator.
|
||||||
|
# Sets SERIAL / ANDROID_SERIAL on success. Returns 0 ok, 3 no device.
|
||||||
|
android_ensure_device() {
|
||||||
|
local serial
|
||||||
|
serial="${SERIAL:-${ANDROID_SERIAL:-}}"
|
||||||
|
if [ -z "$serial" ]; then
|
||||||
|
serial=$(android_adb_serial || true)
|
||||||
|
fi
|
||||||
|
if [ -n "$serial" ]; then
|
||||||
|
SERIAL="$serial"
|
||||||
|
export ANDROID_SERIAL="$serial"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${AUTO_START_EMULATOR}" != "1" ]; then
|
||||||
|
echo "no adb device (AUTO_START_EMULATOR=0 — plug phone or start AVD manually)" >&2
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v emulator >/dev/null 2>&1; then
|
||||||
|
echo "no adb device and emulator binary missing under $ANDROID_HOME" >&2
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "no adb device → starting AVD ${EMULATOR_AVD} (headless=${EMULATOR_HEADLESS} gpu=${EMULATOR_GPU})"
|
||||||
|
local starter
|
||||||
|
starter="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/start-android-emulator.sh"
|
||||||
|
if [ ! -x "$starter" ]; then
|
||||||
|
echo "missing $starter" >&2
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
EMULATOR_HEADLESS="$EMULATOR_HEADLESS" EMULATOR_GPU="$EMULATOR_GPU" \
|
||||||
|
EMULATOR_AVD="$EMULATOR_AVD" EMULATOR_MEMORY="$EMULATOR_MEMORY" \
|
||||||
|
EMULATOR_CORES="$EMULATOR_CORES" EMULATOR_LOG="$EMULATOR_LOG" \
|
||||||
|
EMULATOR_BOOT_TIMEOUT="$EMULATOR_BOOT_TIMEOUT" \
|
||||||
|
"$starter" --wait || return 3
|
||||||
|
|
||||||
|
serial=$(android_adb_serial || true)
|
||||||
|
if [ -z "$serial" ]; then
|
||||||
|
echo "emulator started but no adb device yet — see $EMULATOR_LOG" >&2
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
SERIAL="$serial"
|
||||||
|
export ANDROID_SERIAL="$serial"
|
||||||
|
echo "device: $SERIAL (headless=${EMULATOR_HEADLESS})"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
@ -12,14 +12,9 @@
|
||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
# shellcheck source=lib_android_env.sh
|
||||||
|
. "$ROOT/lib_android_env.sh"
|
||||||
|
|
||||||
# Platform flags (GUI-AUTOMATION-NOTES.md). Linux → Android only.
|
|
||||||
os=$(uname -s)
|
|
||||||
case "${AUTO_PLATFORM:-auto}" in
|
|
||||||
auto) case "$os" in Linux|Darwin) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;; *) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;; esac ;;
|
|
||||||
linux|macos) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
|
||||||
*) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;;
|
|
||||||
esac
|
|
||||||
[ "${AUTO_ANDROID}" = "1" ] || { echo "skipped: AUTO_ANDROID=${AUTO_ANDROID}"; exit 0; }
|
[ "${AUTO_ANDROID}" = "1" ] || { echo "skipped: AUTO_ANDROID=${AUTO_ANDROID}"; exit 0; }
|
||||||
if [ "${AUTO_GUI}" != "1" ]; then
|
if [ "${AUTO_GUI}" != "1" ]; then
|
||||||
echo "AUTO_GUI=0 → deep-link smoke only"
|
echo "AUTO_GUI=0 → deep-link smoke only"
|
||||||
|
|
@ -46,17 +41,12 @@ STACK="${STACK:-auto}"
|
||||||
SERIAL="${SERIAL:-}"
|
SERIAL="${SERIAL:-}"
|
||||||
mkdir -p "$OUT_DIR"
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
if ! command -v adb >/dev/null 2>&1; then
|
|
||||||
[ -x "$HOME/Android/Sdk/platform-tools/adb" ] && export PATH="$HOME/Android/Sdk/platform-tools:$PATH"
|
|
||||||
fi
|
|
||||||
command -v adb >/dev/null || { echo "adb missing" >&2; exit 2; }
|
command -v adb >/dev/null || { echo "adb missing" >&2; exit 2; }
|
||||||
|
|
||||||
if [ -z "$SERIAL" ]; then
|
# Headless default: no host window; guest GLES via SwiftShader (uiautomator).
|
||||||
SERIAL=$(adb devices | awk '/\tdevice$/{print $1; exit}')
|
android_ensure_device || { echo "no adb device (try ./start-android-emulator.sh --wait)" >&2; exit 3; }
|
||||||
fi
|
|
||||||
[ -n "$SERIAL" ] || { echo "no adb device" >&2; exit 3; }
|
|
||||||
ADB=(adb -s "$SERIAL")
|
ADB=(adb -s "$SERIAL")
|
||||||
echo "device: $SERIAL mode: GUI (uiautomator)"
|
echo "device: $SERIAL mode: GUI (uiautomator) headless=${EMULATOR_HEADLESS} gpu=${EMULATOR_GPU}"
|
||||||
|
|
||||||
case "$STACK" in
|
case "$STACK" in
|
||||||
auto)
|
auto)
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,9 @@
|
||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
# shellcheck source=lib_android_env.sh
|
||||||
|
. "$ROOT/lib_android_env.sh"
|
||||||
|
|
||||||
# Platform flags (see GUI-AUTOMATION-NOTES.md). Linux default: Android only.
|
|
||||||
os=$(uname -s)
|
|
||||||
case "${AUTO_PLATFORM:-auto}" in
|
|
||||||
auto) case "$os" in Linux) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;; Darwin) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;; *) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;; esac ;;
|
|
||||||
linux) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
|
||||||
macos) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
|
||||||
*) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;;
|
|
||||||
esac
|
|
||||||
if [ "${AUTO_ANDROID}" != "1" ]; then
|
if [ "${AUTO_ANDROID}" != "1" ]; then
|
||||||
echo "skipped: AUTO_ANDROID=${AUTO_ANDROID} (platform flags — see GUI-AUTOMATION-NOTES.md)"
|
echo "skipped: AUTO_ANDROID=${AUTO_ANDROID} (platform flags — see GUI-AUTOMATION-NOTES.md)"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
@ -46,28 +40,23 @@ OUT_DIR="${OUT_DIR:-$ROOT/out}"
|
||||||
mkdir -p "$APK_DIR" "$OUT_DIR"
|
mkdir -p "$APK_DIR" "$OUT_DIR"
|
||||||
|
|
||||||
if ! command -v adb >/dev/null 2>&1; then
|
if ! command -v adb >/dev/null 2>&1; then
|
||||||
if [ -x "$HOME/Android/Sdk/platform-tools/adb" ]; then
|
|
||||||
export PATH="$HOME/Android/Sdk/platform-tools:$PATH"
|
|
||||||
else
|
|
||||||
echo "adb missing — install android-tools-adb or user SDK platform-tools" >&2
|
echo "adb missing — install android-tools-adb or user SDK platform-tools" >&2
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$SERIAL" ]; then
|
# Default: headless AVD (no host window). WINDOWED=1 / EMULATOR_HEADLESS=0 for UI.
|
||||||
SERIAL=$(adb devices | awk '/\tdevice$/{print $1; exit}')
|
if ! android_ensure_device; then
|
||||||
fi
|
cat >&2 <<EOF
|
||||||
if [ -z "$SERIAL" ]; then
|
No adb device. Options:
|
||||||
cat >&2 <<'EOF'
|
|
||||||
No adb device. Options (no root for user-local emulator if /dev/kvm is usable):
|
|
||||||
1) Plug phone with USB debugging
|
1) Plug phone with USB debugging
|
||||||
2) Start AVD: $HOME/Android/Sdk/emulator/emulator -avd TalerWallet34 -no-window
|
2) Headless AVD (default): $ROOT/start-android-emulator.sh --wait
|
||||||
3) Then re-run this script
|
3) Windowed AVD: WINDOWED=1 $ROOT/start-android-emulator.sh --wait
|
||||||
|
4) AUTO_START_EMULATOR=0 disables auto-start from this smoke
|
||||||
EOF
|
EOF
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
ADB=(adb -s "$SERIAL")
|
ADB=(adb -s "$SERIAL")
|
||||||
echo "device: $SERIAL"
|
echo "device: $SERIAL emulator_headless=${EMULATOR_HEADLESS} gpu=${EMULATOR_GPU}"
|
||||||
|
|
||||||
# Resolve stack endpoints
|
# Resolve stack endpoints
|
||||||
case "$STACK" in
|
case "$STACK" in
|
||||||
|
|
|
||||||
|
|
@ -37,19 +37,12 @@ step() { echo; echo "======== $* ========"; }
|
||||||
info() { echo " $*"; }
|
info() { echo " $*"; }
|
||||||
pause() { sleep "${1:-${PAUSE:-0.8}}"; }
|
pause() { sleep "${1:-${PAUSE:-0.8}}"; }
|
||||||
|
|
||||||
# Platform flags — Linux default Android+GUI (see GUI-AUTOMATION-NOTES.md)
|
# Platform flags + headless emulator defaults (see GUI-AUTOMATION-NOTES.md)
|
||||||
os=$(uname -s)
|
# shellcheck source=lib_android_env.sh
|
||||||
case "${AUTO_PLATFORM:-auto}" in
|
. "$ROOT/lib_android_env.sh"
|
||||||
auto) case "$os" in Linux|Darwin) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;; *) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;; esac ;;
|
|
||||||
linux|macos) : "${AUTO_ANDROID:=1}"; : "${AUTO_GUI:=1}" ;;
|
|
||||||
*) : "${AUTO_ANDROID:=0}"; : "${AUTO_GUI:=0}" ;;
|
|
||||||
esac
|
|
||||||
[ "${AUTO_ANDROID}" = "1" ] || { echo "skipped: AUTO_ANDROID=${AUTO_ANDROID}"; exit 0; }
|
[ "${AUTO_ANDROID}" = "1" ] || { echo "skipped: AUTO_ANDROID=${AUTO_ANDROID}"; exit 0; }
|
||||||
[ "${AUTO_GUI}" = "1" ] || { echo "skipped: AUTO_GUI=${AUTO_GUI} (chain is GUI)"; exit 0; }
|
[ "${AUTO_GUI}" = "1" ] || { echo "skipped: AUTO_GUI=${AUTO_GUI} (chain is GUI)"; exit 0; }
|
||||||
|
|
||||||
if ! command -v adb >/dev/null 2>&1; then
|
|
||||||
[ -x "$HOME/Android/Sdk/platform-tools/adb" ] && export PATH="$HOME/Android/Sdk/platform-tools:$PATH"
|
|
||||||
fi
|
|
||||||
command -v adb >/dev/null || die "adb not found"
|
command -v adb >/dev/null || die "adb not found"
|
||||||
command -v python3 >/dev/null || die "python3 required"
|
command -v python3 >/dev/null || die "python3 required"
|
||||||
|
|
||||||
|
|
@ -112,12 +105,11 @@ if [[ ! -f "${EXP_PW_FILE:-}" && "$STACK" = "stage" ]]; then
|
||||||
fi
|
fi
|
||||||
[[ -n "${EXP_PW_FILE:-}" && -f "$EXP_PW_FILE" ]] || die "set EXP_PW_FILE (explorer password)"
|
[[ -n "${EXP_PW_FILE:-}" && -f "$EXP_PW_FILE" ]] || die "set EXP_PW_FILE (explorer password)"
|
||||||
|
|
||||||
if [[ -z "${ANDROID_SERIAL:-}" ]]; then
|
# Headless AVD by default (no host window). WINDOWED=1 for a visible emulator.
|
||||||
n=$(adb devices | awk 'NR>1 && $2=="device"{c++} END{print c+0}')
|
SERIAL="${SERIAL:-${ANDROID_SERIAL:-}}"
|
||||||
[[ "$n" -ge 1 ]] || die "no adb device (start emulator or plug phone)"
|
android_ensure_device || die "no adb device (./start-android-emulator.sh --wait)"
|
||||||
export ANDROID_SERIAL=$(adb devices | awk 'NR>1 && $2=="device"{print $1; exit}')
|
export ANDROID_SERIAL="$SERIAL"
|
||||||
fi
|
info "ANDROID_SERIAL=$ANDROID_SERIAL STACK=$STACK PKG=$PKG SHOTDIR=$SHOTDIR headless=$EMULATOR_HEADLESS gpu=$EMULATOR_GPU"
|
||||||
info "ANDROID_SERIAL=$ANDROID_SERIAL STACK=$STACK PKG=$PKG SHOTDIR=$SHOTDIR"
|
|
||||||
ADB=(adb -s "$ANDROID_SERIAL")
|
ADB=(adb -s "$ANDROID_SERIAL")
|
||||||
|
|
||||||
adb_sh() { "${ADB[@]}" shell "$@"; }
|
adb_sh() { "${ADB[@]}" shell "$@"; }
|
||||||
|
|
|
||||||
90
scripts/taler-monitoring/android-test/start-android-emulator.sh
Executable file
90
scripts/taler-monitoring/android-test/start-android-emulator.sh
Executable file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Start the Taler Android AVD. **Default = headless** (no host window).
|
||||||
|
# Guest GLES still runs via SwiftShader so uiautomator / screenshots work.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./start-android-emulator.sh # headless, background
|
||||||
|
# ./start-android-emulator.sh --wait # headless + wait for boot
|
||||||
|
# ./start-android-emulator.sh --windowed # show emulator window
|
||||||
|
# EMULATOR_HEADLESS=0 ./start-android-emulator.sh
|
||||||
|
# EMULATOR_GPU=host WINDOWED=1 ./start-android-emulator.sh
|
||||||
|
#
|
||||||
|
# Env: EMULATOR_AVD EMULATOR_MEMORY EMULATOR_CORES EMULATOR_GPU
|
||||||
|
# EMULATOR_HEADLESS EMULATOR_LOG EMULATOR_BOOT_TIMEOUT EMULATOR_EXTRA_ARGS
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
# shellcheck source=lib_android_env.sh
|
||||||
|
. "$ROOT/lib_android_env.sh"
|
||||||
|
|
||||||
|
WAIT=0
|
||||||
|
for a in "$@"; do
|
||||||
|
case "$a" in
|
||||||
|
--wait) WAIT=1 ;;
|
||||||
|
--windowed| --gui) EMULATOR_HEADLESS=0; export EMULATOR_HEADLESS ;;
|
||||||
|
--headless) EMULATOR_HEADLESS=1; export EMULATOR_HEADLESS ;;
|
||||||
|
-h|--help)
|
||||||
|
sed -n '2,18p' "$0"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
command -v emulator >/dev/null || {
|
||||||
|
echo "emulator not found (ANDROID_HOME=$ANDROID_HOME)" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
command -v adb >/dev/null || {
|
||||||
|
echo "adb not found" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Already booted?
|
||||||
|
if serial=$(android_adb_serial); [ -n "$serial" ]; then
|
||||||
|
boot=$(adb -s "$serial" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
|
||||||
|
if [ "$boot" = "1" ]; then
|
||||||
|
echo "already running: $serial (boot_completed=1) — headless default still applies to *new* starts"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Avoid pkill patterns that match this wrapper's argv (self-kill).
|
||||||
|
mapfile -t EMU_ARGS < <(android_emulator_args "$EMULATOR_AVD")
|
||||||
|
echo "starting: emulator ${EMU_ARGS[*]}"
|
||||||
|
echo " headless=$EMULATOR_HEADLESS gpu=$EMULATOR_GPU log=$EMULATOR_LOG"
|
||||||
|
|
||||||
|
if [ "${EMULATOR_HEADLESS}" = "1" ]; then
|
||||||
|
export QT_QPA_PLATFORM="${QT_QPA_PLATFORM:-offscreen}"
|
||||||
|
# Do not require DISPLAY
|
||||||
|
unset DISPLAY || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$EMULATOR_LOG")"
|
||||||
|
# Background; do not use pkill -f emulator from callers matching full cmdline
|
||||||
|
nohup emulator "${EMU_ARGS[@]}" >"$EMULATOR_LOG" 2>&1 &
|
||||||
|
echo "emulator pid=$! log=$EMULATOR_LOG"
|
||||||
|
|
||||||
|
if [ "$WAIT" != "1" ]; then
|
||||||
|
echo "not waiting (pass --wait for boot). adb devices when ready."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "waiting for boot (timeout ${EMULATOR_BOOT_TIMEOUT}s)…"
|
||||||
|
deadline=$((SECONDS + EMULATOR_BOOT_TIMEOUT))
|
||||||
|
serial=""
|
||||||
|
while (( SECONDS < deadline )); do
|
||||||
|
adb wait-for-device 2>/dev/null || true
|
||||||
|
serial=$(android_adb_serial || true)
|
||||||
|
if [ -n "$serial" ]; then
|
||||||
|
boot=$(adb -s "$serial" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
|
||||||
|
if [ "$boot" = "1" ]; then
|
||||||
|
echo "BOOT_OK serial=$serial headless=$EMULATOR_HEADLESS gpu=$EMULATOR_GPU"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "boot timeout — last log:" >&2
|
||||||
|
tail -30 "$EMULATOR_LOG" >&2 || true
|
||||||
|
exit 3
|
||||||
Loading…
Add table
Add a link
Reference in a new issue