Home | History | Annotate | Download | only in gatt
      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 """
     17 This test script exercises different GATT connection tests.
     18 """
     19 
     20 import pprint
     21 from queue import Empty
     22 import time
     23 
     24 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
     25 from acts.test_utils.bt.BtEnum import BluetoothProfile
     26 from acts.test_utils.bt.GattEnum import GattCharacteristic
     27 from acts.test_utils.bt.GattEnum import GattDescriptor
     28 from acts.test_utils.bt.GattEnum import GattService
     29 from acts.test_utils.bt.GattEnum import MtuSize
     30 from acts.test_utils.bt.GattEnum import GattCbErr
     31 from acts.test_utils.bt.GattEnum import GattCbStrings
     32 from acts.test_utils.bt.GattEnum import GattTransport
     33 from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError
     34 from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
     35 from acts.test_utils.bt.bt_gatt_utils import log_gatt_server_uuids
     36 from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection
     37 from acts.test_utils.bt.bt_gatt_utils import setup_gatt_characteristics
     38 from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection
     39 from acts.test_utils.bt.bt_gatt_utils import setup_gatt_descriptors
     40 from acts.test_utils.bt.bt_gatt_utils import setup_multiple_services
     41 from acts.test_utils.bt.bt_test_utils import get_mac_address_of_generic_advertisement
     42 
     43 
     44 class GattConnectTest(BluetoothBaseTest):
     45     adv_instances = []
     46     bluetooth_gatt_list = []
     47     gatt_server_list = []
     48     default_timeout = 10
     49     default_discovery_timeout = 3
     50 
     51     def __init__(self, controllers):
     52         BluetoothBaseTest.__init__(self, controllers)
     53         self.cen_ad = self.android_devices[0]
     54         self.per_ad = self.android_devices[1]
     55 
     56     def setup_test(self):
     57         super(BluetoothBaseTest, self).setup_test()
     58         bluetooth_gatt_list = []
     59         self.gatt_server_list = []
     60         self.adv_instances = []
     61 
     62     def teardown_test(self):
     63         for bluetooth_gatt in self.bluetooth_gatt_list:
     64             self.cen_ad.droid.gattClientClose(bluetooth_gatt)
     65         for gatt_server in self.gatt_server_list:
     66             self.per_ad.droid.gattServerClose(gatt_server)
     67         for adv in self.adv_instances:
     68             self.per_ad.droid.bleStopBleAdvertising(adv)
     69         return True
     70 
     71     def _orchestrate_gatt_disconnection(self, bluetooth_gatt, gatt_callback):
     72         self.log.info("Disconnecting from peripheral device.")
     73         try:
     74             disconnect_gatt_connection(self.cen_ad, bluetooth_gatt,
     75                                        gatt_callback)
     76             if bluetooth_gatt in self.bluetooth_gatt_list:
     77                 self.bluetooth_gatt_list.remove(bluetooth_gatt)
     78         except GattTestUtilsError as err:
     79             self.log.error(err)
     80             return False
     81         return True
     82 
     83     def _find_service_added_event(self, gatt_server_cb, uuid):
     84         expected_event = GattCbStrings.SERV_ADDED.value.format(gatt_server_cb)
     85         try:
     86             event = self.per_ad.ed.pop_event(expected_event,
     87                                              self.default_timeout)
     88         except Empty:
     89             self.log.error(
     90                 GattCbErr.SERV_ADDED_ERR.value.format(expected_event))
     91             return False
     92         if event['data']['serviceUuid'].lower() != uuid.lower():
     93             self.log.error("Uuid mismatch. Found: {}, Expected {}.".format(
     94                 event['data']['serviceUuid'], uuid))
     95             return False
     96         return True
     97 
     98     def _verify_mtu_changed_on_client_and_server(
     99             self, expected_mtu, gatt_callback, gatt_server_callback):
    100         expected_event = GattCbStrings.MTU_CHANGED.value.format(gatt_callback)
    101         try:
    102             mtu_event = self.cen_ad.ed.pop_event(expected_event,
    103                                                  self.default_timeout)
    104             mtu_size_found = mtu_event['data']['MTU']
    105             if mtu_size_found != expected_mtu:
    106                 self.log.error("MTU size found: {}, expected: {}".format(
    107                     mtu_size_found, expected_mtu))
    108                 return False
    109         except Empty:
    110             self.log.error(
    111                 GattCbErr.MTU_CHANGED_ERR.value.format(expected_event))
    112             return False
    113 
    114         expected_event = GattCbStrings.MTU_SERV_CHANGED.value.format(
    115             gatt_server_callback)
    116         try:
    117             mtu_event = self.per_ad.ed.pop_event(expected_event,
    118                                                  self.default_timeout)
    119             mtu_size_found = mtu_event['data']['MTU']
    120             if mtu_size_found != expected_mtu:
    121                 self.log.error("MTU size found: {}, expected: {}".format(
    122                     mtu_size_found, expected_mtu))
    123                 return False
    124         except Empty:
    125             self.log.error(
    126                 GattCbErr.MTU_SERV_CHANGED_ERR.value.format(expected_event))
    127             return False
    128         return True
    129 
    130     @BluetoothBaseTest.bt_test_wrap
    131     def test_gatt_connect(self):
    132         """Test GATT connection over LE.
    133 
    134         Test establishing a gatt connection between a GATT server and GATT
    135         client.
    136 
    137         Steps:
    138         1. Start a generic advertisement.
    139         2. Start a generic scanner.
    140         3. Find the advertisement and extract the mac address.
    141         4. Stop the first scanner.
    142         5. Create a GATT connection between the scanner and advertiser.
    143         6. Disconnect the GATT connection.
    144 
    145         Expected Result:
    146         Verify that a connection was established and then disconnected
    147         successfully.
    148 
    149         Returns:
    150           Pass if True
    151           Fail if False
    152 
    153         TAGS: LE, Advertising, Filtering, Scanning, GATT
    154         Priority: 0
    155         """
    156         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    157         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    158             gatt_server_cb)
    159         self.gatt_server_list.append(gatt_server)
    160         try:
    161             bluetooth_gatt, gatt_callback, adv_callback = (
    162                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    163             self.bluetooth_gatt_list.append(bluetooth_gatt)
    164         except GattTestUtilsError as err:
    165             self.log.error(err)
    166             return False
    167         self.adv_instances.append(adv_callback)
    168         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    169                                                     gatt_callback)
    170 
    171     @BluetoothBaseTest.bt_test_wrap
    172     def test_gatt_connect_stop_advertising(self):
    173         """Test GATT connection over LE then stop advertising
    174 
    175         A test case that verifies the GATT connection doesn't
    176         disconnect when LE advertisement is stopped.
    177 
    178         Steps:
    179         1. Start a generic advertisement.
    180         2. Start a generic scanner.
    181         3. Find the advertisement and extract the mac address.
    182         4. Stop the first scanner.
    183         5. Create a GATT connection between the scanner and advertiser.
    184         6. Stop the advertiser.
    185         7. Verify no connection state changed happened.
    186         8. Disconnect the GATT connection.
    187 
    188         Expected Result:
    189         Verify that a connection was established and not disconnected
    190         when advertisement stops.
    191 
    192         Returns:
    193           Pass if True
    194           Fail if False
    195 
    196         TAGS: LE, Advertising, Filtering, Scanning, GATT
    197         Priority: 0
    198         """
    199         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    200         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    201             gatt_server_cb)
    202         self.gatt_server_list.append(gatt_server)
    203         try:
    204             bluetooth_gatt, gatt_callback, adv_callback = (
    205                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    206             self.bluetooth_gatt_list.append(bluetooth_gatt)
    207         except GattTestUtilsError as err:
    208             self.log.error(err)
    209             return False
    210         self.per_ad.droid.bleStopBleAdvertising(adv_callback)
    211         try:
    212             event = self.cen_ad.ed.pop_event(
    213                 GattCbStrings.GATT_CONN_CHANGE.value.format(
    214                     gatt_callback, self.default_timeout))
    215             self.log.error(
    216                 "Connection event found when not expected: {}".format(event))
    217             return False
    218         except Empty:
    219             self.log.info("No connection state change as expected")
    220         try:
    221             self._orchestrate_gatt_disconnection(bluetooth_gatt, gatt_callback)
    222         except Exception as err:
    223             self.log.info("Failed to orchestrate disconnect: {}".format(e))
    224             return False
    225         return True
    226 
    227     @BluetoothBaseTest.bt_test_wrap
    228     def test_gatt_connect_autoconnect(self):
    229         """Test GATT connection over LE.
    230 
    231         Test re-establishing a gat connection using autoconnect
    232         set to True in order to test connection whitelist.
    233 
    234         Steps:
    235         1. Start a generic advertisement.
    236         2. Start a generic scanner.
    237         3. Find the advertisement and extract the mac address.
    238         4. Stop the first scanner.
    239         5. Create a GATT connection between the scanner and advertiser.
    240         6. Disconnect the GATT connection.
    241         7. Create a GATT connection with autoconnect set to True
    242         8. Disconnect the GATT connection.
    243 
    244         Expected Result:
    245         Verify that a connection was re-established and then disconnected
    246         successfully.
    247 
    248         Returns:
    249           Pass if True
    250           Fail if False
    251 
    252         TAGS: LE, Advertising, Filtering, Scanning, GATT
    253         Priority: 0
    254         """
    255         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    256         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    257             gatt_server_cb)
    258         self.gatt_server_list.append(gatt_server)
    259         autoconnect = False
    260         mac_address, adv_callback = (
    261             get_mac_address_of_generic_advertisement(self.cen_ad, self.per_ad))
    262         try:
    263             bluetooth_gatt, gatt_callback = setup_gatt_connection(
    264                 self.cen_ad, mac_address, autoconnect)
    265             self.bluetooth_gatt_list.append(bluetooth_gatt)
    266         except GattTestUtilsError as err:
    267             self.log.error(err)
    268             return False
    269         try:
    270             disconnect_gatt_connection(self.cen_ad, bluetooth_gatt,
    271                                        gatt_callback)
    272             if bluetooth_gatt in self.bluetooth_gatt_list:
    273                 self.bluetooth_gatt_list.remove(bluetooth_gatt)
    274         except GattTestUtilsError as err:
    275             self.log.error(err)
    276             return False
    277         autoconnect = True
    278         bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt(
    279             gatt_callback, mac_address, autoconnect,
    280             GattTransport.TRANSPORT_AUTO.value)
    281         self.bluetooth_gatt_list.append(bluetooth_gatt)
    282         expected_event = GattCbStrings.GATT_CONN_CHANGE.value.format(
    283             gatt_callback)
    284         try:
    285             event = self.cen_ad.ed.pop_event(expected_event,
    286                                              self.default_timeout)
    287         except Empty:
    288             self.log.error(
    289                 GattCbErr.GATT_CONN_CHANGE_ERR.value.format(expected_event))
    290             test_result = False
    291         return True
    292 
    293     @BluetoothBaseTest.bt_test_wrap
    294     def test_gatt_request_min_mtu(self):
    295         """Test GATT connection over LE and exercise MTU sizes.
    296 
    297         Test establishing a gatt connection between a GATT server and GATT
    298         client. Request an MTU size that matches the correct minimum size.
    299 
    300         Steps:
    301         1. Start a generic advertisement.
    302         2. Start a generic scanner.
    303         3. Find the advertisement and extract the mac address.
    304         4. Stop the first scanner.
    305         5. Create a GATT connection between the scanner and advertiser.
    306         6. From the scanner (client) request MTU size change to the
    307         minimum value.
    308         7. Find the MTU changed event on the client.
    309         8. Disconnect the GATT connection.
    310 
    311         Expected Result:
    312         Verify that a connection was established and the MTU value found
    313         matches the expected MTU value.
    314 
    315         Returns:
    316           Pass if True
    317           Fail if False
    318 
    319         TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU
    320         Priority: 0
    321         """
    322         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    323         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    324             gatt_server_cb)
    325         self.gatt_server_list.append(gatt_server)
    326         try:
    327             bluetooth_gatt, gatt_callback, adv_callback = (
    328                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    329             self.bluetooth_gatt_list.append(bluetooth_gatt)
    330         except GattTestUtilsError as err:
    331             self.log.error(err)
    332             return False
    333         self.adv_instances.append(adv_callback)
    334         expected_mtu = MtuSize.MIN.value
    335         self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, expected_mtu)
    336         if not self._verify_mtu_changed_on_client_and_server(
    337                 expected_mtu, gatt_callback, gatt_server_cb):
    338             return False
    339         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    340                                                     gatt_callback)
    341 
    342     @BluetoothBaseTest.bt_test_wrap
    343     def test_gatt_request_max_mtu(self):
    344         """Test GATT connection over LE and exercise MTU sizes.
    345 
    346         Test establishing a gatt connection between a GATT server and GATT
    347         client. Request an MTU size that matches the correct maximum size.
    348 
    349         Steps:
    350         1. Start a generic advertisement.
    351         2. Start a generic scanner.
    352         3. Find the advertisement and extract the mac address.
    353         4. Stop the first scanner.
    354         5. Create a GATT connection between the scanner and advertiser.
    355         6. From the scanner (client) request MTU size change to the
    356         maximum value.
    357         7. Find the MTU changed event on the client.
    358         8. Disconnect the GATT connection.
    359 
    360         Expected Result:
    361         Verify that a connection was established and the MTU value found
    362         matches the expected MTU value.
    363 
    364         Returns:
    365           Pass if True
    366           Fail if False
    367 
    368         TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU
    369         Priority: 0
    370         """
    371         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    372         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    373             gatt_server_cb)
    374         self.gatt_server_list.append(gatt_server)
    375         try:
    376             bluetooth_gatt, gatt_callback, adv_callback = (
    377                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    378             self.bluetooth_gatt_list.append(bluetooth_gatt)
    379         except GattTestUtilsError as err:
    380             self.log.error(err)
    381             return False
    382         self.adv_instances.append(adv_callback)
    383         expected_mtu = MtuSize.MAX.value
    384         self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, expected_mtu)
    385         if not self._verify_mtu_changed_on_client_and_server(
    386                 expected_mtu, gatt_callback, gatt_server_cb):
    387             return False
    388         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    389                                                     gatt_callback)
    390 
    391     @BluetoothBaseTest.bt_test_wrap
    392     def test_gatt_request_out_of_bounds_mtu(self):
    393         """Test GATT connection over LE and exercise an out of bound MTU size.
    394 
    395         Test establishing a gatt connection between a GATT server and GATT
    396         client. Request an MTU size that is the MIN value minus 1.
    397 
    398         Steps:
    399         1. Start a generic advertisement.
    400         2. Start a generic scanner.
    401         3. Find the advertisement and extract the mac address.
    402         4. Stop the first scanner.
    403         5. Create a GATT connection between the scanner and advertiser.
    404         6. From the scanner (client) request MTU size change to the
    405         minimum value minus one.
    406         7. Find the MTU changed event on the client.
    407         8. Disconnect the GATT connection.
    408 
    409         Expected Result:
    410         Verify that an MTU changed event was not discovered and that
    411         it didn't cause an exception when requesting an out of bounds
    412         MTU.
    413 
    414         Returns:
    415           Pass if True
    416           Fail if False
    417 
    418         TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU
    419         Priority: 0
    420         """
    421         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    422         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    423             gatt_server_cb)
    424         self.gatt_server_list.append(gatt_server)
    425         try:
    426             bluetooth_gatt, gatt_callback, adv_callback = (
    427                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    428             self.bluetooth_gatt_list.append(bluetooth_gatt)
    429         except GattTestUtilsError as err:
    430             self.log.error(err)
    431             return False
    432         self.adv_instances.append(adv_callback)
    433         unexpected_mtu = MtuSize.MIN.value - 1
    434         self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, unexpected_mtu)
    435         if self._verify_mtu_changed_on_client_and_server(
    436                 unexpected_mtu, gatt_callback, gatt_server_cb):
    437             return False
    438         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    439                                                     gatt_callback)
    440 
    441     @BluetoothBaseTest.bt_test_wrap
    442     def test_gatt_connect_trigger_on_read_rssi(self):
    443         """Test GATT connection over LE read RSSI.
    444 
    445         Test establishing a gatt connection between a GATT server and GATT
    446         client then read the RSSI.
    447 
    448         Steps:
    449         1. Start a generic advertisement.
    450         2. Start a generic scanner.
    451         3. Find the advertisement and extract the mac address.
    452         4. Stop the first scanner.
    453         5. Create a GATT connection between the scanner and advertiser.
    454         6. From the scanner, request to read the RSSI of the advertiser.
    455         7. Disconnect the GATT connection.
    456 
    457         Expected Result:
    458         Verify that a connection was established and then disconnected
    459         successfully. Verify that the RSSI was ready correctly.
    460 
    461         Returns:
    462           Pass if True
    463           Fail if False
    464 
    465         TAGS: LE, Advertising, Filtering, Scanning, GATT, RSSI
    466         Priority: 1
    467         """
    468         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    469         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    470             gatt_server_cb)
    471         self.gatt_server_list.append(gatt_server)
    472         try:
    473             bluetooth_gatt, gatt_callback, adv_callback = (
    474                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    475             self.bluetooth_gatt_list.append(bluetooth_gatt)
    476         except GattTestUtilsError as err:
    477             self.log.error(err)
    478             return False
    479         self.adv_instances.append(adv_callback)
    480         expected_event = GattCbStrings.RD_REMOTE_RSSI.value.format(
    481             gatt_callback)
    482         if self.cen_ad.droid.gattClientReadRSSI(bluetooth_gatt):
    483             try:
    484                 self.cen_ad.ed.pop_event(expected_event, self.default_timeout)
    485             except Empty:
    486                 self.log.error(
    487                     GattCbErr.RD_REMOTE_RSSI_ERR.value.format(expected_event))
    488         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    489                                                     gatt_callback)
    490 
    491     @BluetoothBaseTest.bt_test_wrap
    492     def test_gatt_connect_trigger_on_services_discovered(self):
    493         """Test GATT connection and discover services of peripheral.
    494 
    495         Test establishing a gatt connection between a GATT server and GATT
    496         client the discover all services from the connected device.
    497 
    498         Steps:
    499         1. Start a generic advertisement.
    500         2. Start a generic scanner.
    501         3. Find the advertisement and extract the mac address.
    502         4. Stop the first scanner.
    503         5. Create a GATT connection between the scanner and advertiser.
    504         6. From the scanner (central device), discover services.
    505         7. Disconnect the GATT connection.
    506 
    507         Expected Result:
    508         Verify that a connection was established and then disconnected
    509         successfully. Verify that the service were discovered.
    510 
    511         Returns:
    512           Pass if True
    513           Fail if False
    514 
    515         TAGS: LE, Advertising, Filtering, Scanning, GATT, Services
    516         Priority: 1
    517         """
    518         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    519         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    520             gatt_server_cb)
    521         self.gatt_server_list.append(gatt_server)
    522         try:
    523             bluetooth_gatt, gatt_callback, adv_callback = (
    524                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    525             self.bluetooth_gatt_list.append(bluetooth_gatt)
    526         except GattTestUtilsError as err:
    527             self.log.error(err)
    528             return False
    529         self.adv_instances.append(adv_callback)
    530         if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
    531             expected_event = GattCbStrings.GATT_SERV_DISC.value.format(
    532                 gatt_callback)
    533             try:
    534                 event = self.cen_ad.ed.pop_event(expected_event,
    535                                                  self.default_timeout)
    536             except Empty:
    537                 self.log.error(
    538                     GattCbErr.GATT_SERV_DISC_ERR.value.format(expected_event))
    539                 return False
    540         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    541                                                     gatt_callback)
    542 
    543     @BluetoothBaseTest.bt_test_wrap
    544     def test_gatt_connect_trigger_on_services_discovered_iterate_attributes(
    545             self):
    546         """Test GATT connection and iterate peripherals attributes.
    547 
    548         Test establishing a gatt connection between a GATT server and GATT
    549         client and iterate over all the characteristics and descriptors of the
    550         discovered services.
    551 
    552         Steps:
    553         1. Start a generic advertisement.
    554         2. Start a generic scanner.
    555         3. Find the advertisement and extract the mac address.
    556         4. Stop the first scanner.
    557         5. Create a GATT connection between the scanner and advertiser.
    558         6. From the scanner (central device), discover services.
    559         7. Iterate over all the characteristics and descriptors of the
    560         discovered features.
    561         8. Disconnect the GATT connection.
    562 
    563         Expected Result:
    564         Verify that a connection was established and then disconnected
    565         successfully. Verify that the services, characteristics, and descriptors
    566         were discovered.
    567 
    568         Returns:
    569           Pass if True
    570           Fail if False
    571 
    572         TAGS: LE, Advertising, Filtering, Scanning, GATT, Services
    573         Characteristics, Descriptors
    574         Priority: 1
    575         """
    576         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    577         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    578             gatt_server_cb)
    579         self.gatt_server_list.append(gatt_server)
    580         try:
    581             bluetooth_gatt, gatt_callback, adv_callback = (
    582                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    583             self.bluetooth_gatt_list.append(bluetooth_gatt)
    584         except GattTestUtilsError as err:
    585             self.log.error(err)
    586             return False
    587         self.adv_instances.append(adv_callback)
    588         if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
    589             expected_event = GattCbStrings.GATT_SERV_DISC.value.format(
    590                 gatt_callback)
    591             try:
    592                 event = self.cen_ad.ed.pop_event(expected_event,
    593                                                  self.default_timeout)
    594                 discovered_services_index = event['data']['ServicesIndex']
    595             except Empty:
    596                 self.log.error(
    597                     GattCbErr.GATT_SERV_DISC_ERR.value.format(expected_event))
    598                 return False
    599             log_gatt_server_uuids(self.cen_ad, discovered_services_index)
    600         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    601                                                     gatt_callback)
    602 
    603     @BluetoothBaseTest.bt_test_wrap
    604     def test_gatt_connect_with_service_uuid_variations(self):
    605         """Test GATT connection with multiple service uuids.
    606 
    607         Test establishing a gatt connection between a GATT server and GATT
    608         client with multiple service uuid variations.
    609 
    610         Steps:
    611         1. Start a generic advertisement.
    612         2. Start a generic scanner.
    613         3. Find the advertisement and extract the mac address.
    614         4. Stop the first scanner.
    615         5. Create a GATT connection between the scanner and advertiser.
    616         6. From the scanner (central device), discover services.
    617         7. Verify that all the service uuid variations are found.
    618         8. Disconnect the GATT connection.
    619 
    620         Expected Result:
    621         Verify that a connection was established and then disconnected
    622         successfully. Verify that the service uuid variations are found.
    623 
    624         Returns:
    625           Pass if True
    626           Fail if False
    627 
    628         TAGS: LE, Advertising, Filtering, Scanning, GATT, Services
    629         Priority: 2
    630         """
    631         try:
    632             gatt_server_cb, gatt_server = setup_multiple_services(self.per_ad)
    633             self.gatt_server_list.append(gatt_server)
    634         except GattTestUtilsError as err:
    635             self.log.error(err)
    636             return False
    637         try:
    638             bluetooth_gatt, gatt_callback, adv_callback = (
    639                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    640             self.bluetooth_gatt_list.append(bluetooth_gatt)
    641         except GattTestUtilsError as err:
    642             self.log.error(err)
    643             return False
    644         self.adv_instances.append(adv_callback)
    645         if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
    646             expected_event = GattCbStrings.GATT_SERV_DISC.value.format(
    647                 gatt_callback)
    648             try:
    649                 event = self.cen_ad.ed.pop_event(expected_event,
    650                                                  self.default_timeout)
    651             except Empty:
    652                 self.log.error(
    653                     GattCbErr.GATT_SERV_DISC_ERR.value.format(expected_event))
    654                 return False
    655             discovered_services_index = event['data']['ServicesIndex']
    656             log_gatt_server_uuids(self.cen_ad, discovered_services_index)
    657 
    658         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    659                                                     gatt_callback)
    660 
    661     @BluetoothBaseTest.bt_test_wrap
    662     def test_gatt_connect_in_quick_succession(self):
    663         """Test GATT connections multiple times.
    664 
    665         Test establishing a gatt connection between a GATT server and GATT
    666         client with multiple iterations.
    667 
    668         Steps:
    669         1. Start a generic advertisement.
    670         2. Start a generic scanner.
    671         3. Find the advertisement and extract the mac address.
    672         4. Stop the first scanner.
    673         5. Create a GATT connection between the scanner and advertiser.
    674         6. Disconnect the GATT connection.
    675         7. Repeat steps 5 and 6 twenty times.
    676 
    677         Expected Result:
    678         Verify that a connection was established and then disconnected
    679         successfully twenty times.
    680 
    681         Returns:
    682           Pass if True
    683           Fail if False
    684 
    685         TAGS: LE, Advertising, Filtering, Scanning, GATT, Stress
    686         Priority: 1
    687         """
    688         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    689         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    690             gatt_server_cb)
    691         self.gatt_server_list.append(gatt_server)
    692         mac_address, adv_callback = get_mac_address_of_generic_advertisement(
    693             self.cen_ad, self.per_ad)
    694         autoconnect = False
    695         for i in range(1000):
    696             self.log.info("Starting connection iteration {}".format(i + 1))
    697             try:
    698                 bluetooth_gatt, gatt_callback = setup_gatt_connection(
    699                     self.cen_ad, mac_address, autoconnect)
    700             except GattTestUtilsError as err:
    701                 self.log.error(err)
    702                 return False
    703             test_result = self._orchestrate_gatt_disconnection(bluetooth_gatt,
    704                                                                gatt_callback)
    705             self.cen_ad.droid.gattClientClose(bluetooth_gatt)
    706             if not test_result:
    707                 self.log.info("Failed to disconnect from peripheral device.")
    708                 return False
    709         self.adv_instances.append(adv_callback)
    710         return True
    711 
    712     @BluetoothBaseTest.bt_test_wrap
    713     def test_gatt_connect_mitm_attack(self):
    714         """Test GATT connection with permission write encrypted mitm.
    715 
    716         Test establishing a gatt connection between a GATT server and GATT
    717         client while the GATT server's characteristic includes the property
    718         write value and the permission write encrypted mitm value. This will
    719         prompt LE pairing and then the devices will create a bond.
    720 
    721         Steps:
    722         1. Create a GATT server and server callback on the peripheral device.
    723         2. Create a unique service and characteristic uuid on the peripheral.
    724         3. Create a characteristic on the peripheral with these properties:
    725             GattCharacteristic.PROPERTY_WRITE.value,
    726             GattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM.value
    727         4. Create a GATT service on the peripheral.
    728         5. Add the characteristic to the GATT service.
    729         6. Create a GATT connection between your central and peripheral device.
    730         7. From the central device, discover the peripheral's services.
    731         8. Iterate the services found until you find the unique characteristic
    732             created in step 3.
    733         9. Once found, write a random but valid value to the characteristic.
    734         10. Start pairing helpers on both devices immediately after attempting
    735             to write to the characteristic.
    736         11. Within 10 seconds of writing the characteristic, there should be
    737             a prompt to bond the device from the peripheral. The helpers will
    738             handle the UI interaction automatically. (see
    739             BluetoothConnectionFacade.java bluetoothStartPairingHelper).
    740         12. Verify that the two devices are bonded.
    741 
    742         Expected Result:
    743         Verify that a connection was established and the devices are bonded.
    744 
    745         Returns:
    746           Pass if True
    747           Fail if False
    748 
    749         TAGS: LE, Advertising, Filtering, Scanning, GATT, Characteristic, MITM
    750         Priority: 1
    751         """
    752         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    753         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    754             gatt_server_cb)
    755         self.gatt_server_list.append(gatt_server)
    756         service_uuid = "3846D7A0-69C8-11E4-BA00-0002A5D5C51B"
    757         test_uuid = "aa7edd5a-4d1d-4f0e-883a-d145616a1630"
    758         bonded = False
    759         characteristic = self.per_ad.droid.gattServerCreateBluetoothGattCharacteristic(
    760             test_uuid, GattCharacteristic.PROPERTY_WRITE.value,
    761             GattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM.value)
    762         gatt_service = self.per_ad.droid.gattServerCreateService(
    763             service_uuid, GattService.SERVICE_TYPE_PRIMARY.value)
    764         self.per_ad.droid.gattServerAddCharacteristicToService(gatt_service,
    765                                                                characteristic)
    766         self.per_ad.droid.gattServerAddService(gatt_server, gatt_service)
    767         result = self._find_service_added_event(gatt_server_cb, service_uuid)
    768         if not result:
    769             return False
    770         bluetooth_gatt, gatt_callback, adv_callback = (
    771             orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    772         self.bluetooth_gatt_list.append(bluetooth_gatt)
    773         self.adv_instances.append(adv_callback)
    774         if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt):
    775             expected_event = GattCbStrings.GATT_SERV_DISC.value.format(
    776                 gatt_callback)
    777             try:
    778                 event = self.cen_ad.ed.pop_event(expected_event,
    779                                                  self.default_timeout)
    780             except Empty:
    781                 self.log.error(
    782                     GattCbErr.GATT_SERV_DISC_ERR.value.format(expected_event))
    783                 return False
    784             discovered_services_index = event['data']['ServicesIndex']
    785         else:
    786             self.log.info("Failed to discover services.")
    787             return False
    788         test_value = [1, 2, 3, 4, 5, 6, 7]
    789         services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount(
    790             discovered_services_index)
    791         for i in range(services_count):
    792             characteristic_uuids = (
    793                 self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids(
    794                     discovered_services_index, i))
    795             for characteristic_uuid in characteristic_uuids:
    796                 if characteristic_uuid == test_uuid:
    797                     self.cen_ad.droid.bluetoothStartPairingHelper()
    798                     self.per_ad.droid.bluetoothStartPairingHelper()
    799                     self.cen_ad.droid.gattClientCharacteristicSetValue(
    800                         bluetooth_gatt, discovered_services_index, i,
    801                         characteristic_uuid, test_value)
    802                     self.cen_ad.droid.gattClientWriteCharacteristic(
    803                         bluetooth_gatt, discovered_services_index, i,
    804                         characteristic_uuid)
    805                     start_time = time.time() + self.default_timeout
    806                     target_name = self.per_ad.droid.bluetoothGetLocalName()
    807                     while time.time() < start_time and bonded == False:
    808                         bonded_devices = self.cen_ad.droid.bluetoothGetBondedDevices(
    809                         )
    810                         for device in bonded_devices:
    811                             if ('name' in device.keys() and
    812                                     device['name'] == target_name):
    813                                 bonded = True
    814                                 break
    815         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    816                                                     gatt_callback)
    817 
    818     @BluetoothBaseTest.bt_test_wrap
    819     def test_gatt_connect_get_connected_devices(self):
    820         """Test GATT connections show up in getConnectedDevices
    821 
    822         Test establishing a gatt connection between a GATT server and GATT
    823         client. Verify that active connections show up using
    824         BluetoothManager.getConnectedDevices API.
    825 
    826         Steps:
    827         1. Start a generic advertisement.
    828         2. Start a generic scanner.
    829         3. Find the advertisement and extract the mac address.
    830         4. Stop the first scanner.
    831         5. Create a GATT connection between the scanner and advertiser.
    832         7. Verify the GATT Client has an open connection to the GATT Server.
    833         8. Verify the GATT Server has an open connection to the GATT Client.
    834         9. Disconnect the GATT connection.
    835 
    836         Expected Result:
    837         Verify that a connection was established, connected devices are found
    838         on both the central and peripheral devices, and then disconnected
    839         successfully.
    840 
    841         Returns:
    842           Pass if True
    843           Fail if False
    844 
    845         TAGS: LE, Advertising, Scanning, GATT
    846         Priority: 2
    847         """
    848         gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
    849         gatt_server = self.per_ad.droid.gattServerOpenGattServer(
    850             gatt_server_cb)
    851         self.gatt_server_list.append(gatt_server)
    852         try:
    853             bluetooth_gatt, gatt_callback, adv_callback = (
    854                 orchestrate_gatt_connection(self.cen_ad, self.per_ad))
    855             self.bluetooth_gatt_list.append(bluetooth_gatt)
    856         except GattTestUtilsError as err:
    857             self.log.error(err)
    858             return False
    859         conn_cen_devices = self.cen_ad.droid.bluetoothGetConnectedLeDevices(
    860             BluetoothProfile.GATT.value)
    861         conn_per_devices = self.per_ad.droid.bluetoothGetConnectedLeDevices(
    862             BluetoothProfile.GATT_SERVER.value)
    863         target_name = self.per_ad.droid.bluetoothGetLocalName()
    864         error_message = ("Connected device {} not found in list of connected "
    865                          "devices {}")
    866         if not any(d['name'] == target_name for d in conn_cen_devices):
    867             self.log.error(error_message.format(target_name, conn_cen_devices))
    868             return False
    869         # For the GATT server only check the size of the list since
    870         # it may or may not include the device name.
    871         target_name = self.cen_ad.droid.bluetoothGetLocalName()
    872         if not conn_per_devices:
    873             self.log.error(error_message.format(target_name, conn_per_devices))
    874             return False
    875         self.adv_instances.append(adv_callback)
    876         return self._orchestrate_gatt_disconnection(bluetooth_gatt,
    877                                                     gatt_callback)
    878 
    879