285 lines
12 KiB
Python
285 lines
12 KiB
Python
|
|
#!/usr/bin/env python3.4
|
||
|
|
#
|
||
|
|
# Copyright 2016 - 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 time
|
||
|
|
import json
|
||
|
|
import pprint
|
||
|
|
|
||
|
|
from acts import asserts
|
||
|
|
from acts import utils
|
||
|
|
from acts.keys import Config
|
||
|
|
from acts.test_decorators import test_tracker_info
|
||
|
|
from acts_contrib.test_utils.wifi import wifi_constants
|
||
|
|
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
|
||
|
|
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
|
||
|
|
from acts_contrib.test_utils.wifi.wifi_constants import\
|
||
|
|
COEX_BAND, COEX_CHANNEL, COEX_POWER_CAP_DBM, KEY_COEX_UNSAFE_CHANNELS, KEY_COEX_RESTRICTIONS
|
||
|
|
|
||
|
|
WifiEnums = wutils.WifiEnums
|
||
|
|
WIFI_CONFIG_APBAND_2G = WifiEnums.WIFI_CONFIG_APBAND_2G
|
||
|
|
WIFI_CONFIG_APBAND_5G = WifiEnums.WIFI_CONFIG_APBAND_5G
|
||
|
|
WIFI_CONFIG_APBAND_AUTO = WifiEnums.WIFI_CONFIG_APBAND_AUTO
|
||
|
|
WPA3_SAE_TRANSITION_SOFTAP = WifiEnums.SoftApSecurityType.WPA3_SAE_TRANSITION
|
||
|
|
WPA3_SAE_SOFTAP = WifiEnums.SoftApSecurityType.WPA3_SAE
|
||
|
|
WAIT_AFTER_REBOOT = 10
|
||
|
|
|
||
|
|
BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS = 5
|
||
|
|
|
||
|
|
|
||
|
|
class WifiCellCoexChannelAvoidTest(WifiBaseTest):
|
||
|
|
def __init__(self, configs):
|
||
|
|
super().__init__(configs)
|
||
|
|
self.generate_test_list()
|
||
|
|
|
||
|
|
def generate_test_list(self):
|
||
|
|
"""Generates a test list sorted with coex_unsafe_list_sap list.
|
||
|
|
Test with a sorted list can reduce lots of time
|
||
|
|
on switch radio and band start up.
|
||
|
|
"""
|
||
|
|
sorted_list = sorted(self.user_params["coex_unsafe_list_sap"],
|
||
|
|
key=lambda radio: radio["band"])
|
||
|
|
for test_item in sorted_list:
|
||
|
|
self.init_test_case(self.coex_unsafechannel_avoidance, test_item)
|
||
|
|
pprint.pprint("self.tests = {}".format(self.tests))
|
||
|
|
|
||
|
|
def init_test_case(self, coex_unsafechannel_avoidance, test_item):
|
||
|
|
"""Generates a single test case from the given data.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
coex_unsafechannel_avoidance: The base test case function to run.
|
||
|
|
test_item: test case required info include ["uuid","coex_unsafe_case"]
|
||
|
|
"""
|
||
|
|
test_name = test_item["coex_unsafe_case"]
|
||
|
|
test_tracker_uuid = test_item["uuid"]
|
||
|
|
if not test_name.startswith("test_"):
|
||
|
|
test_name = "test_{}".format(test_name)
|
||
|
|
test_case = test_tracker_info(uuid=test_tracker_uuid)(
|
||
|
|
lambda: coex_unsafechannel_avoidance(test_item))
|
||
|
|
setattr(self, test_name, test_case)
|
||
|
|
self.tests.append(test_name)
|
||
|
|
|
||
|
|
def setup_class(self):
|
||
|
|
"""It will setup the required dependencies from config file and configure
|
||
|
|
the devices for softap mode testing.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
True if successfully configured the requirements for testing.
|
||
|
|
"""
|
||
|
|
super().setup_class()
|
||
|
|
self.dut = self.android_devices[0]
|
||
|
|
self.dut_client = self.android_devices[1]
|
||
|
|
req_params = [
|
||
|
|
"dbs_supported_models", "sta_concurrency_supported_models",
|
||
|
|
"wifi6_models", "coex_unsafe_list_sap"
|
||
|
|
]
|
||
|
|
opt_param = ["reference_networks"]
|
||
|
|
self.unpack_userparams(req_param_names=req_params,
|
||
|
|
opt_param_names=opt_param)
|
||
|
|
if "AccessPoint" in self.user_params:
|
||
|
|
self.legacy_configure_ap_and_start()
|
||
|
|
elif "OpenWrtAP" in self.user_params:
|
||
|
|
self.configure_openwrt_ap_and_start(wpa_network=True)
|
||
|
|
self.wifi_network = self.reference_networks[0]["2g"]
|
||
|
|
# Do a simple version of init - mainly just sync the time and enable
|
||
|
|
# verbose logging. This test will fail if the DUT has a sim and cell
|
||
|
|
# data is disabled. We would also like to test with phones in less
|
||
|
|
# constrained states (or add variations where we specifically
|
||
|
|
# constrain).
|
||
|
|
utils.require_sl4a((self.dut, self.dut_client))
|
||
|
|
utils.sync_device_time(self.dut)
|
||
|
|
utils.sync_device_time(self.dut_client)
|
||
|
|
# Enable verbose logging on the duts
|
||
|
|
self.dut.droid.wifiEnableVerboseLogging(1)
|
||
|
|
asserts.assert_equal(
|
||
|
|
self.dut.droid.wifiGetVerboseLoggingLevel(), 1,
|
||
|
|
"Failed to enable WiFi verbose logging on the softap dut.")
|
||
|
|
self.dut_client.droid.wifiEnableVerboseLogging(1)
|
||
|
|
asserts.assert_equal(
|
||
|
|
self.dut_client.droid.wifiGetVerboseLoggingLevel(), 1,
|
||
|
|
"Failed to enable WiFi verbose logging on the client dut.")
|
||
|
|
wutils.wifi_toggle_state(self.dut, True)
|
||
|
|
wutils.wifi_toggle_state(self.dut_client, True)
|
||
|
|
self.AP_IFACE = 'wlan0'
|
||
|
|
if self.dut.model in self.dbs_supported_models:
|
||
|
|
self.AP_IFACE = 'wlan1'
|
||
|
|
if self.dut.model in self.sta_concurrency_supported_models:
|
||
|
|
self.AP_IFACE = 'wlan2'
|
||
|
|
if len(self.android_devices) > 2:
|
||
|
|
utils.sync_device_time(self.android_devices[2])
|
||
|
|
self.android_devices[2].droid.wifiEnableVerboseLogging(1)
|
||
|
|
asserts.assert_equal(
|
||
|
|
self.android_devices[2].droid.wifiGetVerboseLoggingLevel(), 1,
|
||
|
|
"Failed to enable WiFi verbose logging on the client dut.")
|
||
|
|
self.dut_client_2 = self.android_devices[2]
|
||
|
|
|
||
|
|
def teardown_class(self):
|
||
|
|
super().teardown_class()
|
||
|
|
for ad in self.android_devices:
|
||
|
|
wutils.wifi_toggle_state(ad, True)
|
||
|
|
wutils.reset_wifi(ad)
|
||
|
|
time.sleep(WAIT_AFTER_REBOOT)
|
||
|
|
if self.dut.droid.wifiIsApEnabled():
|
||
|
|
wutils.stop_wifi_tethering(self.dut)
|
||
|
|
if "AccessPoint" in self.user_params:
|
||
|
|
del self.user_params["reference_networks"]
|
||
|
|
del self.user_params["open_network"]
|
||
|
|
|
||
|
|
def setup_test(self):
|
||
|
|
super().setup_test()
|
||
|
|
for ad in self.android_devices:
|
||
|
|
wutils.wifi_toggle_state(ad, True)
|
||
|
|
self.dut.reboot()
|
||
|
|
time.sleep(WAIT_AFTER_REBOOT)
|
||
|
|
|
||
|
|
def teardown_test(self):
|
||
|
|
super().teardown_test()
|
||
|
|
for ad in self.android_devices:
|
||
|
|
wutils.wifi_toggle_state(ad, True)
|
||
|
|
if self.dut.droid.wifiIsApEnabled():
|
||
|
|
wutils.stop_wifi_tethering(self.dut)
|
||
|
|
self.dut.log.debug("Toggling Airplane mode OFF.")
|
||
|
|
asserts.assert_true(
|
||
|
|
utils.force_airplane_mode(self.dut, False),
|
||
|
|
"Can not turn off airplane mode: %s" % self.dut.serial)
|
||
|
|
#reset coexcell setting
|
||
|
|
self.dut.adb.shell('cmd wifi reset-coex-cell-channels')
|
||
|
|
|
||
|
|
""" Helper Functions """
|
||
|
|
|
||
|
|
def coex_unsafe_channel_key(self, unsafe_channel):
|
||
|
|
if COEX_POWER_CAP_DBM in unsafe_channel:
|
||
|
|
return (unsafe_channel[COEX_BAND], unsafe_channel[COEX_CHANNEL],
|
||
|
|
unsafe_channel[COEX_POWER_CAP_DBM])
|
||
|
|
return (unsafe_channel[COEX_BAND], unsafe_channel[COEX_CHANNEL])
|
||
|
|
|
||
|
|
def enable_softap(self, ad, band=None):
|
||
|
|
""" Enable SoftAp of the DUT
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
(freq1, freq2): Integer; a 2G frequency and a 5G frequency if DUT
|
||
|
|
support BridgedAp.
|
||
|
|
freq: Integer; a frequency from SoftAp.
|
||
|
|
None, bandwidth: Just a placeholder, won't be used.
|
||
|
|
"""
|
||
|
|
# Enable SoftAp
|
||
|
|
# Create SoftAp config.
|
||
|
|
config = wutils.create_softap_config()
|
||
|
|
# If DUT support BridgedAp, then two BridgedAp instances enabled.
|
||
|
|
if self.dut.droid.wifiIsBridgedApConcurrencySupported():
|
||
|
|
wutils.save_wifi_soft_ap_config(
|
||
|
|
ad,
|
||
|
|
config,
|
||
|
|
bands=[
|
||
|
|
WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G,
|
||
|
|
WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G
|
||
|
|
])
|
||
|
|
# If DUT does not support BridgedAp, 2G OR 5G SoftAp enabled.
|
||
|
|
else:
|
||
|
|
if self.init_softap_band == BAND_2G:
|
||
|
|
band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G
|
||
|
|
if self.init_softap_band == BAND_5G:
|
||
|
|
band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_5G
|
||
|
|
wutils.save_wifi_soft_ap_config(ad, config, band=band)
|
||
|
|
wutils.start_wifi_tethering_saved_config(ad)
|
||
|
|
time.sleep(BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS)
|
||
|
|
|
||
|
|
# if DUT support BridgedAp:
|
||
|
|
if ad.droid.wifiIsBridgedApConcurrencySupported():
|
||
|
|
callbackId = ad.droid.registerSoftApCallback()
|
||
|
|
infos = wutils.get_current_softap_infos(ad, callbackId, True)
|
||
|
|
ad.droid.unregisterSoftApCallback(callbackId)
|
||
|
|
# if DUT BridgedAp has two instances, return two frequencies.
|
||
|
|
if len(infos) == 2:
|
||
|
|
freq_1 = infos[0]["frequency"]
|
||
|
|
freq_2 = infos[1]["frequency"]
|
||
|
|
self.dut.log.info(
|
||
|
|
"DUT connected to AP on freq: {},{}, chan: {} ,{}".format(
|
||
|
|
freq_1, freq_2, WifiEnums.freq_to_channel[freq_1],
|
||
|
|
WifiEnums.freq_to_channel[freq_2]))
|
||
|
|
return freq_1, freq_2
|
||
|
|
# if DUT BridgedAp has only one instances, return the frequency.
|
||
|
|
elif len(infos) == 1:
|
||
|
|
freq = infos[0]["frequency"]
|
||
|
|
self.dut.log.info(
|
||
|
|
"DUT connected to AP on freq: {}, chan: {}".format(
|
||
|
|
freq, WifiEnums.freq_to_channel[freq]))
|
||
|
|
return freq
|
||
|
|
else:
|
||
|
|
raise signals.TestFailure("There should be SoftAp instance.")
|
||
|
|
# if DUT does not support BridgedAp:
|
||
|
|
else:
|
||
|
|
# Return SoftAp frequency.
|
||
|
|
callbackId = ad.droid.registerSoftApCallback()
|
||
|
|
freq, bandwidth = wutils.get_current_softap_info(
|
||
|
|
ad, callbackId, True)
|
||
|
|
ad.log.info("SoftAp freq: {}".format(freq))
|
||
|
|
ad.droid.unregisterSoftApCallback(callbackId)
|
||
|
|
self.dut.log.info(
|
||
|
|
"DUT connected to AP on freq: {}, chan: {}".format(
|
||
|
|
freq, WifiEnums.freq_to_channel[freq]))
|
||
|
|
return freq, bandwidth
|
||
|
|
|
||
|
|
""" Tests Begin """
|
||
|
|
|
||
|
|
def coex_unsafechannel_avoidance(self, test_item):
|
||
|
|
self.radio = test_item["radio"]
|
||
|
|
self.band = test_item["band"]
|
||
|
|
self.cellchannels = test_item["setcoexcellchannels"]
|
||
|
|
time.sleep(WAIT_AFTER_REBOOT)
|
||
|
|
wutils.set_wifi_country_code(self.dut, country_code='US')
|
||
|
|
asserts.skip_if(not self.dut.droid.isSdkAtLeastS(),
|
||
|
|
"Require SDK at least S to use wifi coex apis.")
|
||
|
|
self.dut.ed.clear_all_events()
|
||
|
|
#Listing the test coex setting from configuration
|
||
|
|
self.dut.log.info(
|
||
|
|
"DUT test cellcoex radio:{}, band:{}, channels setting:{}".format(
|
||
|
|
self.radio, self.band, self.cellchannels))
|
||
|
|
self.dut.adb.shell('cmd wifi set-coex-cell-channels %s %s %s' %
|
||
|
|
(self.radio, self.band, self.cellchannels))
|
||
|
|
self.dut.droid.wifiRegisterCoexCallback()
|
||
|
|
try:
|
||
|
|
# Wait for the immediate callback from registering and store the current values
|
||
|
|
event = self.dut.ed.pop_event(
|
||
|
|
"WifiManagerCoexCallback#onCoexUnsafeChannelsChanged", 5)
|
||
|
|
except queue.Empty:
|
||
|
|
asserts.fail("Coex callback event not received after registering.")
|
||
|
|
prev_unsafe_channels = sorted(json.loads(
|
||
|
|
event["data"][KEY_COEX_UNSAFE_CHANNELS]),
|
||
|
|
key=self.coex_unsafe_channel_key)
|
||
|
|
prev_restrictions = sorted(
|
||
|
|
json.loads(event["data"][KEY_COEX_RESTRICTIONS]))
|
||
|
|
unsafe_channels = []
|
||
|
|
for i in range(len(prev_unsafe_channels)):
|
||
|
|
unsafe_channels.append(prev_unsafe_channels[i]['channel'])
|
||
|
|
self.dut.log.info("DUT unsafe channels:{}".format(unsafe_channels))
|
||
|
|
freq1, freq2 = self.enable_softap(self.dut)
|
||
|
|
sapchan1, sapchan2 = WifiEnums.freq_to_channel[
|
||
|
|
freq1], WifiEnums.freq_to_channel[freq2]
|
||
|
|
if sapchan1 in unsafe_channels or sapchan2 in unsafe_channels:
|
||
|
|
asserts.fail(
|
||
|
|
"devices hotspot's channel open on current unsafe channels " +
|
||
|
|
str(unsafe_channels))
|
||
|
|
else:
|
||
|
|
pass
|
||
|
|
self.dut.droid.wifiUnregisterCoexCallback()
|
||
|
|
self.dut.adb.shell('cmd wifi reset-coex-cell-channels')
|
||
|
|
|
||
|
|
""" Tests End """
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
pass
|