21 · settingslib 架构与事件流

核心文件:settingslib “七姐妹”——LocalBluetoothManager/LocalBluetoothAdapter/BluetoothEventManager/CachedBluetoothDeviceManager/CachedBluetoothDevice/LocalBluetoothProfileManager/BluetoothCallback 三 flavorbase/settingsLibAndroid/src/{dcddif,xcddif,f3dif}/java/com/android/settingslib/bluetooth/dcddif=骁龙8295 / xcddif=玄戒A14 / f3dif=玄戒A17主线(dev_a17_0610 编译 f3dif)。 适用范围:理解本仓蓝牙事件流的前提。

0. 为什么先读这篇

前序文档反复出现 MiBluetoothUtils.getLocalBtManager()getEventManager().registerCallback(this)CachedBluetoothDevice.connect()——它们都落到 AOSP settingslib 的”四件套”上:连接车机蓝牙 UI 与系统 BluetoothAdapter 的中间层。本仓在 AOSP 基础上做了 MIUI/MICAR 定制。

🚨 关键认知(对抗审查+主控核实)“settingslib 是 AOSP 原样拷贝”错误;但 MICAR 定制只存在于 dcddif/xcddiff3dif(A17 主线)= 纯上游 AOSPCachedBluetoothDevice.java0 个 MICAR-PORTING 标记(xcddif 33 个、dcddif 10 个),黑名单/半关/try-catch/timeout 翻倍等定制全部回归。改 A17 蓝牙逻辑时不能假设这些定制点存在。下文凡 MICAR 定制均标注仅 dcddif/xcddif。

1. LocalBluetoothManager:单例与聚合

业务层入口 MiBluetoothUtils.getLocalBtManager()(:73-89) → LocalBluetoothManager.getInstance。构造(:109-121 dcddif/xcddif;f3dif :110-129 因 EventManager 6 参)聚合四件套并立即 updateLocalProfiles() + readPairedDevices()——构造完即广播已注册、profile handler 已挂、已配对设备已入 Cache。

f3dif getInstance(:60-62) 调 LocalBluetoothAdapter.getInstance(context, user)(双参),xcddif/dcddif 调无参 getInstance();f3dif 还新增 mCachedFocussedDisplayId(:55) 多屏 focus。

classDiagram
    class LocalBluetoothManager {
        +getInstance(ctx,cb)$
        +getCachedDeviceManager()
        +getEventManager()
        +getProfileManager()
        -WeakReference mForegroundActivity
    }
    class LocalBluetoothAdapter { +startScanning(force) }
    class BluetoothEventManager {
        -Map Handler mHandlerMap
        -CopyOnWriteArrayList BluetoothCallback mCallbacks
        +registerCallback(cb)
    }
    class CachedBluetoothDeviceManager { +findDevice()/addDevice() }
    class LocalBluetoothProfileManager { +updateLocalProfiles() }
    class CachedBluetoothDevice {
        +connect()/connectProfile()
        +onBondingStateChanged()/onUuidChanged()
    }
    LocalBluetoothManager o--> LocalBluetoothAdapter
    LocalBluetoothManager o--> BluetoothEventManager
    LocalBluetoothManager o--> CachedBluetoothDeviceManager
    LocalBluetoothManager o--> LocalBluetoothProfileManager
    BluetoothEventManager --> CachedBluetoothDeviceManager : dispatch
    CachedBluetoothDeviceManager *-- CachedBluetoothDevice

mForegroundActivity 弱持有(:44)。Fragment 进前台调 setForegroundActivity(BluetoothMainEntrySettingsFragment:217),让 settingslib 知道”有 BT UI 在前台”。

2. BluetoothEventManager:广播总线

构造器里 addHandler(action, handler) 注册 action→Handler 路由表,action 累加到 IntentFilterregisterReceiver三 flavor 广播数量不同

flavoraddHandler 范围数量特征
xcddif:108-18129全集:含 CSIS/TWSP/LeAudio/Codec/Broadcast/VCP/Screen
dcddif:91-12718少 11 项(无 Le/Auracast/CSIS/VCP/Screen)
f3dif:103-14320新增 ACTION_AUTO_ON_STATE_CHANGED(:143,A17独有);缺 CSIS/TWSP/Codec/Broadcast/VCP/Screen

主要 action→Handler 路由(xcddif):

