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