Files
IronStorage/docs/android/hardening.md
T
hugo 6669b77f4e
Android ARM verification / rust (push) Failing after 46m41s
Android ARM verification / android (push) Failing after 8s
Dependency security audit / rustsec (push) Successful in 22s
Harden Android accessibility, localization and startup (#105)
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.
2026-10-11 15:56:33 +02:00

6.5 KiB
Raw Blame History

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.