- Code: GPL-3.0-or-later (LICENSE, SPDX headers on all .kt/.aidl). Specs in docs/: CC-BY-4.0 (docs/LICENSE). Rationale in build-status.md; server decided GPL (not AGPL). - Root README for the public repo. - web/: Cloudflare Worker site for echo-lot.app. /apk resolves the newest APK from the Gitea latest-release API at request time (edge-cached 5 min), so tagging a release is the only publish step. /fdroid, /source, and a manual DOWNLOAD_URL fallback are wrangler vars. - .gitea/workflows/release.yml: tag-driven (v*) signed semver APK builds for the future production app in echolot-app/. Parked; the prober is deliberately not CI-built. - Fix UserService.kt: drop the explicit secondary constructor that conflicted with the implicit primary (never compiled before — first local build caught it). Prober now builds: :app:assembleDebug OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.7 KiB
Echolot — context for Claude Code
This repo is the capability prober for the Echolot project: an F/OSS Android app for detecting and debugging local network issues (target audience: network engineers). The prober validates the no-root feasibility matrix on real hardware before the production app is built.
Project facts
- Name: Echolot. Domain echo-lot.app. URI scheme
echolot://. Namespaceapp.echo_lot.*(hyphen→underscore; appIds/packages can't contain hyphens). Prober appId:app.echo_lot.prober. - Stack: native Kotlin + Jetpack Compose. No Flutter (all value is in platform APIs; Flutter would be a Dart skin over a full Kotlin app + F-Droid build friction).
- Tiers:
app(no root),shizuku(ADB-shell privileges via wireless pairing, shipped in v1),root(future module). Every result records which tier produced it. - License: code is GPL-3.0-or-later (
LICENSE), the specs indocs/are CC-BY-4.0 (docs/LICENSE). New source files get the two-line SPDX header the existing ones carry. The server, when it lands, is GPL too — not AGPL (seedocs/build-status.mdfor the reasoning).
Design docs (source of truth, in docs/)
docs/feature-catalog-and-feasibility.md— full feature list + no-root feasibility matrix.docs/measurement-schema.md— the archived/exportable measurement JSON format (observation vs finding separation, two-clock rule, columnar trains, anonymization types).docs/probe-protocol.md— client↔server wire protocol (pinned-TLS control plane, binary UDP data plane with anti-amplification HMAC, STUN, canary DNS reference records).docs/build-status.md— running log of decisions, what is delivered, and the next steps.
The three specs are draft-complete and user-reviewed; treat them as the contract. build-status.md
is the mutable one — update it as work lands.
Keep prober result IDs aligned with the measurement-schema test-type registry.
Layout
Monorepo. The prober is one deliverable; the Go server and the production app land as siblings.
docs/ design docs (above) — apply repo-wide, not just to the prober
echolot-prober/ the capability prober (self-contained Gradle build)
app/src/main/java/app/echo_lot/prober/
MainActivity.kt Compose host, runs probes sequentially
probe/ Probe interface + all app-tier probes + OS ABI helper
shizuku/ AIDL UserService + ShizukuRunner (shell command exec)
export/Report.kt JSON report + share intent
ui/ProberScreen.kt result cards colored by verdict
Conventions
- Every probe returns a
ProbeResult— never throws to the caller (MainActivity wraps anyway). - Uncertain OS API paths (getsockoptInt, recvmsg, nat64Prefix) are reached via reflection/runCatching and reported, not assumed — the prober's purpose is to discover what exists.
- Hardcoded Linux sockopt ABI numbers live in
OsAbi.ktwith rationale; do not "fix" them to OsConstants names that don't exist.
Build
From echolot-prober/: ./gradlew :app:assembleDebug (needs local Android SDK; set sdk.dir in
echolot-prober/local.properties). The Gradle build is rooted there, not at the repo root.
First build downloads AGP/Compose/Shizuku from Google Maven + Maven Central.
Likely next steps
- Run on physical devices; collect JSON reports across Android versions/vendors.
- If
trace.errqueue_reachableis PARTIAL, add the C-over-JNI errqueue shim (recvmsg + cmsg parse) as a:nativemodule and a realtraceroute.udp4probe. - Fold the confirmed capabilities + Shizuku dump-format samples back into the production
core-probe/core-shizukumodules.