Skip to content

Latest commit

 

History

History
349 lines (266 loc) · 14.1 KB

debugging.md

File metadata and controls

349 lines (266 loc) · 14.1 KB

Debugging Navi

Practical loops for host (Rust) and Android Automotive (Kotlin + libnavi.so). Build/install details: android-build.md. Hardware checklist: real-hardware-testing.md. Where to change zoom, approach, routing, HUD: codebase-map.md. Callable APIs: API.md.

Debug route simulation (debuggable builds only; feeds the live applyFix pipeline at maxspeed / highway-fallback pace): route-simulation.md.

Quick orientation

Layer What breaks First tool
Rust core (driver-break-core) Routing, POI, eco, config cargo test / RUST_LOG
UniFFI (navi-ffi → libnavi.so) Missing symbols, wrong ABI Rebuild native + reinstall APK
Android host (app/) HUD, MapLibre, sheets adb logcat, Android Studio
Emulator / AAOS Yellow border UI, wrong user ./scripts/launch-navi-emulator.sh

Application id: no.navi.app. Main activity: no.navi.app/.MainActivity.


1. Host (Rust) debugging

Unit / integration tests

# Fast focused modules
cargo test -p driver-break-core poi::
cargo test -p driver-break-core config::eco -- --nocapture

# Ignored (large) integrations — need fixtures under core/target/…
cargo test -p driver-break-core --test kongsvinger_lillehammer_integration \
  -- --nocapture --ignored
cargo test -p driver-break-core --test dnt_hiking_integration \
  -- --nocapture --ignored

Use --nocapture so println! / logging from the test binary stays on the terminal. Notes from past runs: test-results.md.

IDE / debugger

  • Open the workspace in VS Code (rust-analyzer) or RustRover.
  • Set breakpoints in core/src/… and debug a single cargo test target (same filters as above).
  • For UniFFI boundary issues, prefer a failing cargo test -p navi-ffi or an Android instrumented call that hits the same FFI function, then bisect in Rust.

Logging

The core does not require a special env for most tests. When adding temporary diagnostics, prefer eprintln! in tests or structured logs you already use in that crate — remove noise before committing.


2. Android: install a debuggable build

Always rebuild the native library when Rust changed, then install the debug APK:

export ANDROID_HOME="${ANDROID_HOME:-$HOME/Android/Sdk}"
export ANDROID_NDK_HOME="${ANDROID_NDK_HOME:-$ANDROID_HOME/ndk/<version>}"

# Emulator ABI
./scripts/build-android-native.sh x86_64-linux-android debug   # or release
./gradlew :app:installDebug
./scripts/launch-navi-emulator.sh

Physical arm64 head unit: use aarch64-linux-android instead of x86_64-….

Stale libnavi.so is a common “debug red herring”: Kotlin looks fine, FFI returns wrong data or crashes. If behaviour and code disagree, re-run build-android-native.sh and reinstall.


3. Logcat (primary on-device tool)

# Clear, then follow Navi-related tags
adb logcat -c
adb logcat -v time \
  HudVerification:V NaviTracks:V NaviMapTest:V BearingCrash:V \
  AndroidRuntime:E libc:F DEBUG:F *:S

Useful tags seen in-tree:

Tag Area
HudVerification HUD / settings hooks, screenshots, camera errors
NaviTracks Moving-icon / APRS overlay load
NaviMapTest Corridor / map instrumented tests
BearingCrash MapLibre bearing isolation tests
AndroidRuntime Java/Kotlin uncaught exceptions
DEBUG / tombstones Native crashes (libnavi.so, MapLibre)

Broader MapLibre / GL noise (when investigating map crashes):

adb logcat -v time | grep -iE 'maplibre|libEGL|GLES|vulkan|navi|UnsatisfiedLink'

On Automotive multi-user AVDs, confirm you are looking at the driver user (often user 10):

adb shell am get-current-user
adb shell ps --user 10 | grep navi || true

3b. Diagnostic session log (on-device file)

When Tools → Diagnostic logging is on, Navi writes a pipe-delimited session file under shared storage so you can copy it with a plain USB cable (MTP) — no adb or developer tools required.

Preferred path on the device:

/storage/emulated/0/Documents/debug/navi_session_YYYY-MM-DD_HH-mm-ss.log

In a file browser / MTP mount that usually appears as:

Internal storage → Documents → debug → navi_session_….log

(Linux desktops may show a GVFS path such as /run/user/…/gvfs/mtp:host=…/Intern lagring/Documents/debug/ — that is the desktop’s mount of the same folder, not something the app hardcodes.)

