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