Отключение во время сопряжения с удаленным устройством Bluetooth Low Energy (BLE)


В настоящее время я запускаю процедуру сопряжения (ну, она запускается автоматически, чтобы быть честным), когда я пытаюсь выполнить операцию 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 как файлы, где слишком большой, чтобы добавить сюда)

Из этого logCat вы можете видеть шаги, которые я выполняю

Приложение LogCat, завершено

1 3

1 ответ:

Похоже, вы нашли ошибку в bluedroid, стеке bluetooth для Android.

Сигнал 11 (SIGSEGV), код 1 (SEGV_MAPERR) , ошибка 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 стека BT "bluedroid" для Android.

Это сбивает с толку , так как на первый взгляд проблемная функция выглядит как 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

Мы видим, что пытаемся ссылаться на count член структуры BUFFER_Q, на который указывает r0, однако происходит то, что мы были вызваны с нулевым буфером, поэтому мы добавляем 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, который является полупривилегированной учетной записью, а не идентификатором пользователя вашего приложения. Таким образом, в принципе, ничто из того, что делает ваше непривилегированное приложение, не должно приводить к его сбою, и мы можем классифицировать это как ошибку в стеке платформы bluetooth, а не в вашем приложении.