429 lines
18 KiB
Python
429 lines
18 KiB
Python
#!/usr/bin/env python3.4
|
|
#
|
|
# Copyright 2018 - 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 queue
|
|
|
|
from acts import asserts
|
|
from acts.controllers.android_device import SL4A_APK_NAME
|
|
from acts.test_decorators import test_tracker_info
|
|
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
|
|
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
|
|
import acts.utils
|
|
|
|
WifiEnums = wutils.WifiEnums
|
|
SSID = WifiEnums.SSID_KEY
|
|
CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 5
|
|
SCANS_REQUIRED_TO_FIND_SSID = 5
|
|
LAST_DISCONNECT_TIMEOUT_MILLIS = 5000
|
|
LAST_DISCONNECT_TIMEOUT_SEC = LAST_DISCONNECT_TIMEOUT_MILLIS / 1000
|
|
PRESCAN_DELAY_SEC = 5
|
|
WIFI_TOGGLE_DELAY_SEC = 3
|
|
DISCONNECT_TIMEOUT_SEC = 20
|
|
|
|
|
|
class WifiWakeTest(WifiBaseTest):
|
|
"""
|
|
Tests Wifi Wake.
|
|
|
|
Test Bed Requirements:
|
|
* One Android Device
|
|
* Two APs that can be turned on and off
|
|
"""
|
|
def __init__(self, configs):
|
|
super().__init__(configs)
|
|
self.enable_packet_log = True
|
|
|
|
def setup_class(self):
|
|
super().setup_class()
|
|
|
|
self.dut = self.android_devices[0]
|
|
wutils.wifi_test_device_init(self.dut)
|
|
# turn location back on
|
|
acts.utils.set_location_service(self.dut, True)
|
|
self.dut.droid.wifiScannerToggleAlwaysAvailable(True)
|
|
|
|
self.unpack_userparams(req_param_names=[],
|
|
opt_param_names=["reference_networks"])
|
|
|
|
if "AccessPoint" in self.user_params:
|
|
self.legacy_configure_ap_and_start(mirror_ap=False, ap_count=2)
|
|
elif "OpenWrtAP" in self.user_params:
|
|
self.configure_openwrt_ap_and_start(wpa_network=True,
|
|
ap_count=2)
|
|
|
|
# use 2G since Wifi Wake does not work if an AP is on a 5G DFS channel
|
|
self.ap_a = self.reference_networks[0]["2g"]
|
|
self.ap_b = self.reference_networks[1]["2g"]
|
|
|
|
self.ap_a_atten = self.attenuators[0]
|
|
self.ap_b_atten = self.attenuators[2]
|
|
if "OpenWrtAP" in self.user_params:
|
|
self.ap_b_atten = self.attenuators[1]
|
|
|
|
# TODO(b/119040540): this method of disabling/re-enabling Wifi on APs is
|
|
# hacky, switch to using public methods when they are implemented
|
|
def ap_a_off(self):
|
|
if "OpenWrtAP" in self.user_params:
|
|
self.access_points[0].stop_ap()
|
|
self.log.info('Turned AP A off')
|
|
return
|
|
ap_a_hostapd = self.access_points[0]._aps['wlan0'].hostapd
|
|
if ap_a_hostapd.is_alive():
|
|
ap_a_hostapd.stop()
|
|
self.log.info('Turned AP A off')
|
|
|
|
def ap_a_on(self):
|
|
if "OpenWrtAP" in self.user_params:
|
|
self.access_points[0].start_ap()
|
|
self.log.info('Turned AP A on')
|
|
return
|
|
ap_a_hostapd = self.access_points[0]._aps['wlan0'].hostapd
|
|
if not ap_a_hostapd.is_alive():
|
|
ap_a_hostapd.start(ap_a_hostapd.config)
|
|
self.log.info('Turned AP A on')
|
|
|
|
def ap_b_off(self):
|
|
if "OpenWrtAP" in self.user_params:
|
|
self.access_points[1].stop_ap()
|
|
self.log.info('Turned AP B off')
|
|
return
|
|
ap_b_hostapd = self.access_points[1]._aps['wlan0'].hostapd
|
|
if ap_b_hostapd.is_alive():
|
|
ap_b_hostapd.stop()
|
|
self.log.info('Turned AP B off')
|
|
|
|
def ap_b_on(self):
|
|
if "OpenWrtAP" in self.user_params:
|
|
self.access_points[1].start_ap()
|
|
self.log.info('Turned AP B on')
|
|
return
|
|
ap_b_hostapd = self.access_points[1]._aps['wlan0'].hostapd
|
|
if not ap_b_hostapd.is_alive():
|
|
ap_b_hostapd.start(ap_b_hostapd.config)
|
|
self.log.info('Turned AP B on')
|
|
|
|
def setup_test(self):
|
|
super().setup_test()
|
|
self.dut.droid.wakeLockAcquireBright()
|
|
self.dut.droid.wakeUpNow()
|
|
self.ap_a_on()
|
|
self.ap_b_on()
|
|
self.ap_a_atten.set_atten(0)
|
|
self.ap_b_atten.set_atten(0)
|
|
wutils.reset_wifi(self.dut)
|
|
wutils.wifi_toggle_state(self.dut, new_state=True)
|
|
# clear events from event dispatcher
|
|
self.dut.droid.wifiStartTrackingStateChange()
|
|
self.dut.droid.wifiStopTrackingStateChange()
|
|
self.dut.ed.clear_all_events()
|
|
|
|
def teardown_test(self):
|
|
super().teardown_test()
|
|
self.dut.droid.wakeLockRelease()
|
|
self.dut.droid.goToSleepNow()
|
|
|
|
def find_ssid_in_scan_results(self, scan_results_batches, ssid):
|
|
scan_results_batch = scan_results_batches[0]
|
|
scan_results = scan_results_batch["ScanResults"]
|
|
for scan_result in scan_results:
|
|
if ssid == scan_result["SSID"]:
|
|
return True
|
|
return False
|
|
|
|
def do_location_scan(self, num_times=1, ssid_to_find=None):
|
|
scan_settings = {
|
|
"band": wutils.WifiEnums.WIFI_BAND_BOTH,
|
|
"periodInMs": 0,
|
|
"reportEvents": wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN
|
|
}
|
|
|
|
wifi_chs = wutils.WifiChannelUS(self.dut.model)
|
|
stime_channel = 47 # dwell time plus 2ms
|
|
leeway = 10
|
|
|
|
for i in range(num_times):
|
|
self.log.info("Scan count: {}".format(i))
|
|
data = wutils.start_wifi_single_scan(self.dut, scan_settings)
|
|
idx = data["Index"]
|
|
scan_rt = data["ScanElapsedRealtime"]
|
|
self.log.debug(
|
|
"Wifi single shot scan started index: %s at real time: %s", idx,
|
|
scan_rt)
|
|
# generating event wait time from scan setting plus leeway
|
|
scan_time, scan_channels = wutils.get_scan_time_and_channels(
|
|
wifi_chs, scan_settings, stime_channel)
|
|
wait_time = int(scan_time / 1000) + leeway
|
|
# track number of result received
|
|
result_received = 0
|
|
try:
|
|
for _ in range(1, 3):
|
|
event_name = "{}{}onResults".format("WifiScannerScan", idx)
|
|
self.log.debug("Waiting for event: %s for time %s",
|
|
event_name, wait_time)
|
|
event = self.dut.ed.pop_event(event_name, wait_time)
|
|
self.log.debug("Event received: %s", event)
|
|
result_received += 1
|
|
scan_results_batches = event["data"]["Results"]
|
|
if ssid_to_find and self.find_ssid_in_scan_results(
|
|
scan_results_batches, ssid_to_find):
|
|
return
|
|
except queue.Empty as error:
|
|
asserts.assert_true(
|
|
result_received >= 1,
|
|
"Event did not triggered for single shot {}".format(error))
|
|
finally:
|
|
self.dut.droid.wifiScannerStopScan(idx)
|
|
# For single shot number of result received and length of result
|
|
# should be one
|
|
asserts.assert_true(
|
|
result_received == 1,
|
|
"Test fail because received result {}".format(
|
|
result_received))
|
|
|
|
@test_tracker_info(uuid="372b9b74-4241-46ce-8f18-e6a97d3a3452")
|
|
def test_no_reconnect_manual_disable_wifi(self):
|
|
"""
|
|
Tests that Wifi Wake does not reconnect to a network if the user turned
|
|
off Wifi while connected to that network and the user has not moved
|
|
(i.e. moved out of range of the AP then came back).
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(
|
|
2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
asserts.assert_false(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to not enable Wifi, but Wifi was enabled.")
|
|
|
|
@test_tracker_info(uuid="ec7a54a5-f293-43f5-a1dd-d41679aa1825")
|
|
def test_reconnect_wifi_saved_network(self):
|
|
"""Tests that Wifi Wake re-enables Wifi for a saved network."""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5)
|
|
self.dut.ed.clear_all_events()
|
|
self.ap_a_off()
|
|
self.ap_b_off()
|
|
wutils.wait_for_disconnect(self.dut, DISCONNECT_TIMEOUT_SEC)
|
|
self.log.info("Wifi Disconnected")
|
|
self.do_location_scan(2)
|
|
time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
|
|
self.ap_a_on()
|
|
self.do_location_scan(
|
|
SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY])
|
|
time.sleep(WIFI_TOGGLE_DELAY_SEC)
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to enable Wifi, but Wifi is disabled.")
|
|
|
|
@test_tracker_info(uuid="3cecd1c5-54bc-44a2-86f7-ad84625bf094")
|
|
def test_reconnect_wifi_network_suggestion(self):
|
|
"""Tests that Wifi Wake re-enables Wifi for app provided suggestion."""
|
|
self.dut.log.info("Adding network suggestions")
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiAddNetworkSuggestions([self.ap_a]),
|
|
"Failed to add suggestions")
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiAddNetworkSuggestions([self.ap_b]),
|
|
"Failed to add suggestions")
|
|
# Enable suggestions by the app.
|
|
self.dut.log.debug("Enabling suggestions from test")
|
|
self.dut.adb.shell("cmd wifi network-suggestions-set-user-approved"
|
|
+ " " + SL4A_APK_NAME + " yes")
|
|
# Ensure network is seen in scan results & auto-connected to.
|
|
self.do_location_scan(2)
|
|
wutils.wait_for_connect(self.dut)
|
|
current_network = self.dut.droid.wifiGetConnectionInfo()
|
|
self.dut.ed.clear_all_events()
|
|
if current_network[SSID] == self.ap_a[SSID]:
|
|
# connected to AP A, so turn AP B off first to prevent the
|
|
# device from immediately reconnecting to AP B
|
|
self.ap_b_off()
|
|
self.ap_a_off()
|
|
else:
|
|
self.ap_a_off()
|
|
self.ap_b_off()
|
|
|
|
wutils.wait_for_disconnect(self.dut, DISCONNECT_TIMEOUT_SEC)
|
|
self.log.info("Wifi Disconnected")
|
|
self.do_location_scan(2)
|
|
time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
|
|
self.ap_a_on()
|
|
self.do_location_scan(
|
|
SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY])
|
|
time.sleep(WIFI_TOGGLE_DELAY_SEC)
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to enable Wifi, but Wifi is disabled.")
|
|
|
|
@test_tracker_info(uuid="6c77ca9b-ff34-4bc7-895f-cc7340e0e645")
|
|
def test_reconnect_wifi_move_back_in_range(self):
|
|
"""
|
|
Tests that Wifi Wake re-enables Wifi if the device moves out of range of
|
|
the AP then came back.
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
# init Wakeup Lock with AP A
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_a_off()
|
|
# evict AP A from Wakeup Lock
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_a_on()
|
|
self.do_location_scan(
|
|
SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY])
|
|
time.sleep(WIFI_TOGGLE_DELAY_SEC)
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to enable Wifi, but Wifi is disabled.")
|
|
|
|
@test_tracker_info(uuid="08e8284a-a523-48f3-b9ea-9c6bf27d711e")
|
|
def test_no_reconnect_to_flaky_ap(self):
|
|
"""
|
|
Tests that Wifi Wake does not reconnect to flaky networks.
|
|
If a network sporadically connects and disconnects, and the user turns
|
|
off Wifi even during the disconnected phase, Wifi Wake should not
|
|
re-enable Wifi for that network.
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
self.ap_a_off()
|
|
time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 0.4)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_a_on()
|
|
self.do_location_scan(
|
|
2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
asserts.assert_false(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to not enable Wifi, but Wifi was enabled.")
|
|
|
|
@test_tracker_info(uuid="b990a8f7-e3a0-4774-89cf-2067ccd64903")
|
|
def test_reconnect_wifi_disabled_after_disconnecting(self):
|
|
"""
|
|
Tests that Wifi Wake reconnects to a network if Wifi was disabled long
|
|
after disconnecting from a network.
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
self.dut.ed.clear_all_events()
|
|
self.ap_a_off()
|
|
wutils.wait_for_disconnect(self.dut, DISCONNECT_TIMEOUT_SEC)
|
|
self.log.info("Wifi Disconnected")
|
|
self.do_location_scan(2)
|
|
time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_a_on()
|
|
self.do_location_scan(
|
|
SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY])
|
|
time.sleep(WIFI_TOGGLE_DELAY_SEC)
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to enable Wifi, but Wifi is disabled.")
|
|
|
|
@test_tracker_info(uuid="bb217794-d3ee-4fb9-87ff-7a594d0223b0")
|
|
def test_no_reconnect_if_exists_ap_in_wakeup_lock(self):
|
|
"""
|
|
2 APs in Wakeup Lock, user moves out of range of one AP but stays in
|
|
range of the other, should not reconnect when user moves back in range
|
|
of both.
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_b_off()
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_b_on()
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
asserts.assert_false(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to not enable Wifi, but Wifi was enabled.")
|
|
|
|
@test_tracker_info(uuid="567a0663-4ce0-488d-8fe2-db79a3ebf068")
|
|
def test_reconnect_if_both_ap_evicted_from_wakeup_lock(self):
|
|
"""
|
|
2 APs in Wakeup Lock, user moves out of range of both APs, should
|
|
reconnect when user moves back in range of either AP.
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_a_off()
|
|
self.ap_b_off()
|
|
self.do_location_scan(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
self.ap_a_on()
|
|
self.do_location_scan(
|
|
SCANS_REQUIRED_TO_FIND_SSID, self.ap_a[wutils.WifiEnums.SSID_KEY])
|
|
time.sleep(WIFI_TOGGLE_DELAY_SEC)
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to enable Wifi, but Wifi is disabled.")
|
|
|
|
@test_tracker_info(uuid="d67657c8-3de3-46a6-a103-428cdab89423")
|
|
def test_reconnect_to_better_saved_network(self):
|
|
"""
|
|
2 saved APs, one attenuated, one unattenuated, Wifi Wake should connect
|
|
to the unattenuated AP
|
|
"""
|
|
wutils.wifi_connect(self.dut, self.ap_a, num_of_tries=5)
|
|
wutils.wifi_connect(self.dut, self.ap_b, num_of_tries=5)
|
|
self.dut.ed.clear_all_events()
|
|
self.ap_a_off()
|
|
self.ap_b_off()
|
|
wutils.wait_for_disconnect(self.dut, DISCONNECT_TIMEOUT_SEC)
|
|
self.log.info("Wifi Disconnected")
|
|
|
|
if self.dut.model in self.user_params["google_pixel_watch_models"]:
|
|
wutils.disable_wear_wifimediator(self.dut, True)
|
|
|
|
self.do_location_scan(2)
|
|
time.sleep(LAST_DISCONNECT_TIMEOUT_SEC * 1.2)
|
|
wutils.wifi_toggle_state(self.dut, new_state=False)
|
|
time.sleep(PRESCAN_DELAY_SEC)
|
|
self.do_location_scan(2 * CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT + 2)
|
|
|
|
self.ap_a_on()
|
|
self.ap_b_on()
|
|
self.ap_a_atten.set_atten(30)
|
|
self.ap_b_atten.set_atten(0)
|
|
|
|
if self.dut.model in self.user_params["google_pixel_watch_models"]:
|
|
wutils.disable_wear_wifimediator(self.dut, False)
|
|
|
|
self.do_location_scan(
|
|
SCANS_REQUIRED_TO_FIND_SSID, self.ap_b[wutils.WifiEnums.SSID_KEY])
|
|
time.sleep(WIFI_TOGGLE_DELAY_SEC)
|
|
asserts.assert_true(
|
|
self.dut.droid.wifiCheckState(),
|
|
"Expect Wifi Wake to enable Wifi, but Wifi is disabled.")
|
|
expected_ssid = self.ap_b[wutils.WifiEnums.SSID_KEY]
|
|
wutils.wait_for_connect(self.dut, expected_ssid)
|