bluetooth: readValue from characteristic with same UUID doesn't retrieve correct values |
||||
Issue descriptionGoogle Chrome 55.0.2883.7 (Official Build) dev (64-bit) Platform 8872.6.0 (Official Build) dev-channel link What steps will reproduce the problem? (1) Go to https://beaufortfrancois.github.io/sandbox/web-bluetooth/get-characteristics-with-same-uuid/ (2) Make sure a Bluetooth device advertising the Battery Service is nearby and has two "Battery Level" characteristics with different returned values to identify them uniquely. (3) Click "Test" button (4) Open Dev Tools What is the expected output? I should see "1" and "2" as Battery Level characteristics have different values. What do you see instead? (index):19 [BluetoothRemoteGATTCharacteristic, BluetoothRemoteGATTCharacteristic] (index):24 1 (index):26 1 See web app source code at https://github.com/beaufortfrancois/sandbox/blob/gh-pages/web-bluetooth/get-characteristics-with-same-uuid/index.html#L20 And here's attached the nRF Server Configuration file I've used to reproduce this issue. See inline as well: <server-configuration name="Read"> <service uuid="0000180f-0000-1000-8000-00805f9b34fb"> <characteristic uuid="00002a19-0000-1000-8000-00805f9b34fb" value="01"> <permission name="READ"/> <property name="READ"/> </characteristic> <characteristic uuid="00002a19-0000-1000-8000-00805f9b34fb" value="02"> <permission name="READ"/> <property name="READ"/> </characteristic> </service> </server-configuration>
,
Oct 14 2016
It looks like the issue is not about getCharacteristics getting wrong characteristics but readValue sending back wrong values.
,
Oct 14 2016
The HCI trace might help to check which handles are being read, from the object path it looks like its 0x0029 and 0x002b. Btw, is the same reproducible with bluetoothctl for example?
,
Oct 14 2016
Oooooooooooh you're right! I can reproduce it from bluetoothctl as well.
Here's the btmon trace:
< ACL Data TX: Handle 33 flags 0x00 dlen 7 [hci0] 8.928174
ATT: Read Request (0x0a) len 2
Handle: 0x002a
> HCI Event: Number of Completed Packets (0x13) plen 5 [hci0] 8.987206
Num handles: 1
Handle: 33
Count: 1
> ACL Data RX: Handle 33 flags 0x02 dlen 6 [hci0] 9.121916
ATT: Read Response (0x0b) len 1
Value: 01
< ACL Data TX: Handle 33 flags 0x00 dlen 7 [hci0] 9.126153
ATT: Read Request (0x0a) len 2
Handle: 0x002c
> HCI Event: Number of Completed Packets (0x13) plen 5 [hci0] 9.190201
Num handles: 1
Handle: 33
Count: 1
> ACL Data RX: Handle 33 flags 0x02 dlen 6 [hci0] 9.324433
ATT: Read Response (0x0b) len 1
Value: 01
,
Oct 14 2016
Note that I can reproduce this issue on macOS as well.
,
Oct 14 2016
I've pinged nRF Connect folks to see if they're aware of a potential issue with how they deal with multiple characteristics with same UUID.
,
Oct 14 2016
Here's the great answer I got from nRF Connect folks: Hi Francois, Here how it works in nRF Connect: When user configures a server I open the GATT Server with defined services and characteristics. Whenever a device is connected, connects to, or is already connected when server config was modified I create a copy of server’s services per each device. This copy contains characteristics and descriptors values, so you may modify them independently for each connected device and you will get the last written value per this device, not by any device. [It’s not how spec says how it should be, but how I decided. Perhaps it would be better to keep only CCCD values per device and all other globally (line PC version of nRF Connect does), but at that time I decided it to be like this.] nvm. Then, when I get a read request for characteristic, I look for its copy in the device’s corresponding copy. I just look for service index, char index and descr index in the original server services and return the characteristic or descriptor matching given indexes from device’s copy. So let’s say I want to read the 2nd Battery Level characteristic from nRF Connect. I used your server configuration file on another phone. In my readCharacteristic(..) method I have the following objects: [IMAGE ATTACHED #1] A you see the object ID 6562 matches the second characteristic in the service. So I should be looking for the second characteristic in this service to obtain the correct value. Now let’s look at what my server gets. This image was taken in onCharacteristicReadRequest method. [IMAGE ATTACHED #2] Looks like the client wants to get the first characteristic’s value, not the second. And nRF Connect correctly reports the requested value. The problem lies in instance IDs on the server side. They are all 0, even for characteristics with the same UUID. On client side it used to be that instance ids were counted from 0 and increased for each same UUID. The Google’s BLE team in Android 7 changed the implementation of ‘getInstanceId()’ method for services and characteristics. Now, when you connect to a device, do service discovery the instance ids are the Handle IDs. As you see on the top image the service’s instance id = 46 as I’m testing on Android 7.0 Nexus 6P. This actually made some complications for me, as e.g. automated tests, macros and my views are counting attributes using the old way so I have to count them manually now. But the gatt server services, characteristics and descriptors always have instance id = 0. You may see it on the second image, the instance id is 0 for all attributes. I tried it on Nexus 6P and HTC One M8 with Android 6.0.1 and I think it was like this since beginning. So, unfortunately, the bug is on Android side. It just loses the instance id value somewhere in between and asks me always for the first instance of given UUID. I can’t do any workaround here and count anything on my own as from the app’s point of view the client is asking for the first characteristic value and I have no way to say it’s not true. *- why it may be a “feature”: otherwise, by exposing the real instance id or handle id, an app could be informed that there is another app that has the same service already defined, or how many Services/characteristics were defined before. I don’t see any security issue with this, and in fact that could be hidden as I could be getting ‘per-app-instance-id’. It is also not said that handle numbers must be without any gaps, so each app could get a random set of handles. I’m pretty sure you should not get this issue when connected to nRF5 device with 2 characteristics with the same UUID.
,
Oct 16 2016
Closing since it seems unrelated to chrome.
,
Oct 17 2016
According to Android folks, Characteristic in android is described not only by UUID, but also instanceId, so if you have two characteristics with same UUID are you using ones with proper instanceId ? https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getInstanceId() InstanceId on older androids is 0,1,2,3... on newer phones (android 7.0) it's value is similar(but not same as) attribute handle. |
||||
►
Sign in to add a comment |
||||
Comment 1 by fbeaufort@chromium.org
, Oct 14 2016