blob: e2134383efe0a28fd6a4047ef8fcefe40beee917 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2019 - The Android Open Source Project
#
# 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 inspect
import logging
import acts_contrib.test_utils.wifi.wifi_test_utils as awutils
from acts.utils import get_interface_ip_addresses
from acts.utils import adb_shell_ping
from acts import asserts
from acts.controllers.fuchsia_device import FuchsiaDevice
from acts.controllers.android_device import AndroidDevice
def create_wlan_device(hardware_device):
"""Creates a generic WLAN device based on type of device that is sent to
the functions.
Args:
hardware_device: A WLAN hardware device that is supported by ACTS.
"""
if isinstance(hardware_device, FuchsiaDevice):
return FuchsiaWlanDevice(hardware_device)
elif isinstance(hardware_device, AndroidDevice):
return AndroidWlanDevice(hardware_device)
else:
raise ValueError('Unable to create WlanDevice for type %s' %
type(hardware_device))
FUCHSIA_VALID_SECURITY_TYPES = {"none", "wep", "wpa", "wpa2", "wpa3"}
class WlanDevice(object):
"""Class representing a generic WLAN device.
Each object of this class represents a generic WLAN device.
Android device and Fuchsia devices are the currently supported devices/
Attributes:
device: A generic WLAN device.
"""
def __init__(self, device):
self.device = device
self.log = logging
self.identifier = None
def wifi_toggle_state(self, state):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def reset_wifi(self):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def take_bug_report(self, test_name, begin_time):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def get_log(self, test_name, begin_time):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def turn_location_off_and_scan_toggle_off(self):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def associate(self,
target_ssid,
target_pwd=None,
check_connectivity=True,
hidden=False,
target_security=None):
"""Base generic WLAN interface. Only called if not overriden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def disconnect(self):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def get_wlan_interface_id_list(self):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def destroy_wlan_interface(self, iface_id):
"""Base generic WLAN interface. Only called if not overridden by
another supported device.
"""
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def send_command(self, command):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def get_interface_ip_addresses(self, interface):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def is_connected(self, ssid=None):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def can_ping(self,
dest_ip,
count=3,
interval=1000,
timeout=1000,
size=25,
additional_ping_params=None):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def ping(self,
dest_ip,
count=3,
interval=1000,
timeout=1000,
size=25,
additional_ping_params=None):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def hard_power_cycle(self, pdus=None):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def save_network(self, ssid):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
def clear_saved_networks(self):
raise NotImplementedError("{} must be defined.".format(
inspect.currentframe().f_code.co_name))
class AndroidWlanDevice(WlanDevice):
"""Class wrapper for an Android WLAN device.
Each object of this class represents a generic WLAN device.
Android device and Fuchsia devices are the currently supported devices/
Attributes:
android_device: An Android WLAN device.
"""
def __init__(self, android_device):
super().__init__(android_device)
self.identifier = android_device.serial
def wifi_toggle_state(self, state):
awutils.wifi_toggle_state(self.device, state)
def reset_wifi(self):
awutils.reset_wifi(self.device)
def take_bug_report(self, test_name, begin_time):
self.device.take_bug_report(test_name, begin_time)
def get_log(self, test_name, begin_time):
self.device.cat_adb_log(test_name, begin_time)
def turn_location_off_and_scan_toggle_off(self):
awutils.turn_location_off_and_scan_toggle_off(self.device)
def associate(self,
target_ssid,
target_pwd=None,
key_mgmt=None,
check_connectivity=True,
hidden=False,
target_security=None):
"""Function to associate an Android WLAN device.
Args:
target_ssid: SSID to associate to.
target_pwd: Password for the SSID, if necessary.
key_mgmt: The hostapd wpa_key_mgmt value, distinguishes wpa3 from
wpa2 for android tests.
check_connectivity: Whether to check for internet connectivity.
hidden: Whether the network is hidden.
Returns:
True if successfully connected to WLAN, False if not.
"""
network = {'SSID': target_ssid, 'hiddenSSID': hidden}
if target_pwd:
network['password'] = target_pwd
if key_mgmt:
network['security'] = key_mgmt
try:
awutils.connect_to_wifi_network(
self.device,
network,
check_connectivity=check_connectivity,
hidden=hidden)
return True
except Exception as e:
self.device.log.info('Failed to associated (%s)' % e)
return False
def disconnect(self):
awutils.turn_location_off_and_scan_toggle_off(self.device)
def get_wlan_interface_id_list(self):
pass
def destroy_wlan_interface(self, iface_id):
pass
def send_command(self, command):
return self.device.adb.shell(str(command))
def get_interface_ip_addresses(self, interface):
return get_interface_ip_addresses(self.device, interface)
def is_connected(self, ssid=None):
wifi_info = self.device.droid.wifiGetConnectionInfo()
if ssid:
return 'BSSID' in wifi_info and wifi_info['SSID'] == ssid
return 'BSSID' in wifi_info
def can_ping(self,
dest_ip,
count=3,
interval=1000,
timeout=1000,
size=25,
additional_ping_params=None):
return adb_shell_ping(self.device,
dest_ip=dest_ip,
count=count,
timeout=timeout)
def ping(self, dest_ip, count=3, interval=1000, timeout=1000, size=25):
pass
def hard_power_cycle(self, pdus):
pass
def save_network(self, ssid):
pass
def clear_saved_networks(self):
pass
class FuchsiaWlanDevice(WlanDevice):
"""Class wrapper for an Fuchsia WLAN device.
Each object of this class represents a generic WLAN device.
Android device and Fuchsia devices are the currently supported devices/
Attributes:
fuchsia_device: A Fuchsia WLAN device.
"""
def __init__(self, fuchsia_device):
super().__init__(fuchsia_device)
self.identifier = fuchsia_device.ip
self.device.configure_wlan()
def wifi_toggle_state(self, state):
"""Stub for Fuchsia implementation."""
pass
def reset_wifi(self):
"""Stub for Fuchsia implementation."""
pass
def take_bug_report(self, test_name, begin_time):
"""Stub for Fuchsia implementation."""
pass
def get_log(self, test_name, begin_time):
"""Stub for Fuchsia implementation."""
pass
def turn_location_off_and_scan_toggle_off(self):
"""Stub for Fuchsia implementation."""
pass
def associate(self,
target_ssid,
target_pwd=None,
key_mgmt=None,
check_connectivity=True,
hidden=False,
target_security=None):
"""Function to associate a Fuchsia WLAN device.
Args:
target_ssid: SSID to associate to.
target_pwd: Password for the SSID, if necessary.
key_mgmt: the hostapd wpa_key_mgmt, if specified.
check_connectivity: Whether to check for internet connectivity.
hidden: Whether the network is hidden.
target_security: string, target security for network, used to
save the network in policy connects (see wlan_policy_lib)
Returns:
True if successfully connected to WLAN, False if not.
"""
if self.device.association_mechanism == 'drivers':
bss_scan_response = self.device.wlan_lib.wlanScanForBSSInfo()
if bss_scan_response.get('error'):
self.log.error('Scan for BSS info failed. Err: %s' %
bss_scan_response['error'])
return False
bss_descs_for_ssid = bss_scan_response['result'].get(
target_ssid, None)
if not bss_descs_for_ssid or len(bss_descs_for_ssid) < 1:
self.log.error(
'Scan failed to find a BSS description for target_ssid %s'
% target_ssid)
return False
connection_response = self.device.wlan_lib.wlanConnectToNetwork(
target_ssid, bss_descs_for_ssid[0], target_pwd=target_pwd)
return self.device.check_connect_response(connection_response)
else:
return self.device.wlan_policy_controller.save_and_connect(
target_ssid, target_security, password=target_pwd)
def disconnect(self):
"""Function to disconnect from a Fuchsia WLAN device.
Asserts if disconnect was not successful.
"""
if self.device.association_mechanism == 'drivers':
disconnect_response = self.device.wlan_lib.wlanDisconnect()
return self.device.check_disconnect_response(disconnect_response)
else:
return self.device.wlan_policy_controller.remove_all_networks_and_wait_for_no_connections(
)
def status(self):
return self.device.wlan_lib.wlanStatus()
def can_ping(self,
dest_ip,
count=3,
interval=1000,
timeout=1000,
size=25,
additional_ping_params=None):
return self.device.can_ping(
dest_ip,
count=count,
interval=interval,
timeout=timeout,
size=size,
additional_ping_params=additional_ping_params)
def ping(self,
dest_ip,
count=3,
interval=1000,
timeout=1000,
size=25,
additional_ping_params=None):
return self.device.ping(dest_ip,
count=count,
interval=interval,
timeout=timeout,
size=size,
additional_ping_params=additional_ping_params)
def get_wlan_interface_id_list(self):
"""Function to list available WLAN interfaces.
Returns:
A list of wlan interface IDs.
"""
return self.device.wlan_lib.wlanGetIfaceIdList().get('result')
def destroy_wlan_interface(self, iface_id):
"""Function to associate a Fuchsia WLAN device.
Args:
target_ssid: SSID to associate to.
target_pwd: Password for the SSID, if necessary.
check_connectivity: Whether to check for internet connectivity.
hidden: Whether the network is hidden.
Returns:
True if successfully destroyed wlan interface, False if not.
"""
result = self.device.wlan_lib.wlanDestroyIface(iface_id)
if result.get('error') is None:
return True
else:
self.log.error("Failed to destroy interface with: {}".format(
result.get('error')))
return False
def send_command(self, command):
return self.device.send_command_ssh(str(command)).stdout
def get_interface_ip_addresses(self, interface):
return get_interface_ip_addresses(self.device, interface)
def is_connected(self, ssid=None):
""" Determines if wlan_device is connected to wlan network.
Args:
ssid (optional): string, to check if device is connect to a specific
network.
Returns:
True, if connected to a network or to the correct network when SSID
is provided.
False, if not connected or connect to incorrect network when SSID is
provided.
"""
response = self.status()
if response.get('error'):
raise ConnectionError(
'Failed to get client network connection status')
status = response.get('result')
if status and status.get('connected_to'):
if ssid:
connected_ssid = ''.join(
chr(i) for i in status['connected_to']['ssid'])
if ssid != connected_ssid:
return False
return True
return False
def hard_power_cycle(self, pdus):
self.device.reboot(reboot_type='hard', testbed_pdus=pdus)
def save_network(self, target_ssid, security_type=None, target_pwd=None):
if self.device.association_mechanism == 'drivers':
raise EnvironmentError(
'Cannot save network using the drivers. Saved networks are a '
'policy layer concept.')
if security_type and security_type not in FUCHSIA_VALID_SECURITY_TYPES:
raise TypeError('Invalid security type: %s' % security_type)
if not self.device.wlan_policy_controller.save_network(
target_ssid, security_type, password=target_pwd):
raise EnvironmentError('Failed to save network: %s' % target_ssid)
def clear_saved_networks(self):
if self.device.association_mechanism == 'drivers':
raise EnvironmentError(
'Cannot clear saved network using the drivers. Saved networks '
'are a policy layer concept.')
if not self.device.wlan_policy_controller.remove_all_networks():
raise EnvironmentError('Failed to clear saved networks')