Overview
Near Field Communication (NFC) provides short-range, wireless connectivity that enables simple and secure two-way interactions between electronic devices. In Android, the NFC stack governs reading and writing passive tags, peer-to-peer data exchange (historically Android Beam), and crucial secure transaction capabilities through card emulation.
The Framework API
Applications interact with NFC functionality via the android.nfc package.
NfcManager and NfcAdapter
The entry point for NFC operations is the NfcAdapter. Unlike other connectivity managers, obtaining the adapter relies on a static helper method or the system service.
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter = manager.getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
// NFC is available and active
}
The adapter allows applications to enable foreground dispatch (intercepting scanned tags while the app is open) and configure card emulation services.
Tag Dispatch System
When an Android device is brought near an NFC tag, the hardware detects it and the NFC stack reads its contents (typically NDEF - NFC Data Exchange Format messages). The system must then determine which application should handle the tag.
Dispatch Prioritization
Android uses an Intent-based dispatch system with strict prioritization to resolve the scanned tag:
- Foreground Activity Dispatch: If an activity is currently in the foreground and has called
NfcAdapter.enableForegroundDispatch(), it receives the tag immediately, overriding all other rules. This is essential for apps that expect users to scan tags while actively using the application. - NDEF Payload Resolution (
ACTION_NDEF_DISCOVERED): If the tag contains an NDEF message with a recognized URI or MIME type, Android searches the manifest for activities registered to handle that specific data type. - Technology Resolution (
ACTION_TECH_DISCOVERED): If no NDEF handler is found, Android checks if any app is registered to handle the specific low-level technologies present on the tag (e.g., NfcA, IsoDep, MifareClassic). - Fallback (
ACTION_TAG_DISCOVERED): The lowest priority intent, fired if no other application claims the tag.
<!-- Example manifest intent filter for an NDEF URI -->
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https" android:host="mycompany.com"/>
</intent-filter>
Host Card Emulation (HCE)
Historically, simulating a smart card (like a transit pass or credit card) required a Secure Element (SE) - a specialized, tamper-resistant chip often tied to the SIM card.
Host Card Emulation (HCE) revolutionized mobile payments by allowing an Android application running on the main CPU to emulate a smart card.
How HCE Works
When an NFC reader (like a payment terminal) interrogates the phone, it sends Application Protocol Data Units (APDUs).
- The NFC controller receives the APDU.
- The NFC stack analyzes the APDU. If it targets an Application Identifier (AID) registered to an HCE application, it routes the APDU up to the framework.
- The framework invokes the registered
HostApduService. - The application processes the APDU and returns a response APDU.
public class MyPaymentService extends HostApduService {
@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
// Parse incoming APDU from the terminal
// Execute payment logic
// Return response APDU
return new byte[] { (byte)0x90, (byte)0x00 }; // Success status word
}
@Override
public void onDeactivated(int reason) {
// Connection lost or routed elsewhere
}
}
This architecture enables platforms like Google Wallet to operate without relying on carrier-controlled Secure Elements.
NFC HAL and NCI Protocol
Below the framework sits the native NFC service (com.android.nfc) and the Hardware Abstraction Layer.
The NCI Protocol
Communication between the Android host (the native service) and the NFC Controller hardware is standardized by the NFC Forum Controller Interface (NCI) specification.
NCI defines a common command set and packet structure. This standardization allows Android to use a single generic NFC stack to drive controllers from various vendors (NXP, Broadcom, STMicroelectronics) with minimal vendor-specific code.
The HAL Interface
The NFC HAL (android.hardware.nfc) is extremely lightweight. Its primary responsibility is not to implement NFC logic, but simply to transport raw NCI control packets and data packets between the native stack and the hardware driver via shared memory or serial interfaces.
// Simplified representation of the HAL transport interface
interface INfc {
// Send an NCI packet to the controller
int write(in byte[] data);
// Callback to receive an NCI packet from the controller
interface INfcClientCallback {
void sendEvent(in NfcEvent event, in NfcStatus status);
void sendData(in byte[] data);
}
}
Debugging the NFC Stack
Debugging NFC interactions, particularly complex HCE transactions, requires observing the flow of APDUs.
# Dump the state of the NFC service, showing registered AIDs and active routing tables
adb shell dumpsys nfc
For protocol-level debugging, developers analyze logcat for NCI packet traces or APDU exchanges handled by the HostApduService. If the payment terminal and the phone fail to negotiate, the APDU logs are the primary source of truth for identifying the protocol violation.