ActionHandler分发目标
ACTION_STATE_CHANGEDAdapterStateChangedHandleronBluetoothStateChanged + MIUI 半关(仅xcddif :180-181)
ACTION_FOUNDDeviceFoundHandlermDeviceManager.addDevice + dispatchDeviceAdded
ACTION_BOND_STATE_CHANGEDBondStateChangedHandleronDeviceBondStateChanged + cachedDevice.onBondingStateChanged
ACTION_UUIDUuidChangedHandlercachedDevice.onUuidChanged()触发自动连接旁路
ACTION_ACL_CONNECTED/DISCONNECTEDAclStateChangedHandleronAclConnectionStateChanged
ACTION_ACTIVE_DEVICE_CHANGEDActiveDeviceChangedHandleronActiveDeviceChanged
各 profile ACTION_CONNECTION_STATE_CHANGEDStateChangedHandler(LBPM)onProfileStateChanged

MICAR 定制 try/catch 包裹广播分发仅 xcddif 有(:386-392),dcddif/f3dif 无——单个 handler 抛异常在 f3dif/dcddif 会让后续广播丢失。RECEIVER_EXPORTED:xcddif(:231,235)+f3dif(:179,183) 有,dcddif 无(A14 兼容老 API)。

事件总线模型

flowchart LR
    subgraph 系统["系统 BluetoothAdapter"]
        A1[广播 ACTION_*]
    end
    subgraph EM["BluetoothEventManager(主线程)"]
        BR[onReceive] --> HM[mHandlerMap→Handler]
        HM --> D2[findDevice/addDevice]
        HM --> CD[CachedBluetoothDevice.onXxx]
        HM --> D1[dispatch 遍历 mCallbacks]
    end
    subgraph UI["BluetoothCallback 实现"]
        F1[MainEntryFragment] 
        F2[BondedController]
        F3[UnbondedController]
    end
    A1 --> BR
    D1 --> F1
    D1 --> F2
    D1 --> F3

关键性质:Handler 表 1:1;mCallbacksCopyOnWriteArrayListmReceiverHandler 绑主线程——所有 BluetoothCallback 在主线程触发(上层 Controller 大量 postOnBackgroundThread + mUIHandler.post 切换线程的根本原因)。

3. CachedBluetoothDevice:聚合体

每个实例 = 一个远端设备 + bond 状态 + profile 列表 + 名称/电量/活跃态。三 flavor 的 connect 链与黑名单差异巨大

3.1 connect 链(三栏)

步骤dcddifxcddiff3dif
onBondingStateChanged 签名(int):839(int):1050(int,int):1147
黑名单早退isCloseAutoConnectDevice:853:1079不存在
connect()(public):360:429:503
mConnectAttempted 赋值:365:434onAclStateChanged:1227
connectDevice()/connectAllEnabledProfiles:387(adapter:402):521(mDevice:544):596(mDevice:611)

dcddifmActiveAdapter.connectAllEnabledProfiles(mDevice)xcddif/f3difmDevice.connect()(BluetoothDevice 隐藏 API),让框架按 priority 一次性连所有 profile。

3.2 黑名单 isCloseAutoConnectDevice(仅 dcddif/xcddif)

// xcddif CachedBluetoothDevice.java:1032-1046 + 早退 :1079
private boolean isCloseAutoConnectDevice(BluetoothDevice device) {
    String devicesStr = Settings.Secure.getStringForUser(..., BLUETOOTH_CLOSE_AUTO_CONNECT, ...);
    return device.getAddress().equals(devicesStr);  // 单槽位 MAC 等值匹配
}
// onBondingStateChanged 内: if (isCloseAutoConnectDevice(mDevice)) return;  // :1079

🚨 f3dif 完全没有此方法(grep 0 命中)。onBondingStateChanged(:1147) 直接 if(mDevice.isBondingInitiatedLocally()) connect()(:1192)。disableAutoConnect 写 Settings.Secure 在所有 flavor 都执行——A17 主线”写得到、没人读”,CarPlay 配对后仍自动连 HFP/A2DP。

3.3 onUuidChanged 旁路(三 flavor 一致:都不查黑名单)

onUuidChanged()mConnectAttempted + timeout 窗口内直接 connectDevice()/connectAllEnabledProfiles()不查黑名单。timeout:xcddif/dcddif 翻倍(X+X)f3dif 不翻倍但用大常量——MAX_UUID 35000(vs 5000)、MAX_HOGP 60000(vs 30000)、MAX_HEARING_AIDS 45000(vs 15000)、MAX_LEAUDIO 60000。

3.4 onBondingStateChanged 自动连接(仅车机主动发起)

MICAR 定制:只有 isBondingInitiatedLocally=true(车机主动发起配对)才自动 connect;对端发起的不连。xcddif(:1075 缓存局部变量→:1090)、dcddif(:851 合并在 if);f3dif(:1192 直接调,无黑名单)。

4. 自动连接端到端时序

