蓝牙知识库 2.0 · 建设大纲与调研规划
目的:让刚接手蓝牙模块的新人从「协议概念 → Android 框架 → 本仓代码 → 排障实战」四层递进上手。 现状诊断:已有 01/02/03 三篇偏「代码地图」(写得不错,保留),但缺第 0 层基础知识和第 4 层排障实战——新人没有概念地基,直接看代码地图仍然懵。 使用方式:本文件每个章节 = 一个独立调研任务,含【待回答问题清单 + 代码取证锚点 + 对抗审查点】。拿去 GLM 时每章 spawn 2 个 agent(1 调研 + 1 对抗审查),对抗通过后才落库。 日期:2026-07-23 | 模块根:
settingsPage/micarConnectionSettings/src/main/java/com/android/car/settings/miauto/bluetooth/
总体结构(目标目录树)
docs/连接/蓝牙/
├── 00-蓝牙-README.md (已存在,改造为总索引 + 学习路径)
├── 10-基础概念篇(新)
│ ├── 10-蓝牙协议速成.md ★新人第一课
│ ├── 11-配对与SSP安全机制.md ★MANNPROB-2956 直接相关
│ └── 12-Profile体系与车机角色.md
├── 20-Android框架篇(新)
│ ├── 20-Android蓝牙框架全景.md ★新人第二课
│ ├── 21-settingslib架构与事件流.md ★理解本仓的前提
│ └── 22-双flavor差异-dcddif-xcddif.md
├── 30-模块流程篇(已有,补强)
│ ├── 01-蓝牙-发现流程.md (已存在)
│ ├── 02-蓝牙-配对流程.md (已存在,待补 2956 案例修正)
│ ├── 03-蓝牙-设备详情与状态控制.md (已存在)
│ ├── 31-连接与自动连接策略.md (新)
│ ├── 32-双蓝牙上限与Picker.md (新)
│ └── 33-CarPlay特殊链路.md (新)
├── 40-排障实战篇(新)
│ ├── 40-日志取证速查.md ★logcat tag / bugreport 定向 grep
│ ├── 41-经典案例-MANNPROB-2956.md ★配对取消仍成功(已完成根因分析,素材现成)
│ └── 42-踩坑与反直觉设计.md (死代码/过滤设计/UI先行 汇总)
└── 50-速查卡(新)
├── 50-术语与类职责速查.md
└── 51-广播与事件清单.md
学习路径建议(写进 README):新人按 10→11→12→20→21→01→02→03→31~33→40 顺序读;排障时直接查 40/50。
任务卡 · 10 基础概念篇
任务 10:《蓝牙协议速成》★新人第一课
目标:不依赖本仓代码,建立协议层心智模型。读完能听懂「BR/EDR、BLE、ACL、SDP、UUID、配对码」这些词。 待回答问题清单:
- BR/EDR(经典蓝牙)与 BLE 的区别?车机连手机走哪个?(MANNPROB-2956 日志里 Transport: 1 和 LE 侧 45.088 各是什么)
- 蓝牙设备怎么被「发现」?Inquiry / Scan / Advertise 的过程;设备 class of device(CoD)里的 major class(PHONE/AUDIO…)——为什么本仓扫描列表只显示手机(
MiBluetoothUtils.isDeviceClassTypeSupport:131-160的过滤依据)? - SDP 是什么?UUID 怎么标识服务?
ACTION_UUID广播什么时候来? - ACL 连接是什么?
ACTION_ACL_CONNECTED/DISCONNECTED和 profile 连接(HFP connect)是什么关系? - 蓝牙地址、名称、别名(ALIAS)的区别。
对抗审查点:把「配对=连接」「发现=可连接」这类常见混淆逐个证伪;明确「bond(配对/绑钥)≠ ACL 连接 ≠ profile 连接」三层独立状态。
产出:
10-蓝牙协议速成.md,含一张「三层状态」图。
任务 11:《配对与 SSP 安全机制》★MANNPROB-2956 直接相关
目标:彻底搞懂配对流程与 4 种配对变体,能看懂 variant=2、is_auto_accept_ssp=false 这类日志。
待回答问题清单:
- 配对的本质是什么?(交换并持久化 Link Key/LTK;bond 状态机 BOND_NONE→BOND_BONDING→BOND_BONDED)
- SSP(Secure Simple Pairing)四种模式:Just Works / Numeric Comparison / Passkey Entry / Out of Band——各自的用户交互与安全级别(MITM 防护)。
- Android 侧配对变体常量:
PAIRING_VARIANT_PASSKEY_CONFIRMATION(2)、CONSENT、DISPLAY_PASSKEY、PIN各对应什么 UI?(对照MiBluetoothPairingController.kt各分支 + AOSPBluetoothPairingController.java) createBond→ACTION_PAIRING_REQUEST→setPairingConfirmation→BOND_BONDED的完整时序;cancelBondProcess与removeBond的语义差异(前者只对进行中的配对有效,IDLE 态空转;后者是唯一能撤销已完成配对的动作——2956 的血泪教训)。- 为什么
BOND_BONDED广播会被「wait for service discovery UUIDs」延迟?(BondStateMachine 等 SDP 完成再广播,44.862→46.534 延迟 1.67s 的实例) - 跨传输密钥分发:BR/EDR 配完后 LE 侧怎么也 BONDED 了(SMP over BR,45.087 Save LTK)?
对抗审查点:「Numeric Comparison 必须用户点确认」是否绝对?(本仓车机主动发起时自动 accept,属设计降级为 Just Works 语义——代码
MiBluetoothPairingDialogFragment.kt:179-182);「自动 accept 是协议要求」这一说法要证伪(is_auto_accept_ssp=false证明栈把决定权上抛应用层)。 产出:11-配对与SSP安全机制.md,含配对时序图 + 变体对照表 + 「取消语义」专题框。
任务 12:《Profile 体系与车机角色》
目标:搞清车机在每个 profile 里的角色(谁是 Source 谁是 Sink、谁是 AG 谁是 HF),以及「配对成功后哪些 profile 会自动连」。 待回答问题清单:
- HFP(车机=HF 免提端,手机=AG):通话链路;HfpClientProfile 在 settingslib 的位置。
- A2DP(车机=Sink 放音乐,手机=Source);A2dpSinkProfile vs A2dpProfile 并存的原因。
- PBAP(电话本同步):为什么详情页只有 PBAP 有独立开关(
MiCarBluetoothDeviceDetailFragment),其他 profile 没有? - MAP(短信)、HID(手柄/键鼠)、PAN、SAP、OPP:本仓各自用不用?
- CarPlay 为什么靠一个私有蓝牙 UUID
2d8d2466-e14d-451c-88bc-7301abea291a识别(ConnectionUtils.kt:30-31)?蓝牙在 CarPlay 里只承担「握手跳板」,真正的数据走 WiFi——这个「跳板」机制要讲清。 - BLE Audio / LeAudioProfile / HearingAid 在 xcddif flavor 出现、dcddif 没有——车机用不用?
对抗审查点:「profile 连接由系统自动完成」的说法要细化——本仓是 App 侧 settingslib
CachedBluetoothDevice.onBondingStateChanged→connect()(xcddif:1090)触发,不是纯系统行为;disableAutoConnect黑名单(xcddif:1079)何时生效、为何 2956 里没拦住 HFP/PBAP(待验证项)。 产出:12-Profile体系与车机角色.md,含 profile-角色-开关-自动连接 四列表格。
任务卡 · 20 Android 框架篇
任务 20:《Android 蓝牙框架全景》★新人第二课
目标:建立「App → BluetoothAdapter API → BluetoothAdapterService(packages/apps/Bluetooth)→ BTIF/协议栈 → HCI」的分层模型,知道每层出问题看什么日志。 待回答问题清单:
- BluetoothAdapter / BluetoothDevice 公开 API 概览;binder 到哪个进程(com.android.bluetooth)?
- BondStateMachine 是什么?它为什么要在 BONDED 前等 SDP UUID?(2956 关键:
handleBondStateChanged: is bonded, wait for service discovery UUIDs)——需要读 packages/apps/Bluetooth 仓源码确认挂起/超时机制,这是当前知识空白。 - 日志 tag 速查:BluetoothAdapterService / BluetoothBondStateMachine / bt_btif_dm / bt_btm_sec / smp 各代表哪一层?(示例:
btm_confirm_req_reply() State: IDLE Res: 11怎么读) - 广播体系:ACTION_STATE_CHANGED / ACTION_BOND_STATE_CHANGED / ACTION_ACL_* / ACTION_UUID / ACTION_PAIRING_REQUEST 的产生源与时序保证(重点:广播不是实时信号,应用层不能假设它即时到达)。
- HCI snoop log 是什么、在哪、什么场景才需要它。
对抗审查点:「BOND_BONDED 广播到达 = 配对刚完成」证伪(可能延迟数秒);「getBondState() 和广播哪个可信」——getBondState 读服务侧实时状态,广播有延迟(2956 修复方案的依据)。
产出:
20-Android蓝牙框架全景.md,含分层图 + tag→层映射表。
任务 21:《settingslib 架构与事件流》★理解本仓的前提
目标:搞懂本仓复用的 base/settingsLibAndroid 蓝牙部分:LocalBluetoothManager / BluetoothEventManager / CachedBluetoothDevice(Manager) / LocalBluetoothProfile(Manager) 四件套的职责与数据流。
待回答问题清单:
- LocalBluetoothManager 单例怎么拿(
MiBluetoothUtils.getLocalBtManager())?它聚合了什么? - BluetoothEventManager 注册的 ~25 个广播清单(xcddif 版 :108-181)→ 每个广播分发给谁?(这就是「系统事件 → UI 刷新」的总线)
- CachedBluetoothDevice 是什么?(设备的状态聚合体:bond 状态 + profile 连接状态 + 名称)
onBondingStateChanged(xcddif:1090)里 isBondingInitiatedLocally→connect() 的自动连接链。 - LocalBluetoothProfileManager 如何管理各 profile?
connect()/connectEnabledProfiles的顺序(2956 日志:先 HFP 后 PBAP 排队)。 - UI 层怎么监听:BluetoothCallback 接口(
BluetoothMainEntrySettingsFragment注册)的回调集合。 - 双蓝牙上限:
DOUBLE_BLUETOOTH_DEVICE_LIMIT=2(ConnectionConstants.kt:19)三处拦截点分别在哪、各拦什么场景。 对抗审查点:dcddif 与 xcddif 两套源码并存——同一符号两份实现,引用时必须标注 flavor(2956 分析里 xcddif:1090 与 dcddif:851 同逻辑但行号不同);「settingslib 是 AOSP 原样拷贝」证伪(有小米定制,如自动连接、黑名单)。 产出:21-settingslib架构与事件流.md,含四件套类图 + 事件流图(广播→EventManager→Callback→UI)。
任务 22:《双 flavor 差异 dcddif vs xcddif》
目标:说清为什么会有两套 settingslib(DCD=骁龙 8295 / XCD=自研玄戒),差异点清单,以及「改蓝牙逻辑要不要两边都改」。 待回答问题清单:
- flavor 怎么选(build variant);编译时哪套生效(对照 micarsettings-build skill 的变体规则)。
- diff 两套
settingsLibAndroid/src/{dcddif,xcddif}/java/com/android/settingslib/bluetooth/:xcddif 多出 LeAudio/DeviceGroup/广播音频等——是平台能力差异还是版本差异? - 2956 修复(onCancel 降级 removeBond)是否需要双 flavor 同步改?本仓(非 settingslib)代码有没有 flavor 分支?
对抗审查点:「改一处即可」的说法危险——确认
MiBluetoothPairingController.kt等本仓文件是单份还是按 flavor 分;settingslib 内改逻辑必须双 flavor 对照。 产出:22-双flavor差异.md,含差异点表格 + 「改代码时的 flavor 检查清单」。
任务卡 · 30 模块流程篇(补强 + 新增)
任务 31:《连接与自动连接策略》(新)
待回答问题清单:
- 配对成功后谁触发 profile 连接(settingslib connect 链,见任务 12);「连接/断开」按钮路径(
BluetoothBondedDevicesPrefController.handlePreferClick+ 断开确认弹窗 :220-243)。 - 回连策略:进蓝牙页/开机后自动回连哪台设备?
ConnectionUtils.recordLastConnectedDevice+BluetoothDeviceService(断连时更新 last device 给蓝牙音乐用)的机制。 - CarPlay 设备
disableAutoConnect(MiBluetoothPairingRequest.kt:104-106)与黑名单isCloseAutoConnectDevice(xcddif:1079):2956 里为何没拦住自动连接?这是开放问题,需要代码+日志验证。 - 双蓝牙场景:已连 2 台手机时的互斥/抢占规则。
产出:
31-连接与自动连接策略.md。
任务 32:《双蓝牙上限与 Picker》(新)
待回答问题清单:
DOUBLE_BLUETOOTH_DEVICE_LIMIT=2三处拦截点(配对请求 :85 / 列表 UI / Picker)逐一核。MiBluetoothPickerDialogActivity/Fragment是什么场景拉起(副驾/互联选设备?)与主配对流程的关系。DevicePairStageEvent(isBusy/isConnected/mBondState)在谁和谁之间传递、解决什么并发问题。 产出:32-双蓝牙上限与Picker.md。
任务 33:《CarPlay 特殊链路》(新)
待回答问题清单:
- CarPlay 设备识别(私有 UUID)→ 配对 → 二次弹窗
MiCarplayConnectTypeChooseDialogActivity(蓝牙连接 vs CarPlay)的完整链路;150ms 延迟拉起的设计意图。 - MisComplexSdk(车机互联 SDK,外部 aar)在详情页/配对页的监听(
MiCarBluetoothDeviceDetailFragment:73-79)。 - CarPlay 与双蓝牙上限的交互;CarPlay 断开后的蓝牙残留行为。
- 关联文档:
docs/连接/车机互联/01-车机互联-CarPlay-CarLink-AndroidAuto.md交叉引用。 产出:33-CarPlay特殊链路.md。
任务 30-fix:《02-配对流程.md 修正补强》(已有文档修订)
待办:
- 补 MANNPROB-2956 实证修正:①
onCancel(:283)仅 cancelBondProcess 无降级;②BONDED 广播可被 service discovery 延迟,「配对完成立刻 dismiss」不可依赖;③receiver 取消后未解注册导致迟到广播拉起 CarPlay 弹窗(:190-215在 isFinishing 检查:218之前)。 - 状态机章节补「广播延迟窗口」时序图。
产出:修订
02-蓝牙-配对流程.md。
任务卡 · 40 排障实战篇
任务 40:《日志取证速查》
待回答问题清单(以 MANNPROB-2956 bugreport 为教材,素材在 /home/zbc/下载/test/车机JIRA/jira-data/MANNPROB-2956/):
- logcat 定向 grep 清单:配对问题 grep 什么(
createBond|BOND_|Pairing|btm_|smp)、连接问题 grep 什么(connectEnabledProfile|HeadsetClient|A2dpSink|ACL)。 - bugreport 里蓝牙章节在哪;如何按时间窗过滤(问题时间 16:24 →
awk '/^07-22 16:24:4/')。 - 时间线重建方法:App 层日志(CarSettings-)↔ 服务层(BluetoothAdapterService/BondStateMachine)↔ 协议栈(bt_)三层对齐,找「谁先谁后」。
- 视频/录屏逐帧与日志时间戳对齐技巧(ffmpeg 抽帧)。
产出:
40-日志取证速查.md,grep 命令可直接复制。
任务 41:《经典案例 MANNPROB-2956》
素材现成:jira-data/MANNPROB-2956/analysis/root-cause.md(15 条 bugreport 证据 + 8 处 file:line + 视频 11 帧)。
待办:改写成教学案例——问题现象 → 三层时间线重建 → 四个假设 → 对抗审查推翻过程(H1 被源码证伪、H4 自灭)→ 最终根因(onCancel 无降级 + receiver 未解注册)→ 修复方案。重点呈现「想当然的根因如何被证据推翻」的方法论,不只是结论。
产出:41-经典案例-MANNPROB-2956.md。
任务 42:《踩坑与反直觉设计汇总》
待办(素材在现有 00-README 已确认事实 + 本次分析):
- 死代码清单:
BluetoothDisconnectConfirmDialogFragment(仅自引用)、设备过滤 condition2 耳机分支。 - 反直觉设计:扫描列表只显示手机(预期设计非 bug);UI 先行+防抖的开关;详情页只有 PBAP 开关;AOSP 布局遗产不加载。
- 双 flavor 同名类行号不同,引用必须带 flavor 前缀。
产出:
42-踩坑与反直觉设计.md(持续追加,仿 jira-analyze/LESSONS.md 格式:现象+原因+怎么办+实例锚点)。
任务卡 · 50 速查卡
任务 50:《术语与类职责速查》
待办:两页纸——①术语表(bond/ACL/SDP/SSP/CoD/UUID/profile/flavor…)②本仓 30 个源文件 + settingslib 四件套的一句话职责表(类名 | 职责 | 关键行号)。
产出:50-术语与类职责速查.md。
任务 51:《广播与事件清单》
待办:BluetoothEventManager 全部注册广播表格(action | 含义 | 分发到哪 | 相关代码行),从 xcddif:108-181 逐条整理 + dcddif 差异标注。
产出:51-广播与事件清单.md。
GLM 多 agent 调研编排建议
节奏(3 轮,每轮并行 ≤4 个任务,避免互相踩踏):
- 第 1 轮(概念地基):任务 10、11、12、20 —— 纯知识型,GLM 可直接产出,代码引用用本文锚点。
- 第 2 轮(框架与本仓):任务 21、22、31、32 —— 需要读代码,给 agent 开源码只读权限(仓:
/home/zbc/car/MiCarSettings)。 - 第 3 轮(实战与速查):任务 33、40、41、42、50、51 + 30-fix —— 41 素材现成可直接写。
每个任务的对抗环节(不可省):调研 agent 产出后,spawn 对抗 agent 专挑:
- 无 file:line / 日志行号支撑的「想当然」论断;
- 协议层面的绝对化表述(「必须/一定/从不」);
- 把 AOSP 行为当本仓行为(或反之);
- flavor 混淆(dcddif/xcddif 行号张冠李戴)。
落库规范:
- 每篇头部写
> 核心文件:和适用范围,与现有 01/02/03 风格对齐; - 事实性论断必须带锚点(
file:line或日志时间戳);推测性内容标「待验证」; - 核实过的事实同步追加到
docs/连接/_已核实事实基准.md,对抗过程记录追加_对抗审查记录.md(沿用连接模块既有惯例)。
优先级(如果时间有限,先做这 5 个):任务 11(SSP 配对机制)、20(框架全景)、21(settingslib)、41(2956 案例)、40(日志取证)——这五个读完就能独立排查大部分蓝牙 bug。
2026-09-06 增补:80 系列 + 23 章 + 基础事实修正
- 新增 80-Auracast广播QR篇(80 总览 / 81 QR 协议与编解码 / 篇内
_对抗核验记录-80篇.md):LE Audio 广播扫码链路,此前知识库空白段。 - 新增 23-BluetoothCallback契约与接入指南(20 系列第 4 篇):51 §4 的操作手册延伸——6 个实现者、扩展三步、flavor 成对增删矩阵。
- 基础事实修正(README/22/基准同步):f3dif 已合入 dev(262 文件,与 dev_a17_0610 同 blob);sourceSets 4→5 变体(新增 xcd_global_a14);BluetoothCallback 实现者 1→6。
- 对抗:第四轮(12 声明 11 PASS 1 FAIL),见
../_对抗审查记录.md。 - 留待任务:82+ LocalBluetoothLeBroadcast 源管理与 BroadcastAssistant 链路;f3dif Auracast 事件新机制(EventManager 删分发后走什么);f3dif 版 Ext 的 SIG 格式逐字段对照;BluetoothEventManagerExt/LocalBluetoothManagerExt 两个 f3dif 专属扩展的职责。