Scoped storage on Android 10+ does not allow creating a new top-level /debug folder without MANAGE_EXTERNAL_STORAGE (avoided here). If Documents/debug is not writable, Navi falls back to Download/debug, then (only as a last resort) app-private storage.

Basemap / DEM downloads stay in app-private storage; only diagnostic / plugin debug files use the shared Documents (or Download) debug tree.

Plugin debug files

Product plugins (when shipped) and host-side plugin helpers that need on-device debug artifacts must write under the same shared debug folder, in a subfolder named after the plugin:

/storage/emulated/0/Documents/debug/<plugin-name>/…

USB / MTP:

Internal storage → Documents → debug → <plugin-name> → …

Use a stable plugin id matching the manifest name (e.g. right-to-roam-camping, safety-resupply). Core Navi sessions stay at the debug/ root (navi_session_….log); do not mix plugin files into that root. See plugins.md.

Retrieve via USB (no adb)

  1. Enable Tools → Diagnostic logging and use the app so a session file is written (or turn the toggle off to flush/close the current file).
  2. Connect the device with a USB cable and choose File transfer / MTP (not “Charging only”).
  3. On the computer, open the device storage → Documents → debug.
  4. Copy navi_session_….log (and any debug/<plugin-name>/ trees you need).

Tools → Export diagnostic log still opens Android’s share sheet if you prefer email/Drive/etc.

Categories (only these; not a logcat mirror): GPS, CAMERA, TOGGLE, SETTING_SAVED, ROUTE_PLAN, ROUTE_PLAN_STAGES, ECO_CALC, POI_FOUND, PAUSE_PLANNED, INSTRUCTION, FUEL_ADDED, SYSTEM. GPS is rate-limited (about once per 3 s or 25 m move). Off by default; when off, no file is created and native per-stage plan timing is also gated off. Older sessions are rotated (last 10 kept).

Route-plan timing: with logging on, a completed plan writes status=complete … distance_km=… plan_duration_ms=… on ROUTE_PLAN, plus one ROUTE_PLAN_STAGES line of per-stage milliseconds (motor vs hiking use different stage keys). Useful to confirm planning is PBF-load-bound rather than A*-bound — see README Known issues.

Extreme slowness checklist: if every plan takes tens of seconds across modes, look for pack_hit=false (and usually large graph_build_ms / poi_barrier_ms) in the session report. That means indexed packs are missing, stale, or still converting — A* is typically sub-second. Fix: wait for background indexing after download, or Tools → Rebuild indexed maps. .navigph files are deprecated and do not speed plans.


4. Android Studio / breakpoints

  1. Open the repo (or the app module) in Android Studio.
  2. Run → Attach Debugger to Android Process → no.navi.app (pick the correct user process if several appear).
  3. Set breakpoints in Kotlin under app/src/main/java/no/navi/app/ (MainActivity, DriveHud, tests under androidTest).

Native (Rust / JNI) breakpoints need an NDK debug build of libnavi.so and an lldb attach workflow; day-to-day Navi debugging is usually logcat + Kotlin debugger + Rust unit tests, not full JNI stepping.

Compose UI: use Layout Inspector and test tags (top_drive_hud, bottom_drive_hud, map_settings_sheet, status_toast, …) with instrumented tests or adb shell uiautomator dump.


5. Instrumented tests as a debug harness

./gradlew :app:installDebug :app:installDebugAndroidTest

# One class (APKs stay installed after the run — see
# android.injected.androidTest.leaveApksInstalledAfterRun in gradle.properties)
./gradlew :app:connectedDebugAndroidTest \
  -Pandroid.testInstrumentationRunnerArguments.class=no.navi.app.HudVerificationInstrumentedTest

# One method
./gradlew :app:connectedDebugAndroidTest \
  -Pandroid.testInstrumentationRunnerArguments.class=no.navi.app.HudVerificationInstrumentedTest#hud_map_tap_does_not_affect_settings_sheets

Do not adb uninstall no.navi.app between debug iterations — that deletes app-private indexed packs, place index, and PMTiles. Use :app:installDebug (in-place update) or adb install -r. Uninstall only when switching signing keys (debug ↔ release) or deliberately testing a fresh install.

Watch the same logcat tags while the suite runs. HUD screenshots are written under the app external files dir (and sometimes mirrored under /data/local/tmp/); see android-test-results.md.

