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