Everything this application knew about a failure went to stderr on the desktop and to logcat on Android, and both are gone the moment the terminal closes or the ring buffer wraps. That is fine when the person debugging is sitting at the machine. It is useless for the case NFR-OPS-1 actually describes, and the one Android makes normal: somebody reproduces a bug on a tablet, and then sends us a file. A large amount of Android behaviour has never run on a device — image intents read over JNI, an ExportProvider, a class loaded through the activity's class loader, memory-pressure eviction, lost-root recovery — and the single most likely failure of the lot, the activity's loader not resolving our classes from android_main's thread, produces one line that scrolls past. That line is now in a file, with the thread that emitted it named beside it. dr_plat::state answers "where does this platform keep state for this app": $XDG_STATE_HOME/darkroom on Linux, and on Android whatever the entry point declares. Separate from configuration and from the catalog for the reason XDG separates them — state is the thing nobody backs up and the user may delete without consequence. dr_plat::diagnostics is the sink. Two files of 4 MiB, so the worst case is a number rather than a discovery on a full phone; one line per write with no BufWriter anywhere, because on Android processes are killed rather than ended and a buffered log loses exactly the line it was kept for; and redaction applied at the sink rather than at the call sites, since a rule every author has to remember is not a rule. It tees the platform's own logger rather than replacing it, so logcat is unchanged — losing that while debugging would have made this a downgrade. Android logs to external_data_path, not internal. Both are app-private and both survive backgrounding; what separates them is that /data/data/<pkg>/files needs run-as against a debuggable build to read and /sdcard/Android/data/<pkg>/files is a plain adb pull from any build. A log nobody can retrieve is not a diagnostic. The consequence is that anyone holding the tablet can read it, which is why the redaction is where it is, and why configuration stays on internal_data_path. What is redacted is what NFR-SEC-2 and NFR-OPS-1 name: credentials and tokens, found by the keyword that nearly always sits next to them, plus the two forms that carry one with no keyword at all — an Authorization scheme and a URL's userinfo. What is deliberately not redacted is filesystem paths and the names of the user's photographs. They are in neither requirement's list, and "failed to decode <redacted>" is not a diagnostic; the preview-and-consent step NFR-OPS-1 asks for governs those better than scrubbing would, because it lets the user look. The over-redaction failure is tested as carefully as the under-redaction one. A scrubber that eats "using basic sRGB as the fallback" makes a log useless without ever being caught.
54 lines
2.3 KiB
TOML
54 lines
2.3 KiB
TOML
[package]
|
|
name = "darkroom-android"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
rust-version.workspace = true
|
|
license.workspace = true
|
|
|
|
# A cdylib, not a bin: Android loads the app as a shared library and calls
|
|
# `android_main` through android-activity's glue. Nothing execs a binary, so
|
|
# there is no `main` to provide.
|
|
[lib]
|
|
name = "darkroom"
|
|
crate-type = ["cdylib"]
|
|
|
|
[dependencies]
|
|
# No backend feature to select: dr-ui picks its Slint backend from the target,
|
|
# so building for aarch64-linux-android gets android-activity automatically.
|
|
dr-ui.workspace = true
|
|
# For `account::set_data_dir`: only the platform entry point knows where Android
|
|
# lets this app keep files, and it must be set before any store is opened.
|
|
dr-sync.workspace = true
|
|
# For `state::set_state_dir` and `diagnostics::install`, for the same reason and
|
|
# with the same ordering constraint: the log file has to be opened somewhere the
|
|
# platform will actually let us write, and only this file knows where that is.
|
|
dr-plat.workspace = true
|
|
# Directly, not just through dr-ui: `android_main` takes an `AndroidApp` and
|
|
# calls `slint::android::init`, both of which come from this crate. The backend
|
|
# feature comes from dr-ui's target-specific dependency.
|
|
slint.workspace = true
|
|
log.workspace = true
|
|
android_logger = "0.15"
|
|
|
|
# The launch Intent and the share sheet are Java-only surfaces — see `intents`
|
|
# — and JNI is the only way to reach them.
|
|
#
|
|
# Target-gated because the crate still has to compile on the host: it is a
|
|
# workspace member, `cargo test --workspace` builds it, and the manifest tests
|
|
# in `lib.rs` are the one part of it that runs there.
|
|
#
|
|
# 0.21 rather than the 0.22 that android-activity 0.6 uses. Both are already in
|
|
# the lock — Slint's Android backend depends on two major versions of
|
|
# android-activity and pulls both — so this adds nothing to the build either
|
|
# way, and every object here comes from a raw pointer rather than from a type
|
|
# android-activity handed over, so the two never have to agree.
|
|
[target.'cfg(target_os = "android")'.dependencies]
|
|
jni = "0.21"
|
|
|
|
[features]
|
|
# Mirrors darkroom-desktop: the CPU readback path is gone since S1 landed
|
|
# zero-copy. It mattered more here than on desktop — the same wrong path with
|
|
# far less memory bandwidth to absorb it (ARCH §6.1) — but it is untested on a
|
|
# device, since S1 was verified on desktop only.
|
|
default = []
|