Wi-Fi, Bluetooth and NFC
Three radios, one pattern: a framework service, a vendor HAL, and a Mainline module trying to keep the whole thing updatable. What differs is the permission story — and it changed completely in Android 12.
Wi-Fi, Bluetooth and NFC look like three unrelated technologies. Architecturally they are the same
shape: a Java framework service in system_server, a native daemon, a vendor HAL behind a stable
interface, and a chip below that. Learn one and the others become readable.
TL;DR#
- Each radio follows the same pattern: framework service → native daemon → vendor HAL → chip.
- Wi-Fi is the most complete example of per-network policy: scanning, selection, metering and per-network DNS all live above the HAL.
- Bluetooth's permissions were rewritten in Android 12 (API 31):
BLUETOOTH_SCAN,BLUETOOTH_CONNECTandBLUETOOTH_ADVERTISEreplaced the old pairing permissions plus location. - NFC is not really a networking radio. It is a very short-range data exchange with a payment protocol bolted on top; host card emulation lets a phone act as a card.
- All three ship, at least partly, as Mainline modules, so their behaviour can change without an OS update.
Mental model#
Picture a hotel with three kinds of door.
The Wi-Fi door is the front entrance: many people use it, it opens onto the world, and the concierge keeps a list of which guests are allowed through which door and whether they are on a budget.
The Bluetooth door is the service entrance: it connects to a handful of specific things (headsets, watches, cars) that have been introduced to the building, and what matters is who has been paired.
The NFC door is the ticket reader at the gate: you touch it, it exchanges a few bytes, and the door opens. It is not a path into the building at all — it is a single transaction.
Where the analogy breaks#
All three doors on a phone are behind a shared vendor wall. The same SoC vendor often supplies the Wi-Fi, Bluetooth and sometimes NFC silicon, and the same HAL boundary applies. The analogy also fails on permissions: the doors do not just check "are you a guest", they check whether the guest has been told, this session, what each door is for.
The big picture#
BLUETOOTH plus location for scanning) and a framework service that exposes every capability to any app that holds it.Text description of this diagram
A sequence diagram comparing Bluetooth scanning with NFC tag dispatch. For Bluetooth, the app calls startScan, which requires BLUETOOTH_SCAN. The framework service drives the vendor HAL, the controller listens on the advertising channels, and results arrive as asynchronous callbacks. Connecting is a separate call and requires BLUETOOTH_CONNECT. For NFC, the controller discovers a tag and the system dispatches it as an intent to the app registered for that tag type, so no scan is running.
The change is not cosmetic. Under the old model, an app that wanted to know whether a Bluetooth headset was nearby needed location permission, because a scan could reveal where the user was. Under the new model, the scan itself is a permission, and the app can declare that it does not derive location, which removes the location requirement.
Deep dive#
The shared pattern#
Every one of these stacks has the same four pieces.
| Piece | Wi-Fi | Bluetooth | NFC |
|---|---|---|---|
| Framework service | WifiManager, WifiService | BluetoothManager, BluetoothService | NfcManager, NfcService |
| Native / vendor daemon | wpa_supplicant, hostapd | the vendor Bluetooth stack behind its HAL | the NFC controller firmware + HAL |
| Interface | AIDL HAL | AIDL HAL | AIDL HAL |
| Below | chip and firmware | chip and firmware | controller and antenna |
The framework service is where policy lives. The HAL is where device specifics live. The line between them is the interesting part, because the HAL is vendor code and the service is platform code — so a bug on the wrong side of the line cannot be fixed by a Mainline update.
Wi-Fi: selection is the hard part#
Wi-Fi is not "connect to a network". It is a continuous optimisation problem: which of the visible networks should this device join, given saved credentials, signal strength, band, security, metered status and the user's preferences?
The platform keeps a state machine that moves between scanning, associating, authenticating, obtaining an address, and validating connectivity. When a network is connected but cannot reach the internet — a captive portal or a broken uplink — the system can notice and avoid it. That is why "connected, no internet" is a distinct state rather than a failure.
From an app's point of view the important surface is small: the current connection's information, scan results, and the ability to request a network with certain capabilities. The heavy lifting is in the service and the supplicant.1
Bluetooth: a stack, not a daemon#
Bluetooth is the messiest of the three, because "the Bluetooth stack" is not one thing. It is a profile layer (headsets, audio, input devices, health), a host stack implementing the core protocol, and a controller firmware. Historically Android has shipped more than one host stack over its lifetime, and parts have moved into Mainline.
The safe way to reason about it: vendor-specific code sits behind the Bluetooth HAL; the framework service above it exposes profiles and device management; and some of that framework is updatable as a Mainline module. Which exact implementation is in the host stack on a given device is a device and release detail rather than a stable architectural factunverified(Android has used several Bluetooth host stack implementations over time, and the split between platform, Mainline and vendor code differs by release; I have not verified the current arrangement).3
What is stable is the permission model since API 31. Three runtime permissions, each covering one operation:
BLUETOOTH_SCAN— discover nearby devices.BLUETOOTH_CONNECT— connect to paired devices and read their names.BLUETOOTH_ADVERTISE— make this device discoverable.
The old BLUETOOTH and BLUETOOTH_ADMIN permissions are still declared for older API levels, which
is why manifests typically use maxSdkVersion on them and request the new ones alongside.4
NFC: three modes, one antenna#
NFC is short range by physics — a few centimetres. Android exposes three modes, and they are genuinely different:
- Reader/writer. The phone reads or writes an NDEF tag.
- Peer-to-peer. Two devices exchange data. This is the mode Android Beam used.
- Card emulation. The phone behaves like a contactless card.
Card emulation is the one with the interesting architecture. There are two variants: the secure element in the SIM or an embedded chip does the work, or host card emulation (HCE) does it in the phone's application processor. HCE, added in Android 4.4 (API 19), let a normal app implement a card by responding to APDUs — the command/response protocol a payment terminal speaks — without access to a secure element.5
That is how a phone can act as a transit card or a payment card in software. It is also why the NFC
permission is normal: the security comes from the payment network's provisioning and the tokenisation
scheme, not from a runtime dialog.
Reading an NFC tag without an app in the foreground#
NFC has an unusual delivery model: tags are dispatched as intents. When a tag is read and no app has claimed it, the system can launch the app registered for that tag's type. That is why tapping a tag can open a browser without any app running.
The modern form is the reader-mode API, which lets a foreground activity take exclusive control of the tag stream while it is resumed — better for apps that scan several tags in a row.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 18 | 4.3 Jelly Bean |
|
| 23 | 6.0 Marshmallow |
|
| 28 | 9 Pie |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 33 | 13 Tiramisu |
|
| 37 | 17 Cinnamon Bun |
|
Under the hood#
- the Wi-Fi Mainline module: service, framework and shell
- the Bluetooth module's framework and service
- the NFC service and the reader-mode plumbing
- the HAL contract vendors implement
Curiosity corner#
- NFC predates the smartphone. The standard was published in 2003, as a successor to contactless smart cards.
- Bluetooth and Wi-Fi share an antenna on many phones. They coordinate through a coexistence mechanism, which is why a busy 2.4 GHz Wi-Fi link can degrade Bluetooth audio.
- "Paired" is not "connected". Pairing exchanges keys; connecting uses them. An app needs
BLUETOOTH_CONNECTfor both, which is why the permission dialog sounds broader than it is.
Try it#
adb shell dumpsys wifi | head -40
adb shell dumpsys bluetooth_manager | head -40
adb shell cmd nfc status
Example output
mWifiInfo SSID: home-5g, RSSI: -52, Link speed: 433Mbps
Bonded devices:
AA:BB:CC:DD:EE:FF WH-1000XM5 [CONNECTED]
NFC state: onThe Bluetooth dump lists bonded devices and their connection state separately, which is the quickest way to distinguish "paired but not connected" from "not paired at all".
Check yourself#
Check yourself
Which component decides which network an app's socket should use?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsWi-Fi overviewdeveloper.android.comaccessed 2026-10-27↩
- docsManifest.permission | API referencedeveloper.android.comaccessed 2026-10-27↩
- docsBluetooth overviewdeveloper.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 12developer.android.comaccessed 2026-10-27↩
- docsNear Field Communication (NFC)developer.android.comaccessed 2026-10-27↩
- docsConnectivity overviewsource.android.comaccessed 2026-10-27↩
- docsModular system componentssource.android.comaccessed 2026-10-27↩