Android Bluetooth: DeadObjectException в обратном вызове BLE onNotify

Мы используем устройство ble, которое имеет заметную характеристику, и мы используем EnableNotification для получения данных через обратный вызов. Мы реализовали очередь команд и достигли состояния, в котором больше не выдаем команды, а только слушаем характерное уведомление.

Через случайное количество времени мы сталкиваемся с ошибкой, из-за которой служба/адаптер bluetooth умирает, в логарифме мы находим DeadObjectException. Эту ошибку очень сложно воспроизвести и отследить, но она критична для нашего приложения. В обратном вызове мы пытаемся обработать все возможные исключения (в каждом из методов класса), но DeadObjectException не может быть обработано, похоже, оно выброшено в другом процессе.

Используемое нами устройство отправляет 2 байта данных при каждом срабатывании и может отправлять около 20 пакетов в секунду.

Нам не повезло найти помощь по этому поводу. Кто-нибудь может дать нам совет? Есть ли способ зафиксировать исключения, вызванные связывателем Bluetooth или службой? Как правильно обращаться с заметными характеристиками?

Это вывод logcat:

          2022-02-22 13:16:50.125 5423-5910/? I/bt_stack: [INFO:gatt_main.cc(919)] gatt_data_process op_code = 27, msg_len = 4
2022-02-22 13:16:50.125 5423-5910/? E/bt_btif: bta_gattc_process_indicate, ignore HID ind/notificiation
2022-02-22 13:16:50.125 5423-5541/? E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 152)
2022-02-22 13:16:50.126 5423-5541/? E/BtGatt.JNI: An exception was thrown by callback 'btgattc_notify_cb'.
2022-02-22 13:16:50.143 5423-5910/? I/bt_stack: [INFO:gatt_main.cc(919)] gatt_data_process op_code = 27, msg_len = 4
2022-02-22 13:16:50.143 5423-5910/? E/bt_btif: bta_gattc_process_indicate, ignore HID ind/notificiation
2022-02-22 13:16:50.171 17518-8879/---.---.--- I/SMNPlugin: Android [Main.cpp:763:_setStatePieceDetected()]     [Piece State Detection] PIECE_NO_CORRECT.
2022-02-22 13:16:50.180 5423-5541/? E/BtGatt.JNI: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(BinderProxy.java:550)
        at android.bluetooth.IBluetoothGattCallback$Stub$Proxy.onNotify(IBluetoothGattCallback.java:561)
        at com.android.bluetooth.gatt.GattService.onNotify(GattService.java:1530)
2022-02-22 13:16:50.180 5423-5541/? E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 152)
2022-02-22 13:16:50.180 5423-5541/? E/BtGatt.JNI: An exception was thrown by callback 'btgattc_notify_cb'.
2022-02-22 13:16:50.181 5423-5541/? E/BtGatt.JNI: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(BinderProxy.java:550)
        at android.bluetooth.IBluetoothGattCallback$Stub$Proxy.onNotify(IBluetoothGattCallback.java:561)
        at com.android.bluetooth.gatt.GattService.onNotify(GattService.java:1530)

