与远程蓝牙低功耗(BLE)设备配对时断开连接

时间:2014-08-08 15:57:07

标签: android bluetooth bluetooth-lowenergy android-bluetooth

目前,当我尝试执行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,因为文件太大而无法在此处添加)

From this logCat you can see the steps i am following

App LogCat, complete

1 个答案:

答案 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。因此,作为一个基本原则,你的无特权应用程序不应该让它崩溃,我们可以将其归类为平台蓝牙堆栈中的错误,而不是你的应用程序。