Signal Collector
Data dictionary · 0.10.0 Čeština

Data dictionary
SIGNAL_COLLECTOR_TXT_V4.

Exactly what an exported file contains: the session header, the TSV columns and every payload key the individual sources write. Matches the implementation of version 0.10.0.

This page is written from the code, not from intent. Where the description and the app disagree, the code wins — app/src/main/java/app/signalcollector/.

File structure

The export is a UTF‑8 text file. Depending on the estimated size it is stored as .txt or packed into GZIP. It has three parts: a first line naming the format, a header block of key=value pairs, a blank line, and then a tab-separated table of samples.

SIGNAL_COLLECTOR_TXT_V4
session_id=42
session_status=COMPLETED
…
sources=accelerometer,collector_heartbeat,gnss_raw,location,wifi

timestamp_iso_utc	epoch_ms	elapsed_realtime_ns	session_id	sequence_number	source	payload
2026-08-10T09:14:02.118Z	1786439642118	918273645000	42	1	location	record_type=fix;provider=gps;latitude=50.087;…

Samples are ordered by timestampEpochMs and, on a tie, by insertion order. A row never contains a raw tab or line break — see escaping.

TSV columns

Seven tab-separated columns. The first six are the same for every source; the seventh is the payload of that particular source.

ColumnTypeDescription
timestamp_iso_utcISO‑8601A readable transcription of epoch_ms in UTC. A derived column, no extra information.
epoch_mslongSystem time when the sample was accepted into the queue. It allows comparison with other devices, but it can jump when the phone's clock is reset.
elapsed_realtime_nslongMonotonic time since the phone booted; it keeps running during sleep. This is the time axis for measuring intervals. Most sources take it straight from the Android API (fix, scan, cell, BLE, GNSS clock), so it matches the moment of measurement, not the moment the callback arrived.
sequence_numberlongRow order in the file, from 1. It is assigned at export time; it is not a database ID.
sourceenumSource of the sample — one of the values described below, or collector_heartbeat.
payloadtextkey=value pairs separated by semicolons. The record_type key says which payload shape follows. A missing value is written as empty — the key stays in the row.

Escaping

Payloads such as raw_scan_result, NMEA sentences or exception text routinely contain characters that would break the structure of the file. Escaping is therefore always applied, even when a particular value holds no problematic character.

CharacterWritten asWhere
\\\payload, header and TSV columns
;\;inside a payload and the header — otherwise it would look like a pair separator
=\=inside a payload and the header — otherwise it would look like a key/value separator
tab\tthe source and payload columns, values in the header
CR / LF\r / \neverywhere

A parser therefore splits the row on tabs first, then the payload on unescaped semicolons, then each pair on the first unescaped equals sign — and unescapes the value last.

Shared payload suffixes

Some keys do not come from the source itself but are attached to the sample along the way. That is how even an accelerometer sample carries the last known location without knowing anything about location.

Location with every sample

Added to every sample for which the last location is known. If a source already carries a location of its own, it is not attached again. For internet_quality it is always attached — empty if need be, so the data shows that no location was available.

KeyTypeDescription
last_locationboolWhether a location was available.
last_latitudedoubleLatitude of the last fix.
last_longitudedoubleLongitude of the last fix.
last_altitudedoubleAltitude, only when the fix carried one.
last_location_accuracyfloatReported horizontal accuracy of the fix, in metres.
location_age_mslongAge of the fix relative to this sample. Without it there would be no telling whether the location is one second or five minutes old.

Network context with internet mapping

Attached only to internet_quality samples, tying the measured transfer to a specific network. The set of keys differs by transport.

KeyTransportDescription
ssid, bssid, rssi_dbm, rssi, frequency_mhz, frequency, channel, wifi_standard, rx_link_speed_mbps, tx_link_speed_mbpsWIFIA snapshot of the connected Wi‑Fi at the moment of the sample. Unknown values are left empty; Android placeholder values (RSSI −127, frequency −1) never reach the export.
operator, mcc, mnc, plmn, technology, cell_id, nci, pci, tac, bands, band, earfcn, nrarfcn, rsrp, rsrq, sinr, ss_rsrp, ss_rsrq, ss_sinrCELLULARA snapshot of the serving cell. On 5G, cell_id is filled in from nci and rsrp/rsrq/sinr from ss_*, so the series can be compared across technologies.
network_context_age_msbothAge of the network snapshot relative to the sample.
network_handle, network_request_transport, network_request_internet, network_has_internet, network_validated, interface_name, subscription_idbothProof of which Android Network the transfer actually went through. Without it, samples could not be told apart when Wi‑Fi and cellular are measured at the same time.

Sensors

source: accelerometer · gyroscope · magnetometer · barometer · light · proximity · rotation_vector

All seven sensors share the same payload shape. Values are taken exactly as SensorEvent returns them, with no filtering and no conversion. elapsed_realtime_ns is the time of the sensor event, not the time of delivery.

KeyTypeDescription
v0, v1, v2, …floatAxes by sensor type: accelerometer m/s² (x, y, z) · gyroscope rad/s · magnetometer µT · barometer hPa (v0 only) · light lx · proximity cm · rotation vector quaternion (v0v3, and possibly v4 as the accuracy in radians).
accuracyintReported sensor accuracy 0–3 (0 = unreliable, 3 = high).
sensortextName of the specific hardware sensor as the device reports it.

noise

source: noise · record_type: none, the payload always has the same shape

Only the loudness of a block of samples is computed from the microphone. No audio is stored or sent anywhere; audio cannot be reconstructed from the stored values.

KeyTypeDescription
rmsdoubleRoot mean square of the block, in units of 16-bit PCM.
dbfsdoubleLoudness in dBFS relative to full scale, floored at −120. It is a relative level, not calibrated dB SPL.
sample_rate_hzintThe actual sample rate at which the microphone could be opened.
samplesintNumber of PCM samples in this block.

