Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
- strict no backward compatibility (0.0.x): change formats and APIs freely, no migrations.
- make changes on the sibling project ../ezvpn (the Rust core this app loads) when needed; its design notes for this app are in ../ezvpn/docs/Android-App.md. Run its `cargo ndk -t arm64-v8a --platform 29 clippy --lib -- -D warnings` after Rust changes touching the Android build.
- always test on the development emulator over adb (`10.22.35.66:5555`, an arm64 Android VM; `adb connect 10.22.35.66`); a VpnService cannot be exercised meaningfully on the JVM. `scripts/run-device.sh` targets it by default (`ADB_SERIAL` overrides), builds the local core, installs, launches, and tails logcat. Never use the physical device (`10.22.38.204:51035`, Nexus 7) for development, debug installs, or testing: it only receives the signed release APK via `scripts/install-release-apk.sh`. When several devices are attached, always pass `-s <serial>` to adb / set `ANDROID_SERIAL` for Gradle install tasks. `scrcpy -s 10.22.35.66:5555` mirrors/controls the emulator screen.
- always test on the development emulator over adb (`10.22.35.66:5555`, an arm64 Android VM; `adb connect 10.22.35.66`); a VpnService cannot be exercised meaningfully on the JVM. `scripts/run-device.sh` targets it by default (`ADB_SERIAL` overrides), builds the local core, installs, launches, and tails logcat. Never use the physical device (`10.22.38.204:5555`, Nexus 7) for development, debug installs, or testing: it only receives the signed release APK via `scripts/install-release-apk.sh`. When several devices are attached, always pass `-s <serial>` to adb / set `ANDROID_SERIAL` for Gradle install tasks. `scrcpy -s 10.22.35.66:5555` mirrors/controls the emulator screen.
- the Rust artifact (`libezvpn.so` per ABI, zipped as `libezvpn-android.zip`) is delivered by download + sha256 pin in `gradle.properties` (`app/build.gradle.kts` `fetchEzvpnJniLibs`). Bump with `scripts/bump-jnilibs.sh <tag>` after the ezvpn release workflow publishes the asset. For FFI dev against a local build run `../ezvpn/build-android.sh` then set `EZVPN_LOCAL_JNILIBS=1` for every gradle invocation — only the exact value `1` opts in.
- `EzvpnNative` must stay at `dev.flexaccess.ezvpn.EzvpnNative`: the JNI symbol names in ../ezvpn/src/ffi_android.rs encode that class. `EzvpnNative.init(context)` must run once before anything else (Application.onCreate): it registers the JVM/context that iroh's Android DNS/interface discovery needs, or the first connect aborts the process.
- pure logic (CIDR math, the bypass-by-subtraction route plan, profile model/validation, split-DNS rules, JSON shapes) lives in `tunnelcore` (no Android deps) so it is unit-testable with `./gradlew :tunnelcore:test`. Put new pure helpers there, not in the service.
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Design and the JNI contract are documented in the core repo:
- An Android 10+ (`minSdk` 29) target. Development is done against the
emulator (`10.22.35.66:5555`, an arm64 Android VM bridged onto the LAN like a
phone; `adb connect 10.22.35.66`) — a `VpnService` cannot be exercised on the
JVM. The physical device (`10.22.38.204:51035`) is reserved for installing
JVM. The physical device (`10.22.38.204:5555`) is reserved for installing
the signed release APK and is never used for development.
- For FFI work: the sibling `../ezvpn` checkout, the Android NDK and
`cargo-ndk` (see that repo's `build-android.sh`).
Expand Down Expand Up @@ -69,11 +69,16 @@ signature); uninstall the other one first.
The signed APK is the only thing that goes on the physical device:

```bash
scripts/install-release-apk.sh # dist/ezvpn-android-<version>.apk → 10.22.38.204:51035
scripts/install-release-apk.sh # dist/ezvpn-android-<version>.apk → 10.22.38.204:5555
scripts/install-release-apk.sh --build # build it first
scripts/install-release-apk.sh --launch # and start the app
```

The tablet listens on a fixed port because `persist.adb.tcp.port=5555` was
set on it as root (Developer options → Rooted debugging, then `adb root` and
`adb shell setprop persist.adb.tcp.port 5555`); Android's *Wireless debugging*
mode would pick a new random port on every toggle or reboot.

It verifies the signature with `apksigner` and refuses unsigned or
debug-signed APKs, and refuses to target the emulator
(`RELEASE_DEVICE_SERIAL` / `EMULATOR_SERIAL` override the serials).
Expand Down
2 changes: 1 addition & 1 deletion scripts/install-release-apk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."

EMULATOR_SERIAL="${EMULATOR_SERIAL:-10.22.35.66:5555}"
RELEASE_DEVICE_SERIAL="${RELEASE_DEVICE_SERIAL:-10.22.38.204:51035}"
RELEASE_DEVICE_SERIAL="${RELEASE_DEVICE_SERIAL:-10.22.38.204:5555}"

BUILD=0
LAUNCH=0
Expand Down
2 changes: 1 addition & 1 deletion scripts/run-device.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ done

# The development emulator and the physical device the signed APK goes to.
EMULATOR_SERIAL="${EMULATOR_SERIAL:-10.22.35.66:5555}"
RELEASE_DEVICE_SERIAL="${RELEASE_DEVICE_SERIAL:-10.22.38.204:51035}"
RELEASE_DEVICE_SERIAL="${RELEASE_DEVICE_SERIAL:-10.22.38.204:5555}"

ADB_SERIAL="${ADB_SERIAL:-$EMULATOR_SERIAL}"
if [ "$ADB_SERIAL" = "$RELEASE_DEVICE_SERIAL" ]; then
Expand Down
Loading