目前,当我尝试执行 GATT 操作但未能成功完成该操作时,我开始了配对程序(老实说它会自动启动)。一旦配对过程完成并且我与远程设备绑定(bind),我将继续执行我的 GATT 操作,其中一切正常。
我注意到配对时:
1) 如果我在不关闭 GATT 客户端的情况下断开与远程设备的连接,那么它仍然会成功配对并且我会进入 BluetoothDevice.BOND_BONDED
状态并且我的应用会继续工作就好了。
2) 如果我断开连接并关闭 GATT 客户端,那么一旦我进入 BluetoothDevice.BOND_BONDED
状态,我的应用就会崩溃
为什么在配对过程中关闭远程设备的 GATT 客户端时,我的应用程序会崩溃?这是正常现象还是我做错了什么?
这是我用于获取远程设备绑定(bind)状态的 BroadcastReceiver 实现
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
if(state == BluetoothDevice.BOND_BONDING){
DebugWrapper.debugMsg("On Bonding...", TAG);
mIsBonding = true;
onBonding();
} else if(state == BluetoothDevice.BOND_BONDED){
DebugWrapper.debugMsg("On Bonded", TAG);
mIsBonded = true;
mActivity.unregisterReceiver(mReceiver);
/*
* finish what we started
*/
if(mBluetoothGatt != null){
if(mOperationState == OperationState.READ_CHARACTERISTIC){
readCharacteristic(mCurrentCharacteristic);
} else if(mOperationState == OperationState.WRITE_CHARACTERISTIC){
writeCharacteristic(mCurrentCharacteristic);
} else if(mOperationState == OperationState.READ_DESCRIPTOR){
readDescriptor(mCurrentDescriptor);
} else if(mOperationState == OperationState.WRITE_DESCRIPTOR){
writeDescriptor(mCurrentDescriptor);
}
mOperationState = OperationState.NONE;
}
onBonded();
} else if(state == BluetoothDevice.BOND_NONE){
DebugWrapper.debugMsg("Not Bonded", TAG);
notBonded();
}
}
}
};
更新 LogCat 文件(链接到 Pastebin.com,因为文件太大,无法在此处添加)
最佳答案
您似乎在 bluedroid(Android 的蓝牙堆栈)中发现了一个错误。
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000008
backtrace:
#00 pc 0007c86e /system/lib/hw/bluetooth.default.so (GKI_getnext+9)
#01 pc 000bd9e3 /system/lib/hw/bluetooth.default.so (gatt_sec_check_complete+10)
#02 pc 000bdde9 /system/lib/hw/bluetooth.default.so (gatt_enc_cmpl_cback+104)
这是 gki/common/gki_buffer.c 中的原生空指针异常Android 的“bluedroid”BT 堆栈。
它恰好是一个令人困惑的,乍一看,有问题的函数似乎是 GKI_getnext(),但实际上,它实际上是紧随其后的函数 GKI_queue_is_empty( )
BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q)
{
return ((BOOLEAN) (p_q->count == 0));
}
如果我们看一下实际的反编译,
<GKI_queue_is_empty>:
ldrh r0, [r0, #8]
rsbs r0, r0, #1
it cc
movcc r0, #0
bx lr
我们看到我们正在尝试引用 r0 指向的 BUFFER_Q
结构的 count
成员,但是实际情况是我们被调用时使用了 NULL 缓冲区,因此我们将 8 添加到 NULL,并尝试从导致 SIGSEGV 的非法地址 00000008
加载寄存器。
更上一层楼,这是从 gatt_sec_check_complete() 调用的 - 事实上,如果我们查看 stack/gatt/gatt_auth.c我们发现它做的第一件事是检查队列是否为空。
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
{
if (GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
但问题是队列不是空的,而是它是空的。
所以要么 bluedroid 中存在一个错误,它没有意识到某些东西可以为 NULL,要么您的程序正在执行一系列无效的操作,从而导致 bluedroid 堆栈为此失败。
然而事实证明,归责很简单,因为我们可以查看安全模型。崩溃的进程作为用户 bluetooth
运行,这是一个半特权帐户,而不是您的应用程序的用户 ID。因此,作为一个基本原则,您的非特权应用所做的任何事情都不应使其崩溃,我们可以将此归类为平台蓝牙堆栈中的错误,而不是您的应用。
关于android - 与远程蓝牙低功耗 (BLE) 设备配对时断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25207503/