Android 由于加密问题,蓝牙文件无法写入描述符

Android bluetooth le fails to write descriptor due to encryption issue

我正在尝试确定使用低功耗蓝牙与支持 BLE 的设备通信的应用程序出了什么问题。令人抓狂的是,这个问题只发生在某些设备上,比如欧洲的摩托罗拉 Moto G3 和中国的三星 S5,而它与欧洲的三星 S5、欧洲的 HTC One M7 和中国的 MI W3 一起正常工作。

当它不工作时,在成功写入描述符后一切都会停止,因为永远不会调用相应的 onDescritorWrite(...) 回调。大概与设置加密失败有关(下面的完整日志):

W/bt-btif (18797): btif_gatt_set_encryption_cb() - Encryption failed (1)

我已经完成了一些常见的事情,比如确保蓝牙事件被发布到主线程上的处理程序,现在我需要新的想法来尝试解决这个问题...

我的日志抓取命令:

adb logcat | grep 'BLEService\|BluetoothGatt\|BtGatt\|bt\-'

日志输出:

D/BtGatt.GattService(18797): registerClient() - UUID=9a90904a-84e8-4f30-9b10-de78ac49f236
D/BtGatt.GattService(18797): onClientRegistered() - UUID=9a90904a-84e8-4f30-9b10-de78ac49f236, clientIf=5
D/BtGatt.GattService(18797): start scan with filters
D/BtGatt.ScanManager(18797): handling starting scan
D/BtGatt.GattService(18797): onScanFilterEnableDisabled() - clientIf=5, status=0, action=1
D/BtGatt.ScanManager(18797): callback done for clientIf - 5 status - 0
D/BtGatt.GattService(18797): onScanFilterParamsConfigured() - clientIf=5, status=0, action=0, availableSpace=15
D/BtGatt.ScanManager(18797): callback done for clientIf - 5 status - 0
D/BtGatt.ScanManager(18797): configureRegularScanParams() - queue=1
D/BtGatt.ScanManager(18797): configureRegularScanParams() - ScanSetting Scan mode=2 mLastConfiguredScanSetting=-2147483648
E/bt-btm  (18797): Device already in IRK list
D/BtGatt.GattService(18797): stopScan() - queue size =1
D/BtGatt.GattService(18797): onScanFilterParamsConfigured() - clientIf=5, status=0, action=1, availableSpace=16
D/BtGatt.ScanManager(18797): callback done for clientIf - 5 status - 0
D/BtGatt.ScanManager(18797): stop scan
D/BtGatt.ScanManager(18797): configureRegularScanParams() - queue=0
D/BtGatt.ScanManager(18797): configureRegularScanParams() - ScanSetting Scan mode=-2147483648 mLastConfiguredScanSetting=2
D/BtGatt.ScanManager(18797): configureRegularScanParams() - queue emtpy, scan stopped
D/BtGatt.GattService(18797): unregisterClient() - clientIf=5
V/BLEService(21323):  - connecting....
D/BluetoothGatt(21323): connect() - device: F4:B8:5E:51:A2:87, auto: false
D/BluetoothGatt(21323): registerApp()
D/BluetoothGatt(21323): registerApp() - UUID=4b8c32a4-4a74-49ff-a43f-a769c8200ab8
D/BtGatt.GattService(18797): registerClient() - UUID=4b8c32a4-4a74-49ff-a43f-a769c8200ab8
D/BtGatt.GattService(18797): onClientRegistered() - UUID=4b8c32a4-4a74-49ff-a43f-a769c8200ab8, clientIf=5
D/BluetoothGatt(21323): onClientRegistered() - status=0 clientIf=5
D/BtGatt.GattService(18797): clientConnect() - address=F4:B8:5E:51:A2:87, isDirect=true
E/bt-btm  (18797): Device already in IRK list
W/bt-btm  (18797): btm_acl_created hci_handle=4 link_role=0  transport=2
W/bt-btif (18797): info:x0
W/bt-l2cap(18797): L2CA_SetDesireRole() new:x1, disallow_switch:0
D/BtGatt.GattService(18797): client onConnected() - clientIf=5, connId=5, address=F4:B8:5E:51:A2:87
D/BluetoothGatt(21323): onClientConnectionState() - status=0 clientIf=5 device=F4:B8:5E:51:A2:87
V/BLEService(21323): Service have changed with old status: 0 and new status: 2
V/BLEService(21323):  - discovering....
D/BluetoothGatt(21323): discoverServices() - device: F4:B8:5E:51:A2:87
D/BtGatt.GattService(18797): discoverServices() - address=F4:B8:5E:51:A2:87, connId=5
D/BtGatt.GattService(18797): onSearchCompleted() - connId=5, status=0
D/BluetoothGatt(21323): onSearchComplete() = Device=F4:B8:5E:51:A2:87 Status=0
V/BLEService(21323): Service have discovered with status: 0
V/BLEService(21323):  - discovered....
D/BluetoothGatt(21323): setCharacteristicNotification() - uuid: f048abf6-3315-4d59-bad7-7e23ac18ee85 enable: true
D/BtGatt.GattService(18797): registerForNotification() - address=F4:B8:5E:51:A2:87 enable: true
D/BtGatt.GattService(18797): onRegisterForNotifications() - address=null, status=0, registered=1, charUuid=f048abf6-3315-4d59-bad7-7e23ac18ee85
I/BTConnectionReceiver(21037): onReceive(context, Intent { act=android.bluetooth.device.action.ACL_CONNECTED flg=0x4000010 cmp=com.google.android.googlequicksearchbox/com.google.android.search.core.service.BluetoothConnectionReceiver (has extras) }, [BluetoothDevice: address=F4:B8:5E:51:A2:87, alias=null, name=BLEDevice, majorDeviceClass=7936, deviceClass=7936]
I/BluetoothClassifier(21037): Bluetooth Device Name: BLEDevice
W/bt-btif (18797): btif_gatt_set_encryption_cb() - Encryption failed (1)
W/bt-smp  (18797): io_cap = 4
W/bt-smp  (18797): new io_cap = 4 p_cb->loc_enc_size = 16
E/bt-smp  (18797): LTK ready
W/bt-smp  (18797): smp_send_enc_info
W/bt-smp  (18797): smp_send_id_info
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=2 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=2 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=16 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=16 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=16 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=2 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=2 
E/bt-btif (18797): bta_dm_gatt_disc_result serivce_id len=16 
W/bt-btif (18797): bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0008
W/bt-btif (18797): bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0008
W/bt-btif (18797): bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x0008
E/bt-btm  (18797): btm_sec_disconnected - Clearing Pending flag

如果有一些有见识的人可以帮助我解决这个问题,我将不胜感激。

BLE 处理代码的重构揭示了一些处理不当的步骤,这掩盖了真正的问题。

正确处理每个步骤允许调用 onDescriptorWrite 回调,状态为 BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION,由日志指示。

收到状态 BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION 后,您需要注册绑定事件,以便在绑定结束后重试,如下所示:

final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(receiver, filter);

接收器(BroadcastReceiver 的子类)包含如下内容:

@Override
public void onReceive(Context context, Intent intent) {
    final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
    final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
    final String action = intent.getAction();

    if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action) && bondState == BluetoothDevice.BOND_BONDED) {
        // retry
    }
}