1#!/usr/bin/env python3 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 os 19import shutil 20import time 21 22from collections import namedtuple 23from enum import IntEnum 24from queue import Empty 25 26from acts import asserts 27from acts import context 28from acts import signals 29from acts import utils 30from acts.controllers import attenuator 31from acts.controllers.ap_lib import hostapd_security 32from acts.controllers.ap_lib import hostapd_ap_preset 33from acts.controllers.ap_lib.hostapd_constants import BAND_2G 34from acts.controllers.ap_lib.hostapd_constants import BAND_5G 35from acts.test_utils.wifi import wifi_constants 36from acts.test_utils.tel import tel_defines 37 38# Default timeout used for reboot, toggle WiFi and Airplane mode, 39# for the system to settle down after the operation. 40DEFAULT_TIMEOUT = 10 41# Number of seconds to wait for events that are supposed to happen quickly. 42# Like onSuccess for start background scan and confirmation on wifi state 43# change. 44SHORT_TIMEOUT = 30 45ROAMING_TIMEOUT = 30 46WIFI_CONNECTION_TIMEOUT_DEFAULT = 30 47WIFI_ABNORMAL_CONNECTION_TIME = 10 48# Speed of light in m/s. 49SPEED_OF_LIGHT = 299792458 50 51DEFAULT_PING_ADDR = "https://www.google.com/robots.txt" 52 53roaming_attn = { 54 "AP1_on_AP2_off": [ 55 0, 56 0, 57 95, 58 95 59 ], 60 "AP1_off_AP2_on": [ 61 95, 62 95, 63 0, 64 0 65 ], 66 "default": [ 67 0, 68 0, 69 0, 70 0 71 ] 72 } 73 74 75class WifiEnums(): 76 77 SSID_KEY = "SSID" 78 SSID_PATTERN_KEY = "ssidPattern" 79 NETID_KEY = "network_id" 80 BSSID_KEY = "BSSID" 81 BSSID_PATTERN_KEY = "bssidPattern" 82 PWD_KEY = "password" 83 frequency_key = "frequency" 84 APBAND_KEY = "apBand" 85 HIDDEN_KEY = "hiddenSSID" 86 IS_APP_INTERACTION_REQUIRED = "isAppInteractionRequired" 87 IS_USER_INTERACTION_REQUIRED = "isUserInteractionRequired" 88 IS_METERED = "isMetered" 89 PRIORITY = "priority" 90 SECURITY = "security" 91 92 WIFI_CONFIG_APBAND_2G = 0 93 WIFI_CONFIG_APBAND_5G = 1 94 WIFI_CONFIG_APBAND_AUTO = -1 95 96 WIFI_WPS_INFO_PBC = 0 97 WIFI_WPS_INFO_DISPLAY = 1 98 WIFI_WPS_INFO_KEYPAD = 2 99 WIFI_WPS_INFO_LABEL = 3 100 WIFI_WPS_INFO_INVALID = 4 101 102 class CountryCode(): 103 CHINA = "CN" 104 JAPAN = "JP" 105 UK = "GB" 106 US = "US" 107 UNKNOWN = "UNKNOWN" 108 109 # Start of Macros for EAP 110 # EAP types 111 class Eap(IntEnum): 112 NONE = -1 113 PEAP = 0 114 TLS = 1 115 TTLS = 2 116 PWD = 3 117 SIM = 4 118 AKA = 5 119 AKA_PRIME = 6 120 UNAUTH_TLS = 7 121 122 # EAP Phase2 types 123 class EapPhase2(IntEnum): 124 NONE = 0 125 PAP = 1 126 MSCHAP = 2 127 MSCHAPV2 = 3 128 GTC = 4 129 130 class Enterprise: 131 # Enterprise Config Macros 132 EMPTY_VALUE = "NULL" 133 EAP = "eap" 134 PHASE2 = "phase2" 135 IDENTITY = "identity" 136 ANON_IDENTITY = "anonymous_identity" 137 PASSWORD = "password" 138 SUBJECT_MATCH = "subject_match" 139 ALTSUBJECT_MATCH = "altsubject_match" 140 DOM_SUFFIX_MATCH = "domain_suffix_match" 141 CLIENT_CERT = "client_cert" 142 CA_CERT = "ca_cert" 143 ENGINE = "engine" 144 ENGINE_ID = "engine_id" 145 PRIVATE_KEY_ID = "key_id" 146 REALM = "realm" 147 PLMN = "plmn" 148 FQDN = "FQDN" 149 FRIENDLY_NAME = "providerFriendlyName" 150 ROAMING_IDS = "roamingConsortiumIds" 151 # End of Macros for EAP 152 153 # Macros for wifi p2p. 154 WIFI_P2P_SERVICE_TYPE_ALL = 0 155 WIFI_P2P_SERVICE_TYPE_BONJOUR = 1 156 WIFI_P2P_SERVICE_TYPE_UPNP = 2 157 WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255 158 159 class ScanResult: 160 CHANNEL_WIDTH_20MHZ = 0 161 CHANNEL_WIDTH_40MHZ = 1 162 CHANNEL_WIDTH_80MHZ = 2 163 CHANNEL_WIDTH_160MHZ = 3 164 CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4 165 166 # Macros for wifi rtt. 167 class RttType(IntEnum): 168 TYPE_ONE_SIDED = 1 169 TYPE_TWO_SIDED = 2 170 171 class RttPeerType(IntEnum): 172 PEER_TYPE_AP = 1 173 PEER_TYPE_STA = 2 # Requires NAN. 174 PEER_P2P_GO = 3 175 PEER_P2P_CLIENT = 4 176 PEER_NAN = 5 177 178 class RttPreamble(IntEnum): 179 PREAMBLE_LEGACY = 0x01 180 PREAMBLE_HT = 0x02 181 PREAMBLE_VHT = 0x04 182 183 class RttBW(IntEnum): 184 BW_5_SUPPORT = 0x01 185 BW_10_SUPPORT = 0x02 186 BW_20_SUPPORT = 0x04 187 BW_40_SUPPORT = 0x08 188 BW_80_SUPPORT = 0x10 189 BW_160_SUPPORT = 0x20 190 191 class Rtt(IntEnum): 192 STATUS_SUCCESS = 0 193 STATUS_FAILURE = 1 194 STATUS_FAIL_NO_RSP = 2 195 STATUS_FAIL_REJECTED = 3 196 STATUS_FAIL_NOT_SCHEDULED_YET = 4 197 STATUS_FAIL_TM_TIMEOUT = 5 198 STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6 199 STATUS_FAIL_NO_CAPABILITY = 7 200 STATUS_ABORTED = 8 201 STATUS_FAIL_INVALID_TS = 9 202 STATUS_FAIL_PROTOCOL = 10 203 STATUS_FAIL_SCHEDULE = 11 204 STATUS_FAIL_BUSY_TRY_LATER = 12 205 STATUS_INVALID_REQ = 13 206 STATUS_NO_WIFI = 14 207 STATUS_FAIL_FTM_PARAM_OVERRIDE = 15 208 209 REASON_UNSPECIFIED = -1 210 REASON_NOT_AVAILABLE = -2 211 REASON_INVALID_LISTENER = -3 212 REASON_INVALID_REQUEST = -4 213 214 class RttParam: 215 device_type = "deviceType" 216 request_type = "requestType" 217 BSSID = "bssid" 218 channel_width = "channelWidth" 219 frequency = "frequency" 220 center_freq0 = "centerFreq0" 221 center_freq1 = "centerFreq1" 222 number_burst = "numberBurst" 223 interval = "interval" 224 num_samples_per_burst = "numSamplesPerBurst" 225 num_retries_per_measurement_frame = "numRetriesPerMeasurementFrame" 226 num_retries_per_FTMR = "numRetriesPerFTMR" 227 lci_request = "LCIRequest" 228 lcr_request = "LCRRequest" 229 burst_timeout = "burstTimeout" 230 preamble = "preamble" 231 bandwidth = "bandwidth" 232 margin = "margin" 233 234 RTT_MARGIN_OF_ERROR = { 235 RttBW.BW_80_SUPPORT: 2, 236 RttBW.BW_40_SUPPORT: 5, 237 RttBW.BW_20_SUPPORT: 5 238 } 239 240 # Macros as specified in the WifiScanner code. 241 WIFI_BAND_UNSPECIFIED = 0 # not specified 242 WIFI_BAND_24_GHZ = 1 # 2.4 GHz band 243 WIFI_BAND_5_GHZ = 2 # 5 GHz band without DFS channels 244 WIFI_BAND_5_GHZ_DFS_ONLY = 4 # 5 GHz band with DFS channels 245 WIFI_BAND_5_GHZ_WITH_DFS = 6 # 5 GHz band with DFS channels 246 WIFI_BAND_BOTH = 3 # both bands without DFS channels 247 WIFI_BAND_BOTH_WITH_DFS = 7 # both bands with DFS channels 248 249 REPORT_EVENT_AFTER_BUFFER_FULL = 0 250 REPORT_EVENT_AFTER_EACH_SCAN = 1 251 REPORT_EVENT_FULL_SCAN_RESULT = 2 252 253 SCAN_TYPE_LOW_LATENCY = 0 254 SCAN_TYPE_LOW_POWER = 1 255 SCAN_TYPE_HIGH_ACCURACY = 2 256 257 # US Wifi frequencies 258 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 259 2457, 2462] 260 DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 261 5600, 5620, 5640, 5660, 5680, 5700, 5720] 262 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 263 5825] 264 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 265 266 band_to_frequencies = { 267 WIFI_BAND_24_GHZ: ALL_2G_FREQUENCIES, 268 WIFI_BAND_5_GHZ: NONE_DFS_5G_FREQUENCIES, 269 WIFI_BAND_5_GHZ_DFS_ONLY: DFS_5G_FREQUENCIES, 270 WIFI_BAND_5_GHZ_WITH_DFS: ALL_5G_FREQUENCIES, 271 WIFI_BAND_BOTH: ALL_2G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES, 272 WIFI_BAND_BOTH_WITH_DFS: ALL_5G_FREQUENCIES + ALL_2G_FREQUENCIES 273 } 274 275 # All Wifi frequencies to channels lookup. 276 freq_to_channel = { 277 2412: 1, 278 2417: 2, 279 2422: 3, 280 2427: 4, 281 2432: 5, 282 2437: 6, 283 2442: 7, 284 2447: 8, 285 2452: 9, 286 2457: 10, 287 2462: 11, 288 2467: 12, 289 2472: 13, 290 2484: 14, 291 4915: 183, 292 4920: 184, 293 4925: 185, 294 4935: 187, 295 4940: 188, 296 4945: 189, 297 4960: 192, 298 4980: 196, 299 5035: 7, 300 5040: 8, 301 5045: 9, 302 5055: 11, 303 5060: 12, 304 5080: 16, 305 5170: 34, 306 5180: 36, 307 5190: 38, 308 5200: 40, 309 5210: 42, 310 5220: 44, 311 5230: 46, 312 5240: 48, 313 5260: 52, 314 5280: 56, 315 5300: 60, 316 5320: 64, 317 5500: 100, 318 5520: 104, 319 5540: 108, 320 5560: 112, 321 5580: 116, 322 5600: 120, 323 5620: 124, 324 5640: 128, 325 5660: 132, 326 5680: 136, 327 5700: 140, 328 5745: 149, 329 5765: 153, 330 5785: 157, 331 5805: 161, 332 5825: 165, 333 } 334 335 # All Wifi channels to frequencies lookup. 336 channel_2G_to_freq = { 337 1: 2412, 338 2: 2417, 339 3: 2422, 340 4: 2427, 341 5: 2432, 342 6: 2437, 343 7: 2442, 344 8: 2447, 345 9: 2452, 346 10: 2457, 347 11: 2462, 348 12: 2467, 349 13: 2472, 350 14: 2484 351 } 352 353 channel_5G_to_freq = { 354 183: 4915, 355 184: 4920, 356 185: 4925, 357 187: 4935, 358 188: 4940, 359 189: 4945, 360 192: 4960, 361 196: 4980, 362 7: 5035, 363 8: 5040, 364 9: 5045, 365 11: 5055, 366 12: 5060, 367 16: 5080, 368 34: 5170, 369 36: 5180, 370 38: 5190, 371 40: 5200, 372 42: 5210, 373 44: 5220, 374 46: 5230, 375 48: 5240, 376 52: 5260, 377 56: 5280, 378 60: 5300, 379 64: 5320, 380 100: 5500, 381 104: 5520, 382 108: 5540, 383 112: 5560, 384 116: 5580, 385 120: 5600, 386 124: 5620, 387 128: 5640, 388 132: 5660, 389 136: 5680, 390 140: 5700, 391 149: 5745, 392 153: 5765, 393 157: 5785, 394 161: 5805, 395 165: 5825 396 } 397 398 399class WifiChannelBase: 400 ALL_2G_FREQUENCIES = [] 401 DFS_5G_FREQUENCIES = [] 402 NONE_DFS_5G_FREQUENCIES = [] 403 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 404 MIX_CHANNEL_SCAN = [] 405 406 def band_to_freq(self, band): 407 _band_to_frequencies = { 408 WifiEnums.WIFI_BAND_24_GHZ: self.ALL_2G_FREQUENCIES, 409 WifiEnums.WIFI_BAND_5_GHZ: self.NONE_DFS_5G_FREQUENCIES, 410 WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY: self.DFS_5G_FREQUENCIES, 411 WifiEnums.WIFI_BAND_5_GHZ_WITH_DFS: self.ALL_5G_FREQUENCIES, 412 WifiEnums.WIFI_BAND_BOTH: 413 self.ALL_2G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES, 414 WifiEnums.WIFI_BAND_BOTH_WITH_DFS: 415 self.ALL_5G_FREQUENCIES + self.ALL_2G_FREQUENCIES 416 } 417 return _band_to_frequencies[band] 418 419 420class WifiChannelUS(WifiChannelBase): 421 # US Wifi frequencies 422 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 423 2457, 2462] 424 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 425 5825] 426 MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5280, 5260, 5300, 5500, 427 5320, 5520, 5560, 5700, 5745, 5805] 428 429 def __init__(self, model=None): 430 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 431 5540, 5560, 5580, 5600, 5620, 5640, 432 5660, 5680, 5700, 5720] 433 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 434 435 436class WifiReferenceNetworks: 437 """ Class to parse and return networks of different band and 438 auth type from reference_networks 439 """ 440 def __init__(self, obj): 441 self.reference_networks = obj 442 self.WIFI_2G = "2g" 443 self.WIFI_5G = "5g" 444 445 self.secure_networks_2g = [] 446 self.secure_networks_5g = [] 447 self.open_networks_2g = [] 448 self.open_networks_5g = [] 449 self._parse_networks() 450 451 def _parse_networks(self): 452 for network in self.reference_networks: 453 for key in network: 454 if key == self.WIFI_2G: 455 if "password" in network[key]: 456 self.secure_networks_2g.append(network[key]) 457 else: 458 self.open_networks_2g.append(network[key]) 459 else: 460 if "password" in network[key]: 461 self.secure_networks_5g.append(network[key]) 462 else: 463 self.open_networks_5g.append(network[key]) 464 465 def return_2g_secure_networks(self): 466 return self.secure_networks_2g 467 468 def return_5g_secure_networks(self): 469 return self.secure_networks_5g 470 471 def return_2g_open_networks(self): 472 return self.open_networks_2g 473 474 def return_5g_open_networks(self): 475 return self.open_networks_5g 476 477 def return_secure_networks(self): 478 return self.secure_networks_2g + self.secure_networks_5g 479 480 def return_open_networks(self): 481 return self.open_networks_2g + self.open_networks_5g 482 483 484def _assert_on_fail_handler(func, assert_on_fail, *args, **kwargs): 485 """Wrapper function that handles the bahevior of assert_on_fail. 486 487 When assert_on_fail is True, let all test signals through, which can 488 terminate test cases directly. When assert_on_fail is False, the wrapper 489 raises no test signals and reports operation status by returning True or 490 False. 491 492 Args: 493 func: The function to wrap. This function reports operation status by 494 raising test signals. 495 assert_on_fail: A boolean that specifies if the output of the wrapper 496 is test signal based or return value based. 497 args: Positional args for func. 498 kwargs: Name args for func. 499 500 Returns: 501 If assert_on_fail is True, returns True/False to signal operation 502 status, otherwise return nothing. 503 """ 504 try: 505 func(*args, **kwargs) 506 if not assert_on_fail: 507 return True 508 except signals.TestSignal: 509 if assert_on_fail: 510 raise 511 return False 512 513 514def assert_network_in_list(target, network_list): 515 """Makes sure a specified target Wi-Fi network exists in a list of Wi-Fi 516 networks. 517 518 Args: 519 target: A dict representing a Wi-Fi network. 520 E.g. {WifiEnums.SSID_KEY: "SomeNetwork"} 521 network_list: A list of dicts, each representing a Wi-Fi network. 522 """ 523 match_results = match_networks(target, network_list) 524 asserts.assert_true( 525 match_results, "Target network %s, does not exist in network list %s" % 526 (target, network_list)) 527 528 529def match_networks(target_params, networks): 530 """Finds the WiFi networks that match a given set of parameters in a list 531 of WiFi networks. 532 533 To be considered a match, the network should contain every key-value pair 534 of target_params 535 536 Args: 537 target_params: A dict with 1 or more key-value pairs representing a Wi-Fi network. 538 E.g { 'SSID': 'wh_ap1_5g', 'BSSID': '30:b5:c2:33:e4:47' } 539 networks: A list of dict objects representing WiFi networks. 540 541 Returns: 542 The networks that match the target parameters. 543 """ 544 results = [] 545 asserts.assert_true(target_params, 546 "Expected networks object 'target_params' is empty") 547 for n in networks: 548 add_network = 1 549 for k, v in target_params.items(): 550 if k not in n: 551 add_network = 0 552 break 553 if n[k] != v: 554 add_network = 0 555 break 556 if add_network: 557 results.append(n) 558 return results 559 560 561def wait_for_wifi_state(ad, state, assert_on_fail=True): 562 """Waits for the device to transition to the specified wifi state 563 564 Args: 565 ad: An AndroidDevice object. 566 state: Wifi state to wait for. 567 assert_on_fail: If True, error checks in this function will raise test 568 failure signals. 569 570 Returns: 571 If assert_on_fail is False, function returns True if the device transitions 572 to the specified state, False otherwise. If assert_on_fail is True, no return value. 573 """ 574 return _assert_on_fail_handler( 575 _wait_for_wifi_state, assert_on_fail, ad, state=state) 576 577 578def _wait_for_wifi_state(ad, state): 579 """Toggles the state of wifi. 580 581 TestFailure signals are raised when something goes wrong. 582 583 Args: 584 ad: An AndroidDevice object. 585 state: Wifi state to wait for. 586 """ 587 if state == ad.droid.wifiCheckState(): 588 # Check if the state is already achieved, so we don't wait for the 589 # state change event by mistake. 590 return 591 ad.droid.wifiStartTrackingStateChange() 592 fail_msg = "Device did not transition to Wi-Fi state to %s on %s." % (state, 593 ad.serial) 594 try: 595 ad.ed.wait_for_event(wifi_constants.WIFI_STATE_CHANGED, 596 lambda x: x["data"]["enabled"] == state, 597 SHORT_TIMEOUT) 598 except Empty: 599 asserts.assert_equal(state, ad.droid.wifiCheckState(), fail_msg) 600 finally: 601 ad.droid.wifiStopTrackingStateChange() 602 603 604def wifi_toggle_state(ad, new_state=None, assert_on_fail=True): 605 """Toggles the state of wifi. 606 607 Args: 608 ad: An AndroidDevice object. 609 new_state: Wifi state to set to. If None, opposite of the current state. 610 assert_on_fail: If True, error checks in this function will raise test 611 failure signals. 612 613 Returns: 614 If assert_on_fail is False, function returns True if the toggle was 615 successful, False otherwise. If assert_on_fail is True, no return value. 616 """ 617 return _assert_on_fail_handler( 618 _wifi_toggle_state, assert_on_fail, ad, new_state=new_state) 619 620 621def _wifi_toggle_state(ad, new_state=None): 622 """Toggles the state of wifi. 623 624 TestFailure signals are raised when something goes wrong. 625 626 Args: 627 ad: An AndroidDevice object. 628 new_state: The state to set Wi-Fi to. If None, opposite of the current 629 state will be set. 630 """ 631 if new_state is None: 632 new_state = not ad.droid.wifiCheckState() 633 elif new_state == ad.droid.wifiCheckState(): 634 # Check if the new_state is already achieved, so we don't wait for the 635 # state change event by mistake. 636 return 637 ad.droid.wifiStartTrackingStateChange() 638 ad.log.info("Setting Wi-Fi state to %s.", new_state) 639 ad.ed.clear_all_events() 640 # Setting wifi state. 641 ad.droid.wifiToggleState(new_state) 642 fail_msg = "Failed to set Wi-Fi state to %s on %s." % (new_state, 643 ad.serial) 644 try: 645 ad.ed.wait_for_event(wifi_constants.WIFI_STATE_CHANGED, 646 lambda x: x["data"]["enabled"] == new_state, 647 SHORT_TIMEOUT) 648 except Empty: 649 asserts.assert_equal(new_state, ad.droid.wifiCheckState(), fail_msg) 650 finally: 651 ad.droid.wifiStopTrackingStateChange() 652 653 654def reset_wifi(ad): 655 """Clears all saved Wi-Fi networks on a device. 656 657 This will turn Wi-Fi on. 658 659 Args: 660 ad: An AndroidDevice object. 661 662 """ 663 networks = ad.droid.wifiGetConfiguredNetworks() 664 if not networks: 665 return 666 for n in networks: 667 ad.droid.wifiForgetNetwork(n['networkId']) 668 try: 669 event = ad.ed.pop_event(wifi_constants.WIFI_FORGET_NW_SUCCESS, 670 SHORT_TIMEOUT) 671 except Empty: 672 logging.warning("Could not confirm the removal of network %s.", n) 673 # Check again to see if there's any network left. 674 asserts.assert_true( 675 not ad.droid.wifiGetConfiguredNetworks(), 676 "Failed to remove these configured Wi-Fi networks: %s" % networks) 677 678 679def toggle_airplane_mode_on_and_off(ad): 680 """Turn ON and OFF Airplane mode. 681 682 ad: An AndroidDevice object. 683 Returns: Assert if turning on/off Airplane mode fails. 684 685 """ 686 ad.log.debug("Toggling Airplane mode ON.") 687 asserts.assert_true( 688 utils.force_airplane_mode(ad, True), 689 "Can not turn on airplane mode on: %s" % ad.serial) 690 time.sleep(DEFAULT_TIMEOUT) 691 ad.log.debug("Toggling Airplane mode OFF.") 692 asserts.assert_true( 693 utils.force_airplane_mode(ad, False), 694 "Can not turn on airplane mode on: %s" % ad.serial) 695 time.sleep(DEFAULT_TIMEOUT) 696 697 698def toggle_wifi_off_and_on(ad): 699 """Turn OFF and ON WiFi. 700 701 ad: An AndroidDevice object. 702 Returns: Assert if turning off/on WiFi fails. 703 704 """ 705 ad.log.debug("Toggling wifi OFF.") 706 wifi_toggle_state(ad, False) 707 time.sleep(DEFAULT_TIMEOUT) 708 ad.log.debug("Toggling wifi ON.") 709 wifi_toggle_state(ad, True) 710 time.sleep(DEFAULT_TIMEOUT) 711 712 713def wifi_forget_network(ad, net_ssid): 714 """Remove configured Wifi network on an android device. 715 716 Args: 717 ad: android_device object for forget network. 718 net_ssid: ssid of network to be forget 719 720 """ 721 networks = ad.droid.wifiGetConfiguredNetworks() 722 if not networks: 723 return 724 for n in networks: 725 if net_ssid in n[WifiEnums.SSID_KEY]: 726 ad.droid.wifiForgetNetwork(n['networkId']) 727 try: 728 event = ad.ed.pop_event(wifi_constants.WIFI_FORGET_NW_SUCCESS, 729 SHORT_TIMEOUT) 730 except Empty: 731 asserts.fail("Failed to remove network %s." % n) 732 733 734def wifi_test_device_init(ad): 735 """Initializes an android device for wifi testing. 736 737 0. Make sure SL4A connection is established on the android device. 738 1. Disable location service's WiFi scan. 739 2. Turn WiFi on. 740 3. Clear all saved networks. 741 4. Set country code to US. 742 5. Enable WiFi verbose logging. 743 6. Sync device time with computer time. 744 7. Turn off cellular data. 745 8. Turn off ambient display. 746 """ 747 utils.require_sl4a((ad, )) 748 ad.droid.wifiScannerToggleAlwaysAvailable(False) 749 msg = "Failed to turn off location service's scan." 750 asserts.assert_true(not ad.droid.wifiScannerIsAlwaysAvailable(), msg) 751 wifi_toggle_state(ad, True) 752 reset_wifi(ad) 753 ad.droid.wifiEnableVerboseLogging(1) 754 msg = "Failed to enable WiFi verbose logging." 755 asserts.assert_equal(ad.droid.wifiGetVerboseLoggingLevel(), 1, msg) 756 # We don't verify the following settings since they are not critical. 757 # Set wpa_supplicant log level to EXCESSIVE. 758 output = ad.adb.shell("wpa_cli -i wlan0 -p -g@android:wpa_wlan0 IFNAME=" 759 "wlan0 log_level EXCESSIVE") 760 ad.log.info("wpa_supplicant log change status: %s", output) 761 utils.sync_device_time(ad) 762 ad.droid.telephonyToggleDataConnection(False) 763 # TODO(angli): need to verify the country code was actually set. No generic 764 # way to check right now. 765 ad.adb.shell("halutil -country %s" % WifiEnums.CountryCode.US) 766 utils.set_ambient_display(ad, False) 767 768 769def start_wifi_connection_scan(ad): 770 """Starts a wifi connection scan and wait for results to become available. 771 772 Args: 773 ad: An AndroidDevice object. 774 """ 775 ad.ed.clear_all_events() 776 ad.droid.wifiStartScan() 777 try: 778 ad.ed.pop_event("WifiManagerScanResultsAvailable", 60) 779 except Empty: 780 asserts.fail("Wi-Fi results did not become available within 60s.") 781 782 783def start_wifi_connection_scan_and_return_status(ad): 784 """ 785 Starts a wifi connection scan and wait for results to become available 786 or a scan failure to be reported. 787 788 Args: 789 ad: An AndroidDevice object. 790 Returns: 791 True: if scan succeeded & results are available 792 False: if scan failed 793 """ 794 ad.ed.clear_all_events() 795 ad.droid.wifiStartScan() 796 try: 797 events = ad.ed.pop_events( 798 "WifiManagerScan(ResultsAvailable|Failure)", 60) 799 except Empty: 800 asserts.fail( 801 "Wi-Fi scan results/failure did not become available within 60s.") 802 # If there are multiple matches, we check for atleast one success. 803 for event in events: 804 if event["name"] == "WifiManagerScanResultsAvailable": 805 return True 806 elif event["name"] == "WifiManagerScanFailure": 807 ad.log.debug("Scan failure received") 808 return False 809 810 811def start_wifi_connection_scan_and_check_for_network(ad, network_ssid, 812 max_tries=3): 813 """ 814 Start connectivity scans & checks if the |network_ssid| is seen in 815 scan results. The method performs a max of |max_tries| connectivity scans 816 to find the network. 817 818 Args: 819 ad: An AndroidDevice object. 820 network_ssid: SSID of the network we are looking for. 821 max_tries: Number of scans to try. 822 Returns: 823 True: if network_ssid is found in scan results. 824 False: if network_ssid is not found in scan results. 825 """ 826 for num_tries in range(max_tries): 827 if start_wifi_connection_scan_and_return_status(ad): 828 scan_results = ad.droid.wifiGetScanResults() 829 match_results = match_networks( 830 {WifiEnums.SSID_KEY: network_ssid}, scan_results) 831 if len(match_results) > 0: 832 return True 833 return False 834 835 836def start_wifi_connection_scan_and_ensure_network_found(ad, network_ssid, 837 max_tries=3): 838 """ 839 Start connectivity scans & ensure the |network_ssid| is seen in 840 scan results. The method performs a max of |max_tries| connectivity scans 841 to find the network. 842 This method asserts on failure! 843 844 Args: 845 ad: An AndroidDevice object. 846 network_ssid: SSID of the network we are looking for. 847 max_tries: Number of scans to try. 848 """ 849 ad.log.info("Starting scans to ensure %s is present", network_ssid) 850 assert_msg = "Failed to find " + network_ssid + " in scan results" \ 851 " after " + str(max_tries) + " tries" 852 asserts.assert_true(start_wifi_connection_scan_and_check_for_network( 853 ad, network_ssid, max_tries), assert_msg) 854 855 856def start_wifi_connection_scan_and_ensure_network_not_found(ad, network_ssid, 857 max_tries=3): 858 """ 859 Start connectivity scans & ensure the |network_ssid| is not seen in 860 scan results. The method performs a max of |max_tries| connectivity scans 861 to find the network. 862 This method asserts on failure! 863 864 Args: 865 ad: An AndroidDevice object. 866 network_ssid: SSID of the network we are looking for. 867 max_tries: Number of scans to try. 868 """ 869 ad.log.info("Starting scans to ensure %s is not present", network_ssid) 870 assert_msg = "Found " + network_ssid + " in scan results" \ 871 " after " + str(max_tries) + " tries" 872 asserts.assert_false(start_wifi_connection_scan_and_check_for_network( 873 ad, network_ssid, max_tries), assert_msg) 874 875 876def start_wifi_background_scan(ad, scan_setting): 877 """Starts wifi background scan. 878 879 Args: 880 ad: android_device object to initiate connection on. 881 scan_setting: A dict representing the settings of the scan. 882 883 Returns: 884 If scan was started successfully, event data of success event is returned. 885 """ 886 idx = ad.droid.wifiScannerStartBackgroundScan(scan_setting) 887 event = ad.ed.pop_event("WifiScannerScan{}onSuccess".format(idx), 888 SHORT_TIMEOUT) 889 return event['data'] 890 891 892def start_wifi_tethering(ad, ssid, password, band=None, hidden=None): 893 """Starts wifi tethering on an android_device. 894 895 Args: 896 ad: android_device to start wifi tethering on. 897 ssid: The SSID the soft AP should broadcast. 898 password: The password the soft AP should use. 899 band: The band the soft AP should be set on. It should be either 900 WifiEnums.WIFI_CONFIG_APBAND_2G or WifiEnums.WIFI_CONFIG_APBAND_5G. 901 hidden: boolean to indicate if the AP needs to be hidden or not. 902 903 Returns: 904 No return value. Error checks in this function will raise test failure signals 905 """ 906 config = {WifiEnums.SSID_KEY: ssid} 907 if password: 908 config[WifiEnums.PWD_KEY] = password 909 if band: 910 config[WifiEnums.APBAND_KEY] = band 911 if hidden: 912 config[WifiEnums.HIDDEN_KEY] = hidden 913 asserts.assert_true( 914 ad.droid.wifiSetWifiApConfiguration(config), 915 "Failed to update WifiAp Configuration") 916 ad.droid.wifiStartTrackingTetherStateChange() 917 ad.droid.connectivityStartTethering(tel_defines.TETHERING_WIFI, False) 918 try: 919 ad.ed.pop_event("ConnectivityManagerOnTetheringStarted") 920 ad.ed.wait_for_event("TetherStateChanged", 921 lambda x: x["data"]["ACTIVE_TETHER"], 30) 922 ad.log.debug("Tethering started successfully.") 923 except Empty: 924 msg = "Failed to receive confirmation of wifi tethering starting" 925 asserts.fail(msg) 926 finally: 927 ad.droid.wifiStopTrackingTetherStateChange() 928 929 930def save_wifi_soft_ap_config(ad, wifi_config, band=None, hidden=None): 931 """ Save a soft ap configuration """ 932 if band: 933 wifi_config[WifiEnums.APBAND_KEY] = band 934 if hidden: 935 wifi_config[WifiEnums.HIDDEN_KEY] = hidden 936 asserts.assert_true(ad.droid.wifiSetWifiApConfiguration(wifi_config), 937 "Failed to set WifiAp Configuration") 938 939 wifi_ap = ad.droid.wifiGetApConfiguration() 940 asserts.assert_true( 941 wifi_ap[WifiEnums.SSID_KEY] == wifi_config[WifiEnums.SSID_KEY], 942 "Hotspot SSID doesn't match with expected SSID") 943 944 945def start_wifi_tethering_saved_config(ad): 946 """ Turn on wifi hotspot with a config that is already saved """ 947 ad.droid.wifiStartTrackingTetherStateChange() 948 ad.droid.connectivityStartTethering(tel_defines.TETHERING_WIFI, False) 949 try: 950 ad.ed.pop_event("ConnectivityManagerOnTetheringStarted") 951 ad.ed.wait_for_event("TetherStateChanged", 952 lambda x: x["data"]["ACTIVE_TETHER"], 30) 953 except: 954 asserts.fail("Didn't receive wifi tethering starting confirmation") 955 finally: 956 ad.droid.wifiStopTrackingTetherStateChange() 957 958 959def stop_wifi_tethering(ad): 960 """Stops wifi tethering on an android_device. 961 962 Args: 963 ad: android_device to stop wifi tethering on. 964 """ 965 ad.droid.wifiStartTrackingTetherStateChange() 966 ad.droid.connectivityStopTethering(tel_defines.TETHERING_WIFI) 967 try: 968 ad.ed.pop_event("WifiManagerApDisabled", 30) 969 ad.ed.wait_for_event("TetherStateChanged", 970 lambda x: not x["data"]["ACTIVE_TETHER"], 30) 971 except Empty: 972 msg = "Failed to receive confirmation of wifi tethering stopping" 973 asserts.fail(msg) 974 finally: 975 ad.droid.wifiStopTrackingTetherStateChange() 976 977 978def toggle_wifi_and_wait_for_reconnection(ad, 979 network, 980 num_of_tries=1, 981 assert_on_fail=True): 982 """Toggle wifi state and then wait for Android device to reconnect to 983 the provided wifi network. 984 985 This expects the device to be already connected to the provided network. 986 987 Logic steps are 988 1. Ensure that we're connected to the network. 989 2. Turn wifi off. 990 3. Wait for 10 seconds. 991 4. Turn wifi on. 992 5. Wait for the "connected" event, then confirm the connected ssid is the 993 one requested. 994 995 Args: 996 ad: android_device object to initiate connection on. 997 network: A dictionary representing the network to await connection. The 998 dictionary must have the key "SSID". 999 num_of_tries: An integer that is the number of times to try before 1000 delaring failure. Default is 1. 1001 assert_on_fail: If True, error checks in this function will raise test 1002 failure signals. 1003 1004 Returns: 1005 If assert_on_fail is False, function returns True if the toggle was 1006 successful, False otherwise. If assert_on_fail is True, no return value. 1007 """ 1008 return _assert_on_fail_handler( 1009 _toggle_wifi_and_wait_for_reconnection, 1010 assert_on_fail, 1011 ad, 1012 network, 1013 num_of_tries=num_of_tries) 1014 1015 1016def _toggle_wifi_and_wait_for_reconnection(ad, network, num_of_tries=1): 1017 """Toggle wifi state and then wait for Android device to reconnect to 1018 the provided wifi network. 1019 1020 This expects the device to be already connected to the provided network. 1021 1022 Logic steps are 1023 1. Ensure that we're connected to the network. 1024 2. Turn wifi off. 1025 3. Wait for 10 seconds. 1026 4. Turn wifi on. 1027 5. Wait for the "connected" event, then confirm the connected ssid is the 1028 one requested. 1029 1030 This will directly fail a test if anything goes wrong. 1031 1032 Args: 1033 ad: android_device object to initiate connection on. 1034 network: A dictionary representing the network to await connection. The 1035 dictionary must have the key "SSID". 1036 num_of_tries: An integer that is the number of times to try before 1037 delaring failure. Default is 1. 1038 """ 1039 expected_ssid = network[WifiEnums.SSID_KEY] 1040 # First ensure that we're already connected to the provided network. 1041 verify_con = {WifiEnums.SSID_KEY: expected_ssid} 1042 verify_wifi_connection_info(ad, verify_con) 1043 # Now toggle wifi state and wait for the connection event. 1044 wifi_toggle_state(ad, False) 1045 time.sleep(10) 1046 wifi_toggle_state(ad, True) 1047 ad.droid.wifiStartTrackingStateChange() 1048 try: 1049 connect_result = None 1050 for i in range(num_of_tries): 1051 try: 1052 connect_result = ad.ed.pop_event(wifi_constants.WIFI_CONNECTED, 1053 30) 1054 break 1055 except Empty: 1056 pass 1057 asserts.assert_true(connect_result, 1058 "Failed to connect to Wi-Fi network %s on %s" % 1059 (network, ad.serial)) 1060 logging.debug("Connection result on %s: %s.", ad.serial, 1061 connect_result) 1062 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1063 asserts.assert_equal(actual_ssid, expected_ssid, 1064 "Connected to the wrong network on %s." 1065 "Expected %s, but got %s." % 1066 (ad.serial, expected_ssid, actual_ssid)) 1067 logging.info("Connected to Wi-Fi network %s on %s", actual_ssid, 1068 ad.serial) 1069 finally: 1070 ad.droid.wifiStopTrackingStateChange() 1071 1072 1073def wait_for_connect(ad, expected_ssid=None, expected_id=None, tries=2, 1074 assert_on_fail=True): 1075 """Wait for a connect event. 1076 1077 This will directly fail a test if anything goes wrong. 1078 1079 Args: 1080 ad: An Android device object. 1081 expected_ssid: SSID of the network to connect to. 1082 expected_id: Network Id of the network to connect to. 1083 tries: An integer that is the number of times to try before failing. 1084 assert_on_fail: If True, error checks in this function will raise test 1085 failure signals. 1086 1087 Returns: 1088 Returns a value only if assert_on_fail is false. 1089 Returns True if the connection was successful, False otherwise. 1090 """ 1091 return _assert_on_fail_handler( 1092 _wait_for_connect, assert_on_fail, ad, expected_ssid, expected_id, 1093 tries) 1094 1095 1096def _wait_for_connect(ad, expected_ssid=None, expected_id=None, tries=2): 1097 """Wait for a connect event. 1098 1099 Args: 1100 ad: An Android device object. 1101 expected_ssid: SSID of the network to connect to. 1102 expected_id: Network Id of the network to connect to. 1103 tries: An integer that is the number of times to try before failing. 1104 """ 1105 ad.droid.wifiStartTrackingStateChange() 1106 try: 1107 connect_result = _wait_for_connect_event( 1108 ad, ssid=expected_ssid, id=expected_id, tries=tries) 1109 asserts.assert_true(connect_result, 1110 "Failed to connect to Wi-Fi network %s" % 1111 expected_ssid) 1112 ad.log.debug("Wi-Fi connection result: %s.", connect_result) 1113 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1114 if expected_ssid: 1115 asserts.assert_equal(actual_ssid, expected_ssid, 1116 "Connected to the wrong network") 1117 actual_id = connect_result['data'][WifiEnums.NETID_KEY] 1118 if expected_id: 1119 asserts.assert_equal(actual_id, expected_id, 1120 "Connected to the wrong network") 1121 ad.log.info("Connected to Wi-Fi network %s.", actual_ssid) 1122 except Empty: 1123 asserts.fail("Failed to start connection process to %s" % 1124 expected_ssid) 1125 except Exception as error: 1126 ad.log.error("Failed to connect to %s with error %s", expected_ssid, 1127 error) 1128 raise signals.TestFailure("Failed to connect to %s network" % 1129 expected_ssid) 1130 finally: 1131 ad.droid.wifiStopTrackingStateChange() 1132 1133 1134def _wait_for_connect_event(ad, ssid=None, id=None, tries=1): 1135 """Wait for a connect event on queue and pop when available. 1136 1137 Args: 1138 ad: An Android device object. 1139 ssid: SSID of the network to connect to. 1140 id: Network Id of the network to connect to. 1141 tries: An integer that is the number of times to try before failing. 1142 1143 Returns: 1144 A dict with details of the connection data, which looks like this: 1145 { 1146 'time': 1485460337798, 1147 'name': 'WifiNetworkConnected', 1148 'data': { 1149 'rssi': -27, 1150 'is_24ghz': True, 1151 'mac_address': '02:00:00:00:00:00', 1152 'network_id': 1, 1153 'BSSID': '30:b5:c2:33:d3:fc', 1154 'ip_address': 117483712, 1155 'link_speed': 54, 1156 'supplicant_state': 'completed', 1157 'hidden_ssid': False, 1158 'SSID': 'wh_ap1_2g', 1159 'is_5ghz': False} 1160 } 1161 1162 """ 1163 conn_result = None 1164 1165 # If ssid and network id is None, just wait for any connect event. 1166 if id is None and ssid is None: 1167 for i in range(tries): 1168 try: 1169 start = time.time() 1170 conn_result = ad.ed.pop_event(wifi_constants.WIFI_CONNECTED, 30) 1171 _assert_connection_time(start) 1172 break 1173 except Empty: 1174 pass 1175 else: 1176 # If ssid or network id is specified, wait for specific connect event. 1177 for i in range(tries): 1178 try: 1179 start = time.time() 1180 conn_result = ad.ed.pop_event(wifi_constants.WIFI_CONNECTED, 30) 1181 if id and conn_result['data'][WifiEnums.NETID_KEY] == id: 1182 _assert_connection_time(start) 1183 break 1184 elif ssid and conn_result['data'][WifiEnums.SSID_KEY] == ssid: 1185 _assert_connection_time(start) 1186 break 1187 except Empty: 1188 pass 1189 1190 return conn_result 1191 1192def _assert_connection_time(start): 1193 duration = time.time() - start 1194 asserts.assert_true( 1195 duration < WIFI_ABNORMAL_CONNECTION_TIME, 1196 "Took " + str(duration) + "s to connect to network, " + 1197 " expected " + str(WIFI_ABNORMAL_CONNECTION_TIME)) 1198 1199def wait_for_disconnect(ad, timeout=10): 1200 """Wait for a disconnect event within the specified timeout. 1201 1202 Args: 1203 ad: Android device object. 1204 timeout: Timeout in seconds. 1205 1206 """ 1207 try: 1208 ad.droid.wifiStartTrackingStateChange() 1209 event = ad.ed.pop_event("WifiNetworkDisconnected", timeout) 1210 except Empty: 1211 raise signals.TestFailure("Device did not disconnect from the network") 1212 finally: 1213 ad.droid.wifiStopTrackingStateChange() 1214 1215 1216def ensure_no_disconnect(ad, duration=10): 1217 """Ensure that there is no disconnect for the specified duration. 1218 1219 Args: 1220 ad: Android device object. 1221 duration: Duration in seconds. 1222 1223 """ 1224 try: 1225 ad.droid.wifiStartTrackingStateChange() 1226 event = ad.ed.pop_event("WifiNetworkDisconnected", duration) 1227 raise signals.TestFailure("Device disconnected from the network") 1228 except Empty: 1229 pass 1230 finally: 1231 ad.droid.wifiStopTrackingStateChange() 1232 1233 1234def connect_to_wifi_network(ad, network, assert_on_fail=True, 1235 check_connectivity=True): 1236 """Connection logic for open and psk wifi networks. 1237 1238 Args: 1239 ad: AndroidDevice to use for connection 1240 network: network info of the network to connect to 1241 assert_on_fail: If true, errors from wifi_connect will raise 1242 test failure signals. 1243 """ 1244 start_wifi_connection_scan_and_ensure_network_found( 1245 ad, network[WifiEnums.SSID_KEY]) 1246 wifi_connect(ad, 1247 network, 1248 num_of_tries=3, 1249 assert_on_fail=assert_on_fail, 1250 check_connectivity=check_connectivity) 1251 1252 1253def connect_to_wifi_network_with_id(ad, network_id, network_ssid): 1254 """Connect to the given network using network id and verify SSID. 1255 1256 Args: 1257 network_id: int Network Id of the network. 1258 network_ssid: string SSID of the network. 1259 1260 Returns: True if connect using network id was successful; 1261 False otherwise. 1262 1263 """ 1264 start_wifi_connection_scan_and_ensure_network_found(ad, network_ssid) 1265 wifi_connect_by_id(ad, network_id) 1266 connect_data = ad.droid.wifiGetConnectionInfo() 1267 connect_ssid = connect_data[WifiEnums.SSID_KEY] 1268 ad.log.debug("Expected SSID = %s Connected SSID = %s" % 1269 (network_ssid, connect_ssid)) 1270 if connect_ssid != network_ssid: 1271 return False 1272 return True 1273 1274 1275def wifi_connect(ad, network, num_of_tries=1, assert_on_fail=True, 1276 check_connectivity=True): 1277 """Connect an Android device to a wifi network. 1278 1279 Initiate connection to a wifi network, wait for the "connected" event, then 1280 confirm the connected ssid is the one requested. 1281 1282 This will directly fail a test if anything goes wrong. 1283 1284 Args: 1285 ad: android_device object to initiate connection on. 1286 network: A dictionary representing the network to connect to. The 1287 dictionary must have the key "SSID". 1288 num_of_tries: An integer that is the number of times to try before 1289 delaring failure. Default is 1. 1290 assert_on_fail: If True, error checks in this function will raise test 1291 failure signals. 1292 1293 Returns: 1294 Returns a value only if assert_on_fail is false. 1295 Returns True if the connection was successful, False otherwise. 1296 """ 1297 return _assert_on_fail_handler( 1298 _wifi_connect, assert_on_fail, ad, network, num_of_tries=num_of_tries, 1299 check_connectivity=check_connectivity) 1300 1301 1302def _wifi_connect(ad, network, num_of_tries=1, check_connectivity=True): 1303 """Connect an Android device to a wifi network. 1304 1305 Initiate connection to a wifi network, wait for the "connected" event, then 1306 confirm the connected ssid is the one requested. 1307 1308 This will directly fail a test if anything goes wrong. 1309 1310 Args: 1311 ad: android_device object to initiate connection on. 1312 network: A dictionary representing the network to connect to. The 1313 dictionary must have the key "SSID". 1314 num_of_tries: An integer that is the number of times to try before 1315 delaring failure. Default is 1. 1316 """ 1317 asserts.assert_true(WifiEnums.SSID_KEY in network, 1318 "Key '%s' must be present in network definition." % 1319 WifiEnums.SSID_KEY) 1320 ad.droid.wifiStartTrackingStateChange() 1321 expected_ssid = network[WifiEnums.SSID_KEY] 1322 ad.droid.wifiConnectByConfig(network) 1323 ad.log.info("Starting connection process to %s", expected_ssid) 1324 try: 1325 event = ad.ed.pop_event(wifi_constants.CONNECT_BY_CONFIG_SUCCESS, 30) 1326 connect_result = _wait_for_connect_event( 1327 ad, ssid=expected_ssid, tries=num_of_tries) 1328 asserts.assert_true(connect_result, 1329 "Failed to connect to Wi-Fi network %s on %s" % 1330 (network, ad.serial)) 1331 ad.log.debug("Wi-Fi connection result: %s.", connect_result) 1332 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1333 asserts.assert_equal(actual_ssid, expected_ssid, 1334 "Connected to the wrong network on %s." % 1335 ad.serial) 1336 ad.log.info("Connected to Wi-Fi network %s.", actual_ssid) 1337 1338 # Wait for data connection to stabilize. 1339 time.sleep(5) 1340 1341 if check_connectivity: 1342 internet = validate_connection(ad, DEFAULT_PING_ADDR) 1343 if not internet: 1344 raise signals.TestFailure("Failed to connect to internet on %s" % 1345 expected_ssid) 1346 except Empty: 1347 asserts.fail("Failed to start connection process to %s on %s" % 1348 (network, ad.serial)) 1349 except Exception as error: 1350 ad.log.error("Failed to connect to %s with error %s", expected_ssid, 1351 error) 1352 raise signals.TestFailure("Failed to connect to %s network" % network) 1353 1354 finally: 1355 ad.droid.wifiStopTrackingStateChange() 1356 1357 1358def wifi_connect_by_id(ad, network_id, num_of_tries=3, assert_on_fail=True): 1359 """Connect an Android device to a wifi network using network Id. 1360 1361 Start connection to the wifi network, with the given network Id, wait for 1362 the "connected" event, then verify the connected network is the one requested. 1363 1364 This will directly fail a test if anything goes wrong. 1365 1366 Args: 1367 ad: android_device object to initiate connection on. 1368 network_id: Integer specifying the network id of the network. 1369 num_of_tries: An integer that is the number of times to try before 1370 delaring failure. Default is 1. 1371 assert_on_fail: If True, error checks in this function will raise test 1372 failure signals. 1373 1374 Returns: 1375 Returns a value only if assert_on_fail is false. 1376 Returns True if the connection was successful, False otherwise. 1377 """ 1378 _assert_on_fail_handler(_wifi_connect_by_id, assert_on_fail, ad, 1379 network_id, num_of_tries) 1380 1381 1382def _wifi_connect_by_id(ad, network_id, num_of_tries=1): 1383 """Connect an Android device to a wifi network using it's network id. 1384 1385 Start connection to the wifi network, with the given network id, wait for 1386 the "connected" event, then verify the connected network is the one requested. 1387 1388 Args: 1389 ad: android_device object to initiate connection on. 1390 network_id: Integer specifying the network id of the network. 1391 num_of_tries: An integer that is the number of times to try before 1392 delaring failure. Default is 1. 1393 """ 1394 ad.droid.wifiStartTrackingStateChange() 1395 # Clear all previous events. 1396 ad.ed.clear_all_events() 1397 ad.droid.wifiConnectByNetworkId(network_id) 1398 ad.log.info("Starting connection to network with id %d", network_id) 1399 try: 1400 event = ad.ed.pop_event(wifi_constants.CONNECT_BY_NETID_SUCCESS, 60) 1401 connect_result = _wait_for_connect_event( 1402 ad, id=network_id, tries=num_of_tries) 1403 asserts.assert_true(connect_result, 1404 "Failed to connect to Wi-Fi network using network id") 1405 ad.log.debug("Wi-Fi connection result: %s", connect_result) 1406 actual_id = connect_result['data'][WifiEnums.NETID_KEY] 1407 asserts.assert_equal(actual_id, network_id, 1408 "Connected to the wrong network on %s." 1409 "Expected network id = %d, but got %d." % 1410 (ad.serial, network_id, actual_id)) 1411 expected_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1412 ad.log.info("Connected to Wi-Fi network %s with %d network id.", 1413 expected_ssid, network_id) 1414 1415 # Wait for data connection to stabilize. 1416 time.sleep(5) 1417 1418 internet = validate_connection(ad, DEFAULT_PING_ADDR) 1419 if not internet: 1420 raise signals.TestFailure("Failed to connect to internet on %s" % 1421 expected_ssid) 1422 except Empty: 1423 asserts.fail("Failed to connect to network with id %d on %s" % 1424 (network_id, ad.serial)) 1425 except Exception as error: 1426 ad.log.error("Failed to connect to network with id %d with error %s", 1427 network_id, error) 1428 raise signals.TestFailure("Failed to connect to network with network" 1429 " id %d" % network_id) 1430 finally: 1431 ad.droid.wifiStopTrackingStateChange() 1432 1433def wifi_connect_using_network_request(ad, network, network_specifier, 1434 num_of_tries=3, assert_on_fail=True): 1435 """Connect an Android device to a wifi network using network request. 1436 1437 Trigger a network request with the provided network specifier, 1438 wait for the "onMatch" event, ensure that the scan results in "onMatch" 1439 event contain the specified network, then simulate the user granting the 1440 request with the specified network selected. Then wait for the "onAvailable" 1441 network callback indicating successful connection to network. 1442 1443 This will directly fail a test if anything goes wrong. 1444 1445 Args: 1446 ad: android_device object to initiate connection on. 1447 network_specifier: A dictionary representing the network specifier to 1448 use. 1449 network: A dictionary representing the network to connect to. The 1450 dictionary must have the key "SSID". 1451 num_of_tries: An integer that is the number of times to try before 1452 delaring failure. 1453 assert_on_fail: If True, error checks in this function will raise test 1454 failure signals. 1455 1456 Returns: 1457 Returns a value only if assert_on_fail is false. 1458 Returns True if the connection was successful, False otherwise. 1459 """ 1460 _assert_on_fail_handler(_wifi_connect_using_network_request, assert_on_fail, 1461 ad, network, network_specifier, num_of_tries) 1462 1463 1464def _wifi_connect_using_network_request(ad, network, network_specifier, 1465 num_of_tries=3): 1466 """Connect an Android device to a wifi network using network request. 1467 1468 Trigger a network request with the provided network specifier, 1469 wait for the "onMatch" event, ensure that the scan results in "onMatch" 1470 event contain the specified network, then simulate the user granting the 1471 request with the specified network selected. Then wait for the "onAvailable" 1472 network callback indicating successful connection to network. 1473 1474 Args: 1475 ad: android_device object to initiate connection on. 1476 network_specifier: A dictionary representing the network specifier to 1477 use. 1478 network: A dictionary representing the network to connect to. The 1479 dictionary must have the key "SSID". 1480 num_of_tries: An integer that is the number of times to try before 1481 delaring failure. 1482 """ 1483 ad.droid.wifiRequestNetworkWithSpecifier(network_specifier) 1484 ad.log.info("Sent network request with %s", network_specifier) 1485 # Need a delay here because UI interaction should only start once wifi 1486 # starts processing the request. 1487 time.sleep(wifi_constants.NETWORK_REQUEST_CB_REGISTER_DELAY_SEC) 1488 _wait_for_wifi_connect_after_network_request(ad, network, num_of_tries) 1489 1490 1491def wait_for_wifi_connect_after_network_request(ad, network, num_of_tries=3, 1492 assert_on_fail=True): 1493 """ 1494 Simulate and verify the connection flow after initiating the network 1495 request. 1496 1497 Wait for the "onMatch" event, ensure that the scan results in "onMatch" 1498 event contain the specified network, then simulate the user granting the 1499 request with the specified network selected. Then wait for the "onAvailable" 1500 network callback indicating successful connection to network. 1501 1502 Args: 1503 ad: android_device object to initiate connection on. 1504 network: A dictionary representing the network to connect to. The 1505 dictionary must have the key "SSID". 1506 num_of_tries: An integer that is the number of times to try before 1507 delaring failure. 1508 assert_on_fail: If True, error checks in this function will raise test 1509 failure signals. 1510 1511 Returns: 1512 Returns a value only if assert_on_fail is false. 1513 Returns True if the connection was successful, False otherwise. 1514 """ 1515 _assert_on_fail_handler(_wait_for_wifi_connect_after_network_request, 1516 assert_on_fail, ad, network, num_of_tries) 1517 1518 1519def _wait_for_wifi_connect_after_network_request(ad, network, num_of_tries=3): 1520 """ 1521 Simulate and verify the connection flow after initiating the network 1522 request. 1523 1524 Wait for the "onMatch" event, ensure that the scan results in "onMatch" 1525 event contain the specified network, then simulate the user granting the 1526 request with the specified network selected. Then wait for the "onAvailable" 1527 network callback indicating successful connection to network. 1528 1529 Args: 1530 ad: android_device object to initiate connection on. 1531 network: A dictionary representing the network to connect to. The 1532 dictionary must have the key "SSID". 1533 num_of_tries: An integer that is the number of times to try before 1534 delaring failure. 1535 """ 1536 asserts.assert_true(WifiEnums.SSID_KEY in network, 1537 "Key '%s' must be present in network definition." % 1538 WifiEnums.SSID_KEY) 1539 ad.droid.wifiStartTrackingStateChange() 1540 expected_ssid = network[WifiEnums.SSID_KEY] 1541 ad.droid.wifiRegisterNetworkRequestMatchCallback() 1542 # Wait for the platform to scan and return a list of networks 1543 # matching the request 1544 try: 1545 matched_network = None 1546 for _ in [0, num_of_tries]: 1547 on_match_event = ad.ed.pop_event( 1548 wifi_constants.WIFI_NETWORK_REQUEST_MATCH_CB_ON_MATCH, 60) 1549 asserts.assert_true(on_match_event, 1550 "Network request on match not received.") 1551 matched_scan_results = on_match_event["data"] 1552 ad.log.debug("Network request on match results %s", 1553 matched_scan_results) 1554 matched_network = match_networks( 1555 {WifiEnums.SSID_KEY: network[WifiEnums.SSID_KEY]}, 1556 matched_scan_results) 1557 if matched_network: 1558 break; 1559 1560 asserts.assert_true( 1561 matched_network, "Target network %s not found" % network) 1562 1563 ad.droid.wifiSendUserSelectionForNetworkRequestMatch(network) 1564 ad.log.info("Sent user selection for network request %s", 1565 expected_ssid) 1566 1567 # Wait for the platform to connect to the network. 1568 on_available_event = ad.ed.pop_event( 1569 wifi_constants.WIFI_NETWORK_CB_ON_AVAILABLE, 60) 1570 asserts.assert_true(on_available_event, 1571 "Network request on available not received.") 1572 connected_network = on_available_event["data"] 1573 ad.log.info("Connected to network %s", connected_network) 1574 asserts.assert_equal(connected_network[WifiEnums.SSID_KEY], 1575 expected_ssid, 1576 "Connected to the wrong network." 1577 "Expected %s, but got %s." % 1578 (network, connected_network)) 1579 except Empty: 1580 asserts.fail("Failed to connect to %s" % expected_ssid) 1581 except Exception as error: 1582 ad.log.error("Failed to connect to %s with error %s", 1583 (expected_ssid, error)) 1584 raise signals.TestFailure("Failed to connect to %s network" % network) 1585 finally: 1586 ad.droid.wifiStopTrackingStateChange() 1587 1588 1589def wifi_passpoint_connect(ad, passpoint_network, num_of_tries=1, 1590 assert_on_fail=True): 1591 """Connect an Android device to a wifi network. 1592 1593 Initiate connection to a wifi network, wait for the "connected" event, then 1594 confirm the connected ssid is the one requested. 1595 1596 This will directly fail a test if anything goes wrong. 1597 1598 Args: 1599 ad: android_device object to initiate connection on. 1600 passpoint_network: SSID of the Passpoint network to connect to. 1601 num_of_tries: An integer that is the number of times to try before 1602 delaring failure. Default is 1. 1603 assert_on_fail: If True, error checks in this function will raise test 1604 failure signals. 1605 1606 Returns: 1607 If assert_on_fail is False, function returns network id, if the connect was 1608 successful, False otherwise. If assert_on_fail is True, no return value. 1609 """ 1610 _assert_on_fail_handler(_wifi_passpoint_connect, assert_on_fail, ad, 1611 passpoint_network, num_of_tries = num_of_tries) 1612 1613 1614def _wifi_passpoint_connect(ad, passpoint_network, num_of_tries=1): 1615 """Connect an Android device to a wifi network. 1616 1617 Initiate connection to a wifi network, wait for the "connected" event, then 1618 confirm the connected ssid is the one requested. 1619 1620 This will directly fail a test if anything goes wrong. 1621 1622 Args: 1623 ad: android_device object to initiate connection on. 1624 passpoint_network: SSID of the Passpoint network to connect to. 1625 num_of_tries: An integer that is the number of times to try before 1626 delaring failure. Default is 1. 1627 """ 1628 ad.droid.wifiStartTrackingStateChange() 1629 expected_ssid = passpoint_network 1630 ad.log.info("Starting connection process to passpoint %s", expected_ssid) 1631 1632 try: 1633 connect_result = _wait_for_connect_event( 1634 ad, expected_ssid, num_of_tries) 1635 asserts.assert_true(connect_result, 1636 "Failed to connect to WiFi passpoint network %s on" 1637 " %s" % (expected_ssid, ad.serial)) 1638 ad.log.info("Wi-Fi connection result: %s.", connect_result) 1639 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 1640 asserts.assert_equal(actual_ssid, expected_ssid, 1641 "Connected to the wrong network on %s." % ad.serial) 1642 ad.log.info("Connected to Wi-Fi passpoint network %s.", actual_ssid) 1643 1644 # Wait for data connection to stabilize. 1645 time.sleep(5) 1646 1647 internet = validate_connection(ad, DEFAULT_PING_ADDR) 1648 if not internet: 1649 raise signals.TestFailure("Failed to connect to internet on %s" % 1650 expected_ssid) 1651 except Exception as error: 1652 ad.log.error("Failed to connect to passpoint network %s with error %s", 1653 expected_ssid, error) 1654 raise signals.TestFailure("Failed to connect to %s passpoint network" % 1655 expected_ssid) 1656 1657 finally: 1658 ad.droid.wifiStopTrackingStateChange() 1659 1660 1661def delete_passpoint(ad, fqdn): 1662 """Delete a required Passpoint configuration.""" 1663 try: 1664 ad.droid.removePasspointConfig(fqdn) 1665 return True 1666 except Exception as error: 1667 ad.log.error("Failed to remove passpoint configuration with FQDN=%s " 1668 "and error=%s" , fqdn, error) 1669 return False 1670 1671 1672def start_wifi_single_scan(ad, scan_setting): 1673 """Starts wifi single shot scan. 1674 1675 Args: 1676 ad: android_device object to initiate connection on. 1677 scan_setting: A dict representing the settings of the scan. 1678 1679 Returns: 1680 If scan was started successfully, event data of success event is returned. 1681 """ 1682 idx = ad.droid.wifiScannerStartScan(scan_setting) 1683 event = ad.ed.pop_event("WifiScannerScan%sonSuccess" % idx, SHORT_TIMEOUT) 1684 ad.log.debug("Got event %s", event) 1685 return event['data'] 1686 1687 1688def track_connection(ad, network_ssid, check_connection_count): 1689 """Track wifi connection to network changes for given number of counts 1690 1691 Args: 1692 ad: android_device object for forget network. 1693 network_ssid: network ssid to which connection would be tracked 1694 check_connection_count: Integer for maximum number network connection 1695 check. 1696 Returns: 1697 True if connection to given network happen, else return False. 1698 """ 1699 ad.droid.wifiStartTrackingStateChange() 1700 while check_connection_count > 0: 1701 connect_network = ad.ed.pop_event("WifiNetworkConnected", 120) 1702 ad.log.info("Connected to network %s", connect_network) 1703 if (WifiEnums.SSID_KEY in connect_network['data'] and 1704 connect_network['data'][WifiEnums.SSID_KEY] == network_ssid): 1705 return True 1706 check_connection_count -= 1 1707 ad.droid.wifiStopTrackingStateChange() 1708 return False 1709 1710 1711def get_scan_time_and_channels(wifi_chs, scan_setting, stime_channel): 1712 """Calculate the scan time required based on the band or channels in scan 1713 setting 1714 1715 Args: 1716 wifi_chs: Object of channels supported 1717 scan_setting: scan setting used for start scan 1718 stime_channel: scan time per channel 1719 1720 Returns: 1721 scan_time: time required for completing a scan 1722 scan_channels: channel used for scanning 1723 """ 1724 scan_time = 0 1725 scan_channels = [] 1726 if "band" in scan_setting and "channels" not in scan_setting: 1727 scan_channels = wifi_chs.band_to_freq(scan_setting["band"]) 1728 elif "channels" in scan_setting and "band" not in scan_setting: 1729 scan_channels = scan_setting["channels"] 1730 scan_time = len(scan_channels) * stime_channel 1731 for channel in scan_channels: 1732 if channel in WifiEnums.DFS_5G_FREQUENCIES: 1733 scan_time += 132 #passive scan time on DFS 1734 return scan_time, scan_channels 1735 1736 1737def start_wifi_track_bssid(ad, track_setting): 1738 """Start tracking Bssid for the given settings. 1739 1740 Args: 1741 ad: android_device object. 1742 track_setting: Setting for which the bssid tracking should be started 1743 1744 Returns: 1745 If tracking started successfully, event data of success event is returned. 1746 """ 1747 idx = ad.droid.wifiScannerStartTrackingBssids( 1748 track_setting["bssidInfos"], track_setting["apLostThreshold"]) 1749 event = ad.ed.pop_event("WifiScannerBssid{}onSuccess".format(idx), 1750 SHORT_TIMEOUT) 1751 return event['data'] 1752 1753 1754def convert_pem_key_to_pkcs8(in_file, out_file): 1755 """Converts the key file generated by us to the format required by 1756 Android using openssl. 1757 1758 The input file must have the extension "pem". The output file must 1759 have the extension "der". 1760 1761 Args: 1762 in_file: The original key file. 1763 out_file: The full path to the converted key file, including 1764 filename. 1765 """ 1766 asserts.assert_true(in_file.endswith(".pem"), "Input file has to be .pem.") 1767 asserts.assert_true( 1768 out_file.endswith(".der"), "Output file has to be .der.") 1769 cmd = ("openssl pkcs8 -inform PEM -in {} -outform DER -out {} -nocrypt" 1770 " -topk8").format(in_file, out_file) 1771 utils.exe_cmd(cmd) 1772 1773 1774def validate_connection(ad, ping_addr=DEFAULT_PING_ADDR): 1775 """Validate internet connection by pinging the address provided. 1776 1777 Args: 1778 ad: android_device object. 1779 ping_addr: address on internet for pinging. 1780 1781 Returns: 1782 ping output if successful, NULL otherwise. 1783 """ 1784 ping = ad.droid.httpPing(ping_addr) 1785 ad.log.info("Http ping result: %s.", ping) 1786 return ping 1787 1788 1789#TODO(angli): This can only verify if an actual value is exactly the same. 1790# Would be nice to be able to verify an actual value is one of serveral. 1791def verify_wifi_connection_info(ad, expected_con): 1792 """Verifies that the information of the currently connected wifi network is 1793 as expected. 1794 1795 Args: 1796 expected_con: A dict representing expected key-value pairs for wifi 1797 connection. e.g. {"SSID": "test_wifi"} 1798 """ 1799 current_con = ad.droid.wifiGetConnectionInfo() 1800 case_insensitive = ["BSSID", "supplicant_state"] 1801 ad.log.debug("Current connection: %s", current_con) 1802 for k, expected_v in expected_con.items(): 1803 # Do not verify authentication related fields. 1804 if k == "password": 1805 continue 1806 msg = "Field %s does not exist in wifi connection info %s." % ( 1807 k, current_con) 1808 if k not in current_con: 1809 raise signals.TestFailure(msg) 1810 actual_v = current_con[k] 1811 if k in case_insensitive: 1812 actual_v = actual_v.lower() 1813 expected_v = expected_v.lower() 1814 msg = "Expected %s to be %s, actual %s is %s." % (k, expected_v, k, 1815 actual_v) 1816 if actual_v != expected_v: 1817 raise signals.TestFailure(msg) 1818 1819 1820def check_autoconnect_to_open_network(ad, conn_timeout=WIFI_CONNECTION_TIMEOUT_DEFAULT): 1821 """Connects to any open WiFI AP 1822 Args: 1823 timeout value in sec to wait for UE to connect to a WiFi AP 1824 Returns: 1825 True if UE connects to WiFi AP (supplicant_state = completed) 1826 False if UE fails to complete connection within WIFI_CONNECTION_TIMEOUT time. 1827 """ 1828 if ad.droid.wifiCheckState(): 1829 return True 1830 ad.droid.wifiToggleState() 1831 wifi_connection_state = None 1832 timeout = time.time() + conn_timeout 1833 while wifi_connection_state != "completed": 1834 wifi_connection_state = ad.droid.wifiGetConnectionInfo()[ 1835 'supplicant_state'] 1836 if time.time() > timeout: 1837 ad.log.warning("Failed to connect to WiFi AP") 1838 return False 1839 return True 1840 1841 1842def expand_enterprise_config_by_phase2(config): 1843 """Take an enterprise config and generate a list of configs, each with 1844 a different phase2 auth type. 1845 1846 Args: 1847 config: A dict representing enterprise config. 1848 1849 Returns 1850 A list of enterprise configs. 1851 """ 1852 results = [] 1853 phase2_types = WifiEnums.EapPhase2 1854 if config[WifiEnums.Enterprise.EAP] == WifiEnums.Eap.PEAP: 1855 # Skip unsupported phase2 types for PEAP. 1856 phase2_types = [WifiEnums.EapPhase2.GTC, WifiEnums.EapPhase2.MSCHAPV2] 1857 for phase2_type in phase2_types: 1858 # Skip a special case for passpoint TTLS. 1859 if (WifiEnums.Enterprise.FQDN in config and 1860 phase2_type == WifiEnums.EapPhase2.GTC): 1861 continue 1862 c = dict(config) 1863 c[WifiEnums.Enterprise.PHASE2] = phase2_type.value 1864 results.append(c) 1865 return results 1866 1867 1868def generate_eap_test_name(config, ad=None): 1869 """ Generates a test case name based on an EAP configuration. 1870 1871 Args: 1872 config: A dict representing an EAP credential. 1873 ad object: Redundant but required as the same param is passed 1874 to test_func in run_generated_tests 1875 1876 Returns: 1877 A string representing the name of a generated EAP test case. 1878 """ 1879 eap = WifiEnums.Eap 1880 eap_phase2 = WifiEnums.EapPhase2 1881 Ent = WifiEnums.Enterprise 1882 name = "test_connect-" 1883 eap_name = "" 1884 for e in eap: 1885 if e.value == config[Ent.EAP]: 1886 eap_name = e.name 1887 break 1888 if "peap0" in config[WifiEnums.SSID_KEY].lower(): 1889 eap_name = "PEAP0" 1890 if "peap1" in config[WifiEnums.SSID_KEY].lower(): 1891 eap_name = "PEAP1" 1892 name += eap_name 1893 if Ent.PHASE2 in config: 1894 for e in eap_phase2: 1895 if e.value == config[Ent.PHASE2]: 1896 name += "-{}".format(e.name) 1897 break 1898 return name 1899 1900 1901def group_attenuators(attenuators): 1902 """Groups a list of attenuators into attenuator groups for backward 1903 compatibility reasons. 1904 1905 Most legacy Wi-Fi setups have two attenuators each connected to a separate 1906 AP. The new Wi-Fi setup has four attenuators, each connected to one channel 1907 on an AP, so two of them are connected to one AP. 1908 1909 To make the existing scripts work in the new setup, when the script needs 1910 to attenuate one AP, it needs to set attenuation on both attenuators 1911 connected to the same AP. 1912 1913 This function groups attenuators properly so the scripts work in both 1914 legacy and new Wi-Fi setups. 1915 1916 Args: 1917 attenuators: A list of attenuator objects, either two or four in length. 1918 1919 Raises: 1920 signals.TestFailure is raised if the attenuator list does not have two 1921 or four objects. 1922 """ 1923 attn0 = attenuator.AttenuatorGroup("AP0") 1924 attn1 = attenuator.AttenuatorGroup("AP1") 1925 # Legacy testbed setup has two attenuation channels. 1926 num_of_attns = len(attenuators) 1927 if num_of_attns == 2: 1928 attn0.add(attenuators[0]) 1929 attn1.add(attenuators[1]) 1930 elif num_of_attns == 4: 1931 attn0.add(attenuators[0]) 1932 attn0.add(attenuators[1]) 1933 attn1.add(attenuators[2]) 1934 attn1.add(attenuators[3]) 1935 else: 1936 asserts.fail(("Either two or four attenuators are required for this " 1937 "test, but found %s") % num_of_attns) 1938 return [attn0, attn1] 1939 1940 1941def set_attns(attenuator, attn_val_name): 1942 """Sets attenuation values on attenuators used in this test. 1943 1944 Args: 1945 attenuator: The attenuator object. 1946 attn_val_name: Name of the attenuation value pair to use. 1947 """ 1948 logging.info("Set attenuation values to %s", roaming_attn[attn_val_name]) 1949 try: 1950 attenuator[0].set_atten(roaming_attn[attn_val_name][0]) 1951 attenuator[1].set_atten(roaming_attn[attn_val_name][1]) 1952 attenuator[2].set_atten(roaming_attn[attn_val_name][2]) 1953 attenuator[3].set_atten(roaming_attn[attn_val_name][3]) 1954 except: 1955 logging.exception("Failed to set attenuation values %s.", 1956 attn_val_name) 1957 raise 1958 1959 1960def trigger_roaming_and_validate(dut, attenuator, attn_val_name, expected_con): 1961 """Sets attenuators to trigger roaming and validate the DUT connected 1962 to the BSSID expected. 1963 1964 Args: 1965 attenuator: The attenuator object. 1966 attn_val_name: Name of the attenuation value pair to use. 1967 expected_con: The network information of the expected network. 1968 """ 1969 expected_con = { 1970 WifiEnums.SSID_KEY: expected_con[WifiEnums.SSID_KEY], 1971 WifiEnums.BSSID_KEY: expected_con["bssid"], 1972 } 1973 set_attns(attenuator, attn_val_name) 1974 logging.info("Wait %ss for roaming to finish.", ROAMING_TIMEOUT) 1975 time.sleep(ROAMING_TIMEOUT) 1976 1977 verify_wifi_connection_info(dut, expected_con) 1978 expected_bssid = expected_con[WifiEnums.BSSID_KEY] 1979 logging.info("Roamed to %s successfully", expected_bssid) 1980 if not validate_connection(dut): 1981 raise signals.TestFailure("Fail to connect to internet on %s" % 1982 expected_bssid) 1983 1984def create_softap_config(): 1985 """Create a softap config with random ssid and password.""" 1986 ap_ssid = "softap_" + utils.rand_ascii_str(8) 1987 ap_password = utils.rand_ascii_str(8) 1988 logging.info("softap setup: %s %s", ap_ssid, ap_password) 1989 config = { 1990 WifiEnums.SSID_KEY: ap_ssid, 1991 WifiEnums.PWD_KEY: ap_password, 1992 } 1993 return config 1994 1995 1996def start_softap_and_verify(ad, band): 1997 """Bring-up softap and verify AP mode and in scan results. 1998 1999 Args: 2000 band: The band to use for softAP. 2001 2002 Returns: dict, the softAP config. 2003 2004 """ 2005 config = create_softap_config() 2006 start_wifi_tethering(ad.dut, 2007 config[WifiEnums.SSID_KEY], 2008 config[WifiEnums.PWD_KEY], band=band) 2009 asserts.assert_true(ad.dut.droid.wifiIsApEnabled(), 2010 "SoftAp is not reported as running") 2011 start_wifi_connection_scan_and_ensure_network_found(ad.dut_client, 2012 config[WifiEnums.SSID_KEY]) 2013 return config 2014 2015 2016def start_pcap(pcap, wifi_band, test_name): 2017 """Start packet capture in monitor mode. 2018 2019 Args: 2020 pcap: packet capture object 2021 wifi_band: '2g' or '5g' or 'dual' 2022 test_name: test name to be used for pcap file name 2023 2024 Returns: 2025 Dictionary with wifi band as key and the tuple 2026 (pcap Process object, log directory) as the value 2027 """ 2028 log_dir = os.path.join( 2029 context.get_current_context().get_full_output_path(), 'PacketCapture') 2030 utils.create_dir(log_dir) 2031 if wifi_band == 'dual': 2032 bands = [BAND_2G, BAND_5G] 2033 else: 2034 bands = [wifi_band] 2035 procs = {} 2036 for band in bands: 2037 proc = pcap.start_packet_capture(band, log_dir, test_name) 2038 procs[band] = (proc, os.path.join(log_dir, test_name)) 2039 return procs 2040 2041 2042def stop_pcap(pcap, procs, test_status=None): 2043 """Stop packet capture in monitor mode. 2044 2045 Since, the pcap logs in monitor mode can be very large, we will 2046 delete them if they are not required. 'test_status' if True, will delete 2047 the pcap files. If False, we will keep them. 2048 2049 Args: 2050 pcap: packet capture object 2051 procs: dictionary returned by start_pcap 2052 test_status: status of the test case 2053 """ 2054 for proc, fname in procs.values(): 2055 pcap.stop_packet_capture(proc) 2056 2057 if test_status: 2058 shutil.rmtree(os.path.dirname(fname)) 2059 2060def verify_mac_not_found_in_pcap(mac, packets): 2061 """Verify that a mac address is not found in the captured packets. 2062 2063 Args: 2064 mac: string representation of the mac address 2065 packets: packets obtained by rdpcap(pcap_fname) 2066 """ 2067 for pkt in packets: 2068 logging.debug("Packet Summary = %s", pkt.summary()) 2069 if mac in pkt.summary(): 2070 asserts.fail("Caught Factory MAC: %s in packet sniffer." 2071 "Packet = %s" % (mac, pkt.show())) 2072 2073def verify_mac_is_found_in_pcap(mac, packets): 2074 """Verify that a mac address is found in the captured packets. 2075 2076 Args: 2077 mac: string representation of the mac address 2078 packets: packets obtained by rdpcap(pcap_fname) 2079 """ 2080 for pkt in packets: 2081 if mac in pkt.summary(): 2082 return 2083 asserts.fail("Did not find MAC = %s in packet sniffer." % mac) 2084 2085def start_cnss_diags(ads): 2086 for ad in ads: 2087 start_cnss_diag(ad) 2088 2089 2090def start_cnss_diag(ad): 2091 """Start cnss_diag to record extra wifi logs 2092 2093 Args: 2094 ad: android device object. 2095 """ 2096 if ad.model in wifi_constants.DEVICES_USING_LEGACY_PROP: 2097 prop = wifi_constants.LEGACY_CNSS_DIAG_PROP 2098 else: 2099 prop = wifi_constants.CNSS_DIAG_PROP 2100 if ad.adb.getprop(prop) != 'true': 2101 ad.adb.shell("find /data/vendor/wifi/cnss_diag/wlan_logs/ -type f -delete") 2102 ad.adb.shell("setprop %s true" % prop, ignore_status=True) 2103 2104 2105def stop_cnss_diags(ads): 2106 for ad in ads: 2107 stop_cnss_diag(ad) 2108 2109 2110def stop_cnss_diag(ad): 2111 """Stops cnss_diag 2112 2113 Args: 2114 ad: android device object. 2115 """ 2116 if ad.model in wifi_constants.DEVICES_USING_LEGACY_PROP: 2117 prop = wifi_constants.LEGACY_CNSS_DIAG_PROP 2118 else: 2119 prop = wifi_constants.CNSS_DIAG_PROP 2120 ad.adb.shell("setprop %s false" % prop, ignore_status=True) 2121 2122 2123def get_cnss_diag_log(ad, test_name=""): 2124 """Pulls the cnss_diag logs in the wlan_logs dir 2125 Args: 2126 ad: android device object. 2127 test_name: test case name 2128 """ 2129 logs = ad.get_file_names("/data/vendor/wifi/cnss_diag/wlan_logs/") 2130 if logs: 2131 ad.log.info("Pulling cnss_diag logs %s", logs) 2132 log_path = os.path.join(ad.device_log_path, "CNSS_DIAG_%s" % ad.serial) 2133 utils.create_dir(log_path) 2134 ad.pull_files(logs, log_path) 2135 2136 2137LinkProbeResult = namedtuple('LinkProbeResult', ( 2138 'is_success', 'stdout', 'elapsed_time', 'failure_reason')) 2139 2140 2141def send_link_probe(ad): 2142 """Sends a link probe to the currently connected AP, and returns whether the 2143 probe succeeded or not. 2144 2145 Args: 2146 ad: android device object 2147 Returns: 2148 LinkProbeResult namedtuple 2149 """ 2150 stdout = ad.adb.shell('cmd wifi send-link-probe') 2151 asserts.assert_false('Error' in stdout or 'Exception' in stdout, 2152 'Exception while sending link probe: ' + stdout) 2153 2154 is_success = False 2155 elapsed_time = None 2156 failure_reason = None 2157 if 'succeeded' in stdout: 2158 is_success = True 2159 elapsed_time = next( 2160 (int(token) for token in stdout.split() if token.isdigit()), None) 2161 elif 'failed with reason' in stdout: 2162 failure_reason = next( 2163 (int(token) for token in stdout.split() if token.isdigit()), None) 2164 else: 2165 asserts.fail('Unexpected link probe result: ' + stdout) 2166 2167 return LinkProbeResult( 2168 is_success=is_success, stdout=stdout, 2169 elapsed_time=elapsed_time, failure_reason=failure_reason) 2170 2171 2172def send_link_probes(ad, num_probes, delay_sec): 2173 """Sends a sequence of link probes to the currently connected AP, and 2174 returns whether the probes succeeded or not. 2175 2176 Args: 2177 ad: android device object 2178 num_probes: number of probes to perform 2179 delay_sec: delay time between probes, in seconds 2180 Returns: 2181 List[LinkProbeResult] one LinkProbeResults for each probe 2182 """ 2183 logging.info('Sending link probes') 2184 results = [] 2185 for _ in range(num_probes): 2186 # send_link_probe() will also fail the test if it sees an exception 2187 # in the stdout of the adb shell command 2188 result = send_link_probe(ad) 2189 logging.info('link probe results: ' + str(result)) 2190 results.append(result) 2191 time.sleep(delay_sec) 2192 2193 return results 2194 2195 2196def ap_setup(test, index, ap, network, bandwidth=80, channel=6): 2197 """Set up the AP with provided network info. 2198 2199 Args: 2200 test: the calling test class object. 2201 index: int, index of the AP. 2202 ap: access_point object of the AP. 2203 network: dict with information of the network, including ssid, 2204 password and bssid. 2205 bandwidth: the operation bandwidth for the AP, default 80MHz. 2206 channel: the channel number for the AP. 2207 Returns: 2208 brconfigs: the bridge interface configs 2209 """ 2210 bss_settings = [] 2211 ssid = network[WifiEnums.SSID_KEY] 2212 test.access_points[index].close() 2213 time.sleep(5) 2214 2215 # Configure AP as required. 2216 if "password" in network.keys(): 2217 password = network["password"] 2218 security = hostapd_security.Security( 2219 security_mode="wpa", password=password) 2220 else: 2221 security = hostapd_security.Security(security_mode=None, password=None) 2222 config = hostapd_ap_preset.create_ap_preset( 2223 channel=channel, 2224 ssid=ssid, 2225 security=security, 2226 bss_settings=bss_settings, 2227 vht_bandwidth=bandwidth, 2228 profile_name='whirlwind', 2229 iface_wlan_2g=ap.wlan_2g, 2230 iface_wlan_5g=ap.wlan_5g) 2231 ap.start_ap(config) 2232 logging.info("AP started on channel {} with SSID {}".format(channel, ssid)) 2233 2234 2235def turn_ap_off(test, AP): 2236 """Bring down hostapd on the Access Point. 2237 Args: 2238 test: The test class object. 2239 AP: int, indicating which AP to turn OFF. 2240 """ 2241 hostapd_2g = test.access_points[AP-1]._aps['wlan0'].hostapd 2242 if hostapd_2g.is_alive(): 2243 hostapd_2g.stop() 2244 logging.debug('Turned WLAN0 AP%d off' % AP) 2245 hostapd_5g = test.access_points[AP-1]._aps['wlan1'].hostapd 2246 if hostapd_5g.is_alive(): 2247 hostapd_5g.stop() 2248 logging.debug('Turned WLAN1 AP%d off' % AP) 2249 2250 2251def turn_ap_on(test, AP): 2252 """Bring up hostapd on the Access Point. 2253 Args: 2254 test: The test class object. 2255 AP: int, indicating which AP to turn ON. 2256 """ 2257 hostapd_2g = test.access_points[AP-1]._aps['wlan0'].hostapd 2258 if not hostapd_2g.is_alive(): 2259 hostapd_2g.start(hostapd_2g.config) 2260 logging.debug('Turned WLAN0 AP%d on' % AP) 2261 hostapd_5g = test.access_points[AP-1]._aps['wlan1'].hostapd 2262 if not hostapd_5g.is_alive(): 2263 hostapd_5g.start(hostapd_5g.config) 2264 logging.debug('Turned WLAN1 AP%d on' % AP) 2265