Skip to content

Cap GATT write chunks at 512 bytes to fix crash on Android 13+#227

Open
obook wants to merge 1 commit into
AsteroidOS:masterfrom
obook:fix/ble-write-512
Open

Cap GATT write chunks at 512 bytes to fix crash on Android 13+#227
obook wants to merge 1 commit into
AsteroidOS:masterfrom
obook:fix/ble-write-512

Conversation

@obook
Copy link
Copy Markdown

@obook obook commented May 30, 2026

Summary

On recent Android versions the app stays open for a few seconds and then closes
when connecting to the watch. This pull request fixes that crash. It was
reproduced on a Pixel 8 (Android 14/15) and matches the reports in #217 and
#203.

Root cause

AsteroidBleManager.send() writes characteristics with the default .split()
splitter (added in #195), which chunks data at MTU - 3 bytes. When the system
negotiates the maximum MTU of 517, as the Pixel 8 does, each chunk is 514 bytes.
Since Android 13, BluetoothGatt.writeCharacteristic() rejects any value longer
than 512 bytes (the maximum GATT attribute length) and throws
IllegalArgumentException, so the app crashes on the first notification whose
payload exceeds 512 bytes, a few seconds after connecting to the watch.

The existing requestMtu(256) call does not help, because the connection has
already negotiated an MTU of 517 by the time it runs:

configureMTU() mtu: 256
GATTC_UpdateUserAttMtuIfNeeded: current mtu: 517, max_user_mtu: 256
onConfigureMTU(..., 517, 0)
java.lang.IllegalArgumentException: value should not be longer than max length of an attribute value
    at android.bluetooth.BluetoothGatt.writeCharacteristic(BluetoothGatt.java:1451)
    at no.nordicsemi.android.ble.BleManagerHandler.internalWriteCharacteristic(...)

Fix

Use a custom DataSplitter that caps each chunk at 512 bytes regardless of the
negotiated MTU. The watch reassembles the message from the chunks, so a smaller
chunk size only changes the number of writes, not the result.

Testing

Built and installed on a Pixel 8 (Android 14/15). The app no longer closes after
a few seconds, and notifications reach the watch, including ones larger than 512
bytes that previously triggered the crash.

Fixes #217.

Thanks for AsteroidOS and for maintaining this app. Best regards from France.

…d 13+

The default MTU-based splitter chunks writes at MTU - 3 bytes. When the system negotiates the maximum MTU of 517 (e.g. on a Pixel 8), chunks reach 514 bytes, which BluetoothGatt.writeCharacteristic rejects since Android 13 (max attribute length is 512), throwing IllegalArgumentException and crashing the app a few seconds after connecting to the watch. Use a custom DataSplitter capped at 512 bytes regardless of the negotiated MTU.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android 15 beta 4. App craches

1 participant