Users routinely installed the wrong GKI variant of the kmod zip and
saw no signal beyond "installed, inactive". This adds a full chain
from build to diagnostics so the wrong-variant case is both obvious
to the user and fully captured in bug reports.
Why each piece exists:
- CI stamps `gkiVariant=<kmi>` into each variant's `module.prop`
so the app can identify what was installed without guessing.
- `post-fs-data.sh` records `/data/adb/vpnhide_kmod/load_status`
(boot_id, uname -r, gki_variant, insmod exit+stderr, kprobes,
root manager) and `load_dmesg` at every boot — this survives
reboots and is the only record of insmod failures by the time
the user opens the app.
- Dashboard reads both, always computes the kernel-based
recommendation, and emits targeted issues: wrong-variant,
unknown-variant (pre-stamp zip that also failed to load),
kmod-on-unsupported-kernel, kprobes-missing, or generic
load-failed with the captured stderr.
- Diagnostics screen adds a "Kmod load trace" card so bug
reports can come in as a screenshot, and the debug zip
includes load_status + load_dmesg for deeper analysis.
Also aligns `lsposed/native/Cargo.lock` with Cargo.toml (0.6.1
→ 0.6.2) — a real stale-lock fix surfaced by the gradle build.
Unified repository for the complete Android VPN-hiding stack:
- zygisk/ — Rust Zygisk module (inline libc hooks via shadowhook)
- lsposed/ — Kotlin LSPosed module (Java API + system_server hooks)
- kmod/ — C kernel module (kretprobe hooks, invisible to anti-tamper)
CI workflows use path filters to build only the changed component.