Streamline repro_gioui_hang.sh
Shorter header (bug in two lines), one combined emulator wait loop, am start -S replaces the separate force-stop, fewer section comments. Same behavior: verified REPRODUCED (exit 0) on the emulator.
This commit is contained in:
parent
8bb5038cdb
commit
348895eb7e
|
|
@ -1,89 +1,57 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Reproduce the gioui Android activity-recreation hang with a STOCK gioui
|
# gioui v0.10.x Android bug: after the activity is recreated (relaunch,
|
||||||
# example app (the "hello" example from gioui.org/example).
|
# 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.
|
||||||
#
|
#
|
||||||
# What it does:
|
# This script runs the stock gioui "hello" example on an emulator, recreates
|
||||||
# 1. Builds gioui.org/example's hello app (unmodified) with gogio.
|
# its activity with a uiMode toggle, taps it, and greps logcat.
|
||||||
# 2. Installs it on an emulator (boots one if needed).
|
|
||||||
# 3. Recreates the activity via `cmd uimode night yes` (uiMode is not in
|
|
||||||
# gioui's configChanges mask, so Android destroys/recreates the
|
|
||||||
# activity in the same process).
|
|
||||||
# 4. Taps the app and checks logcat for NO_INPUT_CHANNEL.
|
|
||||||
#
|
#
|
||||||
# The bug (gioui v0.10.x, app/os_android.go onCreateView): on re-attach the
|
# scripts/repro_gioui_hang.sh [avd] [apk] (apk omitted: build stock example)
|
||||||
# second onCreateView sends the window-creation ack
|
# exit 0 = REPRODUCED, 1 = clean, 2 = setup failure
|
||||||
# (mainWindow.windows <- struct{}{}) on the UI thread, but its only
|
|
||||||
# receiver (newWindow in Window.init) never re-runs on Android — the driver
|
|
||||||
# is never reset, so w.Event() never returns to re-init. The UI thread
|
|
||||||
# blocks forever, the activity never attaches an input channel, and the app
|
|
||||||
# is black and unresponsive (process still alive).
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# scripts/repro_gioui_hang.sh [avd-name] [path-to-apk]
|
|
||||||
#
|
|
||||||
# Exit codes: 0 = bug REPRODUCED, 1 = not reproduced, 2 = setup failure.
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
AVD=${1:-pad_avd}
|
AVD=${1:-pad_avd}
|
||||||
APK=${2:-}
|
APK=${2:-}
|
||||||
SDK=${ANDROID_HOME:-$HOME/android-sdk}
|
SDK=${ANDROID_HOME:-$HOME/android-sdk}
|
||||||
export PATH=$PATH:$HOME/go/bin:$SDK/platform-tools:$SDK/build-tools/35.0.0
|
export PATH=$PATH:$HOME/go/bin:$SDK/platform-tools:$SDK/build-tools/35.0.0
|
||||||
|
|
||||||
say() { printf '\n=== %s\n' "$*"; }
|
say() { printf '\n=== %s\n' "$*"; }
|
||||||
die() { say "FAIL: $*"; exit 2; }
|
die() { say "FAIL: $*"; exit 2; }
|
||||||
|
|
||||||
# --- 1. Build the stock hello example, unless an APK was supplied ---------
|
# 1. Build the stock example, if an APK was not supplied
|
||||||
if [ -z "$APK" ]; then
|
if [ -z "$APK" ]; then
|
||||||
|
say "building stock gioui.org/example hello (v0.10.3)"
|
||||||
SRC=$(mktemp -d)
|
SRC=$(mktemp -d)
|
||||||
trap 'rm -rf "$SRC"' EXIT
|
|
||||||
say "building stock gioui.org/example hello app (v0.10.3)"
|
|
||||||
go mod download gioui.org/example@v0.10.3
|
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"
|
cp "$HOME/go/pkg/mod/gioui.org/example@v0.10.3/hello/hello.go" "$SRC/main.go"
|
||||||
cat > "$SRC/go.mod" <<'EOF'
|
printf 'module hello\n\ngo 1.23\n\nrequire gioui.org v0.10.3\n' > "$SRC/go.mod"
|
||||||
module hello
|
(cd "$SRC" && go mod tidy && gogio -target android -targetsdk 34 -arch amd64 -o "$SRC/hello.apk" .)
|
||||||
|
APK=$SRC/hello.apk
|
||||||
go 1.23
|
|
||||||
|
|
||||||
require gioui.org v0.10.3
|
|
||||||
EOF
|
|
||||||
(cd "$SRC" && go mod tidy && gogio -target android -targetsdk 34 -arch amd64 -o /tmp/hello-gioui-repro.apk .)
|
|
||||||
APK=/tmp/hello-gioui-repro.apk
|
|
||||||
fi
|
fi
|
||||||
[ -f "$APK" ] || die "APK not found: $APK"
|
[ -f "$APK" ] || die "APK not found: $APK"
|
||||||
|
|
||||||
# --- 2. Emulator: reuse a booted one or start $AVD ------------------------
|
# 2. Emulator: reuse a booted one, else boot $AVD
|
||||||
say "waiting for emulator (avd $AVD)"
|
say "emulator ($AVD)"
|
||||||
EMU=""
|
EMU=""
|
||||||
for _ in $(seq 1 60); do
|
for _ in $(seq 1 60); do
|
||||||
EMU=$(adb devices | awk '$1 ~ /^emulator-/ {print $1; exit}')
|
EMU=$(adb devices | awk '$1 ~ /^emulator-/ {print $1; exit}')
|
||||||
[ -n "$EMU" ] && break
|
[ -n "$EMU" ] && [ "$(adb -s "$EMU" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" = "1" ] && break
|
||||||
emulator -avd "$AVD" -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect >/dev/null 2>&1 &
|
[ -z "$EMU" ] && emulator -avd "$AVD" -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect >/dev/null 2>&1 &
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
[ -n "$EMU" ] || die "no emulator available"
|
[ -n "$EMU" ] || die "no booted emulator"
|
||||||
for _ in $(seq 1 60); do
|
|
||||||
bc=$(adb -s "$EMU" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')
|
|
||||||
[ "$bc" = "1" ] && break
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
[ "$(adb -s "$EMU" shell getprop sys.boot_completed | tr -d '\r')" = "1" ] || die "emulator did not boot"
|
|
||||||
say "emulator: $EMU"
|
say "emulator: $EMU"
|
||||||
|
|
||||||
# --- 3. Install + launch ---------------------------------------------------
|
# 3. Install + launch
|
||||||
APPID=localhost.hello # gogio's default app id for module "hello"
|
APPID=localhost.hello # gogio's default app id for module "hello"
|
||||||
adb -s "$EMU" install -r "$APK" >/dev/null
|
adb -s "$EMU" install -r "$APK" >/dev/null
|
||||||
adb -s "$EMU" shell am force-stop "$APPID" >/dev/null 2>&1 || true
|
adb -s "$EMU" shell am start -S -n "$APPID/org.gioui.GioActivity" >/dev/null
|
||||||
adb -s "$EMU" logcat -c
|
|
||||||
adb -s "$EMU" shell am start -n "$APPID/org.gioui.GioActivity" >/dev/null
|
|
||||||
sleep 5
|
sleep 5
|
||||||
adb -s "$EMU" shell pidof "$APPID" >/dev/null || die "app did not start"
|
adb -s "$EMU" shell pidof "$APPID" >/dev/null || die "app did not start"
|
||||||
say "baseline: app running"
|
|
||||||
|
|
||||||
# --- 4. Recreate the activity ----------------------------------------------
|
# 4. Recreate the activity, then tap and check logcat.
|
||||||
# uiMode is not in gioui's configChanges mask -> Android recreates the
|
# Toggle to the OPPOSITE uiMode: a no-op toggle recreates nothing.
|
||||||
# activity. Force a real state change (a no-op toggle recreates nothing).
|
case $(adb -s "$EMU" shell cmd uimode night | tr -d '\r') in
|
||||||
cur=$(adb -s "$EMU" shell cmd uimode night | tr -d '\r') # "Night mode: yes/no"
|
|
||||||
case $cur in
|
|
||||||
*yes*) adb -s "$EMU" shell cmd uimode night no >/dev/null ;;
|
*yes*) adb -s "$EMU" shell cmd uimode night no >/dev/null ;;
|
||||||
*) adb -s "$EMU" shell cmd uimode night yes >/dev/null ;;
|
*) adb -s "$EMU" shell cmd uimode night yes >/dev/null ;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -92,11 +60,11 @@ adb -s "$EMU" logcat -c
|
||||||
adb -s "$EMU" shell input tap 540 1200
|
adb -s "$EMU" shell input tap 540 1200
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# --- 5. Verdict -------------------------------------------------------------
|
# 5. Verdict
|
||||||
adb -s "$EMU" exec-out screencap -p > /tmp/gioui-hang-repro.png
|
adb -s "$EMU" exec-out screencap -p > /tmp/gioui-hang-repro.png
|
||||||
if adb -s "$EMU" logcat -d | grep -q NO_INPUT_CHANNEL; then
|
if adb -s "$EMU" logcat -d | grep -q NO_INPUT_CHANNEL; then
|
||||||
say "REPRODUCED: activity recreation left the window with NO_INPUT_CHANNEL (see /tmp/gioui-hang-repro.png)"
|
say "REPRODUCED: window has NO_INPUT_CHANNEL after recreation (screenshot: /tmp/gioui-hang-repro.png)"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
say "NOT reproduced: no NO_INPUT_CHANNEL after recreation (gioui handles re-attach correctly)"
|
say "NOT reproduced: gioui handles re-attach cleanly"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user