1#!/usr/bin/env python3.4 2# 3# Copyright 2016 - The Android Open Source Project 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 time 18import json 19import pprint 20 21from acts import asserts 22from acts import utils 23from acts.keys import Config 24from acts.test_decorators import test_tracker_info 25from acts_contrib.test_utils.wifi import wifi_constants 26from acts_contrib.test_utils.wifi import wifi_test_utils as wutils 27from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest 28from acts_contrib.test_utils.wifi.wifi_constants import\ 29 COEX_BAND, COEX_CHANNEL, COEX_POWER_CAP_DBM, KEY_COEX_UNSAFE_CHANNELS, KEY_COEX_RESTRICTIONS 30 31WifiEnums = wutils.WifiEnums 32WIFI_CONFIG_APBAND_2G = WifiEnums.WIFI_CONFIG_APBAND_2G 33WIFI_CONFIG_APBAND_5G = WifiEnums.WIFI_CONFIG_APBAND_5G 34WIFI_CONFIG_APBAND_AUTO = WifiEnums.WIFI_CONFIG_APBAND_AUTO 35WPA3_SAE_TRANSITION_SOFTAP = WifiEnums.SoftApSecurityType.WPA3_SAE_TRANSITION 36WPA3_SAE_SOFTAP = WifiEnums.SoftApSecurityType.WPA3_SAE 37WAIT_AFTER_REBOOT = 10 38 39BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS = 5 40 41 42class WifiCellCoexChannelAvoidTest(WifiBaseTest): 43 def __init__(self, configs): 44 super().__init__(configs) 45 self.generate_test_list() 46 47 def generate_test_list(self): 48 """Generates a test list sorted with coex_unsafe_list_sap list. 49 Test with a sorted list can reduce lots of time 50 on switch radio and band start up. 51 """ 52 sorted_list = sorted(self.user_params["coex_unsafe_list_sap"], 53 key=lambda radio: radio["band"]) 54 for test_item in sorted_list: 55 self.init_test_case(self.coex_unsafechannel_avoidance, test_item) 56 pprint.pprint("self.tests = {}".format(self.tests)) 57 58 def init_test_case(self, coex_unsafechannel_avoidance, test_item): 59 """Generates a single test case from the given data. 60 61 Args: 62 coex_unsafechannel_avoidance: The base test case function to run. 63 test_item: test case required info include ["uuid","coex_unsafe_case"] 64 """ 65 test_name = test_item["coex_unsafe_case"] 66 test_tracker_uuid = test_item["uuid"] 67 if not test_name.startswith("test_"): 68 test_name = "test_{}".format(test_name) 69 test_case = test_tracker_info(uuid=test_tracker_uuid)( 70 lambda: coex_unsafechannel_avoidance(test_item)) 71 setattr(self, test_name, test_case) 72 self.tests.append(test_name) 73 74 def setup_class(self): 75 """It will setup the required dependencies from config file and configure 76 the devices for softap mode testing. 77 78 Returns: 79 True if successfully configured the requirements for testing. 80 """ 81 super().setup_class() 82 self.dut = self.android_devices[0] 83 self.dut_client = self.android_devices[1] 84 req_params = [ 85 "dbs_supported_models", "sta_concurrency_supported_models", 86 "wifi6_models", "coex_unsafe_list_sap" 87 ] 88 opt_param = ["reference_networks"] 89 self.unpack_userparams(req_param_names=req_params, 90 opt_param_names=opt_param) 91 if "AccessPoint" in self.user_params: 92 self.legacy_configure_ap_and_start() 93 elif "OpenWrtAP" in self.user_params: 94 self.configure_openwrt_ap_and_start(wpa_network=True) 95 self.wifi_network = self.reference_networks[0]["2g"] 96 # Do a simple version of init - mainly just sync the time and enable 97 # verbose logging. This test will fail if the DUT has a sim and cell 98 # data is disabled. We would also like to test with phones in less 99 # constrained states (or add variations where we specifically 100 # constrain). 101 utils.require_sl4a((self.dut, self.dut_client)) 102 utils.sync_device_time(self.dut) 103 utils.sync_device_time(self.dut_client) 104 # Enable verbose logging on the duts 105 self.dut.droid.wifiEnableVerboseLogging(1) 106 asserts.assert_equal( 107 self.dut.droid.wifiGetVerboseLoggingLevel(), 1, 108 "Failed to enable WiFi verbose logging on the softap dut.") 109 self.dut_client.droid.wifiEnableVerboseLogging(1) 110 asserts.assert_equal( 111 self.dut_client.droid.wifiGetVerboseLoggingLevel(), 1, 112 "Failed to enable WiFi verbose logging on the client dut.") 113 wutils.wifi_toggle_state(self.dut, True) 114 wutils.wifi_toggle_state(self.dut_client, True) 115 self.AP_IFACE = 'wlan0' 116 if self.dut.model in self.dbs_supported_models: 117 self.AP_IFACE = 'wlan1' 118 if self.dut.model in self.sta_concurrency_supported_models: 119 self.AP_IFACE = 'wlan2' 120 if len(self.android_devices) > 2: 121 utils.sync_device_time(self.android_devices[2]) 122 self.android_devices[2].droid.wifiEnableVerboseLogging(1) 123 asserts.assert_equal( 124 self.android_devices[2].droid.wifiGetVerboseLoggingLevel(), 1, 125 "Failed to enable WiFi verbose logging on the client dut.") 126 self.dut_client_2 = self.android_devices[2] 127 128 def teardown_class(self): 129 super().teardown_class() 130 for ad in self.android_devices: 131 wutils.wifi_toggle_state(ad, True) 132 wutils.reset_wifi(ad) 133 time.sleep(WAIT_AFTER_REBOOT) 134 if self.dut.droid.wifiIsApEnabled(): 135 wutils.stop_wifi_tethering(self.dut) 136 if "AccessPoint" in self.user_params: 137 del self.user_params["reference_networks"] 138 del self.user_params["open_network"] 139 140 def setup_test(self): 141 super().setup_test() 142 for ad in self.android_devices: 143 wutils.wifi_toggle_state(ad, True) 144 self.dut.reboot() 145 time.sleep(WAIT_AFTER_REBOOT) 146 147 def teardown_test(self): 148 super().teardown_test() 149 for ad in self.android_devices: 150 wutils.wifi_toggle_state(ad, True) 151 if self.dut.droid.wifiIsApEnabled(): 152 wutils.stop_wifi_tethering(self.dut) 153 self.dut.log.debug("Toggling Airplane mode OFF.") 154 asserts.assert_true( 155 utils.force_airplane_mode(self.dut, False), 156 "Can not turn off airplane mode: %s" % self.dut.serial) 157 #reset coexcell setting 158 self.dut.adb.shell('cmd wifi reset-coex-cell-channels') 159 160 """ Helper Functions """ 161 162 def coex_unsafe_channel_key(self, unsafe_channel): 163 if COEX_POWER_CAP_DBM in unsafe_channel: 164 return (unsafe_channel[COEX_BAND], unsafe_channel[COEX_CHANNEL], 165 unsafe_channel[COEX_POWER_CAP_DBM]) 166 return (unsafe_channel[COEX_BAND], unsafe_channel[COEX_CHANNEL]) 167 168 def enable_softap(self, ad, band=None): 169 """ Enable SoftAp of the DUT 170 171 Returns: 172 (freq1, freq2): Integer; a 2G frequency and a 5G frequency if DUT 173 support BridgedAp. 174 freq: Integer; a frequency from SoftAp. 175 None, bandwidth: Just a placeholder, won't be used. 176 """ 177 # Enable SoftAp 178 # Create SoftAp config. 179 config = wutils.create_softap_config() 180 # If DUT support BridgedAp, then two BridgedAp instances enabled. 181 if self.dut.droid.wifiIsBridgedApConcurrencySupported(): 182 wutils.save_wifi_soft_ap_config( 183 ad, 184 config, 185 bands=[ 186 WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G, 187 WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G 188 ]) 189 # If DUT does not support BridgedAp, 2G OR 5G SoftAp enabled. 190 else: 191 if self.init_softap_band == BAND_2G: 192 band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G 193 if self.init_softap_band == BAND_5G: 194 band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_5G 195 wutils.save_wifi_soft_ap_config(ad, config, band=band) 196 wutils.start_wifi_tethering_saved_config(ad) 197 time.sleep(BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS) 198 199 # if DUT support BridgedAp: 200 if ad.droid.wifiIsBridgedApConcurrencySupported(): 201 callbackId = ad.droid.registerSoftApCallback() 202 infos = wutils.get_current_softap_infos(ad, callbackId, True) 203 ad.droid.unregisterSoftApCallback(callbackId) 204 # if DUT BridgedAp has two instances, return two frequencies. 205 if len(infos) == 2: 206 freq_1 = infos[0]["frequency"] 207 freq_2 = infos[1]["frequency"] 208 self.dut.log.info( 209 "DUT connected to AP on freq: {},{}, chan: {} ,{}".format( 210 freq_1, freq_2, WifiEnums.freq_to_channel[freq_1], 211 WifiEnums.freq_to_channel[freq_2])) 212 return freq_1, freq_2 213 # if DUT BridgedAp has only one instances, return the frequency. 214 elif len(infos) == 1: 215 freq = infos[0]["frequency"] 216 self.dut.log.info( 217 "DUT connected to AP on freq: {}, chan: {}".format( 218 freq, WifiEnums.freq_to_channel[freq])) 219 return freq 220 else: 221 raise signals.TestFailure("There should be SoftAp instance.") 222 # if DUT does not support BridgedAp: 223 else: 224 # Return SoftAp frequency. 225 callbackId = ad.droid.registerSoftApCallback() 226 freq, bandwidth = wutils.get_current_softap_info( 227 ad, callbackId, True) 228 ad.log.info("SoftAp freq: {}".format(freq)) 229 ad.droid.unregisterSoftApCallback(callbackId) 230 self.dut.log.info( 231 "DUT connected to AP on freq: {}, chan: {}".format( 232 freq, WifiEnums.freq_to_channel[freq])) 233 return freq, bandwidth 234 235 """ Tests Begin """ 236 237 def coex_unsafechannel_avoidance(self, test_item): 238 self.radio = test_item["radio"] 239 self.band = test_item["band"] 240 self.cellchannels = test_item["setcoexcellchannels"] 241 time.sleep(WAIT_AFTER_REBOOT) 242 wutils.set_wifi_country_code(self.dut, country_code='US') 243 asserts.skip_if(not self.dut.droid.isSdkAtLeastS(), 244 "Require SDK at least S to use wifi coex apis.") 245 self.dut.ed.clear_all_events() 246 #Listing the test coex setting from configuration 247 self.dut.log.info( 248 "DUT test cellcoex radio:{}, band:{}, channels setting:{}".format( 249 self.radio, self.band, self.cellchannels)) 250 self.dut.adb.shell('cmd wifi set-coex-cell-channels %s %s %s' % 251 (self.radio, self.band, self.cellchannels)) 252 self.dut.droid.wifiRegisterCoexCallback() 253 try: 254 # Wait for the immediate callback from registering and store the current values 255 event = self.dut.ed.pop_event( 256 "WifiManagerCoexCallback#onCoexUnsafeChannelsChanged", 5) 257 except queue.Empty: 258 asserts.fail("Coex callback event not received after registering.") 259 prev_unsafe_channels = sorted(json.loads( 260 event["data"][KEY_COEX_UNSAFE_CHANNELS]), 261 key=self.coex_unsafe_channel_key) 262 prev_restrictions = sorted( 263 json.loads(event["data"][KEY_COEX_RESTRICTIONS])) 264 unsafe_channels = [] 265 for i in range(len(prev_unsafe_channels)): 266 unsafe_channels.append(prev_unsafe_channels[i]['channel']) 267 self.dut.log.info("DUT unsafe channels:{}".format(unsafe_channels)) 268 freq1, freq2 = self.enable_softap(self.dut) 269 sapchan1, sapchan2 = WifiEnums.freq_to_channel[ 270 freq1], WifiEnums.freq_to_channel[freq2] 271 if sapchan1 in unsafe_channels or sapchan2 in unsafe_channels: 272 asserts.fail( 273 "devices hotspot's channel open on current unsafe channels " + 274 str(unsafe_channels)) 275 else: 276 pass 277 self.dut.droid.wifiUnregisterCoexCallback() 278 self.dut.adb.shell('cmd wifi reset-coex-cell-channels') 279 280 """ Tests End """ 281 282 283if __name__ == "__main__": 284 pass 285