• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#/usr/bin/env python3.4
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
20import time
21
22from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
23from acts.test_utils.bt.bt_test_utils import reset_bluetooth
24from acts.test_utils.bt.GattEnum import GattCharacteristic
25from acts.test_utils.bt.GattEnum import GattService
26from acts.test_utils.bt.GattEnum import GattTransport
27from acts.test_utils.bt.GattEnum import MtuSize
28from acts.test_utils.bt.GattEnum import GattCbStrings
29from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError
30from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
31from acts.test_utils.bt.bt_gatt_utils import log_gatt_server_uuids
32from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection
33from acts.test_utils.bt.bt_gatt_utils import setup_gatt_characteristics
34from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection
35from acts.test_utils.bt.bt_gatt_utils import setup_gatt_descriptors
36from acts.test_utils.bt.bt_gatt_utils import setup_multiple_services
37from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
38from acts.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 __init__(self, controllers):
50        BluetoothBaseTest.__init__(self, controllers)
51        self.cen_ad = self.android_devices[0]
52        self.per_ad = self.android_devices[1]
53
54    def setup_class(self):
55        super(BluetoothBaseTest, self).setup_class()
56        self.per_droid_mac_address = self.per_ad.droid.bluetoothGetLocalAddress(
57        )
58        if not self.per_droid_mac_address:
59            return False
60        return True
61
62    def setup_test(self):
63        super(BluetoothBaseTest, self).setup_test()
64        bluetooth_gatt_list = []
65        self.gatt_server_list = []
66        self.adv_instances = []
67
68    def teardown_test(self):
69        for bluetooth_gatt in self.bluetooth_gatt_list:
70            self.cen_ad.droid.gattClientClose(bluetooth_gatt)
71        for gatt_server in self.gatt_server_list:
72            self.per_ad.droid.gattServerClose(gatt_server)
73        return True
74
75    def on_fail(self, test_name, begin_time):
76        take_btsnoop_logs(self.android_devices, self, test_name)
77        reset_bluetooth(self.android_devices)
78
79    def _orchestrate_gatt_disconnection(self, bluetooth_gatt, gatt_callback):
80        self.log.info("Disconnecting from peripheral device.")
81        try:
82            disconnect_gatt_connection(self.cen_ad, bluetooth_gatt,
83                                       gatt_callback)
84            if bluetooth_gatt in self.bluetooth_gatt_list:
85                self.bluetooth_gatt_list.remove(bluetooth_gatt)
86        except GattTestUtilsError as err:
87            self.log.error(err)
88            return False
89        return True
90
91    def _find_service_added_event(self, gatt_server_callback, uuid):
92        event = self.per_ad.ed.pop_event(
93            GattCbStrings.SERV_ADDED.value.format(gatt_server_callback),
94            self.default_timeout)
95        if event['data']['serviceUuid'].lower() != uuid.lower():
96            self.log.info("Uuid mismatch. Found: {}, Expected {}.".format(
97                event['data']['serviceUuid'], uuid))
98            return False
99        return True
100
101    @BluetoothBaseTest.bt_test_wrap
102    def test_gatt_bredr_connect(self):
103        """Test GATT connection over BR/EDR.
104
105        Test establishing a gatt connection between a GATT server and GATT
106        client.
107
108        Steps:
109        1. Start a generic advertisement.
110        2. Start a generic scanner.
111        3. Find the advertisement and extract the mac address.
112        4. Stop the first scanner.
113        5. Create a GATT connection between the scanner and advertiser.
114        6. Disconnect the GATT connection.
115
116        Expected Result:
117        Verify that a connection was established and then disconnected
118        successfully.
119
120        Returns:
121          Pass if True
122          Fail if False
123
124        TAGS: BR/EDR, Filtering, GATT, Scanning
125        Priority: 0
126        """
127        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
128        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
129            gatt_server_cb)
130        self.gatt_server_list.append(gatt_server)
131        try:
132            bluetooth_gatt, gatt_callback, adv_callback = (
133                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
134                                            GattTransport.TRANSPORT_BREDR.value,
135                                            self.per_droid_mac_address))
136            self.bluetooth_gatt_list.append(bluetooth_gatt)
137        except GattTestUtilsError as err:
138            self.log.error(err)
139            return False
140        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
141                                                    gatt_callback)
142
143    @BluetoothBaseTest.bt_test_wrap
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                                            GattTransport.TRANSPORT_BREDR.value,
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                GattCbStrings.RD_REMOTE_RSSI.value.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    def test_gatt_bredr_connect_trigger_on_services_discovered(self):
192        """Test GATT connection and discover services of peripheral.
193
194        Test establishing a gatt connection between a GATT server and GATT
195        client the discover all services from the connected device.
196
197        Steps:
198        1. Start a generic advertisement.
199        2. Start a generic scanner.
200        3. Find the advertisement and extract the mac address.
201        4. Stop the first scanner.
202        5. Create a GATT connection between the scanner and advertiser.
203        6. From the scanner (central device), discover services.
204        7. Disconnect the GATT connection.
205
206        Expected Result:
207        Verify that a connection was established and then disconnected
208        successfully. Verify that the service were discovered.
209
210        Returns:
211          Pass if True
212          Fail if False
213
214        TAGS: BR/EDR, Scanning, GATT, Services
215        Priority: 1
216        """
217        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
218        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
219            gatt_server_cb)
220        self.gatt_server_list.append(gatt_server)
221        try:
222            bluetooth_gatt, gatt_callback, adv_callback = (
223                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
224                                            GattTransport.TRANSPORT_BREDR.value,
225                                            self.per_droid_mac_address))
226            self.bluetooth_gatt_list.append(bluetooth_gatt)
227        except GattTestUtilsError as err:
228            self.log.error(err)
229            return False
230        discovered_services_index = -1
231        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
232            event = self.cen_ad.ed.pop_event(
233                GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback),
234                self.default_timeout)
235            discovered_services_index = event['data']['ServicesIndex']
236        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
237                                                    gatt_callback)
238
239    @BluetoothBaseTest.bt_test_wrap
240    def test_gatt_bredr_connect_trigger_on_services_discovered_iterate_attributes(
241            self):
242        """Test GATT connection and iterate peripherals attributes.
243
244        Test establishing a gatt connection between a GATT server and GATT
245        client and iterate over all the characteristics and descriptors of the
246        discovered services.
247
248        Steps:
249        1. Start a generic advertisement.
250        2. Start a generic scanner.
251        3. Find the advertisement and extract the mac address.
252        4. Stop the first scanner.
253        5. Create a GATT connection between the scanner and advertiser.
254        6. From the scanner (central device), discover services.
255        7. Iterate over all the characteristics and descriptors of the
256        discovered features.
257        8. Disconnect the GATT connection.
258
259        Expected Result:
260        Verify that a connection was established and then disconnected
261        successfully. Verify that the services, characteristics, and descriptors
262        were discovered.
263
264        Returns:
265          Pass if True
266          Fail if False
267
268        TAGS: BR/EDR, Scanning, GATT, Services
269        Characteristics, Descriptors
270        Priority: 1
271        """
272        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
273        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
274            gatt_server_cb)
275        self.gatt_server_list.append(gatt_server)
276        try:
277            bluetooth_gatt, gatt_callback, adv_callback = (
278                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
279                                            GattTransport.TRANSPORT_BREDR.value,
280                                            self.per_droid_mac_address))
281            self.bluetooth_gatt_list.append(bluetooth_gatt)
282        except GattTestUtilsError as err:
283            self.log.error(err)
284            return False
285        discovered_services_index = -1
286        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
287            event = self.cen_ad.ed.pop_event(
288                GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback),
289                self.default_timeout)
290            discovered_services_index = event['data']['ServicesIndex']
291            log_gatt_server_uuids(self.cen_ad, discovered_services_index)
292        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
293                                                    gatt_callback)
294
295    @BluetoothBaseTest.bt_test_wrap
296    def test_gatt_bredr_connect_with_service_uuid_variations(self):
297        """Test GATT connection with multiple service uuids.
298
299        Test establishing a gatt connection between a GATT server and GATT
300        client with multiple service uuid variations.
301
302        Steps:
303        1. Start a generic advertisement.
304        2. Start a generic scanner.
305        3. Find the advertisement and extract the mac address.
306        4. Stop the first scanner.
307        5. Create a GATT connection between the scanner and advertiser.
308        6. From the scanner (central device), discover services.
309        7. Verify that all the service uuid variations are found.
310        8. Disconnect the GATT connection.
311
312        Expected Result:
313        Verify that a connection was established and then disconnected
314        successfully. Verify that the service uuid variations are found.
315
316        Returns:
317          Pass if True
318          Fail if False
319
320        TAGS: BR/EDR, Scanning, GATT, Services
321        Priority: 2
322        """
323        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
324        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
325            gatt_server_cb)
326        self.gatt_server_list.append(gatt_server)
327        try:
328            gatt_server_callback, gatt_server = setup_multiple_services(
329                self.per_ad)
330            self.gatt_server_list.append(gatt_server)
331        except GattTestUtilsError as err:
332            self.log.error(err)
333            return False
334        try:
335            bluetooth_gatt, gatt_callback, adv_callback = (
336                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
337                                            GattTransport.TRANSPORT_BREDR.value,
338                                            self.per_droid_mac_address))
339            self.bluetooth_gatt_list.append(bluetooth_gatt)
340        except GattTestUtilsError as err:
341            self.log.error(err)
342            return False
343        discovered_services_index = -1
344        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
345            event = self.cen_ad.ed.pop_event(
346                GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback),
347                self.default_timeout)
348            discovered_services_index = event['data']['ServicesIndex']
349            log_gatt_server_uuids(self.cen_ad, discovered_services_index)
350        return self._orchestrate_gatt_disconnection(bluetooth_gatt,
351                                                    gatt_callback)
352
353    @BluetoothBaseTest.bt_test_wrap
354    def test_gatt_bredr_connect_multiple_iterations(self):
355        """Test GATT connections multiple times.
356
357        Test establishing a gatt connection between a GATT server and GATT
358        client with multiple iterations.
359
360        Steps:
361        1. Start a generic advertisement.
362        2. Start a generic scanner.
363        3. Find the advertisement and extract the mac address.
364        4. Stop the first scanner.
365        5. Create a GATT connection between the scanner and advertiser.
366        6. Disconnect the GATT connection.
367        7. Repeat steps 5 and 6 twenty times.
368
369        Expected Result:
370        Verify that a connection was established and then disconnected
371        successfully twenty times.
372
373        Returns:
374          Pass if True
375          Fail if False
376
377        TAGS: BR/EDR, Scanning, GATT, Stress
378        Priority: 1
379        """
380        gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
381        gatt_server = self.per_ad.droid.gattServerOpenGattServer(
382            gatt_server_cb)
383        self.gatt_server_list.append(gatt_server)
384        autoconnect = False
385        mac_address = self.per_ad.droid.bluetoothGetLocalAddress()
386        for i in range(20):
387            try:
388                bluetooth_gatt, gatt_callback, adv_callback = (
389                    orchestrate_gatt_connection(self.cen_ad, self.per_ad,
390                                                GattTransport.TRANSPORT_BREDR.value,
391                                                self.per_droid_mac_address))
392                self.bluetooth_gatt_list.append(bluetooth_gatt)
393            except GattTestUtilsError as err:
394                self.log.error(err)
395                return False
396            self.log.info("Disconnecting from peripheral device.")
397            test_result = self._orchestrate_gatt_disconnection(bluetooth_gatt,
398                                                               gatt_callback)
399            if not test_result:
400                self.log.info("Failed to disconnect from peripheral device.")
401                return False
402        return True
403
404    @BluetoothBaseTest.bt_test_wrap
405    def test_bredr_write_descriptor_stress(self):
406        """Test GATT connection writing and reading descriptors.
407
408        Test establishing a gatt connection between a GATT server and GATT
409        client with multiple service uuid variations.
410
411        Steps:
412        1. Start a generic advertisement.
413        2. Start a generic scanner.
414        3. Find the advertisement and extract the mac address.
415        4. Stop the first scanner.
416        5. Create a GATT connection between the scanner and advertiser.
417        6. Discover services.
418        7. Write data to the descriptors of each characteristic 100 times.
419        8. Read the data sent to the descriptors.
420        9. Disconnect the GATT connection.
421
422        Expected Result:
423        Each descriptor in each characteristic is written and read 100 times.
424
425        Returns:
426          Pass if True
427          Fail if False
428
429        TAGS: BR/EDR, Scanning, GATT, Stress, Characteristics, Descriptors
430        Priority: 1
431        """
432        try:
433            gatt_server_callback, gatt_server = setup_multiple_services(self.per_ad)
434            self.gatt_server_list.append(gatt_server)
435        except GattTestUtilsError as err:
436            self.log.error(err)
437            return False
438        try:
439            bluetooth_gatt, gatt_callback, adv_callback = (
440                orchestrate_gatt_connection(self.cen_ad, self.per_ad,
441                                            GattTransport.TRANSPORT_BREDR.value,
442                                            self.per_droid_mac_address))
443            self.bluetooth_gatt_list.append(bluetooth_gatt)
444        except GattTestUtilsError as err:
445            self.log.error(err)
446            return False
447        if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
448            try:
449                event = self.cen_ad.ed.pop_event(
450                    GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback),
451                    self.default_timeout)
452            except Empty as err:
453                self.log.error("Event not found: {}".format(err))
454                return False
455            discovered_services_index = event['data']['ServicesIndex']
456        else:
457            self.log.info("Failed to discover services.")
458            return False
459        services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount(
460            discovered_services_index)
461
462        connected_device_list = self.per_ad.droid.gattServerGetConnectedDevices(
463            gatt_server)
464        if len(connected_device_list) == 0:
465            self.log.info("No devices connected from peripheral.")
466            return False
467        bt_device_id = 0
468        status = 1
469        offset = 1
470        test_value = [1, 2, 3, 4, 5, 6, 7]
471        test_value_return = [1, 2, 3]
472        for i in range(services_count):
473            characteristic_uuids = (
474                self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids(
475                    discovered_services_index, i))
476            for characteristic in characteristic_uuids:
477                descriptor_uuids = (
478                    self.cen_ad.droid.gattClientGetDiscoveredDescriptorUuids(
479                        discovered_services_index, i, characteristic))
480                for _ in range(100):
481                    for descriptor in descriptor_uuids:
482                        self.cen_ad.droid.gattClientDescriptorSetValue(
483                            bluetooth_gatt, discovered_services_index, i,
484                            characteristic, descriptor, test_value)
485                        self.cen_ad.droid.gattClientWriteDescriptor(
486                            bluetooth_gatt, discovered_services_index, i,
487                            characteristic, descriptor)
488                        event = self.per_ad.ed.pop_event(
489                            GattCbStrings.DESC_WRITE_REQ.value.format(
490                                gatt_server_callback), self.default_timeout)
491                        self.log.info(
492                            "onDescriptorWriteRequest event found: {}".format(
493                                event))
494                        request_id = event['data']['requestId']
495                        found_value = event['data']['value']
496                        if found_value != test_value:
497                            self.log.info("Values didn't match. Found: {}, "
498                                          "Expected: {}".format(found_value,
499                                                                test_value))
500                            return False
501                        self.per_ad.droid.gattServerSendResponse(
502                            gatt_server, bt_device_id, request_id, status,
503                            offset, test_value_return)
504                        self.log.info(
505                            "onDescriptorWrite event found: {}".format(
506                                self.cen_ad.ed.pop_event(
507                                    GattCbStrings.DESC_WRITE.value.format(
508                                        gatt_callback), self.default_timeout)))
509        return True
510
511