概述
它是典型的适配器模式——屏蔽底层 HCI 操作细节,给上层提供统一的扫描发现能力
上层 (shareservice 等) ↓ 调用标准接口 driver_ble_discovery.c ← 适配层,承上启下 ↓ 操作 HCI socket Linux 内核蓝牙协议栈1. 向上:提供统一接口
通过 softbus_ble_discovery_interface.h 对上层暴露标准接口,如:
SoftbusBleDiscoveryStartScan— 开始扫描SoftbusBleDiscoveryStopScan— 停止扫描SoftbusBleDiscoveryRegisterScanListener— 注册扫描监听SoftbusBleDiscoveryUnRegisterScanListener— 反注册扫描监听
上层(如 shareservice)只调用这些接口,不关心底层实现。
2. 向下:适配 Linux HCI 层
通过直接操作 Linux Bluetooth HCI socket 实现扫描功能:
DriverExtendBleScanSwitch— 发送 HCI 命令控制扫描开关ExtendedEventListenerThread— 通过 HCI socket 轮询读取 BLE 广播包ProcessExtendedBleAdvEvent— 解析 HCI 层上报的扩展广播数据
SoftbusBleDiscoveryStartScan
参数说明
scannerId扫描通道ID,项目定义了8个通道,可实际上只用到了1个1号。每个通道包含
| 字段 | 含义 | |----------------|-----------------------| | `isUsed` | 该通道是否已被注册占用 | | `isScanning` | 该通道是否正在扫描 | | `scannerId` | 通道编号(等于数组下标)| | `scanCallback` | 上层注册的回调函数 |softbusscanparams----HCI扫描物理参数
typedef struct { uint8_t scanType; // 扫描类型:被动扫描(0) / 主动扫描(1) uint8_t scanPhy; // 扫描物理信道:1M PHY / 2M PHY / Coded PHY uint8_t scanFilterPolicy; // 过滤策略:接受所有 / 只接受白名单 uint8_t frameType; // 帧类型 uint16_t scanInterval; // 扫描间隔(单位 0.625ms) uint16_t scanWindow; // 扫描窗口(单位 0.625ms) } SoftBusBcScanParams;这些参数会通过ConvertSoftbus2HciExtScanParams转换成 HCI 命令,直接下发给蓝牙控制器,控制硬件层面怎么扫描:
| 参数 | 作用 | 举例 |
|---|---|---|
scanInterval | 每隔多久扫描一次 | 100(即 62.5ms) |
scanWindow | 每次扫描持续多久 | 50(即 31.25ms) |
scanPhy | 用哪个物理信道 | Coded PHY(远距离) |
scanType | 主动扫描会发 SCAN_REQ 请求更多数据 | 主动扫描可获取 ScanRsp |
SoftBusBcScanFilter *scanFilter— 过滤条件数组
typedef struct { uint16_t serviceUuid; // 服务 UUID uint32_t serviceDataLength; // 服务数据长度 uint16_t manufactureId; // 厂商 ID uint32_t manufactureDataLength; // 厂商数据长度 int8_t *address; // 设备 MAC 地址 int8_t *deviceName; // 设备名称 uint8_t *serviceData; // 服务数据 uint8_t *serviceDataMask; // 服务数据掩码 uint8_t *manufactureData; // 厂商数据 uint8_t *manufactureDataMask; // 厂商数据掩码 uint8_t filterIndex; // 过滤器索引 } SoftBusBcScanFilter;作用:启动蓝牙扫描
阶段一:参数校验
① 检查入参 param / scanFilter / filterSize 是否合法 ② 检查 scanCallback 是否已注册(否则启动后无法回调通知上层)LOGI("Enter scannerId=%d", scannerId); if (param == NULL || scanFilter == NULL || filterSize <= 0) { LOGE("invalid param, scannerId=%d", scannerId); return SOFTBUS_INVALID_PARAM; } // 调用启动回调 if (g_scanChannel[scannerId].scanCallback == NULL || g_scanChannel[scannerId].scanCallback->OnStartScanCallback == NULL) { LOGE("invalid param, OnStartScanCallback is null"); return SOFTBUS_INVALID_PARAM; }阶段二:状态检查
作用:检查通道未注册或者已经在扫描就提前解锁返回错误
加锁 g_scannerLock → 检查扫描通道是否已注册(isUsed) → 检查是否已经在扫描(isScanning) 解锁 g_scannerLock// 获取互斥锁 if (pthread_mutex_lock(&g_scannerLock) != 0) { LOGE("lock failed, scannerId=%d", scannerId); return SOFTBUS_LOCK_ERR; } // 检查扫描通道状态 if (!CheckScanChannelInUsed(scannerId)) { LOGE("scanner is not in used, scannerId=%d", scannerId); pthread_mutex_unlock(&g_scannerLock); return SOFTBUS_BC_ADAPTER_NOT_IN_USED_FAIL; } // 检查是否已经在扫描 if (g_scanChannel[scannerId].isScanning) { LOGE("already scanning, scannerId=%d, btScanId=%d", scannerId, g_scanChannel[scannerId].scannerId); pthread_mutex_unlock(&g_scannerLock); return SOFTBUS_ALREADY_TRIGGERED; } pthread_mutex_unlock(&g_scannerLock);sharkit暂时先看到这吧,PL和我说让我负责文件互传模块,WiFi适配暂时搁置
阶段三:启动底层扫描
调用 DriverBleDiscoveryStartScan() → 向 HCI 层发送扫描命令 再次加锁 g_scannerLock → 根据 HCI 返回值更新 isScanning 状态 解锁 g_scannerLock阶段四:通知上层启动结果
作用:不直接在当前线程回调上层,而是丢到线程池异步执行。这是为了避免回调中如果上层又调用了其他接口(比如 StopScan),形成同线程递归调用导致死锁。
malloc 一个 ScanResultReportData ThreadPoolAdd(ThreadOnStartScanCallback) → 通过线程池异步回调上层阶段五:启动事件监听线程
作用:事件监听线程通过 HCI socket 持续读取 BLE 广播包。如果线程创建失败,会回滚:调用DriverExtendBleScanSwitch(false)停止 HCI 扫描,并将isScanning置回 false。
设置全局 g_scannerId = scannerId pthread_create(ExtendedEventListenerThread) → 创建事件监听线程