Skip to content

android: rebuild Xwayland instead of trusting an existing binary - #29

Merged
joshuatam merged 1 commit into
gamenativefrom
fix/gamescope-xwayland-rebuild
Nov 2, 2026
Merged

joshuatam merged 1 commit into
gamenativefrom
fix/gamescope-xwayland-rebuild

Conversation

@joshuatam

Copy link
Copy Markdown
Collaborator

Problem

android/package-gamescope.sh absorbed the Xwayland payload behind an existence check:

[ -x "$XW_DIR/build-android/hw/xwayland/Xwayland" ] || bash "$XW_DIR/android/build-xwayland.sh"

So the binary was built only when it was missing. The daemon libraries staged a few dozen lines above it get a strict check_fresh guard against the sources they compile, but Xwayland got nothing: once a binary existed, any change to gamenative-xwayland source — hw/xwayland, Xext, the glamor/GBM path — packaged the previous build silently and the asset shipped a stale Xwayland.

That is not hypothetical. The tree this was written on was in exactly that state: Xext/shm.c and hw/xwayland/xwayland-glamor-gbm.c were newer than the 2026-10-22 Xwayland binary, and the old predicate would have copied that binary into the payload without a word. On device it presents as a missing or wrong behaviour in the X server behind gamescope — an X extension the guest expects, a glamor/GBM fix that simply is not there — with nothing in the build log pointing at the binary.

Fix

Build it always, the way the daemon libraries above are built, and assert the result converged:

bash "$XW_DIR/android/build-xwayland.sh"
if ! ninja -C "$XW_DIR/build-android" -n 2>/dev/null | grep -qx 'ninja: no work to do.'; then
    echo "error: $XW_BIN is not current after build-xwayland.sh — ninja still has work" >&2
    exit 1
fi

build-xwayland.sh is incremental (meson reconfigure, ninja relinks only what changed), so a current tree pays only its xkbcomp/xkeyboard-config tail; a stale tree pays a rebuild, which is the point. If the dry run still reports work, the script fails naming the binary rather than packaging it.

Why ninja's dry run and not a check_fresh source scan

A find -newer scan cannot answer this question for this tree: the xkbcomp tail rewrites android/deps/xkbcomp-build/config.h after the link, so "any source newer than the binary" is true on every run and the check would fail the build permanently. ninja already knows every input, including that generated header, so ninja: no work to do. is the honest statement that the binary matches its sources.

Measurement

On a current tree the always-rebuild costs 8.9–9.5 s over three warm runs, and the dry run settles at ninja: no work to do.

Touch nothing else: this is one file, and the patch train's dirty src/ tree is not part of the commit.

android/package-gamescope.sh absorbed the Xwayland payload behind an
existence check:

    [ -x "$XW_DIR/build-android/hw/xwayland/Xwayland" ] || bash build-xwayland.sh

so the binary was built only when it was missing. The daemon libraries
staged a few dozen lines above get a strict check_fresh guard against
their sources, but Xwayland got nothing: once a binary existed, a change
to gamenative-xwayland source — hw/xwayland, Xext, the glamor path —
packaged the previous build silently and the payload shipped a stale
Xwayland. The tree was in exactly that state when this was written:
Xext/shm.c and hw/xwayland/xwayland-glamor-gbm.c were newer than the
2026-10-22 Xwayland binary, and the old predicate would have copied it
into the asset without a word. On device that shows up as a missing or
wrong behaviour in the X server behind gamescope — an X extension the
guest expects, a glamor/GBM fix that is simply not there — with nothing
in the build log pointing at the binary.

Build it always, the way the daemon libraries are built, and assert the
result converged:

    bash "$XW_DIR/android/build-xwayland.sh"
    ninja -C "$XW_DIR/build-android" -n | grep -qx 'ninja: no work to do.'

build-xwayland.sh is incremental (meson reconfigure, ninja relinks only
what changed), so a current tree pays only its xkbcomp/xkeyboard-config
tail: 8.9-9.5 s over three warm runs here. A stale tree pays a rebuild,
which is the point. If the dry run still reports work, the script fails
with the binary path instead of packaging it.

The assertion is ninja's dry run rather than a find-based check_fresh
because a source scan cannot answer the question for this tree: the
xkbcomp tail rewrites android/deps/xkbcomp-build/config.h after the link,
so a "source newer than the binary" test reports the tree stale on every
run. ninja already knows every input, including that generated header, so
"no work to do" is the honest statement that the binary matches its
sources.

Verified on a tree where the old predicate would have shipped the stale
binary: the always-rebuild costs 8.9-9.5 s over three warm runs, and the
dry run settles at "ninja: no work to do."
@joshuatam
joshuatam merged commit f8edbc8 into gamenative Nov 2, 2026
1 check passed
@joshuatam
joshuatam deleted the fix/gamescope-xwayland-rebuild branch November 2, 2026 00:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant