Implement independent hardening and regression coverage. Keep #105 open for final feature and environment coverage after #106–#110; document the completion boundary and resume order.
109 lines
6.5 KiB
Markdown
109 lines
6.5 KiB
Markdown
# Android hardening
|
||
|
||
The Android presentation layer uses resource strings for Kotlin-owned notices,
|
||
action labels, counts, and durations. Rust-owned presentation text remains opaque:
|
||
frontends do not parse or translate it. Repeated editor actions include the field
|
||
label, and hidden editor values are checked against the actual Android accessibility
|
||
node tree as well as Compose semantics. Compose accessibility checks run before
|
||
interactions in every app screen test.
|
||
|
||
Blank name searches do not traverse the password store. QR luminance inputs reject
|
||
zero or greater-than-4096 dimensions before allocating the decoder image; owned
|
||
decoded luminance bytes are zeroized. License loading runs on the IO dispatcher.
|
||
Editor keystrokes coalesce encrypted recovery checkpoints for 150 ms; save,
|
||
reorder, and recovery wait for the latest checkpoint. This changes persistence
|
||
scheduling, not authorization or the interactive unlock boundary.
|
||
|
||
## Native journey budgets
|
||
|
||
The `android_ci.py emulator <serial>` gate requires exactly one numeric measurement
|
||
for each journey below and rejects missing, duplicate, malformed, or over-budget
|
||
values. Raw fixture output remains local; published reports contain numeric values
|
||
and test status only. The large-tree fixture contains 1,000 valid encrypted entries
|
||
in 50 folders. These timings measure native/repository work, not rendered frame
|
||
latency or a physical device.
|
||
|
||
| Journey | Required budget | API 26 ARM64 / 4 KB | API 37 ARM64 / strict 16 KB |
|
||
| --- | ---: | ---: | ---: |
|
||
| 100 editor input updates | < 500 ms | 4 ms | 6 ms |
|
||
| Editor update p95 | < 32,000 μs | 61 μs | 102 μs |
|
||
| TOTP discovery cache rebuild | < 15,000 ms | 1,924 ms | 1,861 ms |
|
||
| QR image analysis | < 5,000 ms | 99 ms | 91 ms |
|
||
| 1,000-entry tree navigation | < 3,000 ms | 11 ms | 11 ms |
|
||
| 1,000-entry name search | < 5,000 ms | 27 ms | 26 ms |
|
||
|
||
Both configurations reported `OK (31 tests)` for app instrumentation and passed
|
||
the native core journey and bridge suite. Opt-in inspection and biometric tests
|
||
remain assumption-skipped unless explicitly requested; these runs do not establish
|
||
their manual coverage. Native load samples ranged from 32.7–35.2 ms on API 26 and
|
||
63.3–78.7 ms on API 37 with strict 16 KB pages. Five debug cold starts ranged from
|
||
202–279 ms and 708–1,086 ms respectively. These debug activity timings are separate
|
||
from release Macrobenchmark startup measurements.
|
||
|
||
## Adaptive checks
|
||
|
||
`Tier2WindowTest` exercises searchable Preferences and keyboard activation using
|
||
actual window dimensions. The API 26 emulator passed compact (411 dp), medium
|
||
(640 dp), expanded (1,067 dp), 200% font with RTL, landscape with 200% font and RTL,
|
||
and a smaller window with 200% font. Size, density, font scale, and rotation settings
|
||
were restored after the run. This covers window geometry; it does not establish
|
||
hinge occlusion or folded/tabletop posture behavior.
|
||
|
||
The shell consumes IME insets, and the activity explicitly requests `adjustResize`.
|
||
The optional `hardeningIme=true` instrumentation argument opens a real keyboard
|
||
and checks shell content bounds against the platform IME inset. It reproduced an
|
||
overlap before the shared-shell fix and passes afterward on API 26 and API 37 with
|
||
strict 16 KB pages. Temporarily enable `show_ime_with_hard_keyboard` for this check
|
||
and restore its original value afterward. Full app instrumentation also reported
|
||
`OK (31 tests)` with `hardeningRtl=true` on the strict 16 KB image.
|
||
|
||
## Release benchmarks
|
||
|
||
`android_ci.py performance <serial>` installs the benchmark app over the retained
|
||
installation and records five cold and five warm startup iterations. The benchmark
|
||
variant uses release code and shrinking, debug signing, and shell profiling; the
|
||
distributed release variant does not enable profiling. `ReportDrawnWhen` waits for
|
||
the shell to leave its native loading state. Compilation is preserved rather than
|
||
resetting application data.
|
||
|
||
The startup gate requires five complete numeric initial/full-display samples for
|
||
each mode, with cold startup below 5,000 ms and warm startup below 3,000 ms.
|
||
Before installing the generated profile, release-like median full-display times
|
||
were 268.6 ms cold / 131.2 ms warm on API 26 and 1,203.5 ms cold / 427.0 ms warm on
|
||
API 37. These emulator observations preserve existing compilation state and are
|
||
not a claim of profile speedup. Raw traces and device metadata stay local; CI
|
||
artifacts retain only API/ABI and the reviewed numeric samples.
|
||
|
||
`android_ci.py profiles <serial>` generates a profile from startup and the existing
|
||
Preferences journey. Generation requires API 34 or newer so compilation reset
|
||
does not fall back to reinstalling the app on older non-rooted images. Inspect the
|
||
generated local artifacts before promoting them into the app source set. Generation
|
||
uses a non-obfuscated `profile` variant, while startup measurements use the shrunk
|
||
`benchmark` variant. Both use release source code and debug signing.
|
||
|
||
The committed `app/src/main/baseline-prof.txt` was generated on the API 37 ARM64
|
||
emulator from the startup/Preferences journey on 2026-10-11, with 22,331 rules and
|
||
SHA-256 `687afdc199dacf0736dc1c577767dea9b81ddc987b5b61b02b5afed5e501b503`.
|
||
Regenerate it with the `profiles` command after changing those journeys; use the
|
||
untimestamped `BaselineProfile_startupAndPreferences-baseline-prof.txt` output,
|
||
check that application class names are unobfuscated, and rebuild the release APK
|
||
to verify its compiled `assets/dexopt/baseline.prof` remains within ART's size limit.
|
||
|
||
## Completion boundary
|
||
|
||
Issue #105 explicitly depends on every Android feature UI issue. CameraX (#106),
|
||
TOTP list/detail (#107), mutation workflows (#108), Credential Manager/Autofill
|
||
(#109), and TOTP discovery UI (#110) are still open. Their final screen accessibility,
|
||
camera interruption, cached-open/refresh presentation, and provider response
|
||
latency cannot be certified by tests of the existing screens. Keep #105 open until
|
||
those implementations and the remaining environment/posture checks are complete.
|
||
ARMv7 is package-validated; the installed runnable emulator images are ARM64.
|
||
|
||
On 2026-10-11 the user explicitly requested committing the independent implementation
|
||
now and delaying final coverage. Issues #106–#110 received `critical`; resume those
|
||
eligible Android enhancements in numeric order, then revisit #105. Remaining
|
||
checks include TalkBack/Switch Access and contrast/motion modes across the finished
|
||
screens, real hinge/posture and live-resize coverage, and low-memory, doze, battery,
|
||
network, camera-interruption, and storage-pressure scenarios. Do not close #105
|
||
based solely on the current instrumentation and window-geometry results.
|