SkQP: new docker test code

`tools/skqp/docker_run_apk.sh` executes SkQP tests in an emulator

`tools/skqp/run_apk.sh` is used by `docker_run_apk.sh` and
`tools/skqp/test_apk.sh` to factor out common code.

Also: `bin/sysopen` now pipes output to `/dev/null` and doesn't block.

TODO: harmonize with test code executed by bots in `infra/skqp/`.

No-Try: true
Change-Id: Ia212a84565ff52279a845e20372a0ad7cc0726a4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/209401
Reviewed-by: Hal Canary <halcanary@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
diff --git a/bin/sysopen b/bin/sysopen
index f104ab9..84100c2 100755
--- a/bin/sysopen
+++ b/bin/sysopen
@@ -7,14 +7,18 @@
 import subprocess
 import sys
 
+def spawn(cmd):
+  with open(os.devnull, 'w') as o:
+    subprocess.Popen(cmd, stdout=o, stderr=o)
+
 def sysopen(arg):
   plat = sys.platform
   if plat.startswith('darwin'):
-    subprocess.call(["open", arg])
+    spawn(["open", arg])
   elif plat.startswith('win'):
     os.startfile(arg)
   else:
-    subprocess.call(["xdg-open", arg])
+    spawn(["xdg-open", arg])
 
 if __name__ == '__main__':
   for a in sys.argv[1:]:
diff --git a/tools/skqp/docker_run_apk.sh b/tools/skqp/docker_run_apk.sh
new file mode 100755
index 0000000..5c54bf4
--- /dev/null
+++ b/tools/skqp/docker_run_apk.sh
@@ -0,0 +1,43 @@
+#! /bin/sh
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Notes:
+#
+#   You may need to run as root for docker permissions.
+#
+#   The SKQP_ARGS environment variable affects this script.
+
+if ! [ -f "$1" ] ; then
+  echo "Usage:  $0 SKQP_APK_FILE_PATH" >&2
+  exit 1
+fi
+
+APK_DIR="$(cd "$(dirname "$1")"; pwd)"
+APK_FILE="$(basename "$1")"
+DST="$(mktemp -d "${TMPDIR:-/tmp}/skqp_emulated_test.XXXXXXXXXX")"
+SED_CMD='s/^.* org.skia.skqp: output written to "\([^"]*\)".*$/\1/p'
+SKQP="$(cd $(dirname "$0"); pwd)"
+
+set -x
+
+cd "${SKQP}/../../infra/skqp/docker"
+
+docker build -t android-skqp ./android-skqp/ > "$DST"/docker-build || exit 2
+
+docker run --privileged --rm -d \
+  --name android_em \
+  --env=DEVICE="Samsung Galaxy S6" \
+  --env=SKQP_SLEEP="30" \
+  --env=SKQP_ARGS="$SKQP_ARGS" \
+  --volume="$DST":/DST \
+  --volume="$APK_DIR":/APK:ro \
+  --volume="$SKQP":/SKQP:ro \
+  android-skqp > "$DST"/docker-run || exit 3
+
+docker exec android_em sh "/SKQP/run_apk.sh" "/APK/$APK_FILE" "/DST"
+
+docker kill android_em
+
+"${SKQP}/../../bin/sysopen" "$DST"/skqp_report_*/report.html
diff --git a/tools/skqp/run_apk.sh b/tools/skqp/run_apk.sh
new file mode 100644
index 0000000..b35933e
--- /dev/null
+++ b/tools/skqp/run_apk.sh
@@ -0,0 +1,39 @@
+#! /bin/sh
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Note:
+#   The ANDROID_SERIAL, SKQP_ARGS, and SKQP_SLEEP environment variables affect
+#   this script.
+
+if ! [ -f "$1" ] || ! [ -d "$2" ] ; then
+  echo "Usage:  $0 SKQP_APK_FILE_PATH RESULTS_DIRECTORY" >&2
+  exit 1
+fi
+
+SED_CMD='s/^.* org.skia.skqp: output written to "\([^"]*\)".*$/\1/p'
+APK="$1"
+DST="$2"
+
+printf '\n\nAPK = "%s"\nDST = "%s"\n\n' "$APK" "$DST"
+
+set -x
+
+timeout 60 adb wait-for-device || exit 1
+
+sleep ${SKQP_SLEEP:-0}
+
+adb uninstall org.skia.skqp > /dev/null 2>&1
+
+adb install "$APK" || exit 1
+
+adb logcat -c
+
+adb shell am instrument $SKQP_ARGS -w org.skia.skqp 2>&1 | tee "$DST"/stdout
+
+adb logcat -d TestRunner org.skia.skqp skia DEBUG '*:S' > "$DST"/logcat
+
+ODIR="$(sed -n "$SED_CMD" "$DST"/logcat | head -1)"
+
+if adb shell "test -d '$ODIR'"; then adb pull "$ODIR" "$DST"; fi
diff --git a/tools/skqp/test_apk.sh b/tools/skqp/test_apk.sh
index 42a6382..adeb8e3 100755
--- a/tools/skqp/test_apk.sh
+++ b/tools/skqp/test_apk.sh
@@ -23,57 +23,18 @@
     exit 1
 fi
 
