1#!/usr/bin/env python3.4 2# 3# Copyright 2016 Google, Inc. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of 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, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import logging 18import time 19import pprint 20 21from enum import IntEnum 22from queue import Empty 23 24from acts import asserts 25from acts import signals 26from acts import utils 27from acts.controllers import attenuator 28from acts.test_utils.wifi import wifi_constants 29from acts.test_utils.tel import tel_defines 30 31# Default timeout used for reboot, toggle WiFi and Airplane mode, 32# for the system to settle down after the operation. 33DEFAULT_TIMEOUT = 10 34# Number of seconds to wait for events that are supposed to happen quickly. 35# Like onSuccess for start background scan and confirmation on wifi state 36# change. 37SHORT_TIMEOUT = 30 38ROAMING_TIMEOUT = 30 39 40# Speed of light in m/s. 41SPEED_OF_LIGHT = 299792458 42 43DEFAULT_PING_ADDR = "https://www.google.com/robots.txt" 44 45roaming_attn = { 46 "AP1_on_AP2_off": [ 47 0, 48 0, 49 95, 50 95 51 ], 52 "AP1_off_AP2_on": [ 53 95, 54 95, 55 0, 56 0 57 ], 58 "default": [ 59 0, 60 0, 61 0, 62 0 63 ] 64 } 65 66class WifiEnums(): 67 68 SSID_KEY = "SSID" 69 NETID_KEY = "network_id" 70 BSSID_KEY = "BSSID" 71 PWD_KEY = "password" 72 frequency_key = "frequency" 73 APBAND_KEY = "apBand" 74 HIDDEN_KEY = "hiddenSSID" 75 76 WIFI_CONFIG_APBAND_2G = 0 77 WIFI_CONFIG_APBAND_5G = 1 78 WIFI_CONFIG_APBAND_AUTO = -1 79 80 WIFI_WPS_INFO_PBC = 0 81 WIFI_WPS_INFO_DISPLAY = 1 82 WIFI_WPS_INFO_KEYPAD = 2 83 WIFI_WPS_INFO_LABEL = 3 84 WIFI_WPS_INFO_INVALID = 4 85 86 class CountryCode(): 87 CHINA = "CN" 88 JAPAN = "JP" 89 UK = "GB" 90 US = "US" 91 UNKNOWN = "UNKNOWN" 92 93 # Start of Macros for EAP 94 # EAP types 95 class Eap(IntEnum): 96 NONE = -1 97 PEAP = 0 98 TLS = 1 99 TTLS = 2 100 PWD = 3 101 SIM = 4 102 AKA = 5 103 AKA_PRIME = 6 104 UNAUTH_TLS = 7 105 106 # EAP Phase2 types 107 class EapPhase2(IntEnum): 108 NONE = 0 109 PAP = 1 110 MSCHAP = 2 111 MSCHAPV2 = 3 112 GTC = 4 113 114 class Enterprise: 115 # Enterprise Config Macros 116 EMPTY_VALUE = "NULL" 117 EAP = "eap" 118 PHASE2 = "phase2" 119 IDENTITY = "identity" 120 ANON_IDENTITY = "anonymous_identity" 121 PASSWORD = "password" 122 SUBJECT_MATCH = "subject_match" 123 ALTSUBJECT_MATCH = "altsubject_match" 124 DOM_SUFFIX_MATCH = "domain_suffix_match" 125 CLIENT_CERT = "client_cert" 126 CA_CERT = "ca_cert" 127 ENGINE = "engine" 128 ENGINE_ID = "engine_id" 129 PRIVATE_KEY_ID = "key_id" 130 REALM = "realm" 131 PLMN = "plmn" 132 FQDN = "FQDN" 133 FRIENDLY_NAME = "providerFriendlyName" 134 ROAMING_IDS = "roamingConsortiumIds" 135 # End of Macros for EAP 136 137 # Macros for wifi p2p. 138 WIFI_P2P_SERVICE_TYPE_ALL = 0 139 WIFI_P2P_SERVICE_TYPE_BONJOUR = 1 140 WIFI_P2P_SERVICE_TYPE_UPNP = 2 141 WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255 142 143 class ScanResult: 144 CHANNEL_WIDTH_20MHZ = 0 145 CHANNEL_WIDTH_40MHZ = 1 146 CHANNEL_WIDTH_80MHZ = 2 147 CHANNEL_WIDTH_160MHZ = 3 148 CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4 149 150 # Macros for wifi rtt. 151 class RttType(IntEnum): 152 TYPE_ONE_SIDED = 1 153 TYPE_TWO_SIDED = 2 154 155 class RttPeerType(IntEnum): 156 PEER_TYPE_AP = 1 157 PEER_TYPE_STA = 2 # Requires NAN. 158 PEER_P2P_GO = 3 159 PEER_P2P_CLIENT = 4 160 PEER_NAN = 5 161 162 class RttPreamble(IntEnum): 163 PREAMBLE_LEGACY = 0x01 164 PREAMBLE_HT = 0x02 165 PREAMBLE_VHT = 0x04 166 167 class RttBW(IntEnum): 168 BW_5_SUPPORT = 0x01 169 BW_10_SUPPORT = 0x02 170 BW_20_SUPPORT = 0x04 171 BW_40_SUPPORT = 0x08 172 BW_80_SUPPORT = 0x10 173 BW_160_SUPPORT = 0x20 174 175 class Rtt(IntEnum): 176 STATUS_SUCCESS = 0 177 STATUS_FAILURE = 1 178 STATUS_FAIL_NO_RSP = 2 179 STATUS_FAIL_REJECTED = 3 180 STATUS_FAIL_NOT_SCHEDULED_YET = 4 181 STATUS_FAIL_TM_TIMEOUT = 5 182 STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6 183 STATUS_FAIL_NO_CAPABILITY = 7 184 STATUS_ABORTED = 8 185 STATUS_FAIL_INVALID_TS = 9 186 STATUS_FAIL_PROTOCOL = 10 187 STATUS_FAIL_SCHEDULE = 11 188 STATUS_FAIL_BUSY_TRY_LATER = 12 189 STATUS_INVALID_REQ = 13 190 STATUS_NO_WIFI = 14 191 STATUS_FAIL_FTM_PARAM_OVERRIDE = 15 192 193 REASON_UNSPECIFIED = -1 194 REASON_NOT_AVAILABLE = -2 195 REASON_INVALID_LISTENER = -3 196 REASON_INVALID_REQUEST = -4 197 198 class RttParam: 199 device_type = "deviceType" 200 request_type = "requestType" 201 BSSID = "bssid" 202 channel_width = "channelWidth" 203 frequency = "frequency" 204 center_freq0 = "centerFreq0" 205 center_freq1 = "centerFreq1" 206 number_burst = "numberBurst" 207 interval = "interval" 208 num_samples_per_burst = "numSamplesPerBurst" 209 num_retries_per_measurement_frame = "numRetriesPerMeasurementFrame" 210 num_retries_per_FTMR = "numRetriesPerFTMR" 211 lci_request = "LCIRequest" 212 lcr_request = "LCRRequest" 213 burst_timeout = "burstTimeout" 214 preamble = "preamble" 215 bandwidth = "bandwidth" 216 margin = "margin" 217 218 RTT_MARGIN_OF_ERROR = { 219 RttBW.BW_80_SUPPORT: 2, 220 RttBW.BW_40_SUPPORT: 5, 221 RttBW.BW_20_SUPPORT: 5 222 } 223 224 # Macros as specified in the WifiScanner code. 225 WIFI_BAND_UNSPECIFIED = 0 # not specified 226 WIFI_BAND_24_GHZ = 1 # 2.4 GHz band 227 WIFI_BAND_5_GHZ = 2 # 5 GHz band without DFS channels 228 WIFI_BAND_5_GHZ_DFS_ONLY = 4 # 5 GHz band with DFS channels 229 WIFI_BAND_5_GHZ_WITH_DFS = 6 # 5 GHz band with DFS channels 230 WIFI_BAND_BOTH = 3 # both bands without DFS channels 231 WIFI_BAND_BOTH_WITH_DFS = 7 # both bands with DFS channels 232 233 REPORT_EVENT_AFTER_BUFFER_FULL = 0 234 REPORT_EVENT_AFTER_EACH_SCAN = 1 235 REPORT_EVENT_FULL_SCAN_RESULT = 2 236 237 SCAN_TYPE_LOW_LATENCY = 0 238 SCAN_TYPE_LOW_POWER = 1 239 SCAN_TYPE_HIGH_ACCURACY = 2 240 241 # US Wifi frequencies 242 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 243 2457, 2462] 244 DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 245 5600, 5620, 5640, 5660, 5680, 5700, 5720] 246 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 247 5825] 248 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 249 250 band_to_frequencies = { 251 WIFI_BAND_24_GHZ: ALL_2G_FREQUENCIES, 252 WIFI_BAND_5_GHZ: NONE_DFS_5G_FREQUENCIES, 253 WIFI_BAND_5_GHZ_DFS_ONLY: DFS_5G_FREQUENCIES, 254 WIFI_BAND_5_GHZ_WITH_DFS: ALL_5G_FREQUENCIES, 255 WIFI_BAND_BOTH: ALL_2G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES, 256 WIFI_BAND_BOTH_WITH_DFS: ALL_5G_FREQUENCIES + ALL_2G_FREQUENCIES 257 } 258 259 # All Wifi frequencies to channels lookup. 260 freq_to_channel = { 261 2412: 1, 262 2417: 2, 263 2422: 3, 264 2427: 4, 265 2432: 5, 266 2437: 6, 267 2442: 7, 268 2447: 8, 269 2452: 9, 270 2457: 10, 271 2462: 11, 272 2467: 12, 273 2472: 13, 274 2484: 14, 275 4915: 183, 276 4920: 184, 277 4925: 185, 278 4935: 187, 279 4940: 188, 280 4945: 189, 281 4960: 192, 282 4980: 196, 283 5035: 7, 284 5040: 8, 285 5045: 9, 286 5055: 11, 287 5060: 12, 288 5080: 16, 289 5170: 34, 290 5180: 36, 291 5190: 38, 292 5200: 40, 293 5210: 42, 294 5220: 44, 295 5230: 46, 296 5240: 48, 297 5260: 52, 298 5280: 56, 299 5300: 60, 300 5320: 64, 301 5500: 100, 302 5520: 104, 303 5540: 108, 304 5560: 112, 305 5580: 116, 306 5600: 120, 307 5620: 124, 308 5640: 128, 309 5660: 132, 310 5680: 136, 311 5700: 140, 312 5745: 149, 313 5765: 153, 314 5785: 157, 315 5805: 161, 316 5825: 165, 317 } 318 319 # All Wifi channels to frequencies lookup. 320 channel_2G_to_freq = { 321 1: 2412, 322 2: 2417, 323 3: 2422, 324 4: 2427, 325 5: 2432, 326 6: 2437, 327 7: 2442, 328 8: 2447, 329 9: 2452, 330 10: 2457, 331 11: 2462, 332 12: 2467, 333 13: 2472, 334 14: 2484 335 } 336 337 channel_5G_to_freq = { 338 183: 4915, 339 184: 4920, 340 185: 4925, 341 187: 4935, 342 188: 4940, 343 189: 4945, 344 192: 4960, 345 196: 4980, 346 7: 5035, 347 8: 5040, 348 9: 5045, 349 11: 5055, 350 12: 5060, 351 16: 5080, 352 34: 5170, 353 36: 5180, 354 38: 5190, 355 40: 5200, 356 42: 5210, 357 44: 5220, 358 46: 5230, 359 48: 5240, 360 52: 5260, 361 56: 5280, 362 60: 5300, 363 64: 5320, 364 100: 5500, 365 104: 5520, 366 108: 5540, 367 112: 5560, 368 116: 5580, 369 120: 5600, 370 124: 5620, 371 128: 5640, 372 132: 5660, 373 136: 5680, 374 140: 5700, 375 149: 5745, 376 153: 5765, 377 157: 5785, 378 161: 5805, 379 165: 5825 380 } 381 382 383class WifiChannelBase: 384 ALL_2G_FREQUENCIES = [] 385 DFS_5G_FREQUENCIES = [] 386 NONE_DFS_5G_FREQUENCIES = [] 387 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 388 MIX_CHANNEL_SCAN = [] 389 390 def band_to_freq(self, band): 391 _band_to_frequencies = { 392 WifiEnums.WIFI_BAND_24_GHZ: self.ALL_2G_FREQUENCIES, 393 WifiEnums.WIFI_BAND_5_GHZ: self.NONE_DFS_5G_FREQUENCIES, 394 WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY: self.DFS_5G_FREQUENCIES, 395 WifiEnums.WIFI_BAND_5_GHZ_WITH_DFS: self.ALL_5G_FREQUENCIES, 396 WifiEnums.WIFI_BAND_BOTH: 397 self.ALL_2G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES, 398 WifiEnums.WIFI_BAND_BOTH_WITH_DFS: 399 self.ALL_5G_FREQUENCIES + self.ALL_2G_FREQUENCIES 400 } 401 return _band_to_frequencies[band] 402 403 404class WifiChannelUS(WifiChannelBase): 405 # US Wifi frequencies 406 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 407 2457, 2462] 408 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 409 5825] 410 MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5280, 5260, 5300, 5500, 411 5320, 5520, 5560, 5700, 5745, 5805] 412 413 def __init__(self, model=None): 414 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 415 5540, 5560, 5580, 5600, 5620, 5640, 416 5660, 5680, 5700, 5720] 417 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 418 419class WifiReferenceNetworks: 420 """ Class to parse and return networks of different band and 421 auth type from reference_networks 422 """ 423 def __init__(self, obj): 424 self.reference_networks = obj 425 self.WIFI_2G = "2g" 426 self.WIFI_5G = "5g" 427 428 self.secure_networks_2g = [] 429 self.secure_networks_5g = [] 430 self.open_networks_2g = [] 431 self.open_networks_5g = [] 432 self._parse_networks() 433 434 def _parse_networks(self): 435 for network in self.reference_networks: 436 for key in network: 437 if key == self.WIFI_2G: 438 if "password" in network[key]: 439 self.secure_networks_2g.append(network[key]) 440 else: 441 self.open_networks_2g.append(network[key]) 442 else: 443 if "password" in network[key]: 444 self.secure_networks_5g.append(network[key]) 445 else: 446 self.open_networks_5g.append(network[key]) 447 448 def return_2g_secure_networks(self): 449 return self.secure_networks_2g 450 451 def return_5g_secure_networks(self): 452 return self.secure_networks_5g 453 454 def return_2g_open_networks(self): 455 return self.open_networks_2g 456 457 def return_5g_open_networks(self): 458 return self.open_networks_5g 459 460 def return_secure_networks(self): 461 return self.secure_networks_2g + self.secure_networks_5g 462 463 def return_open_networks(self): 464 return self.open_networks_2g + self.open_networks_5g 465 466 467def _assert_on_fail_handler(func, assert_on_fail, *args, **kwargs): 468 """Wrapper function that handles the bahevior of assert_on_fail. 469 470 When assert_on_fail is True, let all test signals through, which can 471 terminate test cases directly. When assert_on_fail is False, the wrapper 472 raises no test signals and reports operation status by returning True or 473 False. 474 475 Args: 476 func: The function to wrap. This function reports operation status by 477 raising test signals. 478 assert_on_fail: A boolean that specifies if the output of the wrapper 479 is test signal based or return value based. 480 args: Positional args for func. 481 kwargs: Name args for func. 482 483 Returns: 484 If assert_on_fail is True, returns True/False to signal operation 485 status, otherwise return nothing. 486 """ 487 try: 488 func(*args, **kwargs) 489 if not assert_on_fail: 490 return True 491 except signals.TestSignal: 492 if assert_on_fail: 493 raise 494 return False 495 496 497def assert_network_in_list(target, network_list): 498 """Makes sure a specified target Wi-Fi network exists in a list of Wi-Fi 499 networks. 500 501 Args: 502 target: A dict representing a Wi-Fi network. 503 E.g. {WifiEnums.SSID_KEY: "SomeNetwork"} 504 network_list: A list of dicts, each representing a Wi-Fi network. 505 """ 506 match_results = match_networks(target, network_list) 507 asserts.assert_true( 508 match_results, "Target network %s, does not exist in network list %s" % 509 (target, network_list)) 510 511 512def match_networks(target_params, networks): 513 """Finds the WiFi networks that match a given set of parameters in a list 514 of WiFi networks. 515 516 To be considered a match, the network should contain every key-value pair 517 of target_params 518 519 Args: 520 target_params: A dict with 1 or more key-value pairs representing a Wi-Fi network. 521 E.g { 'SSID': 'wh_ap1_5g', 'BSSID': '30:b5:c2:33:e4:47' } 522 networks: A list of dict objects representing WiFi networks. 523 524 Returns: 525 The networks that match the target parameters. 526 """ 527 results = [] 528 asserts.assert_true(target_params, 529 "Expected networks object 'target_params' is empty") 530 for n in networks: 531 add_network = 1 532 for k, v in target_params.items(): 533 if k not in n: 534 add_network = 0 535 break 536 if n[k] != v: 537 add_network = 0 538 break 539 if add_network: 540 results.append(n) 541 return results 542 543def wait_for_wifi_state(ad, state, assert_on_fail=True): 544 """Waits for the device to transition to the specified wifi state 545 546 Args: 547 ad: An AndroidDevice object. 548 state: Wifi state to wait for. 549 assert_on_fail: If True, error checks in this function will raise test 550 failure signals. 551 552 Returns: 553 If assert_on_fail is False, function returns True if the device transitions 554 to the specified state, False otherwise. If assert_on_fail is True, no return value. 555 """ 556 return _assert_on_fail_handler( 557 _wait_for_wifi_state, assert_on_fail, ad, state=state) 558 559 560def _wait_for_wifi_state(ad, state): 561 """Toggles the state of wifi. 562 563 TestFailure signals are raised when something goes wrong. 564 565 Args: 566 ad: An AndroidDevice object. 567 state: Wifi state to wait for. 568 """ 569 if state == ad.droid.wifiCheckState(): 570 # Check if the state is already achieved, so we don't wait for the 571 # state change event by mistake. 572 return 573 ad.droid.wifiStartTrackingStateChange() 574 fail_msg = "Device did not transition to Wi-Fi state to %s on %s." % (state, 575 ad.serial) 576 try: 577 ad.ed.wait_for_event(wifi_constants.WIFI_STATE_CHANGED, 578 lambda x: x["data"]["enabled"] == state, 579 SHORT_TIMEOUT) 580 except Empty: 581 asserts.assert_equal(state, ad.droid.wifiCheckState(), fail_msg) 582 finally: 583 ad.droid.wifiStopTrackingStateChange() 584 585def wifi_toggle_state(ad, new_state=None, assert_on_fail=True): 586 """Toggles the state of wifi. 587 588 Args: 589 ad: An AndroidDevice object. 590 new_state: Wifi state to set to. If None, opposite of the current state. 591 assert_on_fail: If True, error checks in this function will raise test 592 failure signals. 593 594 Returns: 595 If assert_on_fail is False, function returns True if the toggle was 596 successful, False otherwise. If assert_on_fail is True, no return value. 597 """ 598 return _assert_on_fail_handler( 599 _wifi_toggle_state, assert_on_fail, ad, new_state=new_state) 600 601 602def _wifi_toggle_state(ad, new_state=None): 603 """Toggles the state of wifi. 604 605 TestFailure signals are raised when something goes wrong. 606 607 Args: 608 ad: An AndroidDevice object. 609 new_state: The state to set Wi-Fi to. If None, opposite of the current 610 state will be set. 611 """ 612 if new_state is None: 613 new_state = not ad.droid.wifiCheckState() 614 elif new_state == ad.droid.wifiCheckState(): 615 # Check if the new_state is already achieved, so we don't wait for the 616 # state change event by mistake. 617 return 618 ad.droid.wifiStartTrackingStateChange() 619 ad.log.info("Setting Wi-Fi state to %s.", new_state) 620 ad.ed.clear_all_events() 621 # Setting wifi state. 622 ad.droid.wifiToggleState(new_state) 623 fail_msg = "Failed to set Wi-Fi state to %s on %s." % (new_state, 624 ad.serial) 625 try: 626 ad.ed.wait_for_event(wifi_constants.WIFI_STATE_CHANGED, 627 lambda x: x["data"]["enabled"] == new_state, 628 SHORT_TIMEOUT) 629 except Empty: 630 asserts.assert_equal(new_state, ad.droid.wifiCheckState(), fail_msg) 631 finally: 632 ad.droid.wifiStopTrackingStateChange() 633 634 635def reset_wifi(ad): 636 """Clears all saved Wi-Fi networks on a device. 637 638 This will turn Wi-Fi on. 639 640 Args: 641 ad: An AndroidDevice object. 642 643 """ 644 networks = ad.droid.wifiGetConfiguredNetworks() 645 if not networks: 646 return 647 for n in networks: 648 ad.droid.wifiForgetNetwork(n['networkId']) 649 try: 650 event = ad.ed.pop_event(wifi_constants.WIFI_FORGET_NW_SUCCESS, 651 SHORT_TIMEOUT) 652 except Empty: 653 logging.warning("Could not confirm the removal of network %s.", n) 654 # Check again to see if there's any network left. 655 asserts.assert_true( 656 not ad.droid.wifiGetConfiguredNetworks(), 657 "Failed to remove these configured Wi-Fi networks: %s" % networks) 658 659 660def toggle_airplane_mode_on_and_off(ad): 661 """Turn ON and OFF Airplane mode. 662 663 ad: An AndroidDevice object. 664 Returns: Assert if turning on/off Airplane mode fails. 665 666 """ 667 ad.log.debug("Toggling Airplane mode ON.") 668 asserts.assert_true( 669 utils.force_airplane_mode(ad, True), 670 "Can not turn on airplane mode on: %s" % ad.serial) 671 time.sleep(DEFAULT_TIMEOUT) 672 ad.log.debug("Toggling Airplane mode OFF.") 673 asserts.assert_true( 674 utils.force_airplane_mode(ad, False), 675 "Can not turn on airplane mode on: %s" % ad.serial) 676 time.sleep(DEFAULT_TIMEOUT) 677 678 679def toggle_wifi_off_and_on(ad): 680 """Turn OFF and ON WiFi. 681 682 ad: An AndroidDevice object. 683 Returns: Assert if turning off/on WiFi fails. 684 685 """ 686 ad.log.debug("Toggling wifi OFF.") 687 wifi_toggle_state(ad, False) 688 time.sleep(DEFAULT_TIMEOUT) 689 ad.log.debug("Toggling wifi ON.") 690 wifi_toggle_state(ad, True) 691 time.sleep(DEFAULT_TIMEOUT) 692 693 694def wifi_forget_network(ad, net_ssid): 695 """Remove configured Wifi network on an android device. 696 697 Args: 698 ad: android_device object for forget network. 699 net_ssid: ssid of network to be forget 700 701 """ 702 networks = ad.droid.wifiGetConfiguredNetworks() 703 if not networks: 704 return 705 for n in networks: 706 if net_ssid in n[WifiEnums.SSID_KEY]: 707 ad.droid.wifiForgetNetwork(n['networkId']) 708 try: 709 event = ad.ed.pop_event(wifi_constants.WIFI_FORGET_NW_SUCCESS, 710 SHORT_TIMEOUT) 711 except Empty: 712 asserts.fail("Failed to remove network %s." % n) 713 714 715def wifi_test_device_init(ad): 716 """Initializes an android device for wifi testing. 717 718 0. Make sure SL4A connection is established on the android device. 719 1. Disable location service's WiFi scan. 720 2. Turn WiFi on. 721 3. Clear all saved networks. 722 4. Set country code to US. 723 5. Enable WiFi verbose logging. 724 6. Sync device time with computer time. 725 7. Turn off cellular data. 726 8. Turn off ambient display. 727 """ 728 utils.require_sl4a((ad, )) 729 ad.droid.wifiScannerToggleAlwaysAvailable(False) 730 msg = "Failed to turn off location service's scan." 731 asserts.assert_true(not ad.droid.wifiScannerIsAlwaysAvailable(), msg) 732 wifi_toggle_state(ad, True) 733 reset_wifi(ad) 734 ad.droid.wifiEnableVerboseLogging(1) 735 msg = "Failed to enable WiFi verbose logging." 736 asserts.assert_equal(ad.droid.wifiGetVerboseLoggingLevel(), 1, msg) 737 # We don't verify the following settings since they are not critical. 738 # Set wpa_supplicant log level to EXCESSIVE. 739 output = ad.adb.shell("wpa_cli -i wlan0 -p -g@android:wpa_wlan0 IFNAME=" 740 "wlan0 log_level EXCESSIVE") 741 ad.log.info("wpa_supplicant log change status: %s", output) 742 utils.sync_device_time(ad) 743 ad.droid.telephonyToggleDataConnection(False) 744 # TODO(angli): need to verify the country code was actually set. No generic 745 # way to check right now. 746 ad.adb.shell("halutil -country %s" % WifiEnums.CountryCode.US) 747 utils.set_ambient_display(ad, False) 748 749 750def start_wifi_connection_scan(ad): 751 """Starts a wifi connection scan and wait for results to become available. 752 753 Args: 754 ad: An AndroidDevice object. 755 """ 756 ad.ed.clear_all_events() 757 ad.droid.wifiStartScan() 758 try: 759 ad.ed.pop_event("WifiManagerScanResultsAvailable", 60) 760 except Empty: 761 asserts.fail("Wi-Fi results did not become available within 60s.") 762 763 764def start_wifi_connection_scan_and_return_status(ad): 765 """ 766 Starts a wifi connection scan and wait for results to become available 767 or a scan failure to be reported. 768 769 Args: 770 ad: An AndroidDevice object. 771 Returns: 772 True: if scan succeeded & results are available 773 False: if scan failed 774 """ 775 ad.ed.clear_all_events() 776 ad.droid.wifiStartScan() 777 try: 778 events = ad.ed.pop_events( 779 "WifiManagerScan(ResultsAvailable|Failure)", 60) 780 except Empty: 781 asserts.fail( 782 "Wi-Fi scan results/failure did not become available within 60s.") 783 # If there are multiple matches, we check for atleast one success. 784 for event in events: 785 if event["name"] == "WifiManagerScanResultsAvailable": 786 return True 787 elif event["name"] == "WifiManagerScanFailure": 788 ad.log.debug("Scan failure received") 789 return False 790 791 792def start_wifi_connection_scan_and_check_for_network(ad, network_ssid, 793 max_tries=3): 794 """ 795 Start connectivity scans & checks if the |network_ssid| is seen in 796 scan results. The method performs a max of |max_tries| connectivity scans 797 to find the network. 798 799 Args: 800 ad: An AndroidDevice object. 801 network_ssid: SSID of the network we are looking for. 802 max_tries: Number of scans to try. 803 Returns: 804 True: if network_ssid is found in scan results. 805 False: if network_ssid is not found in scan results. 806 """ 807 for num_tries in range(max_tries): 808 if start_wifi_connection_scan_and_return_status(ad): 809 scan_results = ad.droid.wifiGetScanResults() 810 match_results = match_networks( 811 {WifiEnums.SSID_KEY: network_ssid}, scan_results) 812 if len(match_results) > 0: 813 return True 814 return False 815 816 817def start_wifi_connection_scan_and_ensure_network_found(ad, network_ssid, 818 max_tries=3): 819 """ 820 Start connectivity scans & ensure the |network_ssid| is seen in 821 scan results. The method performs a max of |max_tries| connectivity scans 822 to find the network. 823 This method asserts on failure! 824 825 Args: 826 ad: An AndroidDevice object. 827 network_ssid: SSID of the network we are looking for. 828 max_tries: Number of scans to try. 829 """ 830 ad.log.info("Starting scans to ensure %s is present", network_ssid) 831 assert_msg = "Failed to find " + network_ssid + " in scan results" \ 832 " after " + str(max_tries) + " tries" 833 asserts.assert_true(start_wifi_connection_scan_and_check_for_network( 834 ad, network_ssid, max_tries), assert_msg) 835 836 837def start_wifi_connection_scan_and_ensure_network_not_found(ad, network_ssid, 838 max_tries=3): 839 """ 840 Start connectivity scans & ensure the |network_ssid| is not seen in 841 scan results. The method performs a max of |max_tries| connectivity scans 842 to find the network. 843 This method asserts on failure! 844 845 Args: 846 ad: An AndroidDevice object. 847 network_ssid: SSID of the network we are looking for. 848 max_tries: Number of scans to try. 849 """ 850 ad.log.info("Starting scans to ensure %s is not present", network_ssid) 851 assert_msg = "Found " + network_ssid + " in scan results" \ 852 " after " + str(max_tries) + " tries" 853 asserts.assert_false(start_wifi_connection_scan_and_check_for_network( 854 ad, network_ssid, max_tries), assert_msg) 855 856 857def start_wifi_background_scan(ad, scan_setting): 858 """Starts wifi background scan. 859 860 Args: 861 ad: android_device object to initiate connection on. 862 scan_setting: A dict representing the settings of the scan. 863 864 Returns: 865 If scan was started successfully, event data of success event is returned. 866 """ 867 idx = ad.droid.wifiScannerStartBackgroundScan(scan_setting) 868 event = ad.ed.pop_event("WifiScannerScan{}onSuccess".format(idx), 869 SHORT_TIMEOUT) 870 return event['data'] 871 872 873def start_wifi_tethering(ad, ssid, password, band=None, hidden=None): 874 """Starts wifi tethering on an android_device. 875 876 Args: 877 ad: android_device to start wifi tethering on. 878 ssid: The SSID the soft AP should broadcast. 879 password: The password the soft AP should use. 880 band: The band the soft AP should be set on. It should be either 881 WifiEnums.WIFI_CONFIG_APBAND_2G or WifiEnums.WIFI_CONFIG_APBAND_5G. 882 hidden: boolean to indicate if the AP needs to be hidden or not. 883 884 Returns: 885 No return value. Error checks in this function will raise test failure signals 886 """ 887 config = {WifiEnums.SSID_KEY: ssid} 888 if password: 889 config[WifiEnums.PWD_KEY] = password 890 if band: 891 config[WifiEnums.APBAND_KEY] = band 892 if hidden: 893 config[WifiEnums.HIDDEN_KEY] = hidden 894 asserts.assert_true( 895 ad.droid.wifiSetWifiApConfiguration(config), 896 "Failed to update WifiAp Configuration") 897 ad.droid.wifiStartTrackingTetherStateChange() 898 ad.droid.connectivityStartTethering(tel_defines.TETHERING_WIFI, False) 899 try: 900 ad.ed.pop_event("ConnectivityManagerOnTetheringStarted") 901 ad.ed.wait_for_event("TetherStateChanged", 902 lambda x: x["data"]["ACTIVE_TETHER"], 30) 903 ad.log.debug("Tethering started successfully.") 904 except Empty: 905 msg = "Failed to receive confirmation of wifi tethering starting" 906 asserts.fail(msg) 907 finally: 908 ad.droid.wifiStopTrackingTetherStateChange() 909 910 911def stop_wifi_tethering(ad): 912 """Stops wifi tethering on an android_device. 913 914 Args: 915 ad: android_device to stop wifi tethering on. 916 """ 917 ad.droid.wifiStartTrackingTetherStateChange() 918 ad.droid.connectivityStopTethering(tel_defines.TETHERING_WIFI) 919 try: 920 ad.ed.pop_event("WifiManagerApDisabled", 30) 921 ad.ed.wait_for_event("TetherStateChanged", 922 lambda x: not x["data"]["ACTIVE_TETHER"], 30) 923 except Empty: 924 msg = "Failed to receive confirmation of wifi tethering stopping" 925 asserts.fail(msg) 926 finally: 927 ad.droid.wifiStopTrackingTetherStateChange() 928 929 930def toggle_wifi_and_wait_for_reconnection(ad, 931 network, 932 num_of_tries=1, 933 assert_on_fail=True): 934 """Toggle wifi state and then wait for Android device to reconnect to 935 the provided wifi network. 936 937 This expects the device to be already connected to the provided network. 938 939 Logic steps are 940 1. Ensure that we're connected to the network. 941 2. Turn wifi off. 942 3. Wait for 10 seconds. 943 4. Turn wifi on. 944 5. Wait for the "connected" event, then confirm the connected ssid is the 945 one requested. 946 947 Args: 948 ad: android_device object to initiate connection on. 949 network: A dictionary representing the network to await connection. The 950 dictionary must have the key "SSID". 951 num_of_tries: An integer that is the number of times to try before 952 delaring failure. Default is 1. 953 assert_on_fail: If True, error checks in this function will raise test 954 failure signals. 955 956 Returns: 957 If assert_on_fail is False, function returns True if the toggle was 958 successful, False otherwise. If assert_on_fail is True, no return value. 959 """ 960 return _assert_on_fail_handler( 961 _toggle_wifi_and_wait_for_reconnection, 962 assert_on_fail, 963 ad, 964 network, 965 num_of_tries=num_of_tries) 966 967 968def _toggle_wifi_and_wait_for_reconnection(ad, network, num_of_tries=1): 969 """Toggle wifi state and then wait for Android device to reconnect to 970 the provided wifi network. 971 972 This expects the device to be already connected to the provided network. 973 974 Logic steps are 975 1. Ensure that we're connected to the network. 976 2. Turn wifi off. 977 3. Wait for 10 seconds. 978 4. Turn wifi on. 979 5. Wait for the "connected" event, then confirm the connected ssid is the 980 one requested. 981 982 This will directly fail a test if anything goes wrong. 983 984 Args: 985 ad: android_device object to initiate connection on. 986 network: A dictionary representing the network to await connection. The 987 dictionary must have the key "SSID". 988 num_of_tries: An integer that is the number of times to try before 989 delaring failure. Default is 1. 990 """ 991 expected_ssid = network[WifiEnums.SSID_KEY] 992 # First ensure that we're already connected to the provided network. 993 verify_con = {WifiEnums.SSID_KEY: expected_ssid} 994 verify_wifi_connection_info(ad, verify_con) 995 # Now toggle wifi state and wait for the connection event. 996 wifi_toggle_state(ad, False) 997 time.sleep(10) 998 wifi_toggle_state(ad, True) 999 ad.droid.wifiStartTrackingStateChange() 1000 try: 1001 connect_result = None 1002 for i in range(num_of_tries): 1003 try: 1004 connect_result = ad.ed.pop_event(wifi_constants.WIFI_CONNECTED, 1005 30) 1006 break 1007 except Empty: 1008 pass 1009 asserts.assert_true(connect_result, 1010 "Failed to connect to Wi-Fi network %s on %s" % 1011 (network, ad.serial)) 1012 logging.debug("Connection result on %s: %s.", ad.serial, 1013 connect_result) 1014 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1015 asserts.assert_equal(actual_ssid, expected_ssid, 1016 "Connected to the wrong network on %s." 1017 "Expected %s, but got %s." % 1018 (ad.serial, expected_ssid, actual_ssid)) 1019 logging.info("Connected to Wi-Fi network %s on %s", actual_ssid, 1020 ad.serial) 1021 finally: 1022 ad.droid.wifiStopTrackingStateChange() 1023 1024 1025def wait_for_connect(ad, ssid=None, id=None, tries=1): 1026 """Wait for a connect event on queue and pop when available. 1027 1028 Args: 1029 ad: An Android device object. 1030 ssid: SSID of the network to connect to. 1031 id: Network Id of the network to connect to. 1032 tries: An integer that is the number of times to try before failing. 1033 1034 Returns: 1035 A dict with details of the connection data, which looks like this: 1036 { 1037 'time': 1485460337798, 1038 'name': 'WifiNetworkConnected', 1039 'data': { 1040 'rssi': -27, 1041 'is_24ghz': True, 1042 'mac_address': '02:00:00:00:00:00', 1043 'network_id': 1, 1044 'BSSID': '30:b5:c2:33:d3:fc', 1045 'ip_address': 117483712, 1046 'link_speed': 54, 1047 'supplicant_state': 'completed', 1048 'hidden_ssid': False, 1049 'SSID': 'wh_ap1_2g', 1050 'is_5ghz': False} 1051 } 1052 1053 """ 1054 conn_result = None 1055 1056 # If ssid and network id is None, just wait for any connect event. 1057 if id is None and ssid is None: 1058 for i in range(tries): 1059 try: 1060 conn_result = ad.ed.pop_event(wifi_constants.WIFI_CONNECTED, 30) 1061 break 1062 except Empty: 1063 pass 1064 else: 1065 # If ssid or network id is specified, wait for specific connect event. 1066 for i in range(tries): 1067 try: 1068 conn_result = ad.ed.pop_event(wifi_constants.WIFI_CONNECTED, 30) 1069 if id and conn_result['data'][WifiEnums.NETID_KEY] == id: 1070 break 1071 elif ssid and conn_result['data'][WifiEnums.SSID_KEY] == ssid: 1072 break 1073 except Empty: 1074 pass 1075 1076 return conn_result 1077 1078 1079def wait_for_disconnect(ad): 1080 """Wait for a Disconnect event from the supplicant. 1081 1082 Args: 1083 ad: Android device object. 1084 1085 """ 1086 try: 1087 ad.droid.wifiStartTrackingStateChange() 1088 event = ad.ed.pop_event("WifiNetworkDisconnected", 10) 1089 ad.droid.wifiStopTrackingStateChange() 1090 except Empty: 1091 raise signals.TestFailure("Device did not disconnect from the network") 1092 1093 1094def connect_to_wifi_network(ad, network, assert_on_fail=True, 1095 check_connectivity=True): 1096 """Connection logic for open and psk wifi networks. 1097 1098 Args: 1099 ad: AndroidDevice to use for connection 1100 network: network info of the network to connect to 1101 assert_on_fail: If true, errors from wifi_connect will raise 1102 test failure signals. 1103 """ 1104 start_wifi_connection_scan_and_ensure_network_found( 1105 ad, network[WifiEnums.SSID_KEY]) 1106 wifi_connect(ad, 1107 network, 1108 num_of_tries=3, 1109 assert_on_fail=assert_on_fail, 1110 check_connectivity=check_connectivity) 1111 1112 1113def connect_to_wifi_network_with_id(ad, network_id, network_ssid): 1114 """Connect to the given network using network id and verify SSID. 1115 1116 Args: 1117 network_id: int Network Id of the network. 1118 network_ssid: string SSID of the network. 1119 1120 Returns: True if connect using network id was successful; 1121 False otherwise. 1122 1123 """ 1124 start_wifi_connection_scan_and_ensure_network_found(ad, network_ssid) 1125 wifi_connect_by_id(ad, network_id) 1126 connect_data = ad.droid.wifiGetConnectionInfo() 1127 connect_ssid = connect_data[WifiEnums.SSID_KEY] 1128 ad.log.debug("Expected SSID = %s Connected SSID = %s" % 1129 (network_ssid, connect_ssid)) 1130 if connect_ssid != network_ssid: 1131 return False 1132 return True 1133 1134 1135def wifi_connect(ad, network, num_of_tries=1, assert_on_fail=True, 1136 check_connectivity=True): 1137 """Connect an Android device to a wifi network. 1138 1139 Initiate connection to a wifi network, wait for the "connected" event, then 1140 confirm the connected ssid is the one requested. 1141 1142 This will directly fail a test if anything goes wrong. 1143 1144 Args: 1145 ad: android_device object to initiate connection on. 1146 network: A dictionary representing the network to connect to. The 1147 dictionary must have the key "SSID". 1148 num_of_tries: An integer that is the number of times to try before 1149 delaring failure. Default is 1. 1150 assert_on_fail: If True, error checks in this function will raise test 1151 failure signals. 1152 1153 Returns: 1154 Returns a value only if assert_on_fail is false. 1155 Returns True if the connection was successful, False otherwise. 1156 """ 1157 return _assert_on_fail_handler( 1158 _wifi_connect, assert_on_fail, ad, network, num_of_tries=num_of_tries, 1159 check_connectivity=check_connectivity) 1160 1161 1162def _wifi_connect(ad, network, num_of_tries=1, check_connectivity=True): 1163 """Connect an Android device to a wifi network. 1164 1165 Initiate connection to a wifi network, wait for the "connected" event, then 1166 confirm the connected ssid is the one requested. 1167 1168 This will directly fail a test if anything goes wrong. 1169 1170 Args: 1171 ad: android_device object to initiate connection on. 1172 network: A dictionary representing the network to connect to. The 1173 dictionary must have the key "SSID". 1174 num_of_tries: An integer that is the number of times to try before 1175 delaring failure. Default is 1. 1176 """ 1177 asserts.assert_true(WifiEnums.SSID_KEY in network, 1178 "Key '%s' must be present in network definition." % 1179 WifiEnums.SSID_KEY) 1180 ad.droid.wifiStartTrackingStateChange() 1181 expected_ssid = network[WifiEnums.SSID_KEY] 1182 ad.droid.wifiConnectByConfig(network) 1183 ad.log.info("Starting connection process to %s", expected_ssid) 1184 try: 1185 event = ad.ed.pop_event(wifi_constants.CONNECT_BY_CONFIG_SUCCESS, 30) 1186 connect_result = wait_for_connect(ad, ssid=expected_ssid, tries=num_of_tries) 1187 asserts.assert_true(connect_result, 1188 "Failed to connect to Wi-Fi network %s on %s" % 1189 (network, ad.serial)) 1190 ad.log.debug("Wi-Fi connection result: %s.", connect_result) 1191 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1192 asserts.assert_equal(actual_ssid, expected_ssid, 1193 "Connected to the wrong network on %s." % 1194 ad.serial) 1195 ad.log.info("Connected to Wi-Fi network %s.", actual_ssid) 1196 1197 # Wait for data connection to stabilize. 1198 time.sleep(5) 1199 1200 if check_connectivity: 1201 internet = validate_connection(ad, DEFAULT_PING_ADDR) 1202 if not internet: 1203 raise signals.TestFailure("Failed to connect to internet on %s" % 1204 expected_ssid) 1205 except Empty: 1206 asserts.fail("Failed to start connection process to %s on %s" % 1207 (network, ad.serial)) 1208 except Exception as error: 1209 ad.log.error("Failed to connect to %s with error %s", expected_ssid, 1210 error) 1211 raise signals.TestFailure("Failed to connect to %s network" % network) 1212 1213 finally: 1214 ad.droid.wifiStopTrackingStateChange() 1215 1216 1217def wifi_connect_by_id(ad, network_id, num_of_tries=3, assert_on_fail=True): 1218 """Connect an Android device to a wifi network using network Id. 1219 1220 Start connection to the wifi network, with the given network Id, wait for 1221 the "connected" event, then verify the connected network is the one requested. 1222 1223 This will directly fail a test if anything goes wrong. 1224 1225 Args: 1226 ad: android_device object to initiate connection on. 1227 network_id: Integer specifying the network id of the network. 1228 num_of_tries: An integer that is the number of times to try before 1229 delaring failure. Default is 1. 1230 assert_on_fail: If True, error checks in this function will raise test 1231 failure signals. 1232 1233 Returns: 1234 Returns a value only if assert_on_fail is false. 1235 Returns True if the connection was successful, False otherwise. 1236 """ 1237 _assert_on_fail_handler(_wifi_connect_by_id, assert_on_fail, ad, 1238 network_id, num_of_tries) 1239 1240 1241def _wifi_connect_by_id(ad, network_id, num_of_tries=1): 1242 """Connect an Android device to a wifi network using it's network id. 1243 1244 Start connection to the wifi network, with the given network id, wait for 1245 the "connected" event, then verify the connected network is the one requested. 1246 1247 Args: 1248 ad: android_device object to initiate connection on. 1249 network_id: Integer specifying the network id of the network. 1250 num_of_tries: An integer that is the number of times to try before 1251 delaring failure. Default is 1. 1252 """ 1253 ad.droid.wifiStartTrackingStateChange() 1254 # Clear all previous events. 1255 ad.ed.clear_all_events() 1256 ad.droid.wifiConnectByNetworkId(network_id) 1257 ad.log.info("Starting connection to network with id %d", network_id) 1258 try: 1259 event = ad.ed.pop_event(wifi_constants.CONNECT_BY_NETID_SUCCESS, 60) 1260 connect_result = wait_for_connect(ad, id=network_id, tries=num_of_tries) 1261 asserts.assert_true(connect_result, 1262 "Failed to connect to Wi-Fi network using network id") 1263 ad.log.debug("Wi-Fi connection result: %s", connect_result) 1264 actual_id = connect_result['data'][WifiEnums.NETID_KEY] 1265 asserts.assert_equal(actual_id, network_id, 1266 "Connected to the wrong network on %s." 1267 "Expected network id = %d, but got %d." % 1268 (ad.serial, network_id, actual_id)) 1269 expected_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1270 ad.log.info("Connected to Wi-Fi network %s with %d network id.", 1271 expected_ssid, network_id) 1272 1273 # Wait for data connection to stabilize. 1274 time.sleep(5) 1275 1276 internet = validate_connection(ad, DEFAULT_PING_ADDR) 1277 if not internet: 1278 raise signals.TestFailure("Failed to connect to internet on %s" % 1279 expected_ssid) 1280 except Empty: 1281 asserts.fail("Failed to connect to network with id %d on %s" % 1282 (network_id, ad.serial)) 1283 except Exception as error: 1284 ad.log.error("Failed to connect to network with id %d with error %s", 1285 network_id, error) 1286 raise signals.TestFailure("Failed to connect to network with network" 1287 " id %d" % network_id) 1288 finally: 1289 ad.droid.wifiStopTrackingStateChange() 1290 1291 1292def wifi_passpoint_connect(ad, passpoint_network, num_of_tries=1, 1293 assert_on_fail=True): 1294 """Connect an Android device to a wifi network. 1295 1296 Initiate connection to a wifi network, wait for the "connected" event, then 1297 confirm the connected ssid is the one requested. 1298 1299 This will directly fail a test if anything goes wrong. 1300 1301 Args: 1302 ad: android_device object to initiate connection on. 1303 passpoint_network: SSID of the Passpoint network to connect to. 1304 num_of_tries: An integer that is the number of times to try before 1305 delaring failure. Default is 1. 1306 assert_on_fail: If True, error checks in this function will raise test 1307 failure signals. 1308 1309 Returns: 1310 If assert_on_fail is False, function returns network id, if the connect was 1311 successful, False otherwise. If assert_on_fail is True, no return value. 1312 """ 1313 _assert_on_fail_handler(_wifi_passpoint_connect, assert_on_fail, ad, 1314 passpoint_network, num_of_tries = num_of_tries) 1315 1316 1317def _wifi_passpoint_connect(ad, passpoint_network, num_of_tries=1): 1318 """Connect an Android device to a wifi network. 1319 1320 Initiate connection to a wifi network, wait for the "connected" event, then 1321 confirm the connected ssid is the one requested. 1322 1323 This will directly fail a test if anything goes wrong. 1324 1325 Args: 1326 ad: android_device object to initiate connection on. 1327 passpoint_network: SSID of the Passpoint network to connect to. 1328 num_of_tries: An integer that is the number of times to try before 1329 delaring failure. Default is 1. 1330 """ 1331 ad.droid.wifiStartTrackingStateChange() 1332 expected_ssid = passpoint_network 1333 ad.log.info("Starting connection process to passpoint %s", expected_ssid) 1334 1335 try: 1336 connect_result = wait_for_connect(ad, expected_ssid, num_of_tries) 1337 asserts.assert_true(connect_result, 1338 "Failed to connect to WiFi passpoint network %s on" 1339 " %s" % (expected_ssid, ad.serial)) 1340 ad.log.info("Wi-Fi connection result: %s.", connect_result) 1341 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1342 asserts.assert_equal(actual_ssid, expected_ssid, 1343 "Connected to the wrong network on %s." % ad.serial) 1344 ad.log.info("Connected to Wi-Fi passpoint network %s.", actual_ssid) 1345 1346 # Wait for data connection to stabilize. 1347 time.sleep(5) 1348 1349 internet = validate_connection(ad, DEFAULT_PING_ADDR) 1350 if not internet: 1351 raise signals.TestFailure("Failed to connect to internet on %s" % 1352 expected_ssid) 1353 except Exception as error: 1354 ad.log.error("Failed to connect to passpoint network %s with error %s", 1355 expected_ssid, error) 1356 raise signals.TestFailure("Failed to connect to %s passpoint network" % 1357 expected_ssid) 1358 1359 finally: 1360 ad.droid.wifiStopTrackingStateChange() 1361 1362 1363def delete_passpoint(ad, fqdn): 1364 """Delete a required Passpoint configuration.""" 1365 try: 1366 ad.droid.removePasspointConfig(fqdn) 1367 return True 1368 except Exception as error: 1369 ad.log.error("Failed to remove passpoint configuration with FQDN=%s " 1370 "and error=%s" , fqdn, error) 1371 return False 1372 1373 1374def start_wifi_single_scan(ad, scan_setting): 1375 """Starts wifi single shot scan. 1376 1377 Args: 1378 ad: android_device object to initiate connection on. 1379 scan_setting: A dict representing the settings of the scan. 1380 1381 Returns: 1382 If scan was started successfully, event data of success event is returned. 1383 """ 1384 idx = ad.droid.wifiScannerStartScan(scan_setting) 1385 event = ad.ed.pop_event("WifiScannerScan%sonSuccess" % idx, SHORT_TIMEOUT) 1386 ad.log.debug("Got event %s", event) 1387 return event['data'] 1388 1389 1390def track_connection(ad, network_ssid, check_connection_count): 1391 """Track wifi connection to network changes for given number of counts 1392 1393 Args: 1394 ad: android_device object for forget network. 1395 network_ssid: network ssid to which connection would be tracked 1396 check_connection_count: Integer for maximum number network connection 1397 check. 1398 Returns: 1399 True if connection to given network happen, else return False. 1400 """ 1401 ad.droid.wifiStartTrackingStateChange() 1402 while check_connection_count > 0: 1403 connect_network = ad.ed.pop_event("WifiNetworkConnected", 120) 1404 ad.log.info("Connected to network %s", connect_network) 1405 if (WifiEnums.SSID_KEY in connect_network['data'] and 1406 connect_network['data'][WifiEnums.SSID_KEY] == network_ssid): 1407 return True 1408 check_connection_count -= 1 1409 ad.droid.wifiStopTrackingStateChange() 1410 return False 1411 1412 1413def get_scan_time_and_channels(wifi_chs, scan_setting, stime_channel): 1414 """Calculate the scan time required based on the band or channels in scan 1415 setting 1416 1417 Args: 1418 wifi_chs: Object of channels supported 1419 scan_setting: scan setting used for start scan 1420 stime_channel: scan time per channel 1421 1422 Returns: 1423 scan_time: time required for completing a scan 1424 scan_channels: channel used for scanning 1425 """ 1426 scan_time = 0 1427 scan_channels = [] 1428 if "band" in scan_setting and "channels" not in scan_setting: 1429 scan_channels = wifi_chs.band_to_freq(scan_setting["band"]) 1430 elif "channels" in scan_setting and "band" not in scan_setting: 1431 scan_channels = scan_setting["channels"] 1432 scan_time = len(scan_channels) * stime_channel 1433 for channel in scan_channels: 1434 if channel in WifiEnums.DFS_5G_FREQUENCIES: 1435 scan_time += 132 #passive scan time on DFS 1436 return scan_time, scan_channels 1437 1438 1439def start_wifi_track_bssid(ad, track_setting): 1440 """Start tracking Bssid for the given settings. 1441 1442 Args: 1443 ad: android_device object. 1444 track_setting: Setting for which the bssid tracking should be started 1445 1446 Returns: 1447 If tracking started successfully, event data of success event is returned. 1448 """ 1449 idx = ad.droid.wifiScannerStartTrackingBssids( 1450 track_setting["bssidInfos"], track_setting["apLostThreshold"]) 1451 event = ad.ed.pop_event("WifiScannerBssid{}onSuccess".format(idx), 1452 SHORT_TIMEOUT) 1453 return event['data'] 1454 1455 1456def convert_pem_key_to_pkcs8(in_file, out_file): 1457 """Converts the key file generated by us to the format required by 1458 Android using openssl. 1459 1460 The input file must have the extension "pem". The output file must 1461 have the extension "der". 1462 1463 Args: 1464 in_file: The original key file. 1465 out_file: The full path to the converted key file, including 1466 filename. 1467 """ 1468 asserts.assert_true(in_file.endswith(".pem"), "Input file has to be .pem.") 1469 asserts.assert_true( 1470 out_file.endswith(".der"), "Output file has to be .der.") 1471 cmd = ("openssl pkcs8 -inform PEM -in {} -outform DER -out {} -nocrypt" 1472 " -topk8").format(in_file, out_file) 1473 utils.exe_cmd(cmd) 1474 1475 1476def validate_connection(ad, ping_addr=DEFAULT_PING_ADDR): 1477 """Validate internet connection by pinging the address provided. 1478 1479 Args: 1480 ad: android_device object. 1481 ping_addr: address on internet for pinging. 1482 1483 Returns: 1484 ping output if successful, NULL otherwise. 1485 """ 1486 ping = ad.droid.httpPing(ping_addr) 1487 ad.log.info("Http ping result: %s.", ping) 1488 return ping 1489 1490 1491#TODO(angli): This can only verify if an actual value is exactly the same. 1492# Would be nice to be able to verify an actual value is one of serveral. 1493def verify_wifi_connection_info(ad, expected_con): 1494 """Verifies that the information of the currently connected wifi network is 1495 as expected. 1496 1497 Args: 1498 expected_con: A dict representing expected key-value pairs for wifi 1499 connection. e.g. {"SSID": "test_wifi"} 1500 """ 1501 current_con = ad.droid.wifiGetConnectionInfo() 1502 case_insensitive = ["BSSID", "supplicant_state"] 1503 ad.log.debug("Current connection: %s", current_con) 1504 for k, expected_v in expected_con.items(): 1505 # Do not verify authentication related fields. 1506 if k == "password": 1507 continue 1508 msg = "Field %s does not exist in wifi connection info %s." % ( 1509 k, current_con) 1510 if k not in current_con: 1511 raise signals.TestFailure(msg) 1512 actual_v = current_con[k] 1513 if k in case_insensitive: 1514 actual_v = actual_v.lower() 1515 expected_v = expected_v.lower() 1516 msg = "Expected %s to be %s, actual %s is %s." % (k, expected_v, k, 1517 actual_v) 1518 if actual_v != expected_v: 1519 raise signals.TestFailure(msg) 1520 1521 1522def expand_enterprise_config_by_phase2(config): 1523 """Take an enterprise config and generate a list of configs, each with 1524 a different phase2 auth type. 1525 1526 Args: 1527 config: A dict representing enterprise config. 1528 1529 Returns 1530 A list of enterprise configs. 1531 """ 1532 results = [] 1533 phase2_types = WifiEnums.EapPhase2 1534 if config[WifiEnums.Enterprise.EAP] == WifiEnums.Eap.PEAP: 1535 # Skip unsupported phase2 types for PEAP. 1536 phase2_types = [WifiEnums.EapPhase2.GTC, WifiEnums.EapPhase2.MSCHAPV2] 1537 for phase2_type in phase2_types: 1538 # Skip a special case for passpoint TTLS. 1539 if (WifiEnums.Enterprise.FQDN in config and 1540 phase2_type == WifiEnums.EapPhase2.GTC): 1541 continue 1542 c = dict(config) 1543 c[WifiEnums.Enterprise.PHASE2] = phase2_type.value 1544 results.append(c) 1545 return results 1546 1547 1548def generate_eap_test_name(config, ad=None): 1549 """ Generates a test case name based on an EAP configuration. 1550 1551 Args: 1552 config: A dict representing an EAP credential. 1553 ad object: Redundant but required as the same param is passed 1554 to test_func in run_generated_tests 1555 1556 Returns: 1557 A string representing the name of a generated EAP test case. 1558 """ 1559 eap = WifiEnums.Eap 1560 eap_phase2 = WifiEnums.EapPhase2 1561 Ent = WifiEnums.Enterprise 1562 name = "test_connect-" 1563 eap_name = "" 1564 for e in eap: 1565 if e.value == config[Ent.EAP]: 1566 eap_name = e.name 1567 break 1568 if "peap0" in config[WifiEnums.SSID_KEY].lower(): 1569 eap_name = "PEAP0" 1570 if "peap1" in config[WifiEnums.SSID_KEY].lower(): 1571 eap_name = "PEAP1" 1572 name += eap_name 1573 if Ent.PHASE2 in config: 1574 for e in eap_phase2: 1575 if e.value == config[Ent.PHASE2]: 1576 name += "-{}".format(e.name) 1577 break 1578 return name 1579 1580 1581def group_attenuators(attenuators): 1582 """Groups a list of attenuators into attenuator groups for backward 1583 compatibility reasons. 1584 1585 Most legacy Wi-Fi setups have two attenuators each connected to a separate 1586 AP. The new Wi-Fi setup has four attenuators, each connected to one channel 1587 on an AP, so two of them are connected to one AP. 1588 1589 To make the existing scripts work in the new setup, when the script needs 1590 to attenuate one AP, it needs to set attenuation on both attenuators 1591 connected to the same AP. 1592 1593 This function groups attenuators properly so the scripts work in both 1594 legacy and new Wi-Fi setups. 1595 1596 Args: 1597 attenuators: A list of attenuator objects, either two or four in length. 1598 1599 Raises: 1600 signals.TestFailure is raised if the attenuator list does not have two 1601 or four objects. 1602 """ 1603 attn0 = attenuator.AttenuatorGroup("AP0") 1604 attn1 = attenuator.AttenuatorGroup("AP1") 1605 # Legacy testbed setup has two attenuation channels. 1606 num_of_attns = len(attenuators) 1607 if num_of_attns == 2: 1608 attn0.add(attenuators[0]) 1609 attn1.add(attenuators[1]) 1610 elif num_of_attns == 4: 1611 attn0.add(attenuators[0]) 1612 attn0.add(attenuators[1]) 1613 attn1.add(attenuators[2]) 1614 attn1.add(attenuators[3]) 1615 else: 1616 asserts.fail(("Either two or four attenuators are required for this " 1617 "test, but found %s") % num_of_attns) 1618 return [attn0, attn1] 1619 1620def set_attns(attenuator, attn_val_name): 1621 """Sets attenuation values on attenuators used in this test. 1622 1623 Args: 1624 attenuator: The attenuator object. 1625 attn_val_name: Name of the attenuation value pair to use. 1626 """ 1627 logging.info("Set attenuation values to %s", roaming_attn[attn_val_name]) 1628 try: 1629 attenuator[0].set_atten(roaming_attn[attn_val_name][0]) 1630 attenuator[1].set_atten(roaming_attn[attn_val_name][1]) 1631 attenuator[2].set_atten(roaming_attn[attn_val_name][2]) 1632 attenuator[3].set_atten(roaming_attn[attn_val_name][3]) 1633 except: 1634 logging.exception("Failed to set attenuation values %s.", 1635 attn_val_name) 1636 raise 1637 1638 1639def trigger_roaming_and_validate(dut, attenuator, attn_val_name, expected_con): 1640 """Sets attenuators to trigger roaming and validate the DUT connected 1641 to the BSSID expected. 1642 1643 Args: 1644 attenuator: The attenuator object. 1645 attn_val_name: Name of the attenuation value pair to use. 1646 expected_con: The network information of the expected network. 1647 """ 1648 expected_con = { 1649 WifiEnums.SSID_KEY: expected_con[WifiEnums.SSID_KEY], 1650 WifiEnums.BSSID_KEY: expected_con["bssid"], 1651 } 1652 set_attns(attenuator, attn_val_name) 1653 logging.info("Wait %ss for roaming to finish.", ROAMING_TIMEOUT) 1654 time.sleep(ROAMING_TIMEOUT) 1655 try: 1656 # Wakeup device and verify connection. 1657 dut.droid.wakeLockAcquireBright() 1658 dut.droid.wakeUpNow() 1659 cur_con = dut.droid.wifiGetConnectionInfo() 1660 verify_wifi_connection_info(dut, expected_con) 1661 expected_bssid = expected_con[WifiEnums.BSSID_KEY] 1662 logging.info("Roamed to %s successfully", expected_bssid) 1663 if not validate_connection(dut): 1664 raise signals.TestFailure("Fail to connect to internet on %s" % 1665 expected_ssid) 1666 finally: 1667 dut.droid.wifiLockRelease() 1668 dut.droid.goToSleepNow() 1669 1670 1671def create_softap_config(): 1672 """Create a softap config with random ssid and password.""" 1673 ap_ssid = "softap_" + utils.rand_ascii_str(8) 1674 ap_password = utils.rand_ascii_str(8) 1675 logging.info("softap setup: %s %s", ap_ssid, ap_password) 1676 config = { 1677 WifiEnums.SSID_KEY: ap_ssid, 1678 WifiEnums.PWD_KEY: ap_password, 1679 } 1680 return config 1681