location

source: location · record_type: fix · registration

record_type=fix

KeyTypeDescription
providerenumgps or network. Both providers run at once when enabled.
latitude / longitudedoublePosition in degrees (WGS‑84).
altitudedoubleHeight above the ellipsoid in metres, only when the fix carries it.
speed_mpsfloatSpeed in m/s.
bearing_degfloatBearing of travel in degrees.
horizontal_accuracy_mfloatRadius of 68 % confidence in metres. Above 20 m the fix does not count towards distance_m.
vertical_accuracy_mfloatUncertainty of the altitude.
speed_accuracy_mpsfloatUncertainty of the speed.
bearing_accuracy_degfloatUncertainty of the bearing.
location_time_epoch_mslongTime of the fix according to the location provider — it need not match the row's epoch_ms.
location_elapsed_realtime_nslongMonotonic time of the fix; the row's elapsed_realtime_ns derives from it.
is_mockboolA mocked location. It does not count towards the distance.
raw_locationrawtoString() of the Location object, in case some new attribute is missing in the future.

record_type=registration

KeyTypeDescription
callbacktextAlways LOCATION_UPDATES.
providerenumWhich provider the registration concerns.
provider_enabledboolWhether the provider was enabled in the system.
statusenumSUCCESS · PROVIDER_DISABLED · FAILED. It tells a disabled GPS apart from a refused registration.
registeredboolWhether the subscription to fixes was actually created.
error / messagetextClass and message of the exception if the registration failed.

gnss_satellite

source: gnss_satellite · record_type: satellite · summary · event · registration · callback_error

On every change of satellite status, one row per satellite is written plus a single summary. The summary is precomputed deliberately — otherwise everyone processing the data would have to compute it.

record_type=satellite

KeyTypeDescription
constellationenumGPS · GALILEO · GLONASS · BEIDOU · QZSS · NAVIC · SBAS · UNKNOWN.
svidintIdentifier of the satellite within its constellation.
cn0_db_hzfloatCarrier-to-noise density in dB‑Hz. The main indicator of satellite signal strength.
baseband_cn0_db_hzfloatC/N0 measured at baseband, when the chip reports it.
elevation_deg / azimuth_degfloatPosition of the satellite in the sky.
carrier_frequency_hzfloatCarrier frequency of the signal — it tells L1 from L5.
used_in_fixboolWhether the satellite was used in computing the position.
has_ephemeris / has_almanacboolWhether the receiver holds ephemeris / almanac data for the satellite.

record_type=summary

KeyTypeDescription
satellites_visible / satellites_usedintHow many satellites the receiver sees and how many it used for the fix.
fix_use_ratiodoubleRatio of used to visible.
cn0_avg_db_hz / cn0_max_db_hzdoubleMean and best C/N0 across all visible satellites.
used_cn0_avg_db_hzdoubleMean C/N0 of the satellites used in the fix only.
ephemeris_count / almanac_countintHow many satellites hold ephemeris / almanac data.
gps_count, galileo_count, glonass_count, beidou_count, qzss_count, navic_count, sbas_count, unknown_countintCounts of visible satellites per constellation.

record_type=event / registration / callback_error

KeyTypeDescription
eventenumGNSS_STARTED · GNSS_STOPPED · GNSS_FIRST_FIX.
ttff_msintTime to first fix — only with GNSS_FIRST_FIX.
callbacktextGNSS_STATUS for a registration.
status, registered, error, messagemixedResult of the registration, the same shape as with location.

gnss_raw

source: gnss_raw · record_type: clock · measurement · agc · capabilities · registration · status · callback_error

Raw GNSS measurements for post-processing. One clock record plus as many measurement rows as the chip tracked satellites in that epoch.

record_type=clock

KeyTypeDescription
measurement_countintHow many measurement rows belong to this epoch.
full_trackingboolWhether the chip runs in full tracking mode (Android 14+).
time_nanoslongHardware time of the receiver in nanoseconds.
time_uncertainty_nanosdoubleUncertainty of the hardware time.
full_bias_nanos / bias_nanoslong / doubleCoarse and fine offset of the receiver clock against GPS time.
bias_uncertainty_nanosdoubleUncertainty of the clock offset.
drift_nanos_per_seconddoubleDrift of the receiver clock.
drift_uncertainty_nanos_per_seconddoubleUncertainty of the drift.
leap_secondintCurrent number of leap seconds.
hardware_clock_discontinuity_countintNumber of clock jumps. A change in the value means phase must not be carried across continuously.
clock_elapsed_realtime_nslongTie of the receiver clock to the system monotonic time.
clock_elapsed_realtime_uncertainty_nsdoubleUncertainty of that tie.
reference_constellation, reference_carrier_frequency_hz, reference_code_typemixedReference signal for inter-system biases.
raw_clockrawtoString() of the GnssClock object.

record_type=measurement

KeyTypeDescription
constellation / svidenum / intConstellation and satellite number.
code_typetextType of the signal code, for example C, L, Q.
stateintBit mask of the tracking state. It determines whether received_sv_time_ns is unambiguous.
received_sv_time_nslongReceived satellite time — the basis for pseudorange.
received_sv_time_uncertainty_nslongUncertainty of the received time.
time_offset_nsdoubleOffset of the measurement against the time in clock.
cn0_db_hz / baseband_cn0_db_hz / snr_dbdoubleSignal strength and signal-to-noise ratio.
carrier_frequency_hzfloatCarrier frequency; it tells L1 from L5.
carrier_cycles, carrier_phase, carrier_phase_uncertaintylong / doubleCarrier phase measurements.
pseudorange_rate_mpsdoubleRate of change of the pseudorange in m/s (Doppler measurement).
pseudorange_rate_uncertainty_mpsdoubleUncertainty of the same.
accumulated_delta_range_mdoubleAccumulated range change from the carrier phase.
accumulated_delta_range_uncertainty_mdoubleUncertainty of the accumulated change.
accumulated_delta_range_stateintState of the accumulation; it reports a lost phase (cycle slip).
multipath_indicatorintIndicator of signal reflection, when the chip provides one.
agc_level_dbdoubleAutomatic gain control level — sensitive to interference in the band.
full_inter_signal_bias_ns, full_inter_signal_bias_uncertainty_ns, satellite_inter_signal_bias_ns, satellite_inter_signal_bias_uncertainty_nsdoubleBiases between signals and between satellites.
raw_measurementrawtoString() of the GnssMeasurement object.

