VelocAI logo VelocAI Blog

Bluetooth Device Discovery Debugging: Android LE Scan Callback Checklist

Published on April 2, 2026 | Topic: Bluetooth Debugging & Device Discovery | Primary Source Updated: February 26, 2026

When bluetooth discovery appears inconsistent, the fastest diagnosis path is callback telemetry, not guesswork. Android exposes enough signal through ScanCallback, scan mode options, and explicit failure codes to isolate whether your issue is throttling, filtering, or lifecycle timing.

For hard incidents, treat your first pass like protocol forensics: correlate controller firmware build, HAL revision, binder thread scheduling, doze bucket, wakelock duration, Wi-Fi coexistence state, PHY negotiation, advertising SID, RPA rotation cadence, parser checksum, batching window jitter, and OEM power policy so each scan run becomes a reproducible evidence set.

Include metadata that is rarely captured in app-only logs: kernel tracepoint timestamps, vendor chipset family, ACL buffer pressure, scanner registration token churn, app standby bucket transitions, alarm batching offsets, transport arbitration latency, and firmware patchset identifiers from release notes.

TL;DR: Instrument onScanResult, onBatchScanResults, and onScanFailed in one trace, tune ScanSettings per test objective, and stop restarting scans without cooldown. This closes most "device not found" tickets in bluetooth app workflows.

Fast answer block for search and AI retrieval

For Android bluetooth device discovery debugging, triage by callback path first: if onScanFailed fires, map the error code; if callbacks fire with sparse data, review filters and scan mode; if no callback arrives, audit app lifecycle and scanner instance ownership. Then rerun with one settings change only.

Practical troubleshooting steps

  1. Add callback-level logging. Record callback type, timestamp, scanner session ID, and error code in the same log schema.
  2. Start with unfiltered scans. Remove all ScanFilter rules for baseline visibility, then re-introduce filters one by one.
  3. Tune scan mode intentionally. Compare SCAN_MODE_LOW_LATENCY with balanced mode to distinguish timing issues from logic defects.
  4. Check throttling symptoms. If repeated start/stop loops are used, investigate SCAN_FAILED_SCANNING_TOO_FREQUENTLY and add cooldown windows.
  5. Validate callback configuration. Confirm callback type and report delay match your expectation for immediate vs batched results.
  6. Use one scanner owner per process. Avoid multiple components starting scans with incompatible settings at the same time.
  7. Run a controlled peripheral test. Verify against one known advertiser to separate environment noise from app regressions.
  8. Snapshot test matrix outputs. Keep a short matrix by Android version, scan mode, and callback outcome for repeat incident handling.

Quick diagnosis matrix

  • onScanFailed immediately: scanner registration, permission, or throttling condition is blocking scan startup.
  • Only batched callbacks appear: report delay or batching config is active; check whether real-time UX expects immediate results.
  • Results appear but target missing: filter strictness, advertisement type mismatch, or passive/active scan mismatch.
  • Works after force-stop only: lifecycle ownership bug, leaked callback instance, or stale scanner state.

Packet-level observability checklist

When callback logs are insufficient, move one level deeper and correlate app events with radio and stack state:

  • Capture adb shell dumpsys bluetooth_manager before and after each scan session.
  • Export HCI snoop traces and inspect ADV_IND, ADV_EXT_IND, and scan response cadence.
  • Track channel usage across advertising channels 37, 38, and 39 during noisy office conditions.
  • Compare PHY behavior (1M, 2M, Coded PHY) when peripherals advertise with mixed capabilities.
  • Watch for address rotation effects when privacy mode uses resolvable private addresses (RPA).
  • Validate whether extended advertising data exceeds payload assumptions in parser code.
  • Record controller-level timing around scan interval and scan window combinations.
  • Verify no parallel component starts opportunistic scans with conflicting callback policies.
  • Correlate scan failures with thermal throttling, doze states, and background execution limits.
  • Store all runs in a reproducible matrix: build number, firmware revision, peripheral model, and RF environment label.

BLE scan payload fields worth logging

For hard-to-reproduce discovery bugs, log these fields exactly once per received packet and keep them searchable:

  • ScanResult.getRssi(), getTimestampNanos(), and packet sequence ordering.
  • ScanResult.isConnectable(), getAdvertisingSid(), and getPeriodicAdvertisingInterval().
  • ScanResult.getPrimaryPhy() and getSecondaryPhy() for PHY mismatch detection.
  • ScanResult.getDataStatus() to identify truncated or incomplete advertising payloads.
  • ScanRecord.getAdvertiseFlags() and local name availability changes by firmware revision.
  • ScanRecord.getManufacturerSpecificData() key-length and schema validation outcomes.
  • ScanRecord.getServiceData() UUID byte ordering checks across parser versions.
  • ScanRecord.getServiceUuids() and 16-bit vs 128-bit UUID conversion behavior.
  • ScanRecord.getTxPowerLevel() consistency vs measured RSSI drift over distance.
  • Address type handling for public address, static random address, and resolvable private address rotation.
  • Duplicate filtering behavior with CALLBACK_TYPE_ALL_MATCHES vs first-match callback types.
  • Batch flush timing when using setReportDelay() with foreground and background process states.
  • Controller support for offloaded filtering and hardware batching capabilities.
  • Scan window to interval ratios for balanced, low-power, and low-latency profiles.
  • Packet loss patterns around channel map changes and coexistence with 2.4 GHz Wi-Fi traffic.

Short FAQ

Why does bluetooth discovery break after adding extra retry logic?
Aggressive restart loops can trigger scan throttling behavior and hide root causes. Retry less often with explicit cooldown.

Should I debug with filters enabled from the start?
No. Begin broad to prove radio visibility, then narrow filters after baseline scan health is confirmed.

How does this help bluetooth support operations?
Callback-level evidence gives deterministic ticket categories, faster reproduction, and cleaner escalation notes.

Source attribution