• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16"""
17Test suite for GATT over BR/EDR.
18"""
19
20from queue import Empty
21
22from acts.test_decorators import test_tracker_info
23from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
24from acts_contrib.test_utils.bt.bt_test_utils import reset_bluetooth
25from acts_contrib.test_utils.bt.bt_constants import gatt_characteristic
26from acts_contrib.test_utils.bt.bt_constants import gatt_service_types
27from acts_contrib.test_utils.bt.bt_constants import gatt_transport
28from acts_contrib.test_utils.bt.bt_constants import gatt_cb_strings
29from acts_contrib.test_utils.bt.bt_gatt_utils import GattTestUtilsError
30from acts_contrib.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
31from acts_contrib.test_utils.bt.bt_gatt_utils import log_gatt_server_uuids
32from acts_contrib.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection
33from acts_contrib.test_utils.bt.bt_gatt_utils import setup_gatt_characteristics
34from acts_contrib.test_utils.bt.bt_gatt_utils import setup_gatt_connection
35from acts_contrib.test_utils.bt.bt_gatt_utils import setup_gatt_descriptors
36from acts_contrib.test_utils.bt.bt_gatt_utils import setup_multiple_services
37from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
38from acts_contrib.test_utils.bt.bt_test_utils import take_btsnoop_logs
39
40
41class GattOverBrEdrTest(BluetoothBaseTest):
42    adv_instances = []
43    bluetooth_gatt_list = []
44    gatt_server_list = []
45    default_timeout = 10
46    default_discovery_timeout = 3
47    per_droid_mac_address = None
48
49    def setup_class(self):
50        super(BluetoothBaseTest, self).setup_class()
51        self.cen_ad = self.android_devices[0]
52        self.per_ad = self.android_devices[1]
53
54        self.per_droid_mac_address = self.per_ad.droid.bluetoothGetLocalAddress(
55        )
56        if not self.per_droid_mac_address:
57            return False
58        return True
59
60    def setup_test(self):
61        super(BluetoothBaseTest, self).setup_test()
62        bluetooth_gatt_list = []
63        self.gatt_server_list = []
64        self.adv_instances = []
65
66    def teardown_test(self):
67        for bluetooth_gatt in self.bluetooth_gatt_list:
68            self.cen_ad.droid.gattClientClose(bluetooth_gatt)
69        for gatt_server in self.gatt_server_list:
70            self.per_ad.droid.gattServerClose(gatt_server)
71        return True
72
73    def on_fail(self, test_name, begin_time):
74        take_btsnoop_logs(self.android_devices, self, test_name)
75        reset_bluetooth(self.android_devices)
76
77    def _orchestrate_gatt_disconnection(self, bluetooth_gatt, gatt_callback):
78        self.log.info("Disconnecting from peripheral device.")
79        try:
80            disconnect_gatt_connection(self.cen_ad, bluetooth_gatt,
81                                       gatt_callback)
82            if bluetooth_gatt in self.bluetooth_gatt_list:
83                self.bluetooth_gatt_list.remove(bluetooth_gatt)
84        except GattTestUtilsError as err:
85            self.log.error(err)
86            return False
87        return True
88
89    def _find_service_added_event(self, gatt_server_callback, uuid):
90        event = self.per_ad.ed.pop_event(
91            gatt_cb_strings['serv_added'].format(gatt_server_callback),
92            self.default_timeout)
93        if event['data']['serviceUuid'].lower() != uuid.lower():
94            self.log.info("Uuid mismatch. Found: {}, Expected {}.".format(
95                event['data']['serviceUuid'], uuid))
96            return False
97        return True
98
99    @BluetoothBaseTest.bt_test_wrap
100    @test_tracker_info(uuid='32d32c87-911e-4f14-9654-29fe1431e995')
101    def test_gatt_bredr_connect(self):
102        """Test GATT connection over BR/EDR.
103
104        Test establishing a gatt connection between a GATT server and GATT
105        client.
106
107        Steps:
108        1. Start a generic advertisement.
109        2. Start a generic scanner.
110        3. Find the advertisement and extract the mac address.
111        4. Stop the first scanner.
112        5. Create a GATT connection between the scanner and advertiser.
113        6. Disconnect the GATT connection.
114
115        Expected Result:
116        Verify that a connection was established and then disconnected
117        successfully.
118
119        Returns:
120          Pass if True
121          Fail if False
122
123        TAGS: BR/EDR, Filtering, GATT, Scanning
124        Priority: 0
125        """
126        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
127        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
128            gatt_server_cb)
129        self.gatt_server_list.append(gatt_server)
130        try:
131            bluetooth_gatt, gatt_callback, adv_callback = (
132                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
133                                            gatt_transport['bredr'],
134                                            self.per_droid_mac_address))
135            self.bluetooth_gatt_list.append(bluetooth_gatt)
136        except GattTestUtilsError as err:
137            self.log.error(err)
138            return False
139        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
140                                                    gatt_callback)
141
142    @BluetoothBaseTest.bt_test_wrap
143    @test_tracker_info(uuid='357b697b-a52c-4c2a-997c-00876a018f37')
144    def test_gatt_bredr_connect_trigger_on_read_rssi(self):
145        """Test GATT connection over BR/EDR read RSSI.
146
147        Test establishing a gatt connection between a GATT server and GATT
148        client then read the RSSI.
149
150        Steps:
151        1. Start a generic advertisement.
152        2. Start a generic scanner.
153        3. Find the advertisement and extract the mac address.
154        4. Stop the first scanner.
155        5. Create a GATT connection between the scanner and advertiser.
156        6. From the scanner, request to read the RSSI of the advertiser.
157        7. Disconnect the GATT connection.
158
159        Expected Result:
160        Verify that a connection was established and then disconnected
161        successfully. Verify that the RSSI was ready correctly.
162
163        Returns:
164          Pass if True
165          Fail if False
166
167        TAGS: BR/EDR, Scanning, GATT, RSSI
168        Priority: 1
169        """
170        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
171        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
172            gatt_server_cb)
173        self.gatt_server_list.append(gatt_server)
174        try:
175            bluetooth_gatt, gatt_callback, adv_callback = (
176                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
177                                            gatt_transport['bredr'],
178                                            self.per_droid_mac_address))
179            self.bluetooth_gatt_list.append(bluetooth_gatt)
180        except GattTestUtilsError as err:
181            self.log.error(err)
182            return False
183        if self.cen_ad.droid.gattClientReadRSSI(bluetooth_gatt):
184            self.cen_ad.ed.pop_event(
185                gatt_cb_strings['rd_remote_rssi'].format(gatt_callback),
186                self.default_timeout)
187        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
188                                                    gatt_callback)
189
190    @BluetoothBaseTest.bt_test_wrap
191    @test_tracker_info(uuid='dee9ef28-b872-428a-821b-cc62f27ba936')
192    def test_gatt_bredr_connect_trigger_on_services_discovered(self):
193        """Test GATT connection and discover services of peripheral.
194
195        Test establishing a gatt connection between a GATT server and GATT
196        client the discover all services from the connected device.
197
198        Steps:
199        1. Start a generic advertisement.
200        2. Start a generic scanner.
201        3. Find the advertisement and extract the mac address.
202        4. Stop the first scanner.
203        5. Create a GATT connection between the scanner and advertiser.
204        6. From the scanner (central device), discover services.
205        7. Disconnect the GATT connection.
206
207        Expected Result:
208        Verify that a connection was established and then disconnected
209        successfully. Verify that the service were discovered.
210
211        Returns:
212          Pass if True
213          Fail if False
214
215        TAGS: BR/EDR, Scanning, GATT, Services
216        Priority: 1
217        """
218        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
219        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
220            gatt_server_cb)
221        self.gatt_server_list.append(gatt_server)
222        try:
223            bluetooth_gatt, gatt_callback, adv_callback = (
224                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
225                                            gatt_transport['bredr'],
226                                            self.per_droid_mac_address))
227            self.bluetooth_gatt_list.append(bluetooth_gatt)
228        except GattTestUtilsError as err:
229            self.log.error(err)
230            return False
231        discovered_services_index = -1
232        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
233            event = self.cen_ad.ed.pop_event(
234                gatt_cb_strings['gatt_serv_disc'].format(gatt_callback),
235                self.default_timeout)
236            discovered_services_index = event['data']['ServicesIndex']
237        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
238                                                    gatt_callback)
239
240    @BluetoothBaseTest.bt_test_wrap
241    @test_tracker_info(uuid='01883bdd-0cf8-48fb-bf15-467bbd4f065b')
242    def test_gatt_bredr_connect_trigger_on_services_discovered_iterate_attributes(
243            self):
244        """Test GATT connection and iterate peripherals attributes.
245
246        Test establishing a gatt connection between a GATT server and GATT
247        client and iterate over all the characteristics and descriptors of the
248        discovered services.
249
250        Steps:
251        1. Start a generic advertisement.
252        2. Start a generic scanner.
253        3. Find the advertisement and extract the mac address.
254        4. Stop the first scanner.
255        5. Create a GATT connection between the scanner and advertiser.
256        6. From the scanner (central device), discover services.
257        7. Iterate over all the characteristics and descriptors of the
258        discovered features.
259        8. Disconnect the GATT connection.
260
261        Expected Result:
262        Verify that a connection was established and then disconnected
263        successfully. Verify that the services, characteristics, and descriptors
264        were discovered.
265
266        Returns:
267          Pass if True
268          Fail if False
269
270        TAGS: BR/EDR, Scanning, GATT, Services
271        Characteristics, Descriptors
272        Priority: 1
273        """
274        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
275        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
276            gatt_server_cb)
277        self.gatt_server_list.append(gatt_server)
278        try:
279            bluetooth_gatt, gatt_callback, adv_callback = (
280                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
281                                            gatt_transport['bredr'],
282                                            self.per_droid_mac_address))
283            self.bluetooth_gatt_list.append(bluetooth_gatt)
284        except GattTestUtilsError as err:
285            self.log.error(err)
286            return False
287        discovered_services_index = -1
288        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
289            event = self.cen_ad.ed.pop_event(
290                gatt_cb_strings['gatt_serv_disc'].format(gatt_callback),
291                self.default_timeout)
292            discovered_services_index = event['data']['ServicesIndex']
293            log_gatt_server_uuids(self.cen_ad, discovered_services_index)
294        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
295                                                    gatt_callback)
296
297    @BluetoothBaseTest.bt_test_wrap
298    @test_tracker_info(uuid='d4277bee-da99-4f48-8a4d-f81b5389da18')
299    def test_gatt_bredr_connect_with_service_uuid_variations(self):
300        """Test GATT connection with multiple service uuids.
301
302        Test establishing a gatt connection between a GATT server and GATT
303        client with multiple service uuid variations.
304
305        Steps:
306        1. Start a generic advertisement.
307        2. Start a generic scanner.
308        3. Find the advertisement and extract the mac address.
309        4. Stop the first scanner.
310        5. Create a GATT connection between the scanner and advertiser.
311        6. From the scanner (central device), discover services.
312        7. Verify that all the service uuid variations are found.
313        8. Disconnect the GATT connection.
314
315        Expected Result:
316        Verify that a connection was established and then disconnected
317        successfully. Verify that the service uuid variations are found.
318
319        Returns:
320          Pass if True
321          Fail if False
322
323        TAGS: BR/EDR, Scanning, GATT, Services
324        Priority: 2
325        """
326        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
327        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
328            gatt_server_cb)
329        self.gatt_server_list.append(gatt_server)
330        try:
331            gatt_server_callback, gatt_server = setup_multiple_services(
332                self.per_ad)
333            self.gatt_server_list.append(gatt_server)
334        except GattTestUtilsError as err:
335            self.log.error(err)
336            return False
337        try:
338            bluetooth_gatt, gatt_callback, adv_callback = (
339                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
340                                            gatt_transport['bredr'],
341                                            self.per_droid_mac_address))
342            self.bluetooth_gatt_list.append(bluetooth_gatt)
343        except GattTestUtilsError as err:
344            self.log.error(err)
345            return False
346        discovered_services_index = -1
347        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
348            event = self.cen_ad.ed.pop_event(
349                gatt_cb_strings['gatt_serv_disc'].format(gatt_callback),
350                self.default_timeout)
351            discovered_services_index = event['data']['ServicesIndex']
352            log_gatt_server_uuids(self.cen_ad, discovered_services_index)
353        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
354                                                    gatt_callback)
355
356    @BluetoothBaseTest.bt_test_wrap
357    @test_tracker_info(uuid='15c726dc-788a-4400-9a90-8c6866b24a3a')
358    def test_gatt_bredr_connect_multiple_iterations(self):
359        """Test GATT connections multiple times.
360
361        Test establishing a gatt connection between a GATT server and GATT
362        client with multiple iterations.
363
364        Steps:
365        1. Start a generic advertisement.
366        2. Start a generic scanner.
367        3. Find the advertisement and extract the mac address.
368        4. Stop the first scanner.
369        5. Create a GATT connection between the scanner and advertiser.
370        6. Disconnect the GATT connection.
371        7. Repeat steps 5 and 6 twenty times.
372
373        Expected Result:
374        Verify that a connection was established and then disconnected
375        successfully twenty times.
376
377        Returns:
378          Pass if True
379          Fail if False
380
381        TAGS: BR/EDR, Scanning, GATT, Stress
382        Priority: 1
383        """
384        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
385        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
386            gatt_server_cb)
387        self.gatt_server_list.append(gatt_server)
388        autoconnect = False
389        mac_address = self.per_ad.droid.bluetoothGetLocalAddress()
390        for i in range(20):
391            try:
392                bluetooth_gatt, gatt_callback, adv_callback = (
393                    orchestrate_gatt_connection(self.cen_ad, self.per_ad,
394                                                gatt_transport['bredr'],
395                                                self.per_droid_mac_address))
396                self.bluetooth_gatt_list.append(bluetooth_gatt)
397            except GattTestUtilsError as err:
398                self.log.error(err)
399                return False
400            self.log.info("Disconnecting from peripheral device.")
401            test_result = self._orchestrate_gatt_disconnection(
402                bluetooth_gatt, gatt_callback)
403            if not test_result:
404                self.log.info("Failed to disconnect from peripheral device.")
405                return False
406        return True
407
408    @BluetoothBaseTest.bt_test_wrap
409    @test_tracker_info(uuid='6ec766ca-6358-48ff-9d85-ede4d2756546')
410    def test_bredr_write_descriptor_stress(self):
411        """Test GATT connection writing and reading descriptors.
412
413        Test establishing a gatt connection between a GATT server and GATT
414        client with multiple service uuid variations.
415
416        Steps:
417        1. Start a generic advertisement.
418        2. Start a generic scanner.
419        3. Find the advertisement and extract the mac address.
420        4. Stop the first scanner.
421        5. Create a GATT connection between the scanner and advertiser.
422        6. Discover services.
423        7. Write data to the descriptors of each characteristic 100 times.
424        8. Read the data sent to the descriptors.
425        9. Disconnect the GATT connection.
426
427        Expected Result:
428        Each descriptor in each characteristic is written and read 100 times.
429
430        Returns:
431          Pass if True
432          Fail if False
433
434        TAGS: BR/EDR, Scanning, GATT, Stress, Characteristics, Descriptors
435        Priority: 1
436        """
437        try:
438            gatt_server_callback, gatt_server = setup_multiple_services(
439                self.per_ad)
440            self.gatt_server_list.append(gatt_server)
441        except GattTestUtilsError as err:
442            self.log.error(err)
443            return False
444        try:
445            bluetooth_gatt, gatt_callback, adv_callback = (
446                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
447                                            gatt_transport['bredr'],
448                                            self.per_droid_mac_address))
449            self.bluetooth_gatt_list.append(bluetooth_gatt)
450        except GattTestUtilsError as err:
451            self.log.error(err)
452            return False
453        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
454            try:
455                event = self.cen_ad.ed.pop_event(
456                    gatt_cb_strings['gatt_serv_disc'].format(gatt_callback),
457                    self.default_timeout)
458            except Empty as err:
459                self.log.error("Event not found: {}".format(err))
460                return False
461            discovered_services_index = event['data']['ServicesIndex']
462        else:
463            self.log.info("Failed to discover services.")
464            return False
465        services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount(
466            discovered_services_index)
467
468        connected_device_list = self.per_ad.droid.gattServerGetConnectedDevices(
469            gatt_server)
470        if len(connected_device_list) == 0:
471            self.log.info("No devices connected from peripheral.")
472            return False
473        bt_device_id = 0
474        status = 1
475        offset = 1
476        test_value = [1, 2, 3, 4, 5, 6, 7]
477        test_value_return = [1, 2, 3]
478        for i in range(services_count):
479            characteristic_uuids = (
480                self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids(
481                    discovered_services_index, i))
482            for characteristic in characteristic_uuids:
483                descriptor_uuids = (
484                    self.cen_ad.droid.gattClientGetDiscoveredDescriptorUuids(
485                        discovered_services_index, i, characteristic))
486                for _ in range(100):
487                    for descriptor in descriptor_uuids:
488                        self.cen_ad.droid.gattClientDescriptorSetValue(
489                            bluetooth_gatt, discovered_services_index, i,
490                            characteristic, descriptor, test_value)
491                        self.cen_ad.droid.gattClientWriteDescriptor(
492                            bluetooth_gatt, discovered_services_index, i,
493                            characteristic, descriptor)
494                        event = self.per_ad.ed.pop_event(
495                            gatt_cb_strings['desc_write_req'].format(
496                                gatt_server_callback), self.default_timeout)
497                        self.log.info(
498                            "onDescriptorWriteRequest event found: {}".format(
499                                event))
500                        request_id = event['data']['requestId']
501                        found_value = event['data']['value']
502                        if found_value != test_value:
503                            self.log.info("Values didn't match. Found: {}, "
504                                          "Expected: {}".format(
505                                              found_value, test_value))
506                            return False
507                        self.per_ad.droid.gattServerSendResponse(
508                            gatt_server, bt_device_id, request_id, status,
509                            offset, test_value_return)
510                        self.log.info(
511                            "onDescriptorWrite event found: {}".format(
512                                self.cen_ad.ed.pop_event(
513                                    gatt_cb_strings['desc_write'].format(
514                                        gatt_callback), self.default_timeout)))
515        return True
516