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