MotorSignal-App/docs/qa-2026-10-01/permission.md

8.4 KiB
Raw Permalink Blame History

P2 permission recovery / ANR investigation

Disposition: permission denial, recovery, recording persistence, and Android revocation termination reproduced. No ANR occurred during this run. GPS re-acquisition after restoring global location could not be verified because the isolated emulator delivered no new fix after the toggle. No product files changed.

Build, device, and isolation

  • Dedicated fresh Pixel 8 Pro AVD Pixel8Pro_QA, serial emulator-5556, Android 17 / API 37. emulator-5554 stayed exclusively with the P1 owner and was not accessed.
  • Installed app.motorsignal.motorcycle, versionCode 102 / versionName 1.0.2, APK SHA-256 279F561D8DB91D01138321EE2666B2029D239BC6008809E802458FF835796AA2 (root-confirmed build).
  • Wi-Fi, cellular data, and airplane-mode state were set offline before launch. dumpsys connectivity reported Active default network: none. No backend account was signed in or created. No production request/write was made.
  • Logcat captured with adb logcat -c and adb -s emulator-5556 logcat -v threadtime to %TEMP%\MotorSignal-QA-2026-10-01-p2-permission.log (3,747,443 bytes; stopped after tests). Permission state and activity state were sampled at each transition. Logcat contains the explicit system revocation kill below; no app FATAL EXCEPTION or ANR lines were found.

Scenario results

Scenario Result Evidence
Deny permission on first launch PASS — degraded UI verified At 06:24–06:25 EDT, denied the Android location and notification prompts. Fine/coarse permissions showed granted=false, `USER_SET
Deny while app is open / retry PASS — denial handled; recovery route limited At 06:26 EDT, tapping Enable while open showed the separate notifications prompt; after denial, another Enable tap left fine/coarse location denied and returned to the app without a location prompt or Settings page. No hang/ANR. User can recover manually through Android Settings; the dashboard banner remained after returning from Settings until Enable was tapped again. See permission-enable-prompt.png, permission-recovery-after-denial.png, and permission-recovery-settings.png.
Grant through Settings PASS — permission state recovered after app action At 06:27–06:28 EDT, Android Settings showed MotorSignal Location as “Don’t allow”; changed to “Allow only while using the app.” Package manager then reported fine/coarse granted=true. Returning to the app alone left the banner stale; tapping Enable invalidated the cached permission result, removed the banner, and the dashboard showed GPS 3D FIX: permission-recovery-app-button.png. No external network was available.
Revoke during recording PASS — Android termination classified; recording data persisted Started Ride 1 at 06:29:13 EDT; dashboard showed RECORDING and GPS 3D FIX: permission-recording-before-revoke.png. Revoked fine then coarse location at 06:29:49. Logcat: ActivityManager: Killing 5633:app.motorsignal.motorcycle/u0a230 (adj 0): permissions revoked; Android removed MainActivity with app died, no saved state. This was expected OS process termination, not an app ANR or crash. lastanr returned <no ANR has occurred since boot>; dumpsys dropbox --print data_app_anr returned (No entries found).
Relaunch after revocation PASS — local ride recovered Relaunched at 06:31:38, denied location again, and app reached STANDBY without ANR. Activity showed Ride 1: permission-restart-after-revoke.png, permission-recovered-ride-history.png. Read-only SQLite copy after restart: SHA-256 FDCB156A688678AFF515898ECCE7422DFAAC2470D9678188C882ACFBC80D67E4; ride 1 had start_time=1790850553, end_time=1790850588, 704 telemetry samples spanning those timestamps. The ride was ended/recovered at its last persisted sample; no sample loss across process termination was observed. DB artifact: permission-recording-after-restart.sqlite. The copy immediately after termination had SHA-256 D12108B8D77BD6294C2BC4FCFCB5B80EEBEE65406C3486E45B1A1A371726F5B4 and the same 704 samples; permission-recording-after-revoke.sqlite.
GPS unavailable during recording PASS — degraded state visible Started Ride 2 at 06:34:52. With permission granted, turned global location off at 06:35:21 (location_mode=0). Android displayed “No location access.” After closing the dialog, recording remained active and dashboard showed NO GPS plus DEGRADED; package manager still showed fine/coarse granted=true: permission-gps-off-recording.png.
GPS restoration during recording BLOCKED — no fresh emulator fix Restored global location to mode 3, confirmed Android Settings “Use location” was on, and sent adb emu geo fix -122.4194 37.7749 15; also toggled location off/on from Android Settings at 06:39:17. No gps provider received location[1] records appeared after 06:29:48, and dashboard remained NO GPS / DEGRADED: permission-location-settings.png, permission-gps-restored-recording.png. Stopped Ride 2 locally at 06:40:43. Final SQLite SHA-256 4488B773924C9571E5DE681D6FA15177AC1EE2BFB81310B5D734B6E2A2074A0C; Ride 2 persisted with 5,624 samples, all with null latitude/longitude/GPS accuracy. permission-final.sqlite. Because the emulator provided no new fix, this does not establish whether app recovery works after a fresh fix; it is not marked PASS or a confirmed app defect.
ANR / hang classification PASS — no current-run ANR Throughout this run dumpsys activity lastanr stayed <no ANR has occurred since boot>, Dropbox had no data_app_anr, and the app remained responsive. Revocation log explicitly attributes process death to Android permission revocation. This classifies the reproduced revocation event only. Root separately found a historical 2026-09-30 18:52:28 data_app_anr on 5554 with an input dispatch timeout and CPU saturation; its root cause remains uncertain and is not explained by this run.

Source inspection (code facts only)

  • lib/services/location_service.dart: startup initializes the location stream; requestPermissions() checks/requests Geolocator and Permission.locationWhenInUse, requests notifications, then calls _startListening() after a recognized grant. Exceptions are swallowed and reported as false. The watchdog attempts a current fix after the last accepted fix is older than two seconds; stream errors schedule a new subscription after two seconds.
  • lib/features/dashboard/widgets/dashboard_alert_region.dart: the banner depends on locationPermissionGrantedProvider; Enable calls the permission service and invalidates the provider. The observed stale banner after a Settings grant persisted until this action invalidated the provider.
  • lib/services/telemetry_service.dart: the authoritative 20 Hz sampler emits while GPS is null/stale; GPS age increases for retained positions. Runtime samples with GPS off were null in Ride 2; this alone does not validate stale-position behavior when a last fix exists.

Cleanup and limits

  • Stopped the app's test recording, stopped the dedicated emulator with adb -s emulator-5556 emu kill, and removed the newly created Pixel8Pro_QA AVD config/data after preserving screenshots and SQLite evidence. emulator-5554 was not touched.
  • Stopped the P2 logcat capture process. Raw log retained in %TEMP% for this session; useful extracted evidence is summarized above.
  • No accounts, fixtures, production settings, or backend data were changed. Permission/GPS tests ran entirely on the isolated emulator.
  • Remaining P2 blocker: emulator does not provide a fresh GPS fix after global location is toggled back on, so post-restoration GPS reacquisition remains unverified. Root should retain the independent historical ANR as unresolved pending its exact reproduction conditions.