#!/usr/bin/env bash # gioui v0.10.x Android bug: after the activity is recreated (relaunch, # config change), the second GioView.onCreateView sends its window-creation # ack on the UI thread with no receiver -> the UI thread deadlocks, the # window never gets an input channel, the app is black and unresponsive. # # This script runs the stock gioui "hello" example on an emulator, recreates # its activity with a uiMode toggle, taps it, and greps logcat. # # scripts/repro_gioui_hang.sh [avd] [apk] (apk omitted: build stock example) # exit 0 = REPRODUCED, 1 = clean, 2 = setup failure set -euo pipefail AVD=${1:-pad_avd} APK=${2:-} SDK=${ANDROID_HOME:-$HOME/android-sdk} export PATH=$PATH:$HOME/go/bin:$SDK/platform-tools:$SDK/build-tools/35.0.0 say() { printf '\n=== %s\n' "$*"; } die() { say "FAIL: $*"; exit 2; } # 1. Build the stock example, if an APK was not supplied if [ -z "$APK" ]; then say "building stock gioui.org/example hello (v0.10.3)" SRC=$(mktemp -d) go mod download gioui.org/example@v0.10.3 cp "$HOME/go/pkg/mod/gioui.org/example@v0.10.3/hello/hello.go" "$SRC/main.go" printf 'module hello\n\ngo 1.23\n\nrequire gioui.org v0.10.3\n' > "$SRC/go.mod" (cd "$SRC" && go mod tidy && gogio -target android -targetsdk 34 -arch amd64 -o "$SRC/hello.apk" .) APK=$SRC/hello.apk fi [ -f "$APK" ] || die "APK not found: $APK" # 2. Emulator: reuse a booted one, else boot $AVD say "emulator ($AVD)" EMU="" for _ in $(seq 1 60); do EMU=$(adb devices | awk '$1 ~ /^emulator-/ {print $1; exit}') [ -n "$EMU" ] && [ "$(adb -s "$EMU" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" = "1" ] && break [ -z "$EMU" ] && emulator -avd "$AVD" -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect >/dev/null 2>&1 & sleep 5 done [ -n "$EMU" ] || die "no booted emulator" say "emulator: $EMU" # 3. Install + launch APPID=localhost.hello # gogio's default app id for module "hello" adb -s "$EMU" install -r "$APK" >/dev/null adb -s "$EMU" shell am start -S -n "$APPID/org.gioui.GioActivity" >/dev/null sleep 5 adb -s "$EMU" shell pidof "$APPID" >/dev/null || die "app did not start" # 4. Recreate the activity, then tap and check logcat. # Toggle to the OPPOSITE uiMode: a no-op toggle recreates nothing. case $(adb -s "$EMU" shell cmd uimode night | tr -d '\r') in *yes*) adb -s "$EMU" shell cmd uimode night no >/dev/null ;; *) adb -s "$EMU" shell cmd uimode night yes >/dev/null ;; esac sleep 5 adb -s "$EMU" logcat -c adb -s "$EMU" shell input tap 540 1200 sleep 2 # 5. Verdict adb -s "$EMU" exec-out screencap -p > /tmp/gioui-hang-repro.png if adb -s "$EMU" logcat -d | grep -q NO_INPUT_CHANNEL; then say "REPRODUCED: window has NO_INPUT_CHANNEL after recreation (screenshot: /tmp/gioui-hang-repro.png)" exit 0 fi say "NOT reproduced: gioui handles re-attach cleanly" exit 1