Keep Android taps responsive during vault saves and WebDAV syncs #6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "perf/android-tap-latency"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What & why
Taps on Android could sit for seconds with no response: every connect stamped last-used with a full vault save (Argon2 is re-derived on every write), and the whole WebDAV round trip then ran on the same worker loop that answers every other tap — with no indicator, because the busy flag clears before the sync starts. This PR batches last-used stamps into one debounced save, moves background syncs off the worker loop onto a client clone, and shows the busy bar while a sync runs, so taps stay responsive and the remaining stalls are visible.
(No screenshot: worker-level change; the only UI difference is the existing busy bar now also covering syncs.)
Verify
cargo test -p ferry-core -p ferry-ffi— 373 tests, including the new touch-batching test and the deferred password-rotation mergeFollow-ups, deliberately not here:
spawn_blockingfor the persist itself (the KDF still runs inline, now at most once per 15 s batch), and splitting transfer progress out of the app state (10 Hz full-tree recomposition).Diagnosed from the tap path: a click dispatches into a serialized Kotlin worker that only forwards to the Rust backend, so tap latency is decided by the worker loop in core/src/runtime.rs. Three things stacked there after the last release: - Every successful Android connect stamps last-used (touch_host) with a full host record, so the worker ran a complete vault save - Argon2id at 64 MiB, re-derived by the keepass crate on every write ("keys and seeds on the fly when saving") - on the loop, right after the user started tapping around the new session. - save_host then awaited the WebDAV sync inline, so the whole network round trip (with retry backoff on failure) also ran on the loop. During those seconds no command was processed and no event emitted: every further tap queued behind the network. - Nothing showed on screen, because HostSaved is emitted before the sync and clears the busy flag; taps just appeared dead. On a phone the KDF is several times slower than the "roughly a second on a desktop" the parameters are tuned for, and the sync rides mobile network. Changes: - touch_host now sends TouchHost; the worker batches stamps like OS observations and flushes them in one save after 15 s, skipping missing or recycled hosts silently. Lock and shutdown flush first, so stamps survive. - Post-save syncs are debounced (2 s) and run on a clone of the WebDav client in a spawned task; the loop keeps taking commands and events while the request is on the network. The finished client copy returns with its updated sync history, guarded by a generation counter against reconfigure or lock mid-flight; a baseline reload requested during a password change is replayed when the client is restored. A sync requested while one is in flight is remembered and runs after. Shutdown still syncs inline and drains an in-flight request first, bounded by the existing timeout. - The Android shell's busy bar also shows while a sync runs, so the remaining rare stalls are visible. Verify: cargo test -p ferry-core -p ferry-ffi (373 tests, including touch batching and the deferred password-rotation merge). The JVM contract tests need a JDK/SDK absent here, so the Gradle suite is left to CI. Debug builds of the native core remain unoptimized by default (FERRY_ANDROID_PROFILE=release for distribution); that is documented and unchanged.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.