Это пример нашего обратного вызова:

      public BluetoothDeviceInterface(final BluetoothDevice device, final int arrayIndex) {
    _device = device;
    _internalArrayIndex = arrayIndex;
    _gatt = null;

    _gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            Log.i(LOGTAG, "On Connection State Change. Status: " + status + ". New state: " + newState);
            try {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    if (newState == BluetoothProfile.STATE_CONNECTED) {
                        Log.i(LOGTAG, "Connected to device: " + GetAddress());
                        _gatt = gatt;
                        _gatt.discoverServices();
                    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                        Log.i(LOGTAG, "Disconnected from device: " + GetAddress());
                        _gatt.close();
                        _gatt = null;
                    }
                } else {
                    Log.i(LOGTAG, "Error connecting GATT.");
                    _gatt.close();
                    _gatt = null;
                }
                _callback.OnStateChanged(status, newState);
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onConnectionStateChange: " + e.toString());
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            Log.i(LOGTAG, "On Services Discovered. Status: " + status);

            try {
                Log.i(LOGTAG, "Services of device " + GetAddress() + " discovered. Total number of: " + gatt.getServices().size());
                _callback.CleanServices();

                for(BluetoothGattService service : gatt.getServices()) {
                    String serviceUUID = service.getUuid().toString();

                    _callback.AddNewService(service.getType(), serviceUUID);

                    for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
                        String characteristicUUID = characteristic.getUuid().toString();
                        int characteristicProperties = characteristic.getProperties();
                        boolean isReadable = (characteristicProperties & BluetoothGattCharacteristic.PROPERTY_READ) != 0;
                        boolean isWritable = (characteristicProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0;
                        boolean isWritableWithoutResponse = (characteristicProperties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0;
                        boolean isIndicateable = (characteristicProperties & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0;
                        boolean isNotifiable = (characteristicProperties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0;

                        _callback.AddNewCharacteristic(serviceUUID, characteristicUUID, isReadable, isWritable,
                                isWritableWithoutResponse, isIndicateable, isNotifiable);
                    }
                }

                _callback.OnServiceDiscoveryEnd();
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onServicesDiscovered: " + e.toString());
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.i(LOGTAG, "On Characteristic Read. Status: " + status);

            try {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    _callback.OnCharacteristicRead(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), characteristic.getValue());
                } else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
                    _callback.OnCharacteristicReadError(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), "Read not permitted.");
                } else {
                    _callback.OnCharacteristicReadError(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), "Status error: " + status);
                }
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onCharacteristicRead: " + e.toString());
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.i(LOGTAG, "On Characteristic Write. Status: " + status);

            try {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    _callback.OnCharacteristicWrite(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString());
                } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
                    _callback.OnCharacteristicWriteError(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), "Write not permitted.");
                } else {
                    _callback.OnCharacteristicWriteError(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), "Status error: " + status);
                }
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onCharacteristicWrite: " + e.toString());
            }
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            Log.i(LOGTAG, "On Descriptor Write. Status: " + status);

            try {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    _callback.OnDescriptorWrite(descriptor.getCharacteristic().getService().getUuid().toString(), descriptor.getCharacteristic().getUuid().toString());
                } else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
                    _callback.OnDescriptorWriteError(descriptor.getCharacteristic().getService().getUuid().toString(), descriptor.getCharacteristic().getUuid().toString(), "Write not permitted.");
                } else {
                    _callback.OnDescriptorWriteError(descriptor.getCharacteristic().getService().getUuid().toString(), descriptor.getCharacteristic().getUuid().toString(), "Status error: " + status);
                }
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onDescriptorWrite: " + e.toString());
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.i(LOGTAG, "On Characteristic Changed.");

            try {
                Log.i(LOGTAG, characteristic.getService().getUuid().toString() + characteristic.getUuid().toString() + characteristic.getValue().toString());
                _callback.OnCharacteristicChange(characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), characteristic.getValue());
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onCharacteristicChanged: " + e.toString());
            }
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            Log.i(LOGTAG, "On Read Remote Rssi. Status: " + status + ". Rssi: " + rssi);


            try {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    _callback.OnRssiRead(rssi);
                } else {
                    _callback.OnRssiRead(-1);
                }
            } catch (Exception e) {
                Log.e(LOGTAG, "Exception in onReadRemoteRssi: " + e.toString());
            }
        }
    };

С пустым обратным вызовом он все еще терпит неудачу:

      public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    Log.i(LOGTAG, "On Characteristic Changed: " + characteristic.getStringValue(0));
}

Это код, который мы используем для включения уведомлений:

      public boolean EnableNotifications(String serviceUUID, String characteristicUUID) {
    if (!IsConnected())
        return false;

    BluetoothGattService service = _gatt.getService(UUID.fromString(serviceUUID));
    if (service == null)
        return false;

    BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicUUID));
    if (characteristic == null)
        return false;

    int properties = characteristic.getProperties();
    byte[] payload;

    if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
        payload = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
    } else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
        payload = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
    } else {
        return false;
    }

    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID);
    if (descriptor == null)
        return false;

    if (!_gatt.setCharacteristicNotification(characteristic, true))
        return false;

    descriptor.setValue(payload);
    return _gatt.writeDescriptor(descriptor);
}

0 ответов

Другие вопросы по тегам