sequenceDiagram
    participant FW as 蓝牙框架
    participant CDC as CachedBluetoothDevice
    participant CB as BluetoothCallback
    FW->>CDC: ACTION_BOND_STATE_CHANGED(BOND_BONDED)
    Note over CDC: xcddif onBondingStateChanged:1050<br/>dcddif :839<br/>f3dif :1147(双参)
    alt dcddif/xcddif 且命中黑名单(CarPlay)
        CDC->>CDC: isCloseAutoConnectDevice 早退<br/>(xcddif:1079/dcddif:853)
    else f3dif(无黑名单,直接走)
        CDC->>CDC: 无黑名单检查
    end
    alt isBondingInitiatedLocally(车机发起)
        CDC->>CDC: connect()
        alt mProfiles 空(UUID未到)
            FW->>CDC: ACTION_UUID→onUuidChanged
            CDC->>CDC: timeout窗口内 connectDevice 旁路(不查黑名单)
        else mProfiles 非空
            CDC->>FW: mDevice.connect()(xcddif:544/f3dif:611)<br/>或 connectAllEnabledProfiles(dcddif:402)
        end
        FW-->>CB: onProfileConnectionStateChanged → UI刷新
    else 对端发起
        Note over CDC: settingslib 不主动 connect
    end

5. LocalBluetoothProfileManager:profile 注册

updateLocalProfiles()adapter.getSupportedProfiles() 动态创建 profile 实例,每个通过 addProfileaddProfileHandler 加到 mProfileIntentFilter(独立 mProfileBroadcastReceiver)。

profile 实例化顺序 ≠ 连接顺序connect() 走框架内部 priority(通常 HFP→A2DP→PBAP),settingslib 不感知。connectProfile(LocalBluetoothProfile)(:568) 才是 settingslib 主动连单个 profile 的入口(详情页 PBAP 开关走这条)。

6. BluetoothCallback:UI 层接入

flavor方法数范围特征
xcddif15:54-238含 Codec/CSIS/Broadcast 回调
dcddif10:36-141少 5 个
f3dif11:52-174新增 onAutoOnStateChanged(:174,A17独有);缺 Codec/CSIS/Broadcast

主要回调:onBluetoothStateChanged/onScanningStateChanged/onDeviceAdded/onDeviceBondStateChanged/onProfileConnectionStateChanged/onAclConnectionStateChanged/onActiveDeviceChanged 等。

注册时机BluetoothMainEntrySettingsFragment onStart:216/onStop:223;各 Controller onStartInternal:115/onStopInternal:123必须配对,漏注销致泄漏。

7. 双蓝牙上限

DOUBLE_BLUETOOTH_DEVICE_LIMIT=2(ConnectionConstants.kt:19)。5 处调用点在应用层(micarConnectionSettings,非 settingslib),详见 32-双蓝牙上限与Picker。判定口径 = 已连 HFP/A2DP 设备数(ConnectionUtils.getConnectedHfpA2dpDevices),非手机类不计入。

8. 三 flavor 对照总表(核心速查)

项目dcddifxcddiff3dif(A17主线)
BluetoothEventManager 广播数182920(含AUTO_ON)
BluetoothCallback 方法数101511(含onAutoOn)
onBondingStateChanged单参:839单参:1050双参:1147
connect 链终点adapter:402mDevice:544mDevice:611
isCloseAutoConnectDevice 黑名单:821/:853:1032/:1079不存在
MICAR-PORTING 标记数(CBD)10330(纯AOSP)
timeout 翻倍X+X:793X+X:1003单X大常量:1113
MAX_UUID_DELAY5000500035000
try/catch 广播保护有:386
半关 ScreenChangedHandler有:180
LeAudio/HapClient/CsipSet
RECEIVER_EXPORTED

9. 对抗自查清单

  1. 行号必标 flavor:上表三栏对照,勿用单 flavor 行号套全 flavor。
  2. isAutoConnectable 不在 connect 链:是 LocalBluetoothProfile 接口方法(:36),各 profile 实现,框架层使用,settingslib 不主动调(grep 三 flavor 0 调用)。
  3. “settingslib 是 AOSP 拷贝”证伪,但 f3dif 接近原版:MICAR 定制(黑名单/半关/try-catch/timeout翻倍)只在 dcddif/xcddif;f3dif 是纯上游 AOSP,改 A17 逻辑勿假设定制存在。
  4. getInstance 非空保证getLocalBtManager()!!,车机必须有蓝牙适配器。
  5. 回调主线程:所有 dispatch 在主线程,Controller 的线程切换是为此。
  6. f3dif 黑名单缺失是 A17 真实风险:CarPlay 配对后自动连蓝牙抢占通道(见 31 H6)。