record_type=agc / capabilities / status

KeyTypeDescription
constellation, carrier_frequency_hz, level_db, raw_agcmixedAGC per band (Android 13+).
hardware_model, hardware_year, capabilitiestext / intModel and year of the GNSS chip and the capabilities it reports. It explains why certain fields are always missing on a given phone.
status / status_nameint / enumREADY · LOCATION_DISABLED · NOT_SUPPORTED · UNKNOWN.

gnss_navigation

source: gnss_navigation · record_type: navigation_message · status · registration

KeyTypeDescription
typeintType of the navigation message, by constellation and signal.
svidintSatellite the message came from.
message_id / submessage_idintFrame and subframe number.
statusintWhether the message passed the parity check.
data_hexhexRaw message data in hexadecimal.
data_lengthintLength of the data in bytes.
raw_navigation_messagerawtoString() of the message object.

gnss_nmea

source: gnss_nmea · record_type: nmea · registration

KeyTypeDescription
nmea_timestamp_epoch_mslongTime of the sentence according to the system.
sentencetextThe whole NMEA sentence without trailing whitespace. The asterisk and the checksum are kept; any separators are escaped.

gnss_antenna

source: gnss_antenna · record_type: antenna_info · registration

KeyTypeDescription
indexintPosition of the antenna in the list the phone reports.
carrier_frequency_mhzdoubleThe band the values relate to.
phase_center_offsetrawOffset of the antenna phase centre, including uncertainties.
phase_center_variation_correctionsrawMap of phase centre corrections by direction.
signal_gain_correctionsrawMap of gain corrections by direction.
raw_antenna_inforawtoString() of the GnssAntennaInfo object.

wifi

source: wifi · record_type: scan · access_point · connection · mlo_link · status

Every fresh scan writes one row per visible access point plus one row about the phone's own connection. Android throttles scans and scanResults then keeps returning the same last result, which is why every scan attempt has its own record_type=scan row and every AP carries its own scan_timestamp_us.

record_type=scan

Written on every scan attempt, even when no new data comes of it. Without it, an old result returned again and again would look like regular sampling at the configured interval, and a coverage map could not tell where measuring actually happened. access_point rows are written only for the FRESH state.

KeyTypeDescription
statusenumFRESH a new scan · THROTTLED the system refused startScan() · UNCHANGED the same scan had already been processed by the system callback. The distinction matters: UNCHANGED also grows on a phone that does no throttling at all, where reading it as throttling would be wrong.
triggerenumPERIODIC_POLL the collector's own tick · SCAN_RESULTS_CALLBACK a scan triggered by the system or another app, which the collector took over instead of waiting for its next tick.
start_scan_requestedboolReturn value of startScan(). Empty for trigger=SCAN_RESULTS_CALLBACK, where the collector did not ask for a scan.
scan_timestamp_uslongTime of the newest result in the scan, in microseconds since boot. This is exactly what reveals that it is the same scan as last time.
scan_age_mslongAge of the result relative to this row. Units to hundreds of ms for FRESH; it grows for a repeated scan.
ap_countintHow many access points the scan returned.
fresh_scans / throttled_scans / unchanged_scanslongCumulative counters for the running stretch. After a resume within a session they start from zero again, so the ratio is always computed within a single stretch.

record_type=access_point

KeyTypeDescription
ssid / bssidtextNetwork name and MAC address of the access point.
rssi_dbmintSignal strength in dBm.
frequency_mhz / channelintFrequency and the channel derived from it.
channel_widthintChannel width as the ScanResult constant (0 = 20 MHz, 1 = 40, 2 = 80, …).
center_freq_0_mhz / center_freq_1_mhzintCentre frequencies of the segments on wide channels.
capabilitiestextCapability and security string as the scan reports it.
security_typeslistNumeric security types (Android 13+).
wifi_standardenumLEGACY · 802.11n · 802.11ac · 802.11ax · 802.11ad · 802.11be. An unknown standard is left empty, not UNKNOWN.
scan_timestamp_uslongWhen the AP was last seen, in microseconds since boot. It exposes an old scan returned again.
passpoint, operator_friendly_name, venue_namebool / textPasspoint metadata, when the network reports it.
raw_scan_resultrawtoString() of the ScanResult object.

record_type=connection

KeyTypeDescription
ssid / bssidtextIdentification of the connected network. Empty when the system hides it for permission reasons.
ssid_available / bssid_availableboolIt tells “the network has no name” from “the system did not give us the name”.
rssi_dbm, frequency_mhz, channelintSignal and channel of the current connection.
link_speed_mbps, rx_link_speed_mbps, tx_link_speed_mbpsintNegotiated link rate. This is not measured throughput — that is measured by internet_quality.
max_rx_link_speed_mbps / max_tx_link_speed_mbpsintThe maximum the connection supports.
wifi_standardenumStandard of the current connection.
security_typeintSecurity type of the connected network.
passpoint_fqdn / passpoint_providertextPasspoint provider, if the phone connected through one.
ap_mld_mac / ap_mlo_link_idtext / intWi‑Fi 7 multi-link: the MLD address and the ID of the active link.
raw_wifi_inforawtoString() of the WifiInfo object.

