diff --git a/CLAUDE.md b/CLAUDE.md index fba0ddb..5bf9160 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -76,7 +76,7 @@ Device notes), but nothing on screen can be verified through a lockscreen and | Command | What it does | |---|---| | `npm run device:keep-awake` | Stay awake while charging. Do this at the start of a session. | -| `npm run device:launch` | Check awake/unlocked, force-stop, start, wait for the page to actually parse | +| `npm run device:launch` | Check awake/unlocked, force-stop, start, wait for the page (debug builds) | | `npm run device:awake` | Just the check — prints a loud warning if locked | | `npm run device:sleep-normal` | Revert the stay-awake setting when finished | @@ -84,6 +84,22 @@ Device notes), but nothing on screen can be verified through a lockscreen and starts fine even when the renderer was denied. On failure it prints the `AppBootManager` denial lines rather than leaving a blank window to puzzle over. +**On a release build it cannot do that, and says so.** A release APK is not +`DEBUGGABLE`, so Capacitor never calls `setWebContentsDebuggingEnabled` and +`webview_devtools_remote_` is never opened — the page simply cannot be +inspected over adb. Demanding that socket anyway made the helper report +`renderer denied` three times for a perfectly healthy app, force-stopping and +restarting it each time. It now checks that the process survived and that +nothing denied *our* renderer, then prints `page load assumed, not verified`. A +blank grey window and a working one are genuinely indistinguishable from here, +so that wording is the honest limit, not hedging. + +The denial grep is filtered by package and bounded to the current launch +(`logcat -d -T`, timestamp from `adb shell "date +'%m-%d %H:%M:%S.000'"` — the +format must be one quoted argument or toybox `date` rejects it). Unfiltered, it +printed `com.xiaomi.wearable` denials from minutes earlier and sent one session +chasing a denial that had never happened to us. + It also reads the pid *after* starting the app. `adb install -r` kills the running process, so a pid captured earlier points at a dead process and the devtools socket lookup fails while the app itself is healthy — that produced one @@ -266,8 +282,10 @@ beats an afternoon of synthetic input. **Stay awake needs `svc power stayon true`, not `usb`.** The `usb` form writes `stay_on_while_plugged_in = 2`, and this phone charges over AC (`USB powered: -false`), so it silently never engages — `mStayOn` stays false. `true` writes 7 -(any source) and works. The screen timeout is separate and was 30s: +false`), so it silently never engages — `mStayOn` stays false. `true` sets every +charging-source bit and works; measured as **15** here (AC|USB|wireless|dock), +not the 7 an earlier note claimed — 7 predates dock charging. The screen timeout +is separate and was 30s: ``` adb shell svc power stayon true diff --git a/scripts/device.sh b/scripts/device.sh index ec47ded..922408f 100755 --- a/scripts/device.sh +++ b/scripts/device.sh @@ -49,7 +49,10 @@ ensure_awake() { } keep_awake() { - "$ADB" shell svc power stayon usb >/dev/null + # `usb` writes stay_on_while_plugged_in=2 (USB only) and this phone charges + # over AC, so it silently never engages. `true` sets every charging-source bit: + # measured as 15 here (AC|USB|wireless|dock), not the 7 that older notes claim. + "$ADB" shell svc power stayon true >/dev/null echo "stay-awake while charging: ON (revert with: scripts/device.sh sleep-normal)" } @@ -58,6 +61,28 @@ sleep_normal() { echo "stay-awake: reverted to system default" } +# Release builds are not DEBUGGABLE, so Capacitor never calls +# setWebContentsDebuggingEnabled and the devtools socket is never opened. Asking +# for it anyway reports "renderer denied" for a perfectly healthy app. +is_debuggable() { + "$ADB" shell dumpsys package "$PKG" | grep -q DEBUGGABLE +} + +# Device-side clock, for bounding logcat to this launch. The format has to be +# quoted as one argument: toybox date rejects a bare `+FMT` after `adb shell`. +device_now() { + "$ADB" shell "date +'%m-%d %H:%M:%S.000'" | tr -d '\r' +} + +# Did the renderer get denied since $1? These lines are emitted whether or not +# the build is debuggable, and the package filter matters - other apps are +# denied constantly and their lines mean nothing here. +denied_since() { + "$ADB" logcat -d -T "$1" 2>/dev/null \ + | grep -E "AppBootManager.*Caller\[$PKG\]|cr_ChildProcessConn: Failed" \ + | grep -v 'Result\[true\]' +} + # Wait until the page is actually parsed, not merely until the activity is up: # the activity starts fine even when the renderer was denied. page_loaded() { @@ -67,6 +92,19 @@ page_loaded() { # app itself is healthy - that produced one false "page never loaded". pid=$("$ADB" shell pidof "$PKG" | tr -d '\r') [ -n "$pid" ] || return 1 + + # Release build: the page cannot be inspected from here at all, so prove what + # can be proved - the process survived and nothing denied its renderer. A + # blank grey window is indistinguishable from a working one over adb, which is + # why this says "assumed" rather than claiming the page loaded. + if ! is_debuggable; then + sleep 2 + [ -n "$("$ADB" shell pidof "$PKG" | tr -d '\r')" ] || return 1 + [ -z "$(denied_since "$1")" ] || return 1 + echo "app running (pid $pid, release build: page load assumed, not verified)" + return 0 + fi + for i in $(seq 1 40); do sock=$("$ADB" shell cat /proc/net/unix | grep -o "webview_devtools_remote_$pid" | head -1) if [ -n "$sock" ]; then @@ -82,19 +120,23 @@ page_loaded() { launch() { ensure_awake || return 1 - local attempt + local attempt started for attempt in $(seq 1 $ATTEMPTS); do + started=$(device_now) "$ADB" shell am force-stop "$PKG" "$ADB" shell am start -W -n "$ACT" >/dev/null - if page_loaded; then + if page_loaded "$started"; then [ "$attempt" -gt 1 ] && echo "(took $attempt attempts - post-install renderer denial)" return 0 fi - echo "attempt $attempt: renderer denied, retrying" >&2 + echo "attempt $attempt: no page, retrying" >&2 done echo "ERROR: page never loaded after $ATTEMPTS attempts." >&2 - "$ADB" logcat -d | grep -E 'AppBootManager.*Result\[false\]|ChildProcessConn: Failed' | tail -4 >&2 + # Bounded to this launch and to our package. Unfiltered, this printed other + # apps' denials from minutes earlier and sent one debugging session chasing a + # denial that had never happened to us. + denied_since "$started" | tail -4 >&2 return 1 }