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