22 · 双 flavor 差异 dcddif vs xcddif vs f3dif
核心文件:
base/settingsLibAndroid/build.gradle:15-82(productFlavors + sourceSets 挂载点)base/settingsBaseLib/src/main/java/com/android/car/settings/miauto/common/DeviceUtil.java:84,163,226(运行时平台判定)base/settingsLibAndroid/src/{dcddif,xcddif,f3dif}/java/com/android/settingslib/bluetooth/(三套 settingslib 蓝牙实现)settingsPage/micarConnectionSettings/src/main/java/.../MiBluetoothPairingController.kt:283(单份,2956 修复落点)适用范围:改蓝牙代码前必读。
0. TL;DR
- 编译期 flavor 决定走哪一套 settingslib:
dcd→dcddif/xcd_cn_a14→xcddif/xcd_cn_a17→f3dif/xcd_global_a17→f3dif+global(build.gradle:59-82)。xcd_cn_a17/xcd_global_a17flavor 编译时使用 f3dif(玄戒 A17 平台),xcddif 是玄戒 A14 历史 flavor。 - 运行时
DeviceUtil.isDCDPlatform()只用ro.board.platform=="msmnile"判骁龙 8295(DeviceUtil.java:226-228),没有isXring()/isKunLunPlatform();isKunLun()(:163) 是车型判定非平台。 - 三个 flavor 目录是同名同包不同实现(都是
com.android.settingslib.bluetooth.*),无继承关系;src/main/java/com/android/settingslib/bluetooth/目录不存在,所有蓝牙类分裂在三 flavor 下。 - 本仓
micarConnectionSettings蓝牙代码绝大多数单份(src/main),仅MiBluetoothCollinear.kt按 flavor 分(dcddif 独立一份 + xcddif/f3dif 共用一份)。 - MANNPROB-2956 修复(commit 7239803be)落在
src/main/.../MiBluetoothPairingController.kt:283,单份代码,所有 flavor 自动同步,无需双改。
1. flavor 选择机制
1.1 flavor → sourceSet 映射(直读 build.gradle:30-82)
flavorDimensions=["miPlatform"],4 个 productFlavors:dcd/xcd_cn_a14/xcd_cn_a17/xcd_global_a17。
| Build Variant | 主源集 | flavor 源集 | 平台/版本 | 物理平台 |
|---|---|---|---|---|
dcdDebug | src/main | src/dcddif | A14/A17 通吃 | 骁龙 8295(msmnile) |
xcd_cn_a14Debug | src/main | src/xcddif | A14 | 玄戒(早期) |
xcd_cn_a17Debug | src/main | src/f3dif | A17 | 玄戒(最新,F3代) |
xcd_global_a17Debug | src/main | src/f3dif + src/global | A17 海外 | 玄戒海外版 |
注:
build.gradle:77-82为xcd_global_a17配置了src/global/java+src/global/res,但src/global目录当前预留暂无内容——海外 flavor 实际只有 f3dif 在生效。
2026-09-06 勘误(第四轮对抗核实):① sourceSets 现为 5 个变体——新增
xcd_global_a14(→xcddif+src/global,海外 A14,build.gradle:71-76),上表应补一行;② f3dif 源集已合入 dev 分支(262 文件被跟踪,随 targetSdk 37 适配 b57402a19 等提交),不再是”A17 分支专属”,本仓 dev 上可直接引用 f3dif 行号;维护者确认 a17 已全面切 dev 交付,a17/xcd/dcd 三机型统一走 dev 分支交付,dev_a17_0610/dev_a17 仅历史参照;③ f3dif CachedBluetoothDevice.java(2719 行)与 dev_a17_0610 同 blob。
1.2 怎么选编译哪一套
./gradlew :app:assembleDcdDebug # dcddif(骁龙8295)
./gradlew :app:assembleXcd_cn_a17Debug # f3dif(玄戒A17国内)
./gradlew :app:assembleXcd_global_a17Debug # f3dif+global(玄戒海外)
# xcd_cn_a14 在 A17 主线已不构建(历史 flavor)1.3 flavor 选择流程图
flowchart TD A[Gradle 启动] --> B{选 build variant} B -->|dcd| C1[src/main + src/dcddif<br/>骁龙8295] B -->|xcd_cn_a14| C2[src/main + src/xcddif<br/>玄戒A14 主线已停] B -->|xcd_cn_a17| C3[src/main + src/f3dif<br/>玄戒A17国内] B -->|xcd_global_a17| C4[src/main + src/f3dif + src/global<br/>玄戒A17海外 global暂空] C1 --> D1[settingslib.bluetooth 来自 dcddif] C2 --> D2[settingslib.bluetooth 来自 xcddif] C3 --> D3[settingslib.bluetooth 来自 f3dif] C4 --> D3 D1 --> E[micarConnectionSettings 同步按<br/>同名 flavor 挂载 src/dcddif xcddif f3dif] D2 --> E D3 --> E style C3 fill:#ffe,stroke:#a80 style D3 fill:#ffe,stroke:#a80
2. 平台判定:DCD=骁龙8295,XCD=玄戒
DeviceUtil.java:226-228:
public static boolean isDCDPlatform() {
return PLATFORM_MSMNILE.equals(getPlatform()); // "msmnile",getPlatform()=ro.board.platform(:84)
}isDCDPlatform()==true⇒ 骁龙 8295;XCD 一律用!isDCDPlatform()表达。isKunLun()(:163) 走 device type 通道判车型,≠平台判定。- 无
isXring()/isKunLunPlatform(),不要自己读ro.board.platform,更不要新增这类判定。
3. 三套 settingslib 蓝牙实现差异
3.1 类清单差异(comm -13/diff 直出)
| 类/能力 | dcddif | xcddif | f3dif | 差异性质 |
|---|---|---|---|---|
| LeAudioProfile | - | ✓ | ✓ | 平台能力(LE Audio) |
| HapClientProfile | - | ✓ | ✓ | 平台能力(助听控制) |
| CsipSetCoordinatorProfile + CsipDeviceManager | - | ✓ | ✓ | 平台能力(设备组协调) |
| VolumeControlProfile | - | ✓ | ✓ | 平台能力(音量控制) |
| LocalBluetoothLeBroadcast + Assistant + Metadata | - | ✓ | ✓ | 平台能力(Auracast 广播音频) |
| BluetoothBroadcastUtils | - | ✓ | ✓ | 平台能力 |
| HearingAidAudioRoutingHelper + Info + Constants | - | ✓ | ✓ | 平台能力(助听音频路由) |
9 个 *Ext.kt(BatteryLevelsInfo/BluetoothEventManagerExt/LeAudioProfileExt/LocalBluetoothManagerExt/LocalBluetoothLeBroadcast*CallbackExt/LocalBluetoothLeBroadcastMetadata/PrivateBroadcastReceiveData/ProfileConnectionState 等) | - | - | ✓ | A17 版本新增(Kotlin 扩展,xcddif 仅 2 个) |
| DeviceGroupClientProfile / DunServerProfile / VcpProfile | - | ✓ | - | xcddif 独有(f3dif 重构移除) |
| HearingAidStatsLogUtils.java | - | ✓ | - | xcddif 独有(f3dif 移除) |
| CachedBluetoothDevice.onBondingStateChanged 签名 | (int):839 | (int):1050 | (int,int prevBondState):1147 | A17 API 升级 |
结论:
dcddif → xcddif/f3dif的差是平台能力差异(骁龙8295 不支持 LE Audio/Auracast/助听全家桶,玄戒支持)。xcddif → f3dif的差是Android 版本差异(A14→A17 的 API 签名升级、净增 9 个*Ext.ktKotlin 扩展、移除DeviceGroupClientProfile/VcpProfile/DunServerProfile/HearingAidStatsLogUtils)。- 只看 dcddif vs xcddif 会漏掉 A17 实际行为——
xcd_cn_a17flavor 编译的是 f3dif。
3.2 同名同包不同实现(无继承)
三个目录的 CachedBluetoothDevice.java 都是 package com.android.settingslib.bluetooth,类名相同、无继承关系,靠 sourceSet 选哪份编进 APK。不要试图在 dcddif 里 extends xcddif 实现,编译期互不可见。
3.3 三套差异对照
classDiagram class dcddif_BT { A2dpProfile/HeadsetProfile/HearingAidProfile/Hid/Pan... 缺 LeAudio/HapClient/CsipSet/VolumeControl/LeBroadcast 全家桶 note: 骁龙8295 经典蓝牙 } class xcddif_BT { 全部 dcddif 类 +LeAudio/HapClient/CsipSet/VolumeControl/LeBroadcast +DeviceGroupClientProfile/VcpProfile/DunServerProfile +HearingAidStatsLogUtils note: 玄戒A14 LE Audio全家桶 } class f3dif_BT { 全部 xcddif 核心类 +9个 Ext.kt Kotlin扩展 -DeviceGroupClientProfile/VcpProfile/DunServerProfile(移除) -HearingAidStatsLogUtils(移除) onBondingStateChanged(int,int) note: 玄戒A17 升级签名+Kotlin化 } dcddif_BT ..> xcddif_BT : 同包同名 不同实现 xcddif_BT ..> f3dif_BT : 同包同名 A17升级
4. 2956 修复是否需双 flavor 同步?——否(但当前未合入)
MiBluetoothPairingController.kt 在 settingsPage/micarConnectionSettings/src/main/java/.../bluetooth/ 下单份(所有 flavor 共用)。
⚠️ 当前状态(2026-07-23 二次核实):修复 commit 7239803be 在 dev_a17_0610 为悬空提交(git merge-base --is-ancestor 返回非祖先、git fsck 显示 dangling),已被 reset,当前分支未合入,bug 仍在。实测 onCancel(:283) 仍是旧版(仅 cancelBondProcess),MiBluetoothPairingDialogActivity.kt 也无 mDismissed 标志。
**修复方案(待合入,一旦合入所有 flavor 自动同步)**改两文件(均在 src/main 单份):
MiBluetoothPairingController.kt:283onCancel加bondState==BOND_BONDED判断,已 bonded 走removeBond(),否则cancelBondProcess()MiBluetoothPairingDialogActivity.ktdismiss 一次性 + 立即解注册 receiver
f3dif(A17 主线)= 纯上游 AOSP:对抗审查实测 f3dif
CachedBluetoothDevice.java0 个 MICAR-PORTING 标记(xcddif 33 个、dcddif 10 个),无黑名单isCloseAutoConnectDevice、无 try/catch 广播保护、无半关 ScreenChangedHandler、timeout 不翻倍(用大常量:MAX_UUID 35000 vs xcddif 5000)。即 A17 主线 MICAR 蓝牙定制全部回归原生。改 A17 蓝牙逻辑时不能假设这些定制点存在。
旧文档
docs/连接/蓝牙/02-蓝牙-配对流程.md:19,75,109仍写onCancel:279→:281 cancelBondProcess,是 2956 修复前行号,已过时(由 02修订 更新)。
5. 本仓(非 settingslib)蓝牙代码的 flavor 分布
| 文件 | 位置 | 是否按 flavor 分 |
|---|---|---|
| MiBluetoothPairingController.kt / MiBluetoothPairingRequest.kt / BluetoothDeviceService.kt / BluetoothScanManager.kt / MiBluetoothUtils.kt / MiBluetoothExt.kt / ConnectionUtils.kt | src/main | 单份 |
| MiBluetoothCollinear.kt | src/{dcddif,xcddif,f3dif} | 分 |
MiBluetoothCollinear.kt 实测:dcddif 独立一份(20行,含卫星设备 DID_PRODUCT_ID 检测,注释”和产品沟通暂时不显示卫星图片”);xcddif 与 f3dif 内容完全相同(18行,diff exit=0)——即”dcddif 独立 + xcddif/f3dif 共用”两份实现。
实务:改 MiBluetoothCollinear.kt 时 dcddif 单独看、xcddif/f3dif 同步改;改其他本仓蓝牙文件改一处即可。
6. 改蓝牙逻辑时的 flavor 检查清单
flowchart TD Start([要改一段蓝牙代码]) --> Q1{改的是 settingslib<br/>com.android.settingslib.bluetooth?} Q1 -->|是| Q2{涉及 API 签名?<br/>如 onBondingStateChanged} Q1 -->|否 改本仓业务| Q3{文件在 src/main 还是<br/>src/dcddif/xcddif/f3dif?} Q2 -->|是 改签名| R1[三套全改:<br/>dcddif单参/xcddif单参/f3dif双参<br/>注意 f3dif 多 prevBondState] Q2 -->|否 仅逻辑| R2[涉及 LE Audio/HapClient/CsipSet<br/>则 dcddif 不需要] Q3 -->|src/main| R3[改一处即可 所有 flavor 共享] Q3 -->|src/flavor| R4[dcddif单独 + xcddif/f3dif同步] R1 --> V[跑三种 variant 编译验证:<br/>assembleDcdDebug<br/>assembleXcd_cn_a17Debug<br/>assembleXcd_global_a17Debug] R2 --> V R3 --> V R4 --> V V --> End([完成]) style R1 fill:#fee style R4 fill:#fee style R3 fill:#efe
实操 checklist
- 先定位文件:
find base/settingsLibAndroid/src -name "<类名>"看出现在哪几个 flavor 目录 - settingslib 内的类默认三份(main 无蓝牙代码),签名变更必须三套都改
- 本仓业务代码默认单份(src/main),除
MiBluetoothCollinear.kt - 运行时分支用
DeviceUtil.isDCDPlatform(),不要自读ro.board.platform,不要新增isXring() - 改
CachedBluetoothDevice.java注意签名:f3difonBondingStateChanged(int,int)(:1147) 比 dcddif(:839)/xcddif(:1050) 多prevBondState - LE Audio/HapClient/CsipSet/VolumeControl/LeBroadcast 相关:dcddif 没有(平台也不支持),不要硬塞
- 提交前编译三个 variant:
./gradlew :app:assembleDcdDebug :app:assembleXcd_cn_a17Debug :app:assembleXcd_global_a17Debug - 旧文档行号警惕:02 文档
onCancel:279/:281已过时
7. 关键结论
xcd_cn_a17/xcd_global_a17flavor 编译用 f3dif,xcddif 仅 A14 历史;改 A17 蓝牙逻辑看 f3dif。- 平台能力差异(dcddif 缺 LE Audio 全家桶)是硬件/协议栈限制;版本差异(xcddif→f3dif API 签名/Kotlin 化)是软件演进——勿混。
- 同名同包不同实现、无继承——sourceSet 编译期叠加,运行时无多态。
- 2956 修复(
7239803be)落单份代码,所有 flavor 自动同步,无”同步另一 flavor”的债。 - 改
MiBluetoothCollinear.kt:dcddif 单独 + xcddif/f3dif 同步;改其他本仓蓝牙文件改一处即可。