Repository navigation
Apps' own Rust functions in WebAssembly, behind the wasm-lab feature (ADR 0011) - #364
Conversation
0f8b831 to
c660cec
Compare
An app may ship its developer's own functions as WebAssembly modules in its bundle's fns/, and the shell runs them for that app in a sandbox (ADR 0011, proposed). Off by default: everything is behind the new `wasm-lab` feature, and default builds change only by the App Hub repin and the libc patch bump below. - crates/wasm-host: Wasmtime 49, compiled by Cranelift. Every call has a 2 s deadline (epochs advanced by wall-clock time), a 256 MiB memory cap, a 512 KiB wasm stack and 16 MiB of input and output; the only import is octo.log. A trap or a deadline spends the instance (a Rust guest's stack pointer and allocator may be half-updated), and the next call gets a fresh one. Compiled code is cached by the module's digest and the engine's compatibility hash; the writer reads the file back in the background, because Microsoft Defender's scanner holds the first open of a new file for about a second. - The `wasm` host service (crates/shell/src/wasm_service.rs): wasm.<function> calls one of the calling app's functions, and wasm.functions lists them with load and per-call numbers. Modules come only from the app's own admitted bundle, the service checks the `wasm` grant itself, and each app has one worker thread, never the UI thread. An agent tool reaches a function with host_method "wasm.<function>". - Wasm Lab (apps/wasmlab), a demo system app shipped only by the desktop/ and phone/system-apps-wasm-lab.json selections: fuzzy ranking as you type, free slots, a line diff, Markdown to HTML and four ways to misbehave, with three of them as its agent's tools. Its guest crate (apps/wasmlab/guest) builds the module. - App Hub -> 2e576896 (main with #140): app-contract 1.7.0 with the `wasm` capability, now from crates.io; the workspace asks for contract 1.7. - libc 0.2.189 -> 0.2.190, also required by crates/wasm-host: on aarch64 Android, 0.2.189's ucontext_t lacked the kernel's padding after the signal mask, Wasmtime misread a trap's pc, and every signal-based trap killed Home. Measured on an M5 Max and a Redmi Note 12: 1.4-2.2x native time for these functions, compile 27-33 ms / 378-421 ms, cached load 1-6 ms / 5-11 ms, about 2 ms from script to function and back, all four misbehaving modes contained on both, the APK 3.5 MiB larger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The decision record, in English and Chinese: modules in a bundle's fns/, Wasmtime with Cranelift behind the wasm host service and capability, wasm.<function> as an agent tool, the runtimes measured against it (with CoreMark), Wasm Lab's numbers on the desktop and a Redmi Note 12 (in a plain binary and in Home), the libc 0.2.190 trap fix, the desktop scanner's effect on the cache, and what is still open: iOS has no JIT, there is no per-app CPU or memory budget, and only a system app has run functions on a device. Listed beside ADR 0012. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
c660cec to
97fbb1b
Compare
|
Linux evidence for the same head (97fbb1b), from a first The extra 🤖 Generated with Claude Code |
|
Local CI passed on 97fbb1b ( GitHub would run for this PR: desktop.yml, phone.yml, apps.yml. Merged on this local pass (macOS runner queue); GitHub CI runs on the merge commit on main.
Notes:
|
What this changes
An app can ship its developer's own Rust functions, compiled to WebAssembly, and the shell runs them for that app in a sandbox. Everything is behind a new
wasm-labfeature, off by default. Default builds are unchanged apart from the App Hub repin and thelibcpatch bump below. Design and measurements: ADR 0011 (简体中文), proposed.crates/wasm-host: the runtime.octo.log. After a trap or a deadline the instance is spent and replaced.wasmhost service (crates/shell/src/wasm_service.rs, featurewasm-lab):wasm.<function>calls one of the calling app's functions;wasm.functionslists them, with load and per-call numbers.fns/*.wasm). The service checks thewasmgrant itself.host_method: "wasm.<function>"(App Hub ADR 0004: OS contacts as a source for approval rules #140).apps/wasmlab), a demo system app:apps/wasmlab/guest, which builds the module.desktop/orphone/system-apps-wasm-lab.json.2e576896(from Implement discoverable host APIs, app backend operations and script tools #360'sb1109a39), App Hubmainwith ADR 0004: OS contacts as a source for approval rules #140 merged. app-contract 1.7.0, with thewasmcapability, comes from crates.io; the workspace asks for 1.7.libc0.2.189 → 0.2.190, also required directly bycrates/wasm-host. On aarch64 Android, 0.2.189'sucontext_tlacks the kernel's padding. Wasmtime then misread the faulting pc, and every signal-based trap killed Home.State
Squashed onto
main4aad89e2as two commits (code, then the ADR); the earlier history is in this PR's timeline. #360 brought the runtime patch that App Hub's appstore needs (SplashRef::set_device_consent), and #363 brought makepad32d6415f. This PR moves App Hub from #360'sb1109a39to2e576896(App Hubmainwith #140), and the workspace asks for contract 1.7.The local CI gate (
tools/ci-local.sh --only desktop,phone,apps --linux-host) runs on the exact head;tools/ci-local-merge.shposts its table here before merging. The ADR stays Proposed until decided.How it was tested
cargo test --locked -p octosense-wasm-host: 18 passed, covering:The same 18 tests on a Redmi Note 12 (cross-compiled, run over adb): all passed, but only with
libc0.2.190.Shell tests, against App Hub
f5434fa4(ADR 0004: OS contacts as a source for approval rules #140's head before it merged); on the rebased head, thewasm_servicetests pass again, and the full suites run in the local CI gate:cargo test --locked -p octosense-shell --features wasm-lab --lib, withOCTOSENSE_SYSTEM_APPS=desktop/system-apps-wasm-lab.json: 973 passed;phone/,cargo test --locked --features mobile-apps -p octosense-shell --lib: 988 passed;cargo check --locked -p octosense: builds;tools/setup.py --check --cargo,native_apps.py --checkandsync-app-interface.py --check: pass.The
wasm_servicetests run, in a process of their own:Hidden desktop shell (
MAKEPAD_HIDE_WINDOWS=1, remote control): Wasm Lab ran end to end:Redmi Note 12, in a separately packaged Home (
dev.makepad.octosense.wasmlab; the installed Home was not touched):Speed (
--example measure, release):Not tested or not done:
🤖 Generated with Claude Code