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

标签 android bluetooth bluetooth-lowenergy android-bluetooth

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

From this logCat you can see the steps i am following

App LogCat, complete

最佳答案

您似乎在 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/

相关文章:

android - 在android中单击Listview的单个项目时选择ListView的多个项目

bluetooth-lowenergy - 为什么 BLE 4.2 比 BLE 4.1 快

iphone - 如何使用 iPhone SDK 通过蓝牙交换数据?

ios - 进入后台时 BLE 扫描停止?

notifications - Android Ble 延迟通知

javascript - 如何从 android -Cordova/Phonegap 调用 javascript 函数

android - 使用 AsyncTask 的图像是并行下载还是顺序下载?

android - 如何检测 Android 中 ListView 项目的双击?

swift - 我可以连接到 BLE 设备并同时广播 iBeacon 吗?

android - 在 Android 4.3-4.4 (API 18-20) 上通过低功耗蓝牙连接请求 MTU