record_type=mlo_link

KeyTypeDescription
mlo_kindenumscan_affiliated · connection_affiliated · connection_associated — where the link came from.
link_idintID of the link within the MLD.
ap_mac / sta_mactextAddresses of both ends of the link.
band, channel, frequency_mhzintBand and channel of the link.
rssi_dbm, rx_link_speed_mbps, tx_link_speed_mbpsintSignal and rate of the link (Android 14+).
stateenumACTIVE · IDLE · UNASSOCIATED · INVALID.
raw_mlo_linkrawtoString() of the MloLink object.

record_type=status

A single state, status=SCAN_CALLBACK_REGISTRATION_FAILED with the keys error and message. It means the subscription to system scans could not be registered — the data will then hold only the scans the collector requested, that is, trigger=PERIODIC_POLL.

wifi_rtt

source: wifi_rtt · record_type: capabilities · ranging_result · status

Ranging to access points that support FTM (802.11mc / 802.11az). Such APs are rare; when none is in range, status=NO_RESPONDERS is written so that it is clear the measurement ran and simply had nothing to measure.

KeyTypeDescription
available / characteristicsbool / textAvailability of RTT and the characteristics the chip reports (record_type=capabilities).
statusint / enumFor a result, a numeric code (0 = success); for a status, UNAVAILABLE · NO_RESPONDERS · FAILURE · ERROR.
mac_addresstextAddress of the access point being ranged.
distance_mm / distance_std_dev_mmintDistance and its standard deviation in millimetres. Filled in only for a successful measurement.
rssi_dbmintSignal at the moment of measurement.
attempted_measurements / successful_measurementsintHow many individual measurements were attempted and how many succeeded.
ranging_timestamp_mslongTime of the measurement according to the chip; the row's elapsed_realtime_ns derives from it.
measurement_frequency_mhz / measurement_bandwidthintChannel and bandwidth of the measurement (Android 14+).
is_80211mc / is_80211az_ntbboolWhich FTM variant the measurement used.
lci_hex / lcr_hexhexReported location and civic address of the access point (Android 15+).
min_ntb_interval_us / max_ntb_interval_uslongRange of intervals for 802.11az non-trigger-based ranging.
ranging_authenticated / ranging_frame_protectedboolSecurity of the ranging (Android 16+).
code, error, messageint / textReason for failure on status records.
raw_ranging_resultrawtoString() of the RangingResult object.

wifi_throughput

source: wifi_throughput · record_type: wifi_throughput · status

One scan gives the signal of every network around at once; throughput does not — the phone is only ever associated with a single AP. The source therefore visits the networks listed in advance one by one through a WifiNetworkSpecifier and measures download, upload and HTTPS RTT on each. The switch applies to this app only; the rest of the phone's traffic stays on the original network.

Measure standing still: while walking, each network in the cycle would be measured from a different place and the numbers could not be compared. On the first connection to each network Android demands consent through a modal system dialog that cannot be suppressed — a walk therefore starts by clearing those dialogs at the first point.

record_type=wifi_throughput

One row per network per cycle, even when the network was never reached — otherwise the data could not tell a network that was not there from a network that was forgotten.

KeyTypeDescription
statusenumSUCCESS both transfers went through · PARTIAL at least one ended in an error · NOT_VISIBLE the network was not in the last scan, so no attempt was made · CONNECT_FAILED the connection did not succeed within connect_timeout_s.
cycle / target_indexintWhich round of the walk, and the position of the network in the configured list. The pair identifies the row uniquely.
requested_ssid / securedtext / boolThe network as entered in the settings, and whether it has a password. The password itself is never written into the data.
connect_msdoubleTime from the start of the attempt to an available network, that is, association and DHCP. Without it a slow network could not be told from slow switching. Zero for NOT_VISIBLE.
total_msdoubleThe whole handling of the network, including both transfers and the RTT probes.
has_internetboolWhether the network reports NET_CAPABILITY_INTERNET. A network without internet is still measured and ends with a transfer error — as a result, not as unavailability.
ssid, bssid, rssi_dbm, frequency_mhz, channel, wifi_standard, rx_link_speed_mbps, tx_link_speed_mbpstext / intSnapshot of the connection at the moment of measurement: which AP the phone actually joined and at what negotiated rate. Filled in only for a successful connection.
latency_ms_median / latency_ok / latency_errorsdouble / int / listMedian HTTPS RTT, the number of probes that came back and the exception types of those that did not. This is not an ICMP ping.
download_mbps / upload_mbpsdoubleThroughput of the transfer. On an error it stays empty even when part of the bytes moved — half a transfer is not a measured rate.
download_bytes / upload_byteslongHow many bytes actually moved; on an error, up to the moment of failure.
download_ms / upload_msdoubleDuration of the transfer, including establishing the connection.
download_error / upload_errortextName of the exception class, for example SocketTimeoutException. A refused HTTP status code arrives here as IllegalStateException. Empty on success.
server_mode / servertextMode and host of the test endpoint, the same as with internet_quality.

record_type=status

A single state, status=NO_TARGETS with an explanatory message. The source is switched on but the list of networks is empty, so it never starts — and the export shows that instead of staying silent.

mobile_network

source: mobile_network · record_type: cell · signal_strength · event

For record_type=cell the set of keys is always the same and always complete — fields a given technology does not have are left empty. The columns of the table therefore never shift about depending on whether the phone is currently on LTE or 5G.

Keys shared by every cell record

