1#!/usr/bin/env python3.4 2# 3# Copyright 2018 - 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 queue 19 20from acts import asserts 21from acts.controllers.android_device import SL4A_APK_NAME 22from acts.test_decorators import test_tracker_info 23from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest 24import acts.test_utils.wifi.wifi_test_utils as wutils 25import acts.utils 26 27WifiEnums = wutils.WifiEnums 28SSID = WifiEnums.SSID_KEY 29CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 5 30SCANS_REQUIRED_TO_FIND_SSID = 5 31LAST_DISCONNECT_TIMEOUT_MILLIS = 5000 32LAST_DISCONNECT_TIMEOUT_SEC = LAST_DISCONNECT_TIMEOUT_MILLIS / 1000 33PRESCAN_DELAY_SEC = 5 34WIFI_TOGGLE_DELAY_SEC = 3 35 36 37class WifiWakeTest(WifiBaseTest): 38 """ 39 Tests Wifi Wake. 40 41 Test Bed Requirements: 42 * One Android Device 43 * Two APs that can be turned on and off 44 """ 45 46 def setup_class(self): 47 super().setup_class() 48 49 self.dut = self.android_devices[0] 50 wutils.wifi_test_device_init(self.dut) 51 # turn location back on 52 acts.utils.set_location_service(self.dut, True) 53 self.dut.droid.wifiScannerToggleAlwaysAvailable(True) 54 55 self.unpack_userparams(req_param_names=[], 56 opt_param_names=["reference_networks"]) 57 58 if "AccessPoint" in self.user_params: 59 self.legacy_configure_ap_and_start(mirror_ap=False, ap_count=2) 60 61 # use 2G since Wifi Wake does not work if an AP is on a 5G DFS channel 62 self.ap_a = self.reference_networks[0]["2g"] 63 self.ap_b = self.reference_networks[1]["2g"] 64 65 self.ap_a_atten = self.attenuators[0] 66 self.ap_b_atten = self.attenuators[2] 67 68 # TODO(b/119040540): this method of disabling/re-enabling Wifi on APs is 69 # hacky, switch to using public methods when they are implemented 70 def ap_a_off(self): 71 ap_a_hostapd = self.access_points[0]._aps['wlan0'].hostapd 72 if ap_a_hostapd.is_alive(): 73 ap_a_hostapd.stop() 74 self.log.info('Turned AP A off') 75 76 def ap_a_on(self): 77 ap_a_hostapd = self.access_points[0]._aps['wlan0'].hostapd 78 if not ap_a_hostapd.is_alive(): 79 ap_a_hostapd.start(ap_a_hostapd.config) 80 self.log.info('Turned AP A on') 81 82 def ap_b_off(self): 83 ap_b_hostapd = self.access_points[1]._aps['wlan0'].hostapd 84 if ap_b_hostapd.is_alive(): 85 ap_b_hostapd.stop() 86 self.log.info('Turned AP B off') 87 88 def ap_b_on(self): 89 ap_b_hostapd = self.access_points[1]._aps['wlan0'].hostapd 90 if not ap_b_hostapd.is_alive(): 91 ap_b_hostapd.start(ap_b_hostapd.config) 92 self.log.info('Turned AP B on') 93 94 def setup_test(self): 95 self.dut.droid.wakeLockAcquireBright() 96 self.dut.droid.wakeUpNow() 97 self.ap_a_on() 98 self.ap_b_on() 99 self.ap_a_atten.set_atten(0) 100 self.ap_b_atten.set_atten(0) 101 wutils.reset_wifi(self.dut) 102 wutils.wifi_toggle_state(self.dut, new_state=True) 103 # clear events from event dispatcher 104 self.dut.droid.wifiStartTrackingStateChange() 105 self.dut.droid.wifiStopTrackingStateChange() 106 self.dut.ed.clear_all_events() 107 108 def teardown_test(self): 109 self.dut.droid.wakeLockRelease() 110 self.dut.droid.goToSleepNow() 111 112 def on_fail(self, test_name, begin_time): 113 self.dut.take_bug_report(test_name, begin_time) 114 self.dut.cat_adb_log(test_name, begin_time) 115 116 def find_ssid_in_scan_results(self, scan_results_batches, ssid): 117 scan_results_batch = scan_results_batches[0] 118 scan_results = scan_results_batch["ScanResults"] 119 for scan_result in scan_results: 120 if ssid == scan_result["SSID"]: 121 return True 122 return False 123 124 def do_location_scan(self, num_times=1, ssid_to_find=None): 125 scan_settings = { 126 "band": wutils.WifiEnums.WIFI_BAND_BOTH, 127 "periodInMs": 0, 128 "reportEvents": wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN 129 } 130 131 wifi_chs = wutils.WifiChannelUS(self.dut.model) 132 stime_channel = 47 # dwell time plus 2ms 133 leeway = 10 134 135 for i in range(num_times): 136 self.log.info("Scan count: {}".format(i)) 137 data = wutils.start_wifi_single_scan(self.dut, scan_settings) 138 idx = data["Index"] 139 scan_rt = data["ScanElapsedRealtime"] 140 self.log.debug( 141 "Wifi single shot scan started index: %s at real time: %s", idx, 142 scan_rt) 143 # generating event wait time from scan setting plus leeway 144 scan_time, scan_channels = wutils.get_scan_time_and_channels( 145 wifi_chs, scan_settings, stime_channel) 146 wait_time = int(scan_time / 1000) + leeway 147 # track number of result received 148 result_received = 0 149 try: 150 for _ in range(1, 3): 151 event_name = "{}{}onResults".format("WifiScannerScan", idx) 152 self.log.debug("Waiting for event: %s for time %s", 153 event_name, wait_time) 154 event = self.dut.ed.pop_event(event_name, wait_time) 155 self.log.debug("Event received: %s", event) 156 result_received += 1 157 scan_results_batches = event["data"]["Results"] 158 if ssid_to_find and self.find_ssid_in_scan_results( 159 scan_results_batches, ssid_to_find): 160 return 161 except queue.Empty as error: 162 asserts.assert_true( 163 result_received >= 1, 164 "Event did not triggered for single shot {}".format(error)) 165 finally: 166 self.dut.droid.wifiScannerStopScan(idx) 167 # For single shot number of result received and length of result 168 # should be one 169 asserts.assert_true( 170 result_received == 1, 171 "Test fail because received result {}".format( 172 result_received)) 173 174 @test_tracker_info(uuid="372b9b74-4241-46ce-8f18-e6a97d3a3452") 175 def test_no_reconnect_manual_disable_wifi(self): 176 """ 177 Tests that Wifi Wake does not reconnect to a network if the user turned 178 off Wifi while connected to that network and the user has not moved 179 (i.e. moved out of range of the AP then came back). 180 """ 181 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 182 wutils.wifi_toggle_state(self.dut, new_state=False) 183 time.sleep(PRESCAN_DELAY_SEC) 184 self.do_location_scan( 185 2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 186 asserts.assert_false( 187 self.dut.droid.wifiCheckState(), 188 "Expect Wifi Wake to not enable Wifi, but Wifi was enabled.") 189 190 @test_tracker_info(uuid="ec7a54a5-f293-43f5-a1dd-d41679aa1825") 191 def test_reconnect_wifi_saved_network(self): 192 """Tests that Wifi Wake re-enables Wifi for a saved network.""" 193 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 194 wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5) 195 self.dut.ed.clear_all_events() 196 self.ap_a_off() 197 self.ap_b_off() 198 wutils.wait_for_disconnect(self.dut) 199 self.log.info("Wifi Disconnected") 200 time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2) 201 wutils.wifi_toggle_state(self.dut, new_state=False) 202 time.sleep(PRESCAN_DELAY_SEC) 203 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 204 205 self.ap_a_on() 206 self.do_location_scan( 207 SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY]) 208 time.sleep(WIFI_TOGGLE_DELAY_SEC) 209 asserts.assert_true( 210 self.dut.droid.wifiCheckState(), 211 "Expect Wifi Wake to enable Wifi, but Wifi is disabled.") 212 213 @test_tracker_info(uuid="3cecd1c5-54bc-44a2-86f7-ad84625bf094") 214 def test_reconnect_wifi_network_suggestion(self): 215 """Tests that Wifi Wake re-enables Wifi for app provided suggestion.""" 216 self.dut.log.info("Adding network suggestions") 217 asserts.assert_true( 218 self.dut.droid.wifiAddNetworkSuggestions([self.ap_a]), 219 "Failed to add suggestions") 220 asserts.assert_true( 221 self.dut.droid.wifiAddNetworkSuggestions([self.ap_b]), 222 "Failed to add suggestions") 223 # Enable suggestions by the app. 224 self.dut.log.debug("Enabling suggestions from test") 225 self.dut.adb.shell("cmd wifi network-suggestions-set-user-approved" 226 + " " + SL4A_APK_NAME + " yes") 227 # Ensure network is seen in scan results & auto-connected to. 228 self.do_location_scan(2) 229 wutils.wait_for_connect(self.dut) 230 current_network = self.dut.droid.wifiGetConnectionInfo() 231 self.dut.ed.clear_all_events() 232 if current_network[SSID] == self.ap_a[SSID]: 233 # connected to AP A, so turn AP B off first to prevent the 234 # device from immediately reconnecting to AP B 235 self.ap_b_off() 236 self.ap_a_off() 237 else: 238 self.ap_a_off() 239 self.ap_b_off() 240 241 wutils.wait_for_disconnect(self.dut) 242 self.log.info("Wifi Disconnected") 243 time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2) 244 wutils.wifi_toggle_state(self.dut, new_state=False) 245 time.sleep(PRESCAN_DELAY_SEC) 246 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 247 248 self.ap_a_on() 249 self.do_location_scan( 250 SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY]) 251 time.sleep(WIFI_TOGGLE_DELAY_SEC) 252 asserts.assert_true( 253 self.dut.droid.wifiCheckState(), 254 "Expect Wifi Wake to enable Wifi, but Wifi is disabled.") 255 256 @test_tracker_info(uuid="6c77ca9b-ff34-4bc7-895f-cc7340e0e645") 257 def test_reconnect_wifi_move_back_in_range(self): 258 """ 259 Tests that Wifi Wake re-enables Wifi if the device moves out of range of 260 the AP then came back. 261 """ 262 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 263 wutils.wifi_toggle_state(self.dut, new_state=False) 264 time.sleep(PRESCAN_DELAY_SEC) 265 # init Wakeup Lock with AP A 266 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 267 self.ap_a_off() 268 # evict AP A from Wakeup Lock 269 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 270 self.ap_a_on() 271 self.do_location_scan( 272 SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY]) 273 time.sleep(WIFI_TOGGLE_DELAY_SEC) 274 asserts.assert_true( 275 self.dut.droid.wifiCheckState(), 276 "Expect Wifi Wake to enable Wifi, but Wifi is disabled.") 277 278 @test_tracker_info(uuid="08e8284a-a523-48f3-b9ea-9c6bf27d711e") 279 def test_no_reconnect_to_flaky_ap(self): 280 """ 281 Tests that Wifi Wake does not reconnect to flaky networks. 282 If a network sporadically connects and disconnects, and the user turns 283 off Wifi even during the disconnected phase, Wifi Wake should not 284 re-enable Wifi for that network. 285 """ 286 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 287 self.ap_a_off() 288 time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 0.4) 289 wutils.wifi_toggle_state(self.dut, new_state=False) 290 time.sleep(PRESCAN_DELAY_SEC) 291 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 292 self.ap_a_on() 293 self.do_location_scan( 294 2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 295 asserts.assert_false( 296 self.dut.droid.wifiCheckState(), 297 "Expect Wifi Wake to not enable Wifi, but Wifi was enabled.") 298 299 @test_tracker_info(uuid="b990a8f7-e3a0-4774-89cf-2067ccd64903") 300 def test_reconnect_wifi_disabled_after_disconnecting(self): 301 """ 302 Tests that Wifi Wake reconnects to a network if Wifi was disabled long 303 after disconnecting from a network. 304 """ 305 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 306 self.dut.ed.clear_all_events() 307 self.ap_a_off() 308 wutils.wait_for_disconnect(self.dut) 309 self.log.info("Wifi Disconnected") 310 time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2) 311 wutils.wifi_toggle_state(self.dut, new_state=False) 312 time.sleep(PRESCAN_DELAY_SEC) 313 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 314 self.ap_a_on() 315 self.do_location_scan( 316 SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY]) 317 time.sleep(WIFI_TOGGLE_DELAY_SEC) 318 asserts.assert_true( 319 self.dut.droid.wifiCheckState(), 320 "Expect Wifi Wake to enable Wifi, but Wifi is disabled.") 321 322 @test_tracker_info(uuid="bb217794-d3ee-4fb9-87ff-7a594d0223b0") 323 def test_no_reconnect_if_exists_ap_in_wakeup_lock(self): 324 """ 325 2 APs in Wakeup Lock, user moves out of range of one AP but stays in 326 range of the other, should not reconnect when user moves back in range 327 of both. 328 """ 329 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 330 wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5) 331 wutils.wifi_toggle_state(self.dut, new_state=False) 332 time.sleep(PRESCAN_DELAY_SEC) 333 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 334 self.ap_b_off() 335 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 336 self.ap_b_on() 337 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 338 asserts.assert_false( 339 self.dut.droid.wifiCheckState(), 340 "Expect Wifi Wake to not enable Wifi, but Wifi was enabled.") 341 342 @test_tracker_info(uuid="567a0663-4ce0-488d-8fe2-db79a3ebf068") 343 def test_reconnect_if_both_ap_evicted_from_wakeup_lock(self): 344 """ 345 2 APs in Wakeup Lock, user moves out of range of both APs, should 346 reconnect when user moves back in range of either AP. 347 """ 348 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 349 wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5) 350 wutils.wifi_toggle_state(self.dut, new_state=False) 351 time.sleep(PRESCAN_DELAY_SEC) 352 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 353 self.ap_a_off() 354 self.ap_b_off() 355 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 356 self.ap_a_on() 357 self.do_location_scan( 358 SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY]) 359 time.sleep(WIFI_TOGGLE_DELAY_SEC) 360 asserts.assert_true( 361 self.dut.droid.wifiCheckState(), 362 "Expect Wifi Wake to enable Wifi, but Wifi is disabled.") 363 364 @test_tracker_info(uuid="d67657c8-3de3-46a6-a103-428cdab89423") 365 def test_reconnect_to_better_saved_network(self): 366 """ 367 2 saved APs, one attenuated, one unattenuated, Wifi Wake should connect 368 to the unattenuated AP 369 """ 370 wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5) 371 wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5) 372 self.dut.ed.clear_all_events() 373 self.ap_a_off() 374 self.ap_b_off() 375 wutils.wait_for_disconnect(self.dut) 376 self.log.info("Wifi Disconnected") 377 time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2) 378 wutils.wifi_toggle_state(self.dut, new_state=False) 379 time.sleep(PRESCAN_DELAY_SEC) 380 self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2) 381 382 self.ap_a_on() 383 self.ap_b_on() 384 self.ap_a_atten.set_atten(30) 385 self.ap_b_atten.set_atten(0) 386 387 self.do_location_scan( 388 SCANS_REQUIRED_TO_FIND_SSID, self.ap_b[wutils.WifiEnums.SSID_KEY]) 389 time.sleep(WIFI_TOGGLE_DELAY_SEC) 390 asserts.assert_true( 391 self.dut.droid.wifiCheckState(), 392 "Expect Wifi Wake to enable Wifi, but Wifi is disabled.") 393 expected_ssid = self.ap_b[wutils.WifiEnums.SSID_KEY] 394 wutils.wait_for_connect(self.dut, expected_ssid) 395