NaviMapTestHooks injects camera, headings, altitude, and sheet open requests for tests — useful when reproducing HUD/map issues without manual UI.


6. Emulator pitfalls

Symptom What to try
Yellow “bordering activity” screen ./scripts/launch-navi-emulator.sh (disables display-compat wrapper)
App missing / wrong UI on AAOS Launch with --user 10 (driver); reinstall for that user
MapLibre SIGSEGV on bearing (old GLES SDK) Default is GLES android-sdk:11.13.5 after AAOS re-check PASS; if regression, re-run BearingCrashIsolationTest — see README known issues
Gestures / pan seem dead Overlay must forward touches (see map Canvas pointerInteropFilter); confirm in logcat / HUD map-tap test
Icons show fallback / no eco leaf Clear app files/icons and relaunch so ensureIconsCopied refreshes leaf.svg

7. Crash dumps

# Java stack
adb logcat -b crash -d

# Native tombstone (path varies by device)
adb shell ls /data/tombstones/ 2>/dev/null
adb bugreport bugreport.zip   # heavy; use when filing hardware issues

For hardware runs, attach full untruncated logcat as required by real-hardware-testing.md.

Nightly instrumented phone-AOSP crash

Evidence from GitHub Actions run 30334233545 (commit 418f952), job connectedDebugAndroidTest:

Fact Value
AVD package system-images;android-30;default;x86_64
Profile Generic phone AOSP (target: default), not Automotive
GPU -gpu swiftshader_indirect
Fail point ApproachInstructionInstrumentedTest.approachAppearAndUrgencyScreenshots at 3/50
Gradle report Empty <failure/>; then Process crashed
Emulator lines (untruncated excerpt) See below
INFO | Created VkInstance:... for application:'maplibre-native' ...
INFO | Created VkDevice:... for application:'maplibre-native' ...
INFO | Destroyed VkDevice:...
INFO | Destroyed VkInstance:... for application:'maplibre-native' ...
no.navi.app.ApproachInstructionInstrumentedTest > approachAppearAndUrgencyScreenshots[...] FAILED
emulator-5554 - 11 Tests 3/50 completed. (0 skipped) (1 failed)
Test run failed to complete. Instrumentation run failed due to Process crashed.

Create→destroy of MapLibre Vulkan in about one second, before any meaningful approach screenshot work, points at a native crash / aborted MapView on that phone image — not a Java assertion with a missing stack, and not OOM from a long suite (positions 1–2 are HideDistance JNI checks with no MapLibre). CI did not upload logcat/tombstones on that run; local AAOS reproduction of tests 1–3 passed with no new tombstone (only Zygote signal 9 after a clean run finished: 3 tests, 0 failed).

Mitigation: nightly workflow retargeted to API 33 android-automotive with -memory 4096, post-boot wm size 1920x1080 (avoid emulator -skin on this AVD), and scripts/ci-connected-android-test.sh for continuous logcat + report upload (instrumented-evidence/). Evidence steps use if: always() / an EXIT trap / host runner/ fallbacks; cancel-in-progress is false so a diagnostic workflow_dispatch is not killed mid-suite by a later push. First Automotive confirmation (30363333076): process-crash abort did not recur; approach failed approach box must be compact (was 209px of 320.0px screen) on the default narrow skin instead — assertion now uses the 420.dp product cap, with the 45% width fraction only on screens ≥ 720px. Note: android-emulator-runner runs each YAML script: line as its own sh -c, so multi-line inline scripts cannot share variables (that broke evidence mkdir on 30364223279). Cancelled mid-suite run 30364672472 still uploaded a 3.7 MB continuous logcat (approach passed after the assert fix; Basemap was in progress when concurrency cancelled the job). Complete evidence from 30369028382: Basemap dies on the Mapterhorn 3D+tilt segment under the 4 GB CI AVD (guest overcommit; no tombstone); offline+boundary shots pass. CI keeps -memory 4096 and skips that 3D segment via instrumentation arg navi.ci=true (host CI= is invisible on-device) — full 3D remains local/hardware.


8. Minimal “something is wrong” loop

  1. Reproduce on emulator with installDebug + launch-navi-emulator.sh.
  2. Capture adb logcat for the tags above from cold start through the failure.
  3. If FFI/routing related: reproduce with a Rust test or re-run build-android-native.sh and reinstall.
  4. If UI/HUD related: run the relevant *InstrumentedTest method; pull screenshots from the device files dir.
  5. On a real head unit: follow real-hardware-testing.md and keep logs + screenshots together.