KeyTypeDescription
scan_modeenumPASSIVE_CELL_SCAN ordinary subscription · ACTIVE_NETWORK_SCAN the experimental active scan.
triggerenumTELEPHONY_CALLBACK · GET_ALL_CELL_INFO · REQUEST_CELL_INFO_UPDATE · ACTIVE_NETWORK_SCAN. It tells a requested snapshot from a spontaneous change.
technologyenumNR · LTE · WCDMA · TDSCDMA · GSM · CDMA.
registeredboolWhether the phone is registered to this cell.
connection_statusenumPRIMARY_SERVING · SECONDARY_SERVING · NONE · UNKNOWN.
subscription_id / sim_slotintWhich SIM the cell belongs to. With two SIMs, two independent sets of records run.
cell_timestamp_mslongTime of the snapshot according to the modem; the row's elapsed_realtime_ns derives from it.
dbm, asu, levelintSignal strength in dBm, in ASU and as a 0–4 level for the UI.
mcc, mnc, plmntextCountry code, network code and the two joined.
operatortextOperator name, or the PLMN when there is no name. UNKNOWN for a cell with no identity.
operator_alpha_long / operator_alpha_shorttextLong and short network name according to the modem.
additional_plmnslistFurther PLMNs the cell broadcasts (network sharing).
raw_cell_info, raw_cell_identity, raw_signal_strengthrawtoString() of three modem objects, as a fallback for fields that have no key of their own here yet.

Keys by technology

KeyTechnologyDescription
cell_idLTE, WCDMA, GSM, TDSCDMA, CDMACell identifier (ci on LTE, cid on the others, base station ID on CDMA).
nciNRThe 48-bit 5G NR Cell Identity.
pciLTE, NRPhysical Cell ID.
tacLTE, NRTracking Area Code.
lacWCDMA, GSM, TDSCDMALocation Area Code.
pscWCDMA, GSM, TDSCDMAPrimary Scrambling Code; on TDSCDMA it is filled from cpid.
bsicGSMBase Station Identity Code.
earfcn / nrarfcn / uarfcn / arfcnLTE / NR / WCDMA, TDSCDMA / GSMChannel number by technology.
bandsLTE, NRBands the cell operates in.
bandwidthLTEBandwidth in kHz.
rssiLTE, GSMTotal received power.
rsrp / rsrqLTEReference signal power and quality.
rssnrLTESignal-to-noise ratio.
sinrLTE, NRA unified key for comparison across technologies: on LTE it copies rssnr, on NR ss_sinr.
ss_rsrp, ss_rsrq, ss_sinrNRMeasurements on the synchronisation signal.
csi_rsrp, csi_rsrq, csi_sinrNRMeasurements on CSI‑RS.
cqi / cqi_table_indexLTE, NRChannel quality indicator; on NR it is a list of values.
timing_advance / timing_advance_usLTE, GSM / NRTiming advance — a coarse hint of the distance to the transmitter.
ec_noWCDMAChip energy to noise ratio.
rscpTDSCDMAReceived Signal Code Power.
bit_error_rateGSMError rate.
network_id, system_id, basestation_latitude, basestation_longitude, cdma_dbm, cdma_ecio, evdo_dbm, evdo_ecio, evdo_snrCDMAFields of the old CDMA networks; they stay empty in Europe.

record_type=signal_strength

KeyTypeDescription
technologytextAndroid's measurement class, for example CellSignalStrengthLte.
dbm, asu, levelintSignal strength in the three usual units.
subscription_id / sim_slotintWhich SIM the measurement concerns.
raw_signal_strengthrawtoString() of the measurement.

record_type=event

KeyTypeDescription
eventenumCELL_LIST_CHANGED · SIGNAL_STRENGTH_CHANGED · SERVICE_STATE_CHANGED · DISPLAY_INFO_CHANGED · DATA_CONNECTION_CHANGED · SERVING_CELL_CHANGED · CELL_INFO_UPDATE_ERROR · RADIO_API_ERROR · ACTIVE_NETWORK_SCAN_*.
before / afterrawState before and after the change, so the transition can be reconstructed.
before_technology, before_cell_id, before_pci, after_technology, after_cell_id, after_pcimixedThe serving-cell transition broken out — this is a handover.
operationtextWhich modem call failed on RADIO_API_ERROR.
has_carrier_privileges / modify_phone_state_grantedboolWhy the system allowed or refused the active scan.
result_countintNumber of cells returned by the active scan.
error_code, error, exception, messageint / textThe exact reason for the refusal or the error.
manufacturer, model, android, sdktext / intDevice and system on active scan records — its availability depends heavily on the phone.

sim_info

source: sim_info · record_type: summary · subscription

Which cards were in the phone while measuring. mobile_network carries the identity of the transmitter but not of whoever was looking at it — and with two cards, or in roaming, that is a crucial difference. It is written once when the measurement starts and after that only when the system reports a change of subscriptions; cards do not change as you walk.

Neither ICCID nor EID is recorded. They are permanent subscription identifiers that outlive even a change of phone, whereas the rest of this section describes the network the measurement ran in. Since Android 10 the system would not hand them to an app anyway.

record_type=summary

KeyTypeDescription
slot_countintHow many subscriptions the phone can hold at once.
active_countintHow many of them are active. Zero means a phone with no card, not a read error.
esim_countintHow many of the active ones are eSIM profiles.
euicc_supportedboolWhether the phone has an eSIM chip, regardless of any profile on it.

record_type=subscription

KeyTypeDescription
subscription_idintLocal subscription number. It changes when the card is re-registered, so it does not identify the phone; it serves to join rows within a single measurement.
slot_indexintThe slot the card sits in. Numbered from zero.
carrier_name / display_nametextOperator according to the card, and the name the user gave the subscription.
mcc / mnctextCountry and network code. It joins the card to the cell records in mobile_network.
country_isotextCountry of the subscription, ISO code.
embeddedbooltrue for an eSIM profile, false for a physical card.
roamingboolWhether the subscription is currently roaming.
default_data, default_voice, default_smsboolWhich card carries data, calls and messages. For analysing a measurement, default_data matters most — its network is the one that shows up in internet_quality.

