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