Android 蓝牙:BLE 回调 onNotify 中出现 DeadObjectException
我们使用的是具有显着特征的 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论