Gobley's cargo plugin enumerates Kotlin targets at gradle configure
time and queries rustup for each one — including the JVM host target,
even though we never build for it (`androidUnitTest = false` skips
wiring the JVM cargo build into Android unit tests, but the build
entry is still created at configure time).
Without `x86_64-unknown-linux-gnu` installed, that lookup returns
null and `:app:lint` / `assembleRelease` die with a bare
`NullPointerException` during project configuration.
Add the target as a workflow step in the lint and lsposed jobs so
this PR's CI passes immediately, and bake it into the CI Dockerfile
so subsequent image rebuilds carry it.
- Rename lint-rust → lint, add clang-format and ktlint checks
- Add cargo test step for zygisk unit tests
- Install clang-format and ktlint 1.8.0 in CI Docker image
- Add Google's AOSP clang (clang-r487747c, same as Pixel kernel build)
to the CI Docker image via sparse checkout. Distro clang caused ABI
mismatches leading to bootloops on device.
- Update kmod workflow to use the Docker image + AOSP clang instead of
system clang from apt.
- Replace symvers with real vmlinux.symvers from Pixel kernel build
(8050 symbols vs 4060 from device .ko extraction).
- Add kmod build deps (bc, kmod, cpio, binutils-aarch64) to Docker image.
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.