Status Update
Comments
an...@google.com <an...@google.com>
de...@gmail.com <de...@gmail.com> #2
BluetoothGatt.requestMTU() always requests 517 , How to deal with it ?
an...@google.com <an...@google.com> #3
We have passed this to the development team and will update this issue with more information as it becomes available.
ha...@google.com <ha...@google.com> #4
I would like to provide you more details about why 517 was chosen instead of 515:
The number 517 was selected because the GATT_MAX_MTU_SIZE constant was set to 517 since the initial drop of Android Bluetooths stack in 2012.
A deeper reason is that the Bluetooth Specification allows the maximum size of an ATT attribute to be 512 bytes and the largest command ATT_PREPARE_WRITE_REQ has 5 bytes of header. Hence 512 + 5 = 517.
The packet data itself should never exceed 512 as per the Bluetooth spec.
Hope that clarifies.
Thank you!
ha...@google.com <ha...@google.com>
ma...@gmail.com <ma...@gmail.com> #5
hey,
thank you for the response and clarification! You are correct! It seems like Android is really following the bluetooth spec.
In meantime we realised that our previous understanding of bluetooth specs was very likely not correct. 5
is really the maximal header size for ATT_PREPARE_WRITE_REQ
so using the 517
as max MTU seems legit since asking for any other MTU doesn't seem to make much sense.
However, I still believe that (almost silently)
The reason for this is simple. Android chosen to strictly adhere bluetooth spec, but appearance of any packet longer then 512 clearly means that the device on the other side didn't. Why keep the connection open in that case? The devices are not following the same spec and it can only lead to unexpected state or a communication deadlock.
sc...@gmail.com <sc...@gmail.com> #6
In android 14, the only way I can get it to work is with this terrible defensive programming (below).
Setting requestMTU to any value in android 14 besides 23 causes the write characteristic to fail. Also, setting requestMTU to 23 in android < 14 also causes my app to fail.
Finding this as the root cause of my app crash has taken the better part of a week, but I finally have a working (hacked) solution. Is there a better, more permanent way to handle this?
device.connect()
.then(device => {
const osVer = Platform.OS === 'android' ? Platform.constants['Release'] : '';
if (Platform.OS === 'android' && Number(osVer) >= '14') {
return device.requestMTU(23);
} else {
return device.requestMTU(100);
}
})
.then( ....
Other strange things I'm seeing:
In Android < 13, if I discoverAllServicesAndCharacteristics, the mtu is the value I set above.
In Android 14, the mtu always shows 517, even though nothing works for me except the code above (even trying to set it to 517, or not setting it at all so it defaults, doesn't work - only setting to 23 works in 14 for me).
sc...@gmail.com <sc...@gmail.com> #7
From my testing:
1. In Android < 14, the requested MTU is used.
2. In Android 14, and according to [this, also referenced in the first comment above](
From adb logcat (Android 14):
11-02 12:58:22.145 13307 13442 D BluetoothGatt: configureMTU() - device: xx:xx:xx:xx:xx:xx mtu: 100
11-02 12:58:22.146 2175 2234 I bluetooth: packages/modules/Bluetooth/system/stack/gatt/gatt_api.cc:768 GATTC_TryMtuRequest: xx:xx:xx:xx:xx:xx conn_id=0x0006
11-02 12:58:22.146 2175 2234 I bluetooth: packages/modules/Bluetooth/system/stack/gatt/gatt_api.cc:728 GATTC_ConfigureMTU: Configuring ATT mtu size conn_id:6 mtu:517 user mtu 100
11-02 12:58:22.204 2175 2234 I bluetooth: packages/modules/Bluetooth/system/stack/gatt/gatt_cl.cc:1113 gatt_process_mtu_rsp: Local pending MTU 100, Remote (xx:xx:xx:xx:xx:xx) MTU 517
11-02 12:58:22.204 2175 2234 I bluetooth: packages/modules/Bluetooth/system/stack/gatt/gatt_cl.cc:1133 gatt_process_mtu_rsp: MTU Exchange resulted in: 517
adb logcat (Android 12):
11-02 19:03:44.071 24114 24245 D BluetoothGatt: configureMTU() - device: 78:21:84:61:3C:46 mtu: 100
11-02 19:03:44.832 24114 24130 D BluetoothGatt: onConfigureMTU() - Device=78:21:84:61:3C:46 mtu=100 status=0
Should the mtu be set to min(517, requestMTU, remoteMTU) instead of min(517, remoteMTU) ? This seems it would give more control.
ha...@google.com <ha...@google.com> #8
To
ha...@google.com <ha...@google.com> #9
sr...@gmail.com <sr...@gmail.com> #10
sr...@gmail.com <sr...@gmail.com> #11
these are my logs:
packages/modules/Bluetooth/system/stack/gatt/gatt_api.cc:768 GATTC_TryMtuRequest: **:**:**:**:49:fe conn_id=0x000d 2023-12-05 17:54:21.669 15046-15098 bluetooth com.google.android.bluetooth I packages/modules/Bluetooth/system/stack/gatt/gatt_api.cc:728 GATTC_ConfigureMTU: Configuring ATT mtu size conn_id:13 mtu:517 user mtu 512 2023-12-05 17:54:21.684 15046-15098 bluetooth com.google.android.bluetooth I packages/modules/Bluetooth/system/stack/gatt/gatt_cl.cc:1113 gatt_process_mtu_rsp: Local pending MTU 512, Remote (**:**:**:**:49:fe) MTU 517 2023-12-05 17:54:21.684 15046-15098 bluetooth com.google.android.bluetooth I packages/modules/Bluetooth/system/stack/gatt/gatt_cl.cc:1133 gatt_process_mtu_rsp: MTU Exchange resulted in: 517 2023-12-05 17:54:21.684 15046-15098 bt_btm_ble com.google.android.bluetooth I packages/modules/Bluetooth/system/stack/btm/btm_ble.cc:619 BTM_SetBleDataLength: xx:xx:xx:xx:49:fe, 516
[ERROR:gatt_cl.cc(693)] value.len larger than GATT_MAX_ATTR_LEN, discard
ha...@google.com <ha...@google.com> #12
Bluetooth Specification allows the maximum size of an ATT attribute to be 512 bytes and the largest command ATT_PREPARE_WRITE_REQ has 5 bytes of header. So even the remote device confirm it could support a MTU of 517, the maximum length of an attribute value shall be 512.
It's a remote device issue here, so I would say the best way is to contact the device side to do a firmware update.
Could you share which devices you've been seeing the isse? Is it a released device?
Description
Hey team,
on 2022/06/05 in this commit you changed the GATT_MAX_ATTR_LEN (maximal attribute size) from bluetooth specs the maximum length of an attribute value shall be
600
to512
. This change makes perfect sense since according to the512
, so there is no need to have buffers larger than that etc.However, you kept GATT_MAX_MTU_SIZE (maximal supported MTU) set to
517
, which just isn't true anymore. The correctGAT_MAX_MTU_SIZE
should now be515
.515 = 512 (max attribute size) + 1 (ATT Opcode) + 2 (length)
This leads to the situation when Android let you negotiate MTU 517 (even though it doesn't support it) by calling BluetoothGatt.requestMTU() with it drops all all the incoming packets larger than 512 . Also it doesn't even terminate the connection when this happens, which it IMO should, but it just log a line and continue like nothing happened.
GATT_MAX_MTU_SIZE
(517
), but thenUnfortunately, since Android 14 the system doesn't take into account the value passed to BluetoothGatt.requestMTU() and always requests unsupported
GATT_MAX_MTU_SIZE
(517
).This whole situation now completely breaks proper MTU negotiation with all the devices which allow MTU 517 to be negotiated. and force us to skip the entire MTU negotiation and default MTU
23
with all it's downsides.It's also interesting that authors of the behaviour changes of Android 14 article seem to be aware of the problem with MTU
517
but instead of fixing this, they choose the other way around and adviced to reduce the packet length by magical constant5
on the sender size instead of choosing3
which is the header length according the bluetooth specs.TLDR
GAT_MAX_MTU_SIZE
needs to be changed to515