Android 车载蓝牙开发笔记:HFP、A2DP、AVRCP、PBAP、MAP、BLE 与系统 API
Android 车机、IVI、T-Box 和工程机械终端中的蓝牙主要分成两类:一类负责手机互联,包括 HFP + A2DP + AVRCP + PBAP + MAP;另一类负责设备通信,包括 BLE GATT + SPP/RFCOMM + HID。Android Automotive 对车载蓝牙的要求也主要围绕手机通话、媒体、媒体控制和通讯录展开,当前 Android Automotive 兼容性要求包含 HFP + A2DP + AVRCP + PBAP,MAP 在存在驾驶员 Occupant Zone 的设备上属于强烈建议支持的 Profile。
典型手机互联链路:Android 车机 ↔ Bluetooth Profiles ↔ 手机。典型 BLE 外设链路:Android 车机 → BLE Central/GATT Client → BLE Peripheral → 传感器/控制器。
车载蓝牙主要涉及:BluetoothAdapter + BluetoothDevice + Pair/Bond + HFP + A2DP + AVRCP + PBAP + MAP + SPP/RFCOMM + BLE/GATT + Audio + Telecom + Contacts + 系统蓝牙服务。
Classic Bluetooth 与 BLE
车载蓝牙首先区分 Classic Bluetooth 和 BLE。Classic Bluetooth 主要承担 手机通话 + 手机音乐 + 媒体控制 + 通讯录 + 短信 + SPP 数据通信;BLE 主要承担 车载传感器 + 控制器 + 私有 BLE 设备 + 广播设备 + 低功耗数据通信。
可以直接记录为:Classic Bluetooth:HFP/A2DP/AVRCP/PBAP/MAP/SPP,BLE:Advertising + GATT + Service/Characteristic。
手机连接车机时通常不是只建立"一条蓝牙连接",而是同一台 BluetoothDevice 上分别建立多个 Profile:Bond → HFP + A2DP + AVRCP + PBAP + MAP。
Android Automotive 蓝牙角色
车机和手机在不同 Profile 中承担不同角色:
| 功能 | Profile | 手机角色 | 车机角色 |
|---|---|---|---|
| 电话 | HFP | Audio Gateway | Hands-Free / HFP Client |
| 音乐 | A2DP | Source | Sink |
| 媒体控制 | AVRCP | Target | Controller |
| 通讯录 | PBAP | Server | Client |
| 短信 | MAP | Server | Client |
| 私有串口数据 | SPP | Client/Server | Client/Server |
| BLE 外设 | GATT | Peripheral/Server | Central/Client |
AOSP Automotive 的实际实现也是按照这个方向组织:车机通过 HFP Client 使用手机电话能力,通过 A2DP Sink 接收手机音频,通过 AVRCP Controller 控制手机播放器,通过 PBAP Client 获取通讯录,通过 MAP Client 处理短信。
普通 SDK API 与车载 System API
Android 车载蓝牙开发中需要特别区分 Public SDK API 和 System API/隐藏 API。
普通 Android SDK 可以直接使用:BluetoothManager + BluetoothAdapter + BluetoothDevice + BluetoothProfile + BluetoothA2dp + BluetoothHeadset + BluetoothSocket + BluetoothGatt + BluetoothGattServer + BluetoothLeScanner + BluetoothLeAdvertiser。Android SDK 的 android.bluetooth 包公开了这些通用蓝牙能力。
但车机连接手机时需要的角色通常是:
HFP Client → BluetoothHeadsetClient
A2DP Sink → BluetoothA2dpSink
AVRCP Controller → BluetoothAvrcpController
PBAP Client → BluetoothPbapClient
MAP Client → BluetoothMapClient
这些类存在于 AOSP Bluetooth Framework 中,但属于车载系统、系统应用和平台代码使用的 System API/隐藏 API,不应该按普通三方 APK API 理解。AOSP 当前 Framework 中仍包含这些 Profile 类。
例如 BluetoothHeadsetClient 明确属于 HFP Client System API,部分操作同时要求 BLUETOOTH_CONNECT + BLUETOOTH_PRIVILEGED;BluetoothA2dpSink、BluetoothPbapClient、BluetoothMapClient 同样属于系统侧 Profile API。
因此车载项目如果需要直接控制 HFP Client/A2DP Sink/PBAP Client/MAP Client,通常意味着应用属于:System App + Platform Signed App + AAOS 系统组件 + 厂商 Framework,而不是普通应用商店 APK。
BluetoothManager
BluetoothManager 是 Android 蓝牙服务的入口之一。
常用 API:
scss
getAdapter():获取 BluetoothAdapter
getConnectedDevices(profile):获取指定 GATT Profile 的连接设备
getConnectionState(device, profile):获取 GATT 连接状态
openGattServer():创建 GATT Server
普通设备扫描、配对和 Classic Bluetooth 操作主要继续通过 BluetoothAdapter 和 BluetoothDevice 完成。
BluetoothAdapter
BluetoothAdapter 表示本机 Bluetooth Adapter,是 Classic Bluetooth 和 BLE 的主要入口。
常见 API:
scss
isEnabled():蓝牙是否开启
getState():Bluetooth Adapter 状态
getBondedDevices():已经 Bond 的设备
startDiscovery():Classic Bluetooth Discovery
cancelDiscovery():停止 Discovery
getRemoteDevice():根据地址获取 BluetoothDevice
getBluetoothLeScanner():BLE Scanner
getBluetoothLeAdvertiser():BLE Advertiser
getProfileProxy():获取 Bluetooth Profile Proxy
closeProfileProxy():关闭 Profile Proxy
getProfileProxy() 是 Android Bluetooth Profile 与 Framework Bluetooth Service 之间的重要入口,公开的 BluetoothA2dp、BluetoothHeadset 等 Profile 都通过这个机制获得代理对象。
车机系统层同样通过这套 Framework 机制获取 A2DP_SINK + HEADSET_CLIENT + AVRCP_CONTROLLER + PBAP_CLIENT + MAP_CLIENT 等 Profile Proxy;AOSP 的 BluetoothAdapter 中存在这些 Profile 对应的构造映射。
BluetoothDevice
BluetoothDevice 表示一台远端蓝牙设备,例如已经配对的手机。
常见 API:
scss
getAddress():Bluetooth Address
getName():设备名称
getType():Classic / LE / Dual
getBondState():Bond 状态
createBond():发起 Bond
getUuids():已发现的服务 UUID
createRfcommSocketToServiceRecord():建立 RFCOMM
connectGatt():建立 BLE GATT Connection
同一个手机在车机中通常只对应一个 BluetoothDevice,但上层可能同时存在多个 Profile Connection。
因此:BluetoothDevice Connected ≠ 所有 Profile 都 Connected。
实际车载状态需要分别维护:
HFP State + A2DP State + AVRCP State + PBAP State + MAP State。
Pairing 与 Bonding
Pairing 负责建立双方安全关系和生成密钥,Bonding 负责保存长期密钥。
Android 常见 Bond State:
BOND_NONE → BOND_BONDING → BOND_BONDED
相关 API 和事件:
scss
BluetoothDevice.createBond()
BluetoothDevice.getBondState()
BluetoothDevice.ACTION_BOND_STATE_CHANGED
BluetoothDevice.ACTION_PAIRING_REQUEST
车机完成 Bond 后通常继续自动建立多个 Profile:
Bonded → HFP → A2DP/AVRCP → PBAP → MAP
因此:
Bonded ≠ HFP Connected
Bonded ≠ A2DP Connected
Bonded ≠ 手机互联全部 Ready
HFP
HFP(Hands-Free Profile)负责车机电话能力。
典型关系:
手机:Audio Gateway(AG)
车机:Hands-Free(HF)/ HFP Client
车机通过 HFP 获取并控制:来电 + 去电 + 接听 + 挂断 + Call State + 电话号码 + 手机网络状态 + 电量 + SCO 通话音频。
典型链路:
Dialer → Telecom → HFP Client → 手机 → 蜂窝网络
在 AAOS 中,每个 HFP 手机连接会注册对应的 Phone Account 到 TelecomManager,车机电话应用再通过 Android Telecom 体系使用手机通话能力。
BluetoothHeadsetClient
车机使用的是 HFP Client,对应 AOSP:
BluetoothHeadsetClient
BluetoothHeadsetClientCall
它属于 System API,而不是普通应用的标准公开 API。AOSP 对该类的定义就是通过 IPC 控制 HFP Client Service。
常见能力包括:
scss
getConnectedDevices():HFP 已连接手机
getConnectionState():HFP Connection State
getCurrentCalls():当前电话列表
dial():拨号
acceptCall():接听
rejectCall():拒接
terminateCall():挂断
holdCall():保持通话
sendDTMF():发送 DTMF
startVoiceRecognition():启动手机语音识别
stopVoiceRecognition():停止语音识别
AOSP 当前 BluetoothHeadsetClient 中仍包含 getCurrentCalls()、acceptCall()、rejectCall()、terminateCall()、dial() 等车机电话控制接口。
相关状态事件包括:ACTION_CONNECTION_STATE_CHANGED + ACTION_AUDIO_STATE_CHANGED + ACTION_CALL_CHANGED + ACTION_AG_EVENT。
SCO
HFP 控制电话状态,真正的通话音频通常通过 SCO/eSCO 链路传输。
可以简单记录为:
HFP Signaling:电话控制
SCO/eSCO:电话语音
因此出现:
电话状态正常 + 能接听 + 没有声音
时,不能只检查 HFP Connection,还需要检查:SCO Audio State + Audio Routing + Audio HAL + Audio Policy。
车载蓝牙电话实际上跨越:
Bluetooth Stack + Telecom + Audio Framework + Audio HAL。
A2DP
A2DP(Advanced Audio Distribution Profile)负责高质量蓝牙媒体音频。
手机播放音乐时:
手机:A2DP Source
车机:A2DP Sink
链路:
手机播放器 → A2DP Source → Bluetooth → A2DP Sink → Android Audio → 车载扬声器
因此车机系统侧真正对应的是:
BluetoothA2dpSink
而普通 Android SDK 中常见的:
BluetoothA2dp
主要对应平台公开的 A2DP Profile API,不能简单等同于车机所需的 A2DP Sink 控制接口。AOSP 的 BluetoothA2dpSink 属于 System API。
BluetoothA2dpSink
车载系统常用能力:
scss
getConnectedDevices()
getConnectionState()
connect()/disconnect()
setConnectionPolicy()
实际音频播放还需要进入 Android Audio Framework,因此:
A2DP Connected ≠ 正在播放
需要分别关注:Profile Connection State + Audio Streaming State + Audio Focus + Audio Routing。
AVRCP
AVRCP(Audio/Video Remote Control Profile)负责媒体控制和媒体信息。
典型角色:
手机:AVRCP Target
车机:AVRCP Controller
主要功能:Play + Pause + Next + Previous + Metadata + 播放状态 + 浏览媒体内容。
A2DP 与 AVRCP 通常同时出现:
A2DP:传音乐声音
AVRCP:控制音乐播放器
因此:
有声音但方向盘下一曲无效 → 优先检查 AVRCP
能切歌但没有声音 → 优先检查 A2DP/Audio
AAOS 中车机作为 AVRCP Controller,通过 AVRCP 控制手机媒体播放,并依赖 A2DP 完成真正的音频传输。
BluetoothAvrcpController
AOSP 车机侧对应:
BluetoothAvrcpController
属于系统 Framework Bluetooth Profile。
主要处理:连接状态 + Playback State + Metadata + Pass Through Command + Player/Browse 信息。
对于普通车机业务应用,媒体控制通常还会经过 Android Media Framework,界面层不一定直接操作 AVRCP Controller。
完整链路更接近:
车机媒体 UI → Media/系统车载媒体服务 → AVRCP Controller → 手机播放器
PBAP
PBAP(Phone Book Access Profile)负责把手机通讯录和通话记录提供给车机。
典型角色:
手机:PBAP Server
车机:PBAP Client
连接后车机可以同步:联系人 + 电话号码 + 通话记录。
AAOS 的 PBAP Client 会维护与手机对应的联系人数据,并将同步结果写入 Android Contacts Provider,供车载电话应用查询;设备断开后,系统会处理该设备关联的联系人和通话记录。
因此车载业务应用通常不需要自己解析 PBAP OBEX 数据,而是从系统联系人体系读取最终数据。
BluetoothPbapClient
系统侧对应:
BluetoothPbapClient
它属于 System API,主要负责:PBAP Connection + Connection Policy + Profile State,部分操作需要 BLUETOOTH_PRIVILEGED。
车载应用层更常使用:
ContactsContract
ContentResolver
读取 PBAP Client 已经同步进 Android 的通讯录数据。
因此完整链路:
手机 Contacts → PBAP → BluetoothPbapClient → Contacts Provider → Dialer
MAP
MAP(Message Access Profile)负责手机短信访问。
典型角色:
手机:MAP Server
车机:MAP Client
主要用于:接收短信 + 读取短信 + 发送短信 + 消息状态同步。
AAOS 中 MAP Client 与手机建立连接后,手机收到新消息时,车机 Bluetooth Stack 可以接收并解析消息,再向系统应用提供消息事件。
BluetoothMapClient
系统侧对应:
BluetoothMapClient
该类属于 System API,AOSP 中用于控制 MAP Message Client Equipment Profile,并提供连接、消息接收、消息发送和状态操作。
常见能力包括:getConnectedDevices() + getConnectionState() + sendMessage() + setMessageStatus() + ACTION_MESSAGE_RECEIVED。
部分 MAP Client 操作需要:BLUETOOTH_CONNECT + BLUETOOTH_PRIVILEGED,消息本身还涉及 SMS 相关系统权限。
因此普通 APK 不应该直接把 MAP 当作普通 Bluetooth Profile 使用。
SPP
SPP(Serial Port Profile)常用于车载厂商私有设备、诊断设备、蓝牙串口模块等传统数据通信场景。
底层使用 RFCOMM:
Android → BluetoothSocket → RFCOMM → Bluetooth Device
Android 对应公开 API:
scss
BluetoothDevice.createRfcommSocketToServiceRecord()
BluetoothDevice.createInsecureRfcommSocketToServiceRecord()
BluetoothAdapter.listenUsingRfcommWithServiceRecord()
BluetoothSocket
BluetoothServerSocket
SPP 更接近连续字节流,上层仍然需要自己定义:帧头 + 长度 + Command + Payload + CRC。
因此:
SPP/RFCOMM:数据传输通道
厂商协议:定义实际数据内容
Bluetooth Profile Proxy
Android Profile 通常通过:
scss
BluetoothAdapter.getProfileProxy()
连接 Framework 中对应的 Bluetooth Profile Service。
公开 SDK 常见 Profile Proxy:BluetoothA2dp + BluetoothHeadset + BluetoothHidDevice + BluetoothLeAudio 等。Android 官方 BluetoothProfile API 公开了 Profile Connection State 查询模型。
车载平台代码还存在:BluetoothHeadsetClient + BluetoothA2dpSink + BluetoothAvrcpController + BluetoothPbapClient + BluetoothMapClient。
因此在 AAOS/厂商系统开发中,经常看到:
Application/System Service → BluetoothProfile Proxy → Bluetooth Profile Service → Native Bluetooth Stack → Controller
BLE
BLE 在车载中更适合连接:胎压/传感器 + 外部仪表 + MCU BLE 模块 + 控制器 + 私有车载附件。
Android 车机通常扮演:
Central + GATT Client
外部设备通常扮演:
Peripheral + GATT Server
典型流程:
Peripheral Advertising → Android Scan → connectGatt → Service Discovery → Characteristic Read/Write/Notify → 厂商协议
BLE 和 HFP/A2DP 等手机 Profile 是两条不同技术线。
BLE 扫描系统 API
BLE 扫描主要使用:
scss
BluetoothAdapter.getBluetoothLeScanner()
BluetoothLeScanner
ScanFilter
ScanSettings
ScanCallback
ScanResult
ScanRecord
流程:
BluetoothAdapter → BluetoothLeScanner → startScan → ScanResult
ScanResult 常关注:BluetoothDevice + RSSI + ScanRecord。
ScanRecord 常关注:Service UUID + Manufacturer Data + Service Data + Device Name。
车载固定外设通常适合通过:Service UUID + Manufacturer Data + Device ID 识别,不建议只依赖 Device Name。
BLE Advertising
如果车机本身需要作为 BLE Peripheral 或广播设备,可以使用:
BluetoothLeAdvertiser
AdvertiseSettings
AdvertiseData
AdvertiseCallback
较新的 BLE 广播还涉及 Extended Advertising 对应 API。
普通车机连接外部 BLE 设备时主要使用 Scanner,不一定需要 Advertiser。
GATT
BLE Connection 建立以后,通过 GATT 访问设备数据。
核心结构:
GATT Server → Service → Characteristic → Descriptor
Android 对应系统 API:
BluetoothGatt
BluetoothGattCallback
BluetoothGattService
BluetoothGattCharacteristic
BluetoothGattDescriptor
典型流程:
BluetoothDevice.connectGatt() → BluetoothGatt → discoverServices() → getService() → getCharacteristic() → Read/Write/Notify
Service 与 Characteristic
Service 表示一组设备能力,Characteristic 表示具体的数据入口。
例如一个车载 BLE 设备可能定义:
Vehicle Sensor Service → Command Characteristic + Notify Characteristic
Characteristic 常见 Properties:
READ + WRITE + WRITE_NO_RESPONSE + NOTIFY + INDICATE
典型厂商 BLE 协议:
Android → WRITE Characteristic → Device
Device → NOTIFY Characteristic → Android
这类设备有时被称为"BLE 串口",但本质仍然是 GATT,不是 RFCOMM/SPP。
Notify 与 CCCD
设备主动向 Android 上传数据通常使用 Notify 或 Indicate。
Android 侧涉及:
scss
BluetoothGatt.setCharacteristicNotification()
BluetoothGattDescriptor
以及 CCCD:
00002902-0000-1000-8000-00805f9b34fb
可以简单记录为:
Notify:设备主动推送,不要求 ATT 确认
Indicate:设备主动推送,需要 ATT 确认
开启 Notify 通常同时涉及:Android 本地 Notification 状态 + 远端 CCCD 配置。
只完成其中一部分,经常表现为:Write 正常 + Characteristic 也支持 Notify + 一直没有数据回调。
MTU
BLE 默认 ATT MTU 为:
23 Byte
常见 Characteristic Value Payload:
23 - 3 = 20 Byte
协商更大的 MTU 后可以提高单次数据量。
相关 API:
scss
BluetoothGatt.requestMtu()
BluetoothGattCallback.onMtuChanged()
但 MTU 只决定 ATT 层数据能力,不等于厂商协议可以任意发送长数据。
实际分包仍需考虑:
Negotiated MTU + Characteristic Write Type + Peripheral Buffer + 厂商协议
BLE GATT 操作顺序
Android BLE 操作基本都是异步流程:
connectGatt → onConnectionStateChange → discoverServices → onServicesDiscovered → MTU → CCCD/Notify → Ready → Read/Write
相关核心 Callback:
scss
onConnectionStateChange()
onServicesDiscovered()
onCharacteristicRead()
onCharacteristicWrite()
onCharacteristicChanged()
onDescriptorWrite()
onMtuChanged()
车载 BLE 长连接更适合维护明确状态:
Disconnected → Connecting → Discovering → Configuring → Ready
不要只根据 BluetoothProfile.STATE_CONNECTED 判断业务设备已经可以通信。
Classic Discovery
Classic Bluetooth 手机和 SPP 设备发现主要通过:
scss
BluetoothAdapter.startDiscovery()
BluetoothAdapter.cancelDiscovery()
BluetoothDevice.ACTION_FOUND
BluetoothAdapter.ACTION_DISCOVERY_STARTED
BluetoothAdapter.ACTION_DISCOVERY_FINISHED
Classic Discovery 本身开销较高,Android 官方说明 Discovery 期间新连接建立和现有连接性能都会受到影响,因此建立 RFCOMM 等连接前通常先 cancelDiscovery()。
车机完成首次手机配对后,日常自动回连通常直接使用 Bond Device 和 Profile Connection Policy,不需要反复 Discovery。
蓝牙权限
Android 12 / API 31 开始主要使用:
BLUETOOTH_SCAN:扫描附近蓝牙设备
BLUETOOTH_CONNECT:连接和读取已连接设备信息
BLUETOOTH_ADVERTISE:BLE Advertising
这些权限属于 Nearby Devices 权限体系。
旧版本主要使用:BLUETOOTH + BLUETOOTH_ADMIN,BLE Scan 还涉及旧 Location 权限模型。
车载 System API 还经常涉及:
BLUETOOTH_PRIVILEGED
例如 HFP Client、PBAP Client、MAP Client 的部分 Profile Control API 不是只拿到 BLUETOOTH_CONNECT 就可以调用。
因此需要区分:
普通 Android 蓝牙应用权限
车载系统 Bluetooth Profile 权限
多手机连接
车机可能同时 Bond 多台手机,例如:
私人手机 + 工作手机
不同 Profile 的最大连接数量并不一定相同,AAOS 的 Profile Service 各自维护自己的连接限制和状态。AOSP Automotive Bluetooth 也按每个 Profile 独立管理多设备连接。
因此车机不能只维护一个:
currentBluetoothDevice
更合理的状态是:
HFP Active Device + A2DP Active Device + PBAP Device + MAP Device + Bonded Devices
并处理不同设备之间的 Profile 优先级和 Active Device 切换。
CarBluetoothService
AAOS 中蓝牙不是只由业务 App 管理,车载系统还有专门的 Bluetooth Connection Management。
AOSP Automotive 使用 CarBluetoothService 配合 Bluetooth Profile Service 管理设备连接和连接策略。Profile 本身仍由 Bluetooth 模块中的 hfpclient + a2dpsink + avrcpcontroller + pbapclient + mapclient 等 Service 实现。AOSP Bluetooth 模块当前仍保留这些独立 Profile Service。
因此车机蓝牙架构更接近:
Car App → Car/System Service → Bluetooth Framework → Profile Service → Native Stack → Bluetooth HAL/Controller
而不是普通 App 自己完整接管所有手机 Profile。
HFP 已连接但电话不可用
重点检查:
HFP Client Connection + Phone Account + TelecomManager + Call State + SCO Audio + Audio Routing + 手机侧授权
如果 BluetoothHeadsetClient 已经 Connected,但 Dialer 中没有电话能力,还需要继续检查 Telecom 注册和车载电话服务。
A2DP 已连接但没有声音
重点检查:
A2DP Sink State + 是否正在 Streaming + Audio Focus + Audio Routing + Audio Policy + 音量 + 手机当前 Media Output
A2DP Profile Connected 只表示媒体 Profile 链路存在,不表示 PCM Audio 已经正常进入车载扬声器。
可以播放但不能切歌
重点检查:
AVRCP Controller + 手机 AVRCP Target + Media Session + Player Browse Support
A2DP 负责音频,AVRCP 负责控制,两者不能混为一个 Profile。
通讯录没有同步
重点检查:
PBAP Client Connection + 手机通讯录授权 + PBAP Profile Policy + Contacts Provider + 手机是否拒绝共享联系人
手机蓝牙设置中的"共享联系人"关闭时,HFP/A2DP 可以正常连接,但 PBAP 可能没有任何可用数据。
收不到短信
重点检查:
MAP Client + 手机消息访问授权 + MAP Connection + SMS Permission/System App + 消息事件
手机音乐和电话正常不代表 MAP 已经授权。
BLE 能扫描但连接失败
重点检查:
RSSI + Device 是否 Connectable + Bond/Security + 当前连接数量 + connectGatt 状态 + Peripheral 是否已经连接其他 Central
能够看到 Advertising 不代表 Peripheral 一定接受 GATT Connection。
BLE Connected 但没有数据
重点检查:
Service Discovery + Service UUID + Characteristic UUID + Characteristic Properties + CCCD + Notify/Indicate + Write Type + MTU + 厂商协议
Connected ≠ GATT Ready。
HCI Snoop Log
车载蓝牙问题只看应用 Log 往往不够。
Android 可以启用 Bluetooth HCI Snoop Log,再通过 Wireshark 分析 Host 与 Bluetooth Controller 之间的数据。
适合排查:
Pairing + HFP + SDP + RFCOMM + BLE Advertising + GATT + ATT + MTU + Notification + Disconnect Reason
例如 BLE Write Success 但设备没有响应,可以继续确认 ATT Write 是否真正发送;HFP 异常可以继续定位 Profile、RFCOMM/SCO 和 Controller 层行为。