blob: 1f374906cb3de29560ad806239ee99082cb4efcd [file] [log] [blame]
#!/usr/bin/env python3.4
#
# Copyright 2016 Google, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import time
import pprint
from enum import IntEnum
from queue import Empty
from acts import signals
from acts.utils import exe_cmd
from acts.utils import require_sl4a
from acts.utils import sync_device_time
from acts.utils import trim_model_name
log = logging
# Number of seconds to wait for events that are supposed to happen quickly.
# Like onSuccess for start background scan and confirmation on wifi state
# change.
SHORT_TIMEOUT = 30
# The currently supported devices that existed before release
#TODO: (navtejsingh) Need to clean up the below lists going forward
K_DEVICES = ["hammerhead", "razor", "razorg"]
L_DEVICES = ["shamu", "ryu"]
L_TAP_DEVICES = ["volantis", "volantisg"]
M_DEVICES = ["angler"]
# Speed of light in m/s.
SPEED_OF_LIGHT = 299792458
DEFAULT_PING_ADDR = "http://www.google.com/robots.txt"
class WifiEnums():
SSID_KEY = "SSID"
BSSID_KEY = "BSSID"
PWD_KEY = "password"
frequency_key = "frequency"
APBAND_KEY = "apBand"
WIFI_CONFIG_APBAND_2G = 0
WIFI_CONFIG_APBAND_5G = 1
WIFI_WPS_INFO_PBC = 0;
WIFI_WPS_INFO_DISPLAY = 1;
WIFI_WPS_INFO_KEYPAD = 2;
WIFI_WPS_INFO_LABEL = 3;
WIFI_WPS_INFO_INVALID = 4;
class CountryCode():
CHINA = "CN"
JAPAN = "JP"
UK = "GB"
US = "US"
UNKNOWN = "UNKNOWN"
# Start of Macros for EAP
# EAP types
class Eap(IntEnum):
NONE = -1
PEAP = 0
TLS = 1
TTLS = 2
PWD = 3
SIM = 4
AKA = 5
# EAP Phase2 types
class EapPhase2(IntEnum):
NONE = 0
PAP = 1
MSCHAP = 2
MSCHAPV2 = 3
GTC = 4
class Enterprise:
# Enterprise Config Macros
EMPTY_VALUE = "NULL"
EAP = "eap"
PHASE2 = "phase2"
IDENTITY = "identity"
ANON_IDENTITY = "anonymous_identity"
PASSWORD = "password"
SUBJECT_MATCH = "subject_match"
ALTSUBJECT_MATCH = "altsubject_match"
DOM_SUFFIX_MATCH = "domain_suffix_match"
CLIENT_CERT = "client_cert"
CA_CERT = "ca_cert"
ENGINE = "engine"
ENGINE_ID = "engine_id"
PRIVATE_KEY_ID = "key_id"
REALM = "realm"
PLMN = "plmn"
FQDN = "FQDN"
FRIENDLY_NAME = "providerFriendlyName"
ROAMING_IDS = "roamingConsortiumIds"
# End of Macros for EAP
# Macros for wifi p2p.
WIFI_P2P_SERVICE_TYPE_ALL = 0
WIFI_P2P_SERVICE_TYPE_BONJOUR = 1
WIFI_P2P_SERVICE_TYPE_UPNP = 2
WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255
class ScanResult:
CHANNEL_WIDTH_20MHZ = 0
CHANNEL_WIDTH_40MHZ = 1
CHANNEL_WIDTH_80MHZ = 2
CHANNEL_WIDTH_160MHZ = 3
CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4
# Macros for wifi rtt.
class RttType(IntEnum):
TYPE_ONE_SIDED = 1
TYPE_TWO_SIDED = 2
class RttPeerType(IntEnum):
PEER_TYPE_AP = 1
PEER_TYPE_STA = 2 # Requires NAN.
PEER_P2P_GO = 3
PEER_P2P_CLIENT = 4
PEER_NAN = 5
class RttPreamble(IntEnum):
PREAMBLE_LEGACY = 0x01
PREAMBLE_HT = 0x02
PREAMBLE_VHT = 0x04
class RttBW(IntEnum):
BW_5_SUPPORT = 0x01
BW_10_SUPPORT = 0x02
BW_20_SUPPORT = 0x04
BW_40_SUPPORT = 0x08
BW_80_SUPPORT = 0x10
BW_160_SUPPORT = 0x20
class Rtt(IntEnum):
STATUS_SUCCESS = 0
STATUS_FAILURE = 1
STATUS_FAIL_NO_RSP = 2
STATUS_FAIL_REJECTED = 3
STATUS_FAIL_NOT_SCHEDULED_YET = 4
STATUS_FAIL_TM_TIMEOUT = 5
STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6
STATUS_FAIL_NO_CAPABILITY = 7
STATUS_ABORTED = 8
STATUS_FAIL_INVALID_TS = 9
STATUS_FAIL_PROTOCOL = 10
STATUS_FAIL_SCHEDULE = 11
STATUS_FAIL_BUSY_TRY_LATER = 12
STATUS_INVALID_REQ = 13
STATUS_NO_WIFI = 14
STATUS_FAIL_FTM_PARAM_OVERRIDE = 15
REASON_UNSPECIFIED = -1
REASON_NOT_AVAILABLE = -2
REASON_INVALID_LISTENER = -3
REASON_INVALID_REQUEST = -4
class RttParam:
device_type = "deviceType"
request_type = "requestType"
BSSID = "bssid"
channel_width = "channelWidth"
frequency = "frequency"
center_freq0 = "centerFreq0"
center_freq1 = "centerFreq1"
number_burst = "numberBurst"
interval = "interval"
num_samples_per_burst = "numSamplesPerBurst"
num_retries_per_measurement_frame = "numRetriesPerMeasurementFrame"
num_retries_per_FTMR = "numRetriesPerFTMR"
lci_request = "LCIRequest"
lcr_request = "LCRRequest"
burst_timeout = "burstTimeout"
preamble = "preamble"
bandwidth = "bandwidth"
margin = "margin"
RTT_MARGIN_OF_ERROR = {
RttBW.BW_80_SUPPORT: 2,
RttBW.BW_40_SUPPORT: 5,
RttBW.BW_20_SUPPORT: 5
}
# Macros as specified in the WifiScanner code.
WIFI_BAND_UNSPECIFIED = 0 # not specified
WIFI_BAND_24_GHZ = 1 # 2.4 GHz band
WIFI_BAND_5_GHZ = 2 # 5 GHz band without DFS channels
WIFI_BAND_5_GHZ_DFS_ONLY = 4 # 5 GHz band with DFS channels
WIFI_BAND_5_GHZ_WITH_DFS = 6 # 5 GHz band with DFS channels
WIFI_BAND_BOTH = 3 # both bands without DFS channels
WIFI_BAND_BOTH_WITH_DFS = 7 # both bands with DFS channels
REPORT_EVENT_AFTER_BUFFER_FULL = 0
REPORT_EVENT_AFTER_EACH_SCAN = 1
REPORT_EVENT_FULL_SCAN_RESULT = 2
# US Wifi frequencies
ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452,
2457, 2462]
DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580,
5600, 5620, 5640, 5660, 5680, 5700, 5720]
NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805,
5825]
ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES
band_to_frequencies = {
WIFI_BAND_24_GHZ: ALL_2G_FREQUENCIES,
WIFI_BAND_5_GHZ: NONE_DFS_5G_FREQUENCIES,
WIFI_BAND_5_GHZ_DFS_ONLY: DFS_5G_FREQUENCIES,
WIFI_BAND_5_GHZ_WITH_DFS: ALL_5G_FREQUENCIES,
WIFI_BAND_BOTH: ALL_2G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES,
WIFI_BAND_BOTH_WITH_DFS: ALL_5G_FREQUENCIES + ALL_2G_FREQUENCIES
}
# All Wifi frequencies to channels lookup.
freq_to_channel = {
2412: 1,
2417: 2,
2422: 3,
2427: 4,
2432: 5,
2437: 6,
2442: 7,
2447: 8,
2452: 9,
2457: 10,
2462: 11,
2467: 12,
2472: 13,
2484: 14,
4915: 183,
4920: 184,
4925: 185,
4935: 187,
4940: 188,
4945: 189,
4960: 192,
4980: 196,
5035: 7,
5040: 8,
5045: 9,
5055: 11,
5060: 12,
5080: 16,
5170: 34,
5180: 36,
5190: 38,
5200: 40,
5210: 42,
5220: 44,
5230: 46,
5240: 48,
5260: 52,
5280: 56,
5300: 60,
5320: 64,
5500: 100,
5520: 104,
5540: 108,
5560: 112,
5580: 116,
5600: 120,
5620: 124,
5640: 128,
5660: 132,
5680: 136,
5700: 140,
5745: 149,
5765: 153,
5785: 157,
5805: 161,
5825: 165,
}
# All Wifi channels to frequencies lookup.
channel_2G_to_freq = {
1: 2412,
2: 2417,
3: 2422,
4: 2427,
5: 2432,
6: 2437,
7: 2442,
8: 2447,
9: 2452,
10: 2457,
11: 2462,
12: 2467,
13: 2472,
14: 2484
}
channel_5G_to_freq = {
183: 4915,
184: 4920,
185: 4925,
187: 4935,
188: 4940,
189: 4945,
192: 4960,
196: 4980,
7: 5035,
8: 5040,
9: 5045,
11: 5055,
12: 5060,
16: 5080,
34: 5170,
36: 5180,
38: 5190,
40: 5200,
42: 5210,
44: 5220,
46: 5230,
48: 5240,
52: 5260,
56: 5280,
60: 5300,
64: 5320,
100: 5500,
104: 5520,
108: 5540,
112: 5560,
116: 5580,
120: 5600,
124: 5620,
128: 5640,
132: 5660,
136: 5680,
140: 5700,
149: 5745,
153: 5765,
157: 5785,
161: 5805,
165: 5825
}
class WifiEventNames:
WIFI_CONNECTED = "WifiNetworkConnected"
SUPPLICANT_CON_CHANGED = "SupplicantConnectionChanged"
WIFI_FORGET_NW_SUCCESS = "WifiManagerForgetNetworkOnSuccess"
class WifiTestUtilsError(Exception):
pass
class WifiChannelBase:
ALL_2G_FREQUENCIES = []
DFS_5G_FREQUENCIES = []
NONE_DFS_5G_FREQUENCIES = []
ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES
MIX_CHANNEL_SCAN = []
def band_to_freq(self, band):
_band_to_frequencies = {
WifiEnums.WIFI_BAND_24_GHZ: self.ALL_2G_FREQUENCIES,
WifiEnums.WIFI_BAND_5_GHZ: self.NONE_DFS_5G_FREQUENCIES,
WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY: self.DFS_5G_FREQUENCIES,
WifiEnums.WIFI_BAND_5_GHZ_WITH_DFS: self.ALL_5G_FREQUENCIES,
WifiEnums.WIFI_BAND_BOTH: self.ALL_2G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES,
WifiEnums.WIFI_BAND_BOTH_WITH_DFS: self.ALL_5G_FREQUENCIES + self.ALL_2G_FREQUENCIES
}
return _band_to_frequencies[band]
class WifiChannelUS(WifiChannelBase):
# US Wifi frequencies
ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452,
2457, 2462]
NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805,
5825]
MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5280, 5260, 5300,5500, 5320,
5520, 5560, 5700, 5745, 5805]
def __init__(self, model=None):
if model and trim_model_name(model) in K_DEVICES:
self.DFS_5G_FREQUENCIES = []
self.ALL_5G_FREQUENCIES = self.NONE_DFS_5G_FREQUENCIES
self.MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5240, 5745, 5765]
elif model and trim_model_name(model) in L_DEVICES:
self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520,
5540, 5560, 5580, 5660, 5680, 5700]
self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES
elif model and trim_model_name(model) in L_TAP_DEVICES:
self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520,
5540, 5560, 5580, 5660, 5680, 5700, 5720]
self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES
elif model and trim_model_name(model) in M_DEVICES:
self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,5580,
5600, 5620, 5640, 5660, 5680, 5700]
self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES
else:
self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,5580,
5600, 5620, 5640, 5660, 5680, 5700, 5720]
self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES
def match_networks(target_params, networks):
"""Finds the WiFi networks that match a given set of parameters in a list
of WiFi networks.
To be considered a match, a network needs to have all the target parameters
and the values of those parameters need to equal to those of the target
parameters.
Args:
target_params: The target parameters to match networks against.
networks: A list of dict objects representing WiFi networks.
Returns:
The networks that match the target parameters.
"""
results = []
for n in networks:
for k, v in target_params.items():
if k not in n:
continue
if n[k] != v:
continue
results.append(n)
return results
def wifi_toggle_state(ad, new_state=None):
"""Toggles the state of wifi.
Args:
ad: An AndroidDevice object.
new_state: Wifi state to set to. If None, opposite of the current state.
Returns:
True if the toggle was successful, False otherwise.
"""
# Check if the new_state is already achieved, so we don't wait for the
# state change event by mistake.
if new_state == ad.droid.wifiCheckState():
return True
ad.droid.wifiStartTrackingStateChange()
log.info("Setting wifi state to {}".format(new_state))
ad.droid.wifiToggleState(new_state)
try:
event = ad.ed.pop_event(WifiEventNames.SUPPLICANT_CON_CHANGED, SHORT_TIMEOUT)
return event['data']['Connected'] == new_state
except Empty:
# Supplicant connection event is not always reliable. We double check here
# and call it a success as long as the new state equals the expected state.
return new_state == ad.droid.wifiCheckState()
finally:
ad.droid.wifiStopTrackingStateChange()
def reset_wifi(ad):
"""Clears all saved networks on a device.
Args:
ad: An AndroidDevice object.
Raises:
WifiTestUtilsError is raised if forget network operation failed.
"""
ad.droid.wifiToggleState(True)
networks = ad.droid.wifiGetConfiguredNetworks()
if not networks:
return
for n in networks:
ad.droid.wifiForgetNetwork(n['networkId'])
try:
event = ad.ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS,
SHORT_TIMEOUT)
except Empty:
raise WifiTestUtilsError("Failed to remove network {}.".format(n))
def wifi_forget_network(ad, net_ssid):
"""Remove configured Wifi network on an android device.
Args:
ad: android_device object for forget network.
net_ssid: ssid of network to be forget
Raises:
WifiTestUtilsError is raised if forget network operation failed.
"""
droid, ed = ad.droid, ad.ed
droid.wifiToggleState(True)
networks = droid.wifiGetConfiguredNetworks()
if not networks:
return
for n in networks:
if net_ssid in n[WifiEnums.SSID_KEY]:
droid.wifiForgetNetwork(n['networkId'])
try:
event = ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS,
SHORT_TIMEOUT)
except Empty:
raise WifiTestUtilsError("Failed to remove network %s." % n)
def wifi_test_device_init(ad):
"""Initializes an android device for wifi testing.
0. Make sure SL4A connection is established on the android device.
1. Disable location service's WiFi scan.
2. Turn WiFi on.
3. Clear all saved networks.
4. Set country code to US.
5. Enable WiFi verbose logging.
6. Sync device time with computer time.
7. Turn off cellular data.
"""
require_sl4a((ad,))
ad.droid.wifiScannerToggleAlwaysAvailable(False)
msg = "Failed to turn off location service's scan."
assert not ad.droid.wifiScannerIsAlwaysAvailable(), msg
msg = "Failed to turn WiFi on %s" % ad.serial
assert wifi_toggle_state(ad, True), msg
reset_wifi(ad)
msg = "Failed to clear configured networks."
assert not ad.droid.wifiGetConfiguredNetworks(), msg
ad.droid.wifiEnableVerboseLogging(1)
msg = "Failed to enable WiFi verbose logging."
assert ad.droid.wifiGetVerboseLoggingLevel() == 1, msg
ad.droid.wifiScannerToggleAlwaysAvailable(False)
# We don't verify the following settings since they are not critical.
sync_device_time(ad)
ad.droid.telephonyToggleDataConnection(False)
# TODO(angli): need to verify the country code was actually set. No generic
# way to check right now.
ad.adb.shell("halutil -country %s" % WifiEnums.CountryCode.US)
def sort_wifi_scan_results(results, key="level"):
"""Sort wifi scan results by key.
Args:
results: A list of results to sort.
key: Name of the field to sort the results by.
Returns:
A list of results in sorted order.
"""
return sorted(results, lambda d: (key not in d, d[key]))
def start_wifi_connection_scan(ad):
"""Starts a wifi connection scan and wait for results to become available.
Args:
ad: An AndroidDevice object.
"""
ad.droid.wifiStartScan()
ad.ed.pop_event("WifiManagerScanResultsAvailable", 60)
def start_wifi_background_scan(ad, scan_setting):
"""Starts wifi background scan.
Args:
ad: android_device object to initiate connection on.
scan_setting: A dict representing the settings of the scan.
Returns:
If scan was started successfully, event data of success event is returned.
"""
droid, ed = ad.droids[0], ad.eds[0]
idx = droid.wifiScannerStartBackgroundScan(scan_setting)
event = ed.pop_event("WifiScannerScan{}onSuccess".format(idx),
SHORT_TIMEOUT)
return event['data']
def start_wifi_tethering(ad, ssid, password, band=None):
"""Starts wifi tethering on an android_device.
Args:
ad: android_device to start wifi tethering on.
ssid: The SSID the soft AP should broadcast.
password: The password the soft AP should use.
band: The band the soft AP should be set on. It should be either
WifiEnums.WIFI_CONFIG_APBAND_2G or WifiEnums.WIFI_CONFIG_APBAND_5G.
Returns:
True if soft AP was started successfully, False otherwise.
"""
droid, ed = ad.droid, ad.ed
droid.wifiStartTrackingStateChange()
config = {
WifiEnums.SSID_KEY: ssid
}
if password:
config[WifiEnums.PWD_KEY] = password
if band:
config[WifiEnums.APBAND_KEY] = band
if not droid.wifiSetApEnabled(True, config):
return False
ed.pop_event("WifiManagerApEnabled", 30)
ed.wait_for_event("TetherStateChanged",
lambda x : x["data"]["ACTIVE_TETHER"], 30)
droid.wifiStopTrackingStateChange()
return True
def stop_wifi_tethering(ad):
"""Stops wifi tethering on an android_device.
Args:
ad: android_device to stop wifi tethering on.
"""
droid, ed = ad.droid, ad.ed
droid.wifiStartTrackingStateChange()
droid.wifiSetApEnabled(False, None)
ed.pop_event("WifiManagerApDisabled", 30)
ed.wait_for_event("TetherStateChanged",
lambda x : not x["data"]["ACTIVE_TETHER"], 30)
droid.wifiStopTrackingStateChange()
def wifi_connect(ad, network):
"""Connect an Android device to a wifi network.
Initiate connection to a wifi network, wait for the "connected" event, then
confirm the connected ssid is the one requested.
Args:
ad: android_device object to initiate connection on.
network: A dictionary representing the network to connect to. The
dictionary must have the key "SSID".
"""
assert WifiEnums.SSID_KEY in network, ("Key '%s' must be present in "
"network definition.") % WifiEnums.SSID_KEY
ad.droid.wifiStartTrackingStateChange()
try:
assert ad.droid.wifiConnect(network), "WiFi connect returned false."
connect_result = ad.ed.pop_event(WifiEventNames.WIFI_CONNECTED)
log.debug("Connection result: %s." % connect_result)
expected_ssid = network[WifiEnums.SSID_KEY]
actual_ssid = connect_result['data'][WifiEnums.SSID_KEY]
assert actual_ssid == expected_ssid, ("Expected to connect to %s, "
"connected to %s") % (expected_ssid, actual_ssid)
log.info("Successfully connected to %s" % actual_ssid)
finally:
ad.droid.wifiStopTrackingStateChange()
def start_wifi_single_scan(ad, scan_setting):
"""Starts wifi single shot scan.
Args:
ad: android_device object to initiate connection on.
scan_setting: A dict representing the settings of the scan.
Returns:
If scan was started successfully, event data of success event is returned.
"""
droid, ed = ad.droid, ad.ed
idx = droid.wifiScannerStartScan(scan_setting)
event = ed.pop_event("WifiScannerScan{}onSuccess".format(idx),
SHORT_TIMEOUT)
log.debug("event {}".format(event))
return event['data']
def track_connection(ad, network_ssid, check_connection_count):
"""Track wifi connection to network changes for given number of counts
Args:
ad: android_device object for forget network.
network_ssid: network ssid to which connection would be tracked
check_connection_count: Integer for maximum number network connection
check.
Returns:
True if connection to given network happen, else return False.
"""
droid, ed = ad.droid, ad.ed
droid.wifiStartTrackingStateChange()
while check_connection_count > 0:
connect_network = ed.pop_event("WifiNetworkConnected", 120)
log.info("connect_network {}".format(connect_network))
if (WifiEnums.SSID_KEY in connect_network['data']
and connect_network['data'][WifiEnums.SSID_KEY] == network_ssid):
return True
check_connection_count -= 1
droid.wifiStopTrackingStateChange()
return False
def get_scan_time_and_channels(wifi_chs, scan_setting, stime_channel):
"""Calculate the scan time required based on the band or channels in scan
setting
Args:
wifi_chs: Object of channels supported
scan_setting: scan setting used for start scan
stime_channel: scan time per channel
Returns:
scan_time: time required for completing a scan
scan_channels: channel used for scanning
"""
scan_time = 0
scan_channels = []
if "band" in scan_setting and "channels" not in scan_setting:
scan_channels = wifi_chs.band_to_freq(scan_setting["band"])
elif "channels" in scan_setting and "band" not in scan_setting:
scan_channels = scan_setting["channels"]
scan_time = len(scan_channels) * stime_channel
for channel in scan_channels:
if channel in WifiEnums.DFS_5G_FREQUENCIES:
scan_time += 132 #passive scan time on DFS
return scan_time, scan_channels
def start_wifi_track_bssid(ad, track_setting):
"""Start tracking Bssid for the given settings.
Args:
ad: android_device object.
track_setting: Setting for which the bssid tracking should be started
Returns:
If tracking started successfully, event data of success event is returned.
"""
droid, ed = ad.droid, ad.ed
idx = droid.wifiScannerStartTrackingBssids(
track_setting["bssidInfos"],
track_setting["apLostThreshold"]
)
event = ed.pop_event("WifiScannerBssid{}onSuccess".format(idx),
SHORT_TIMEOUT)
return event['data']
def convert_pem_key_to_pkcs8(in_file, out_file):
"""Converts the key file generated by us to the format required by
Android using openssl.
The input file must have the extension "pem". The output file must
have the extension "der".
Args:
in_file: The original key file.
out_file: The full path to the converted key file, including
filename.
"""
assert in_file.endswith(".pem")
assert out_file.endswith(".der")
cmd = ("openssl pkcs8 -inform PEM -in {} -outform DER -out {} -nocrypt"
" -topk8").format(in_file, out_file)
exe_cmd(cmd)
def check_internet_connection(ad, ping_addr):
"""Validate internet connection by pinging the address provided.
Args:
ad: android_device object.
ping_addr: address on internet for pinging.
Returns:
True, if address ping successful
"""
droid, ed = ad.droid, ad.ed
ping = droid.httpPing(ping_addr)
log.info("Http ping result: {}".format(ping))
return ping
#TODO(angli): This can only verify if an actual value is exactly the same.
# Would be nice to be able to verify an actual value is one of serveral.
def verify_wifi_connection_info(ad, expected_con):
"""Verifies that the information of the currently connected wifi network is
as expected.
Args:
expected_con: A dict representing expected key-value pairs for wifi
connection. e.g. {"SSID": "test_wifi"}
"""
current_con = ad.droid.wifiGetConnectionInfo()
case_insensitive = ["BSSID", "supplicant_state"]
log.debug("Current connection: %s" % current_con)
for k, expected_v in expected_con.items():
# Do not verify authentication related fields.
if k == "password":
continue
msg = "Field %s does not exist in wifi connection info %s." % (k,
current_con)
if k not in current_con:
raise signals.TestFailure(msg)
actual_v = current_con[k]
if k in case_insensitive:
actual_v = actual_v.lower()
expected_v = expected_v.lower()
msg = "Expected %s to be %s, actual %s is %s." % (k, expected_v, k,
actual_v)
if actual_v != expected_v:
raise signals.TestFailure(msg)
def eap_connect(config, ad, validate_con=True, ping_addr=DEFAULT_PING_ADDR):
"""Connects to an enterprise network and verify connection.
This logic expect the enterprise network to have Internet access.
Args:
config: A dict representing a wifi enterprise configuration.
ad: The android_device to operate with.
validate_con: If True, validate Internet connection after connecting to
the network.
Returns:
True if the connection is successful and Internet access works.
"""
droid, ed = ad.droid, ad.ed
start_wifi_connection_scan(ad)
expect_ssid = None
if WifiEnums.SSID_KEY in config:
expect_ssid = config[WifiEnums.SSID_KEY]
log.info("Connecting to %s." % expect_ssid)
else:
log.info("Connecting.")
log.debug(pprint.pformat(config, indent=4))
ad.droid.wifiEnterpriseConnect(config)
try:
event = ed.pop_event("WifiManagerEnterpriseConnectOnSuccess", 30)
log.info("Started connecting...")
event = ed.pop_event(WifiEventNames.WIFI_CONNECTED, 60)
except Empty:
log.info("Failed to connect.")
return False
log.debug(event)
if expect_ssid:
actual_ssid = event["data"][WifiEnums.SSID_KEY]
msg = "Expected SSID {}, got {}".format(expect_ssid, actual_ssid)
if expect_ssid != actual_ssid:
log.error(msg)
return False
log.info("Connected to %s." % expect_ssid)
else:
log.info("Connected successfully.")
if validate_con:
log.info("Checking Internet access.")
# Wait for data connection to stabilize.
time.sleep(4)
ping = ad.droid.httpPing(ping_addr)
log.info("Http ping result: {}".format(ping))
if not ping:
log.error("No Internet access.")
return False
return True
def expand_enterprise_config_by_phase2(config):
"""Take an enterprise config and generate a list of configs, each with
a different phase2 auth type.
Args:
config: A dict representing enterprise config.
Returns
A list of enterprise configs.
"""
results = []
phase2_types = WifiEnums.EapPhase2
if config[WifiEnums.Enterprise.EAP] == WifiEnums.Eap.PEAP:
# Skip unsupported phase2 types for PEAP.
phase2_types = [WifiEnums.EapPhase2.GTC, WifiEnums.EapPhase2.MSCHAPV2]
for phase2_type in phase2_types:
# Skip a special case for passpoint TTLS.
if (WifiEnums.Enterprise.FQDN in config and
phase2_type == WifiEnums.EapPhase2.GTC):
continue
c = dict(config)
c[WifiEnums.Enterprise.PHASE2] = phase2_type
results.append(c)
return results