Android 蓝牙:BLE 回调 onNotify 中出现 DeadObjectException

发布于 2025-01-09 01:41:18 字数 11706 浏览 4 评论 0原文

我们使用的是具有显着特征的 ble 设备,我们使用 EnableNotification 通过回调来获取数据。 我们实现了一个命令队列,我们​​达到了一种状态,在这种状态下我们不再发出任何命令,而是只听特征 通知。

随机一段时间后,我们遇到蓝牙服务/适配器死亡的错误,在 logcat 中我们发现 DeadObjectException。 这是一个很难复制和跟踪的错误,但它对我们的应用程序至关重要。在回调中,我们尝试处理所有可能的异常(在每个类方法中),但 DeadObjectException 无法处理,看起来它是在另一个进程中抛出的。

我们使用的设备每次触发都会发送2个字节的数据,每秒大约可以发送20个包。

我们没有运气找到这方面的帮助。有人能给我们一些建议吗? 有没有办法捕获蓝牙绑定器或服务抛出的异常? 处理显着特征的正确方法是什么?

这是 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);
}

We are using a ble device that has a noticeable characteristic, and we use the EnableNotification to get data through the callback.
We implemented a queue of commands, and we reach a state in which we do not issue any more commands, we instead only listen to the characteristic
notification.

After a random amount of time, we encounter an error in which the bluetooth service/adapter dies, in the logcat we find a DeadObjectException.
It's an error that is very hard to replicate and track, but it's critical to our app. In the callback we try to handle all possible exceptions (in each one of the class methods) but the DeadObjectException cannot be handled, it seems it is thrown in another process.

The device we are using sends 2 bytes of data every time it is triggered, and can send about 20 packages per second.

We had not any luck finding help about this. Can anybody give us some advice?
Is there any way to capture exceptions thrown by the bluetooth binder or the service?
Which is the correct way of handling noticeable characteristics?

This is the logcat output:

    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)

This is an example of our callback:

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());
            }
        }
    };

With an empty callback it still fails:

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

This is the code we use for enabling the notifications:

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文