diff --git a/tools/benchmark-watch-install.sh b/tools/benchmark-watch-install.sh new file mode 100755 index 0000000..6f83470 --- /dev/null +++ b/tools/benchmark-watch-install.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +# +# Answers MIUI's "Install via USB" dialog while a benchmark run is in flight. +# +# ./tools/benchmark-watch-install.sh # watch for ten minutes, poll every 5 s +# ./tools/benchmark-watch-install.sh --interval 2 # poll more often +# ./tools/benchmark-watch-install.sh --dry-run # report, never tap +# +# Why this exists: macrobenchmark installs its target before measuring it, and on this phone MIUI puts +# that install behind `com.miui.securitycenter/.permcenter.install.AdbInstallActivity`. The test cannot +# answer it itself — `CompilationMode.installPackageFromPaths` builds `pm install -t …` and runs it +# through `Shell.executeScriptCaptureStdout`, so the call blocks until the child exits and no test code +# is running while the dialog is up. This script runs beside the Gradle run instead. +# +# **It never taps blindly.** A dialog is only answered after its Install button has been read off the +# screen and its own bounds are known; if the button is not there, nothing is tapped. That costs a +# `uiautomator dump` per dialog (3-4 s on this device) but it cannot press whatever happens to sit at a +# guessed coordinate. +# +# Measured on the Xiaomi phone (Android 12, MIUI 14), and both numbers matter: +# +# * for an install started from adb, the dialog appears after about 1.7 s and its deny button counts +# down from about ten seconds — so a 5 s poll still leaves time to read the screen and tap; +# * for the install macrobenchmark starts from inside the test, the window is focused for well under +# a second (`13:51:27.70 AdbInstallActivity` → `13:51:28.38 null`), which is shorter than one +# `uiautomator dump`. Those dialogs will not be caught, by this script or by a human. +# +# So this is honest about its limit: it makes adb-driven installs unattended, and it will not rescue a +# reinstall that MIUI refuses instantly. `--interval` and `--wait` are there for tuning per device. +set -euo pipefail + +seconds=600 +interval=5 +wait=10 +dry_run=0 + +while [ $# -gt 0 ]; do + case "$1" in + --seconds) seconds=$2; shift 2 ;; + --interval) interval=$2; shift 2 ;; + --wait) wait=$2; shift 2 ;; + --dry-run) dry_run=1; shift ;; + -h|--help) sed -n '2,26p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; + *) echo "usage: $0 [--seconds N] [--interval N] [--wait N] [--dry-run]" >&2; exit 2 ;; + esac +done + +command -v adb >/dev/null || { echo "benchmark-watch-install: adb is not on PATH" >&2; exit 1; } +command -v python3 >/dev/null || { echo "benchmark-watch-install: python3 is needed to read the UI dump" >&2; exit 1; } + +device_dump=/sdcard/.benchmark-watch.xml +local_dump=$(mktemp) +trap 'rm -f "$local_dump"' EXIT + +# Prints "