network_context

source: network_context · record_type: capabilities · link_properties · event

The operating system's view of the networks: what the phone claims about a network before anything is transferred over it. Written at the start, periodically, and on every change.

record_type=capabilities

KeyTypeDescription
triggerenumINITIAL · PERIODIC · CALLBACK.
network_handlelongNetwork identifier. It joins the record to a specific internet_quality sample.
transportslistCELLULAR, WIFI, VPN, ETHERNET, BLUETOOTH, THREAD, SATELLITE
capabilitieslistNumeric constants of the network capabilities.
internet / validatedboolWhether the network promises internet, and whether the system verified that it really works.
captive_portalboolThe network requires a sign-in through a portal.
metered, roaming, congested, suspendedboolState of the network. Stored in the positive sense, so metered=true means a metered network.
downstream_kbps / upstream_kbpsintThe system's estimate of link capacity — an estimate, not a measurement.
signal_strengthintSignal strength of the network, where the system states it.
owner_uid, network_specifier, transport_infomixedSupplementary identification of the network; on Wi‑Fi it contains WifiInfo.
raw_capabilitiesrawtoString() of the NetworkCapabilities object.

record_type=link_properties

KeyTypeDescription
interface_nametextInterface name, for example wlan0 or rmnet_data0.
link_addresseslistIP addresses of the interface.
dns_servers / domainslist / textDNS servers and search domains.
routeslistRouting entries, separated by a pipe.
mtuintMaximum frame size.
private_dns_active / private_dns_serverbool / textState of private DNS.
dhcp_server, nat64_prefix, http_proxy, wake_on_lanmixedOther properties of the link.
raw_link_propertiesrawtoString() of the LinkProperties object.

record_type=event

KeyTypeDescription
eventenumAVAILABLE · LOSING · LOST · BLOCKED_CHANGED.
max_ms_to_liveintHow much time the system gives the network on LOSING.
blockedboolWhether the app's traffic on this network is blocked.

internet_quality

source: internet_quality · record_type: network_quality_sample · network_capacity_probe · network_capacity_probe_started · speed_test_result · speed_test_event

Real HTTPS transfers bound to a specific Android Network, not an estimate of link capacity. The one-second sample is small on purpose: the goal is a continuous map of quality while walking, not a peak rate. That is why every record also carries measurement_semantics=SMALL_TRANSFER_QUALITY_NOT_MAX_SPEED.

Every sample additionally carries the shared suffixes — the location and the network snapshot.

record_type=network_quality_sample / network_capacity_probe

KeyTypeDescription
timestamp / timestamp_epoch_mslongStart of the sample. Two keys with the same value, for backward compatibility with older scripts.
scheduled_at_epoch_ms / started_at_epoch_mslongWhen the sample was due to start and when it did.
schedule_delay_mslongDelay against the plan. It grows when the link is slow or the system throttles the app.
missed_intervalslongHow many whole intervals were skipped. The per-second sample axis writes a row even when measuring was impossible, so this only grows after the process was genuinely put to sleep.
statusenumMeasured: SUCCESS · PARTIAL · TIMEOUT (everything failed, and only by running out of time) · ERROR. Not measured: BUSY (a burst or a manual test held the transport) · NETWORK_LOST (there was nothing to measure on). The last two carry empty measurement columns and do not count towards the error rate.
busy_reasonenumWho held the transport: QUALITY_SAMPLE · CAPACITY_PROBE · SPEED_TEST. Only with status=BUSY.
measurement_semanticsenumAlways SMALL_TRANSFER_QUALITY_NOT_MAX_SPEED. A safeguard against reading the values as a speed test.
server_mode / servertextMode and host of the test endpoint.
network_bindingenumAlways ANDROID_NETWORK — the transfer demonstrably went over the selected network, not the default one.
transport_targetenumWhat the user chose: AUTO · WIFI · CELLULAR · BOTH.
transportenumWhat the sample actually went over: WIFI · CELLULAR · ETHERNET · BLUETOOTH · VPN · OTHER · NONE.
download_requested_bytes / upload_requested_byteslongHow many bytes were meant to be transferred.
download_bytes / upload_byteslongHow many actually were. On an error, these are the bytes moved up to the moment of failure.
download_duration_ms / upload_duration_msdoubleDuration of the transfer, including establishing the connection.
short_download_mbps / short_upload_mbpsdoubleThroughput of the one-second sample. A small transfer, so it is a lower bound — not the maximum of the link.
burst_download_mbps / burst_upload_mbpsdoubleThe same for the capacity burst, which runs once per configured interval and is considerably larger.
latency_probe_countintHow many RTT probes were meant to be sent.
successful_probes / failed_probesintHow many got through and how many failed.
rtt_min_ms, rtt_avg_ms, rtt_max_msdoubleResponse time of the HTTPS probes.
jitter_msdoubleMean absolute change of RTT between neighbouring probes.
failed_requests / timeout_countintHow many requests failed in total and how many of those timed out.
probe_duration_msdoubleHow long the whole sample took. On a slow link it is longer than the interval — the following seconds then carry status=BUSY.
errors / errortextList of errors in the form phase:type, or a one-word reason (NO_ACTIVE_NETWORK, TARGET_NETWORK_UNAVAILABLE).

record_type=network_capacity_probe_started

Written the moment a burst begins. The burst holds the transport lock for the whole transfer, so during that time rows with status=BUSY arrive instead of measured samples — this marker says from when and why. Its keys are a subset of the previous table plus transfer_deadline_ms (the latest the transfer may take).

record_type=speed_test_result

