Engine audio (gre-widgets R1/R7): switch cubeb ALSA -> PULSE backend, which is what webOS's audio policy requires. mozconfig --enable-pulseaudio, pulse-0.9.22 sysroot headers matching the device ABI, and patch 0030 targeting JIHAD_PULSE_SINK. Device-verified AUDIBLE (user-confirmed "I hear the tone"): decode -> cubeb pulse -> DAC -> codec -> speaker/headphone. The prior ALSA backend was silent because it presented as an anonymous ALSA-plugin stream that module-palm-policy muted; the pulse-native stream identifies as the app and is left at full volume. Chrome-page typing (preferences-ui R6): GoannaRenderPage::InsertText recovers a null mFocusedEditable from document.activeElement, which dodges the focus-manager window-scoping that made chrome documents (about:preferences) unable to receive typed text. Device-verified: text now inserts into about:preferences fields. Cert store (browser-services R5): new JihadCertStore dlopens libPmCertificateMgr and integrates accept/trust with the webOS platform cert store; three defects fixed (empty certFile, nsresult-in-Palm-ordinal-space, Trust-Always vs Trust-Once). Device-verified end to end incl. the platform store write. IPC contract (ipc-contract R1): vendored + patched the YAP generator so a regeneration reproduces the shipped wire with zero hand edits. Touch events (input-bridging R3): doTouchEvent enabled behind JIHAD_TOUCH_EVENTS, 28-byte NpPalmTouchEvent header re-staged, double-activation suppressor. Non-blocking toast (gre-widgets R5): daemon PostNotification + Luna subscription + card toasts; device-verified. Mojo settings entry (preferences-ui R4): app-menu Settings item + settingsUrl(), per product-owner direction reversing the earlier no-mojo-settings instruction. All three variants now have a settings entry. Plus: opal machine kernel string corrected (shortloin), prebuilt-input manifests, build-goanna-arm.sh pipefail fix, desktop test harnesses (prefsui, xpi-mismatch), and extensive device verification recorded in context/impl/impl-device-2026-08-15.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.4 KiB
Full-OE build — oe-env.sh (OpenEmbedded "dylan" host, any Linux)
The reproducible-from-source device build: bitbake the Jihad recipes under the same
2013 OpenEmbedded "dylan" / BitBake 1.18 stack that the openwebos meta-webos layer
(correct for the HP TouchPad) targets. This is the alternative to the direct cross-build
scripts — chosen so the whole stack builds from source with no prebuilt device libraries.
Why a rootfs at all
OpenEmbedded/BitBake is a Linux-host-only build system by design: its pseudo
fakeroot is LD_PRELOAD-based and the recipes/host-tools assume GNU/Linux. It has no
native macOS/*BSD port. On top of that, the dylan stack is Python-2 / Ubuntu-14.04-era,
so it will not run on a modern host userland (Void, Arch, current Ubuntu, …). The build
therefore needs an old GNU/Linux userland regardless of what you run on.
oe-env.sh supplies exactly that userland — one clean, self-contained solution that spans
Linux — without a container runtime:
- Downloads Ubuntu's official
ubuntu-base-14.04rootfs tarball once (justcurl+tar+gpg—gpgpins the GCC PPA's signing key, see below; nodebootstrap, no distro packages) and enters it with plain POSIXchroot. chrootexists on every Linux and every init system — runit / OpenRC / s6 / systemd, no systemd dependency. The rootfs carries its own glibc, so it runs identically on a glibc host or a musl host (Alpine, musl-Void). Native speed (noproot/ptrace).- Privilege for
chroot/mountis taken viasudoordoas(whichever the host has), or run directly if already root. Override withOE_ROOTCMD=....
(There is no macOS/*BSD path: the target is Linux/ARM/glibc, so a Linux build host is unavoidable — on a non-Linux Unix, run this inside a Linux VM.)
Quick start
# 1. Build the OE host rootfs (once). Prompts for sudo/doas; downloads ~65 MB + apt.
build/webos-oe/oe-env.sh provision
# 2. Bring up the OE tree: clone+pin the dylan layers, fetch, wire the Jihad layer.
build/webos-oe/oe-env.sh bringup tenderloin # or: opal
# 3. Build (inside the chroot). A full image needs ~40 GB free.
build/webos-oe/oe-env.sh make webos-image
# …or a single recipe while iterating:
build/webos-oe/oe-env.sh run "bitbake goanna"
Everything after provision runs inside the rootfs as a builder user that shares your
host UID/GID, so bind-mounted files stay owned by you.
Commands
| Command | What it does |
|---|---|
provision |
Fetch + extract the rootfs, install the OE host tools (idempotent). |
bringup [machine] |
provision, then ./mcf -p 0 -b 0 <machine> (clone+pin layers, fetch), then wire the Jihad layer into BBLAYERS. Default machine tenderloin. |
mcf <args…> |
Run ./mcf inside build-webos with your args. |
wire |
(Re)add the Jihad layer to conf/bblayers.conf, idempotent. |
make <args…> |
make inside build-webos (e.g. make webos-image). |
run <cmd…> |
Run any command as builder in the build-webos dir (e.g. run "bitbake goanna"). |
shell |
Interactive shell inside the chroot. |
root <cmd…> |
Run as root inside (debug/provisioning). |
clean |
Remove the rootfs (keeps oe-downloads/ + oe-sstate/). |
Layout
Inside the chroot:
| Path | Bind |
|---|---|
/oe/Jihad-Browser |
this repo |
/oe/build-webos |
the build-webos orchestrator (cloned + pinned by oe-env.sh) |
/oe/downloads |
persistent DL_DIR (host build/webos-oe/oe-downloads/, survives clean) |
/oe/sstate |
persistent sstate (host build/webos-oe/oe-sstate/, survives clean) |
Host-side, all generated state is git-ignored: oe-rootfs/, oe-cache/, oe-downloads/,
oe-sstate/.
apt authentication in the chroot (the GCC 9 PPA)
UXP's host tools need GCC ≥ 9.1 while the dylan OE natives need trusty's stock 4.8, so the
rootfs installs gcc-9/g++-9 from the ubuntu-toolchain-r/test PPA alongside 4.8. That repo
is authenticated — apt verification is never disabled (review #2):
- The PPA signing key is pinned by full fingerprint
60C317803A41BA51845E371A1E9377A2BA9EF27F("Launchpad Toolchain builds"). oe-env.shinstalls it host-side into its own keyring,/etc/apt/trusted.gpg.d/ubuntu-toolchain-r.gpginside the rootfs. (trusty ships apt 1.0.1, which predates the[signed-by=…]sources.list option added in apt 1.1, so a dedicatedtrusted.gpg.dkeyring is the tightest scoping this apt supports.)- Key source: the pre-seeded copy at
build/webos-oe/keys/ubuntu-toolchain-r.ascif present (works offline), otherwise fetched over HTTPS fromkeyserver.ubuntu.com. - It fails closed: a fingerprint mismatch, unreadable key material, or a missing keyring
aborts provisioning — it never falls back to
[trusted=yes]. A rootfs provisioned by an olderoe-env.sh(which did use[trusted=yes]) is repaired in place on the nextprovision.
To re-seed the in-repo key (e.g. after a key rotation), or to seed it on a machine that will build offline:
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 60C317803A41BA51845E371A1E9377A2BA9EF27F
gpg --armor --export 60C317803A41BA51845E371A1E9377A2BA9EF27F \
> build/webos-oe/keys/ubuntu-toolchain-r.asc
PPA_KEY_SEED=<path> and PPA_KEYSERVER=<url> override the seed path and the keyserver.
Task signatures and ${JIHAD_REPO} inputs
The Jihad recipes read several build-control files and prebuilt trees straight from the bound
repo (${JIHAD_REPO}) instead of through SRC_URI — the goanna patch queue and ARM mozconfig,
the deviceroot bundler + upstart job, the PDK adapter build script and its sources, the
crosstool-NG toolchain, the Jessie sysroot, the Palm PDK, adapter-deps/, the Mochi frameworks,
and the LICENSE/NOTICE payload. The fetcher never sees those, so nothing would invalidate sstate
when they change (review #8).
Each task that reads such an input now declares it in its own signature with bitbake's
per-task file-checksums varflag (supported in the pinned bitbake 1.18.0: lib/bb/cache.py:135
collects the flag, lib/bb/siggen.py:189-193 folds every listed file's md5 into the task hash).
The two large prebuilt trees are represented by small identity sets rather than whole-tree walks —
JIHAD_TC_SIG (gcc drivers + crosstool-NG build log) and JIHAD_SYS_SIG (the sysroot's
pkg-config manifest, i.e. exactly what PKG_CONFIG_LIBDIR points at). See
build/webos-oe/recipes-jihad/jihad-common.inc for the full rationale and the glob rules the
1.18 implementation imposes.
Because the declarations change every affected task hash, the first build after this change rebuilds those recipes once instead of restoring from sstate.
How the Jihad layer is wired
oe-env.sh vendors build/webos-oe/weboslayers.py (a copy of build-webos's, pinning the
dylan-era layers: bitbake 1.18, oe-core/meta-oe dylan, the legacy openwebos meta-webos) and
installs it over build-webos's before running mcf — so the layer pins live in this repo and
reproduce from a clean clone. Its only change vs upstream is adding tenderloin and
opal to the Machines list so ./mcf tenderloin is accepted.
The Jihad layer itself (build/webos-oe/, which already has conf/layer.conf +
recipes-jihad/ + the machine confs) is not added as a weboslayers.py tuple — that would
put it under mcf's git layer-management. Instead oe-env.sh appends it to conf/bblayers.conf
after mcf, pointing at the in-chroot path /oe/Jihad-Browser/build/webos-oe. Idempotent.
Status
Tracked as one acceptance criterion — context/kits/cavekit-device-build.md R3 — not restated
here. The short version a reader of this file needs: the OE environment parses and is runnable,
but the do_compiles do not yet cross-build, so the direct cross-build scripts in
docs/DEVICE-BUILD.md remain the verified pipeline and are what every current binary was built
with.
Two fixes are worth keeping here because they are properties of the metadata rather than of the requirement:
recipes-jihad/jihad-common.incpointsFILESEXTRAPATHSat the repo root (/oe/Jihad-Browser) sofile://sources resolve, and supplies the realLIC_FILES_CHKSUM(repoLICENSE) + the webOS app dir.- UI recipes drop the nonexistent
webos-appclass →inherit allarch; the modern:-override in goanna → dylan underscore; the adapterSRC_URI→ the vendoredrender/adapter/.