-ARGS=''
 if [ "$#" -gt 0 ]; then
-    ARGS="-e class org.skia.skqp.SkQPRunner#${1}"
+    SKQP_ARGS="-e class org.skia.skqp.SkQPRunner#${1}"
     shift
     for arg; do
-        ARGS="${ARGS},org.skia.skqp.SkQPRunner#${arg}"
+        SKQP_ARGS="${SKQP_ARGS},org.skia.skqp.SkQPRunner#${arg}"
     done
+    export SKQP_ARGS
 fi
 
 TDIR="$(mktemp -d "${TMPDIR:-/tmp}/skqp_report.XXXXXXXXXX")"
+THIS="$(dirname "$0")"
 
-adb uninstall org.skia.skqp
-adb install "$APK" || exit 2
-adb logcat -c
+sh "$THIS/run_apk.sh" "$APK" "$TDIR"
 
-adb logcat TestRunner org.skia.skqp skia DEBUG "*:S" | tee "${TDIR}/logcat.txt" &
-LOGCAT_PID=$!
-
-ADBSHELL_PID=''
-trap 'kill $LOGCAT_PID; kill $ADBSHELL_PID' INT
-
-printf '\n%s\n\n' "adb shell am instrument $ARGS -w org.skia.skqp"
-adb shell am instrument $ARGS -w org.skia.skqp \
-    >  "${TDIR}/stdout.txt" \
-    2> "${TDIR}/stderr.txt" &
-ADBSHELL_PID=$!
-
-wait $ADBSHELL_PID
-trap - INT
-kill $LOGCAT_PID
-
-printf '\nTEST OUTPUT IS IN: "%s"\n\n' "$TDIR"
-
-SED_CMD='s/^.* org.skia.skqp: output written to "\([^"]*\)".*$/\1/p'
-ODIR="$(sed -n "$SED_CMD" "${TDIR}/logcat.txt" | head -1)"
-
-if ! adb shell "test -d '$ODIR'" ; then
-    echo 'missing output :('
-    exit 3
-fi
-
-odir_basename="$(basename "$ODIR")"
-
-adb pull "${ODIR}" "${TDIR}/${odir_basename}"
-
-REPORT="${TDIR}/${odir_basename}/report.html"
-
-if [ -f "$REPORT" ]; then
-    grep 'f(.*;' "$REPORT"
-    echo "$REPORT"
-    "$(dirname "$0")"/../../bin/sysopen "$REPORT" > /dev/null 2>&1 &
-else
-    echo "$TDIR"
-fi
+"$THIS/../../bin/sysopen" "$TDIR"/skqp_report_*/report.html