A manual test started by the button, not part of continuous mapping. It transfers megabytes, not kilobytes.

KeyTypeDescription
triggertextMANUAL for a test from the UI.
statusenumSUCCESS · PARTIAL · ERROR.
transportenumWIFI · MOBILE. Choosing BOTH writes two separate results.
download_mbps / upload_mbpsdoubleThroughput of the large transfer.
rtt_median_ms / rtt_p95_msdoubleMedian and 95th percentile of the response time — a manual test sends more probes than a sample.
packet_loss_pctdoubleShare of probes that never came back.
download_error, upload_error, latency_errorstextErrors of the individual phases of the test.

record_type=speed_test_event

KeyTypeDescription
eventenumINTERNET_SPEED_TEST_STARTED · _COMPLETE · _ERROR.
targetenumThe chosen target of the test, including BOTH.
status, trigger, error, messagetextState and any error of the test run.

bluetooth_classic

source: bluetooth_classic · record_type: discovery_result · paired_device · event · registration · status

KeyTypeDescription
discovery_modeenumCLASSIC_DISCOVERY found by a scan · BONDED_CACHE listed from the paired devices.
scan_cycle_idlongNumber of the scan cycle. It ties a find to a specific scan window.
result_indexintWhich find it is within this cycle.
name / aliastextDevice name and user alias, where available.
addresstextMAC address of the device.
bond_stateint10 not paired · 11 pairing · 12 paired.
device_typeint1 Classic · 2 LE · 3 Dual.
bluetooth_classtextDevice class (type and services).
uuidslistServices offered.
rssi_dbmintSignal at the moment of the find.
pairedboolOnly on paired_device, always true.
event / statusenumCLASSIC_DISCOVERY with the state REQUESTED · STARTED · FINISHED · REJECTED · ERROR.
found_devicesintHow many devices the cycle found — on FINISHED this is its result.
receiver_flagenumRECEIVER_EXPORTED or IMPLICIT. Discovery broadcasts come from the system, so with a non-exported receiver the scan looks dead in the data — which is why the flag used is recorded.
callback, registered, error, messagemixedResult of registering the receiver.

status=ADAPTER_DISABLED means Bluetooth is switched off. Without that report the source would look enabled, just without a single find.

bluetooth_ble

source: bluetooth_ble · record_type: advertisement · status

The complete advertising payload, raw bytes included. The scan runs in low-latency mode and does not filter, so in a busy environment it is the most prolific source of rows.

KeyTypeDescription
callback_typeintType of the scanner callback (all matches, first match, match lost).
name, alias, addresstextIdentification of the device.
address_typeintPublic or random address (Android 15+). It explains why an address changes over time.
bond_state / device_typeintThe same meaning as with bluetooth_classic.
rssi_dbmintSignal of the received packet.
tx_power / record_tx_powerintTransmit power according to the scanner and according to the advertising content. Together with RSSI it gives a coarse distance estimate.
connectable / legacyboolWhether it can be connected to; whether it is the old advertising format.
data_statusintWhether the payload is complete or continues in another packet.
primary_phy / secondary_phyintPhysical layer (1M, 2M, coded).
advertising_sidintID of the advertising set in extended advertising.
periodic_advertising_intervalintInterval of periodic advertising, where the device uses it.
advertise_flags / advertised_nameint / textFlags and name straight from the advertising packet.
service_uuids / service_solicitation_uuidslistServices offered and services solicited.
manufacturer_datahexManufacturer data as 0xIDID:hex, comma separated. The manufacturer ID allows the device to be typed.
service_datahexService data as uuid:hex.
advertising_datahexThe whole map of AD types as 0xTT:hex (Android 13+).
raw_bytes_hexhexThe raw advertising packet. It allows anything the other keys do not cover to be derived.
raw_scan_record / raw_scan_resultrawtoString() of both objects.
status / error_codeenum / intSCAN_FAILED with an error code, or ADAPTER_DISABLED.

collector_heartbeat

source: collector_heartbeat · record_type: collector_heartbeat · every 5 s

The heartbeat is not a source of data about the surroundings but about the measurement itself. It passes through the same queue and the same writer as every other sample, so a finished file shows which module was really running when, and whether writing ever stalled. Silence in the data therefore cannot be mistaken for a fault.

KeyTypeDescription
active_collectorslistClasses of the running collectors, alphabetically.
active_sourceslistThe sources that were actually registered at start — not the ones ticked.
writer_statusenumOK · RETRYING · DRAINING · DRAINED · FAILED · CANCELLED · STOPPED.
queue_sizelongHow many samples are waiting in the queue right now. A value that keeps growing means the write is falling behind.
accepted_samples, written_samples, dropped_sampleslongRunning counters, the same meaning as in the header.
writer_errortextThe first write error, if there was one.

haptic

source: haptic · record_type: haptic

A vibration is a mechanical impulse and the phone is recording the accelerometer and the gyroscope at the same time, so every buzz writes itself into its own data as a shake that did not come from walking. This record says when it happened, so a window can be cut around it in the sensor stream. What gets written is the loss and return of the default network and the point marker; the alarm for a failed write has no record, because by then the writer is no longer alive — that one is carried by end_reason=WRITER_ERROR, and no sensor data is produced beyond that moment.

KeyTypeDescription
signalenumTRANSPORT_LOST the default network disappeared and nothing replaced it within two seconds · TRANSPORT_RESTORED the network is back · SELECT the operator marked a point, and a survey_point belongs to the same instant.
patterntextRhythm of the signal: thud, tick-tick or tick.
nominal_duration_mslongNominal length of the envelope, not a measured one. For a composed effect the decay is up to the system, so the window to cut should be taken with room to spare.
composedbooltrue = the phone supports VibrationEffect.Composition primitives and this was a tap; false = a substitute waveform with the same rhythm.
deliveredboolfalse means the system refused the vibration — so the shake is not in the data.

