#!/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