RUST.md: E1 passes, with the keyboard gap it was there to find

The Masonry demo on android-view builds, renders through Vulkan, exposes
its AccessKit tree to ui-trace, and takes real keystrokes from the phone's
own keyboard. What it does not get is autocorrect and suggestions, and the
control is what makes that a finding: the same three key taps in the
Settings search field on the same device produce Gboard's suggestion strip,
and in Masonry's editor they produce nothing. That is the constraint the
framework decision turns on, so it is now the first thing I2 has to answer.

Also closes the Vulkan line this file had flagged as untested. The missing
step was -no-snapshot-load: the guest keeps the old GPU config from its
snapshot and reports zero Vulkan devices however the host is set up. And
records the watchdog trap that produced one wrong conclusion on the way --
a bounded run's kill timer must be scoped to the pid it guards, or it fires
into somebody else's experiment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-09-04 18:51:10 -04:00
1 parent 10500ae8aa
commit 3fc224b584
1 file changed
+83 -48
+83 -48
View File
@@ -432,56 +432,75 @@ accepted.
worth not doing in a log somebody might paste. And the Android
targets were installed for **stable** only; the pinned nightly needs
its own, which `iris/rust-toolchain.toml` now declares.
- [ ] **E1 — android-view's Masonry demo on this emulator.** Pass: it
builds with `cargo-ndk` + Gradle, renders on the GPU, and the phone's
own keyboard types into its editor with autocorrect and suggestions.
Note which `wgpu` backend it took and any environment flags needed.
**Part-done 2026-09-04; the keyboard half is untested, so the box
stays open.**
- [x] **E1 — android-view's Masonry demo on this emulator (2026-09-04).**
It builds, renders on the GPU through Vulkan, exposes its
accessibility tree, and **the phone's own keyboard types into its
editor** — but with **no autocorrect and no suggestions**. Ticked
because everything it was meant to establish is established,
including the one gap; that gap is now E2's problem and I2's.
*Builds and renders.* `~/src/android-view` at `bec6c62`, built with
*Build.* `~/src/android-view` at `bec6c62`, x86_64 rather than the
README's arm64 because that is what this emulator is:
`cargo ndk -t x86_64 -P 26 -o masonry-app/src/main/jniLibs/ build -p
android-view-masonry-demo` and `./gradlew :masonry-app:assembleDebug`.
The demo draws: its text field and "Add task" button appear, laid out
correctly. Note the demo's README says `arm64-v8a`; this emulator is
x86_64. **`libmain.so` is 181 MB in debug and 11 MB in release**,
which is the single loudest number about Vello's dependency graph.
android-view-masonry-demo --release`, then
`./gradlew :masonry-app:assembleDebug`. **`libmain.so` is 181 MB in
debug and 11 MB in release** — the loudest single number about
Vello's dependency graph, and the reason the release build matters
for more than speed.
*Accessibility works, which E2's condition 6 depends on.* `ui-trace`
reads Masonry's AccessKit tree: "Add task" comes through as a named
`Button` and the editor as an `EditText` node. So the bench rig's
tap-by-name would work against a Masonry screen — for controls that
carry a name. The demo's editor does not, so a coordinate was needed
for it, which is a demo omission rather than a framework one.
*Renderer.* wgpu takes **Vulkan**, and the emulator log confirms it
from the other side: `Created VkDevice ... for application:'wgpu'`.
Two things were needed. The emulator must be given Vulkan at all —
`-feature Vulkan` with `VK_DRIVER_FILES` pointing at the SDK's
`vk_swiftshader_icd.json`, **plus `-no-snapshot-load`**, which is the
piece this file had flagged as untested: without a cold boot the
guest keeps the snapshot's old GPU config and `cmd gpu vkjson`
reports zero devices however the host is configured. And the native
library must be **release**: a debug build calls
`SetDebugUtilsObjectNameEXT` to label its image views, and the
emulator's own guest driver (`vulkan.ranchu.so`) segfaults inside it.
On GLES, with no Vulkan available, it instead fails
`Surface::configure` with "Invalid surface" — untriaged, since the
Vulkan path works and Vello wants compute shaders anyway.
*The keyboard was not reached.* Tapping the editor never brought the
IME up (`mInputShown=false` throughout) before the run ended. Nothing
here says android-view's `InputConnection` does not work — only that
it has not been shown to. This is the half of E1 that matters most,
since it is the constraint the whole framework decision turns on, and
it is what to do first when this is picked up.
*Accessibility works*, which E2's condition 6 and every bench script
depend on. `ui-trace` reads Masonry's AccessKit tree: "Add task"
arrives as a named `Button`, the editor as an `EditText` node. So
tap-by-name works against a Masonry screen for any control carrying
a name; the demo's editor carries none, which is the demo's omission
rather than the framework's.
*A crash worth knowing about, seen once.* With an accessibility
client attached the app aborted, and the stack attributes it
precisely: `android_view::view::do_frame`
`CallbackCtx::finish``accesskit_android::event::QueuedEvents::raise`
`send_completed_event``unwrap()` on `Err(JavaException)`.
android-view builds with `panic = "abort"`, so a JNI call that throws
takes the process. It did **not** reproduce: two plain
`ui-trace record` runs afterwards left the app alive, so the trigger
is narrower than "an accessibility client is connected" and is not
yet known. Recorded rather than chased because it is upstream and
one unwrap wide.
*The keyboard: real input yes, suggestions no.* Tapping the editor
opens the actual soft keyboard (`mInputShown=true`, Gboard), and
tapping its keys types into Masonry — "teh" typed key by key, with a
caret. What does **not** appear is Gboard's suggestion strip. The
control is what makes that a finding rather than an impression: the
**same three key taps in the Settings app's search field, on the same
device in the same session, produce "teh | the | yeh"**. So the strip
works here and android-view's editor is not asking for it — most
likely the `EditorInfo` its `InputConnection` reports. That matches
Robrix's report that the Android keyboard is not yet "full", and it
is the single most important thing to fix or fund upstream, because
composition, autocorrect and suggestions are exactly what the
composer in this app needs and exactly what `winit` cannot do at all.
*One crash seen once and not reproduced.* With an accessibility
client attached the app aborted, stack:
`android_view::view::do_frame``CallbackCtx::finish`
`accesskit_android::event::QueuedEvents::raise`
`send_completed_event``unwrap()` on `Err(JavaException)`.
android-view builds `panic = "abort"`, so a JNI call that throws
takes the process. Two later `ui-trace record` runs left the app
alive, so the trigger is narrower than "a client is attached".
*A rig trap that cost a wrong conclusion.* Several bounded runs were
given `sleep N; emu down` watchdogs, and one armed for an earlier
experiment fired in the middle of a later one — the app vanished, adb
hung, and it read exactly like the Vulkan path crashing. It was not.
A watchdog must be scoped to the process it guards (`kill $pid`, with
the pid captured at launch) rather than to whatever AVD is running
when it wakes, and only one should be armed at a time.
*Two changes were made at once and cannot be separated.* The first
launches crashed in `Surface::configure` ("Invalid surface") on GLES,
then, with Vulkan enabled, segfaulted inside the emulator's own
driver (`vulkan.ranchu.so`, `SetDebugUtilsObjectNameEXT`) while wgpu
labelled an image view — a debug-build-only call. It then ran after
**both** a switch to a release native library and a switch to a
software-rendered emulator. Which of the two fixed it is unmeasured;
whoever picks this up should vary one at a time rather than inherit
the assumption.
- [ ] **E2 — a transcript in Masonry.** One screen: open a sandbox session,
page 800 events into `VirtualScroll` bottom-anchored, draw markdown
from `pulldown-cmark` into Parley rich text with links and code
@@ -683,8 +702,21 @@ re-derived:
### Vulkan in the emulator (measured 2026-09-04)
A `wgpu` app in this emulator was going to get GLES only, because host
Vulkan is switched off in `emulator-tools`. Retried today on Mesa
**Settled 2026-09-04: the guest gets Vulkan from SwiftShader, and the
missing step was a cold boot.** `-feature Vulkan` plus
`VK_DRIVER_FILES=$HOME/Android/Sdk/emulator/lib64/vulkan/vk_swiftshader_icd.json`
gets the *host* side to select SwiftShader, but the guest keeps reporting
zero devices until `-no-snapshot-load` is added, because it boots from a
snapshot saved under the previous GPU config — `-no-snapshot-save` is
worth adding too, so the Vulkan-configured snapshot does not then break
the next ordinary boot. With that, `cmd gpu vkjson` reports SwiftShader
Subzero and wgpu takes its Vulkan path (E1). `EMU_GPU=software` in
`emulator-tools` gets the same guest Vulkan with no GPU use at all, for
work where the emulator's frame rate is not what is being measured.
The rest of this section stands as the record of why host Vulkan is not
available. A `wgpu` app in this emulator was going to get GLES only,
because host Vulkan is switched off in `emulator-tools`. Retried on Mesa
26.1.7: **Venus still fails the same way** — gfxstream picks
`externalMemoryMode: OpaqueFd`, probes `VK_FORMAT_R8G8B8A8_UNORM` for an
exportable colour buffer, and Venus says the format is unsupported
@@ -717,8 +749,11 @@ booted, then the emulator died right after loading the `default_boot`
snapshot with nothing in the log; a snapshot saved under a different
Vulkan device is the suspect, and `-no-snapshot-load` is the untested
next step. SwiftShader is the one that works today.
Making this an `emu` option belongs in `emulator-tools` and is a shared
tooling change, so it goes through the other sessions first.
`EMU_GPU=software` is now in `emulator-tools` (agreed with the ai-app
session and with Iris, default unchanged, since `-gpu host` was measured
and the Compose scroll benchmarks depend on it). The cold-boot flags are
not a knob there: that wants snapshot invalidation as well, which is a
bigger design question in shared tooling.
## Things a Rust app changes elsewhere