目前,当我尝试执行GATT操作并且无法成功完成该操作时,我开始配对程序(好吧它会自动启动)。一旦配对程序完成并且我与远程设备保持联系,我继续进行GATT操作,其中一切正常。
我注意到的是配对时:
1)如果我在没有关闭GATT客户端的情况下断开与远程设备的连接,那么它仍然成功配对,我进入BluetoothDevice.BOND_BONDED
状态,我的应用程序继续正常工作。
2)如果我断开连接并且我也关闭了GATT客户端,那么一旦我进入BluetoothDevice.BOND_BONDED
状态,那么我的应用程序崩溃
为什么在配对过程中关闭远程设备的GATT客户端时,我的应用程序崩溃了?这是正常的还是我做错了什么?
这是我的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,因为文件太大而无法在此处添加)
答案 0 :(得分:2)
您似乎在bluedroid,Android的蓝牙堆栈中发现了一个错误。
信号11(SIGSEGV),代码1(SEGV_MAPERR),故障地址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)
这是Android的“bluedroid”BT堆栈的gki/common/gki_buffer.c中的本机空指针异常。
碰巧令人困惑,乍一看有问题的函数似乎是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指向的count
结构的BUFFER_Q
成员,但是发生的事情是我们使用NULL缓冲区调用,所以我们添加8到NULL,并尝试从非法地址00000008
加载一个寄存器,导致SIGSEGV。
上升一个级别,这是从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。因此,作为一个基本原则,你的无特权应用程序不应该让它崩溃,我们可以将其归类为平台蓝牙堆栈中的错误,而不是你的应用程序。