session

source: session · record_type: session_started · session_paused · session_resumed · survey_point

Start resumes into the last measurement that was not reset, so one session can consist of several separate stretches. These records say where a stretch began and where it ended — without them a pause in the data could not be told from a hole in coverage or from frozen collection. A pause is deliberately two separate events rather than one record with a length: a record with a length would have to wait for the end of the pause, and if the system killed the app meanwhile, it would never be written at all.

KeyTypeDescription
session_idlongThe session the stretch belongs to. It does not change on a resume — which is how it shows this is a continuation, not a new measurement.
segment_started_at_epoch_mslongStart of the stretch. On session_paused, the start of the one just ended.
session_started_at_epoch_mslongThe first Start of the whole session; on session_started and session_resumed.
paused_at_epoch_mslongThe moment of the Stop; only on session_paused.
paused_since_epoch_mslongWhen the pause being resumed from began; only on session_resumed. The difference against segment_started_at_epoch_ms is the length of the pause.
segment_running_ms / running_ms_totallongLength of the finished stretch and the sum of all so far; only on session_paused. The sum matches running_ms in the header.
running_ms_beforelongTime accumulated before this stretch. Zero on session_started.
distance_m / distance_m_beforedoubleDistance at the end of the stretch, and at the beginning of the resumed one. Ground covered during a pause does not count towards the distance — the anchor is discarded on resume.
accepted_samples_beforelongHow many samples the session had before the resume; only on session_resumed.
end_reason / statusenumWhy and in what state the stretch ended; only on session_paused. The same values as end_reason and session_status in the header.
previous_status / previous_writer_errortextState and error of the previous stretch; only on session_resumed. A resume puts the session row back into the running state and overwrites its status and error, so this is the only place where a failed write remains traceable even after a successful finish.

record_type=survey_point

A marker of the place the measurement is standing at. Indoors GNSS gives no position, so this is the only thing in the data that ties measured values to a point on a floor plan: the operator stops, taps Mark point, waits a moment and walks on. The marker stands on its own in the timeline and point_index is not added to the other records — values are attributed to a point by a time window after the marker, not by a key in every row.

KeyTypeDescription
session_idlongThe session the point belongs to.
point_indexintNumber of the point, from 1, within the running stretch. After a resume it starts from one again — points from two stretches are told apart by running_ms_total or by the preceding session_resumed event.
labeltextOptional label from the field above the button. A point left blank stays a sequence number, which is enough for a walk along a numbered floor plan.
marked_at_epoch_mslongSystem time of the tap. The row also carries the usual elapsed_realtime_ns, which is what the window is cut by.
running_ms_totallongCollection time accumulated at the moment of the marker, including previous stretches and excluding pauses.
distance_mdoubleDistance walked at the moment of the marker. The difference against the previous point says how many metres the operator really covered between them.

The tap also buzzes, so every point has a haptic row with the same timestamp — the shake in the sensors is therefore not unexplained.

Measurement parameters

Every source can be switched on individually before the start, and for some of them the pace can be set as well. Values outside the range are pulled back to the limits — otherwise interval_s=0, say, would turn the periodic loop into a tight loop.

SourceParameterDefault · range
sensors (7×)interval_ms50 ms · 10–1,000
noisesample_rate_hz8,000 Hz · 8,000–48,000
locationinterval_ms1,000 ms · 100–60,000
gnss_rawinterval_ms1,000 ms · 100–60,000
wifi, wifi_rtt, mobile_network, network_contextinterval_s30 s · 5–300
bluetooth_classic, bluetooth_blescan_s / pause_s15 s · 5–60 / 45 s · 5–300
internet_qualitytransport_targetWi‑Fi + cellular data · AUTO, WIFI, CELLULAR, BOTH
sample_interval_ms1,000 ms · 500–5,000
download_kib / upload_kib64 KiB · 1–1,024 / 8 KiB · 1–256
latency_probe_count3 × · 2–3
capacity_interval_s30 s · 10–300
capacity_download_kib1,024 KiB · 64–10,240
capacity_upload_kib128 KiB · 8–2,048
download_mb (manual test)10 MB · 1–100
upload_mb (manual test)5 MB · 1–50
Internal limits: 3 s request timeout, 5 s ceiling for a short transfer, 15 s ceiling for a burst, 60 s ceiling for a manual test.
wifi_throughputcycle_interval_s60 s · 10–600
connect_timeout_s30 s · 5–120
download_kib1,024 KiB · 64–10,240
upload_kib128 KiB · 8–2,048
latency_probe_count3 × · 1–5
Internal limit: 20 s timeout for a single HTTPS request. The list of measured networks is not a parameter — it is entered separately in the source card, and the passwords are stored in the app preferences in readable form.

Storage in the phone

The data sits in a local Room / SQLite database, schema version 4. It is never sent anywhere; exporting to a file is up to the user.

Table sensor_samples

ColumnTypeDescription
idlongPrimary key. It determines the order of samples that share a timestamp.
sessionIdlongReference to the session; deleting the session deletes the samples too.
sourcetextSource of the sample.
timestampEpochMslongExported as epoch_ms.
elapsedRealtimeNanoslongExported as elapsed_realtime_ns.
payloadtextPayload of the source, including the attached suffixes.

Table measurement_sessions

One row per measurement run. The columns match the fields in the export header; on top of that, acceptedSamples, writtenSamples, droppedSamples and lastPersistedAtEpochMs are updated as the run proceeds, in the same transaction as the insert of a batch of samples. If the process dies, the session stays in the RUNNING state and the next app start closes it as INTERRUPTED with end_reason=PROCESS_RECOVERY — the partial record stays exportable.

← Back to the collection diagram