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 os 18import threading 19import time 20 21from acts import base_test 22from acts import asserts 23from acts import utils 24from acts.controllers import adb 25from acts.controllers import iperf_server as ip_server 26from acts.controllers import monsoon 27from acts.test_decorators import test_tracker_info 28from acts.test_utils.wifi import wifi_test_utils as wutils 29from acts.utils import force_airplane_mode 30from acts.utils import set_adaptive_brightness 31from acts.utils import set_ambient_display 32from acts.utils import set_auto_rotate 33from acts.utils import set_location_service 34 35pmc_base_cmd = ("am broadcast -a com.android.pmc.action.AUTOPOWER --es" 36 " PowerAction ") 37start_pmc_cmd = ("am start -S -n com.android.pmc/com.android.pmc." 38 "PMCMainActivity") 39pmc_interval_cmd = ("am broadcast -a com.android.pmc.action.SETPARAMS --es " 40 "Interval %s ") 41pmc_set_params = "am broadcast -a com.android.pmc.action.SETPARAMS --es " 42 43pmc_start_connect_scan_cmd = "%sStartConnectivityScan" % pmc_base_cmd 44pmc_stop_connect_scan_cmd = "%sStopConnectivityScan" % pmc_base_cmd 45pmc_start_gscan_no_dfs_cmd = "%sStartGScanBand" % pmc_base_cmd 46pmc_start_gscan_specific_channels_cmd = "%sStartGScanChannel" % pmc_base_cmd 47pmc_stop_gscan_cmd = "%sStopGScan" % pmc_base_cmd 48pmc_start_iperf_client = "%sStartIperfClient" % pmc_base_cmd 49pmc_stop_iperf_client = "%sStopIperfClient" % pmc_base_cmd 50pmc_turn_screen_on = "%sTurnScreenOn" % pmc_base_cmd 51pmc_turn_screen_off = "%sTurnScreenOff" % pmc_base_cmd 52# Path of the iperf json output file from an iperf run. 53pmc_iperf_json_file = "/sdcard/iperf.txt" 54 55 56class WifiPowerTest(base_test.BaseTestClass): 57 def setup_class(self): 58 self.offset = 5 * 60 59 self.hz = 5000 60 self.scan_interval = 15 61 # Continuosly download 62 self.download_interval = 0 63 self.mon_data_path = os.path.join(self.log_path, "Monsoon") 64 self.mon = self.monsoons[0] 65 self.mon.set_voltage(4.2) 66 self.mon.set_max_current(7.8) 67 self.dut = self.android_devices[0] 68 self.mon.attach_device(self.dut) 69 asserts.assert_true( 70 self.mon.usb("auto"), 71 "Failed to turn USB mode to auto on monsoon.") 72 asserts.assert_true( 73 force_airplane_mode(self.dut, True), 74 "Can not turn on airplane mode on: %s" % self.dut.serial) 75 set_location_service(self.dut, False) 76 set_adaptive_brightness(self.dut, False) 77 set_ambient_display(self.dut, False) 78 self.dut.adb.shell("settings put system screen_brightness 0") 79 set_auto_rotate(self.dut, False) 80 required_userparam_names = ( 81 # These two params should follow the format of 82 # {"SSID": <SSID>, "password": <Password>} 83 "network_2g", 84 "network_5g", 85 "iperf_server_address") 86 self.unpack_userparams(required_userparam_names, threshold=None) 87 wutils.wifi_test_device_init(self.dut) 88 try: 89 self.attn = self.attenuators[0] 90 self.attn.set_atten(0) 91 except AttributeError: 92 self.log.warning("No attenuator found, some tests will fail.") 93 pass 94 95 def teardown_class(self): 96 self.mon.usb("on") 97 98 def setup_test(self): 99 # Default measurement time is 30min with an offset of 5min. Each test 100 # can overwrite this by setting self.duration and self.offset. 101 self.offset = 5 * 60 102 self.duration = 20 * 60 + self.offset 103 self.start_pmc() 104 wutils.reset_wifi(self.dut) 105 self.dut.ed.clear_all_events() 106 107 def on_fail(self, test_name, begin_time): 108 self.dut.take_bug_report(test_name, begin_time) 109 110 def on_pass(self, test_name, begin_time): 111 self.dut.take_bug_report(test_name, begin_time) 112 113 def start_pmc(self): 114 """Starts a new instance of PMC app on the device and initializes it. 115 116 This function performs the following: 117 1. Starts a new instance of PMC (killing any existing instances). 118 2. Turns on PMC verbose logging. 119 3. Sets up the server IP address/port for download/iperf tests. 120 4. Removes an existing iperf json output files. 121 """ 122 self.dut.adb.shell(start_pmc_cmd) 123 self.dut.adb.shell("setprop log.tag.PMC VERBOSE") 124 self.iperf_server = self.iperf_servers[0] 125 # Setup iperf related params on the client side. 126 self.dut.adb.shell("%sServerIP %s" % (pmc_set_params, 127 self.iperf_server_address)) 128 self.dut.adb.shell("%sServerPort %s" % (pmc_set_params, 129 self.iperf_server.port)) 130 try: 131 self.dut.adb.shell("rm %s" % pmc_iperf_json_file) 132 except adb.AdbError: 133 pass 134 135 def get_iperf_result(self): 136 """Pulls the iperf json output from device. 137 138 Returns: 139 An IPerfResult object based on the iperf run output. 140 """ 141 dest = os.path.join(self.iperf_server.log_path, "iperf.txt") 142 self.dut.adb.pull(pmc_iperf_json_file, " ", dest) 143 result = ip_server.IPerfResult(dest) 144 self.dut.adb.shell("rm %s" % pmc_iperf_json_file) 145 return result 146 147 def measure_and_process_result(self): 148 """Measure the current drawn by the device for the period of 149 self.duration, at the frequency of self.hz. 150 151 If self.threshold exists, also verify that the average current of the 152 measurement is below the acceptable threshold. 153 """ 154 tag = self.current_test_name 155 result = self.mon.measure_power(self.hz, 156 self.duration, 157 tag=tag, 158 offset=self.offset) 159 asserts.assert_true(result, 160 "Got empty measurement data set in %s." % tag) 161 self.log.info(repr(result)) 162 data_path = os.path.join(self.mon_data_path, "%s.txt" % tag) 163 monsoon.MonsoonData.save_to_text_file([result], data_path) 164 actual_current = result.average_current 165 actual_current_str = "%.2fmA" % actual_current 166 result_extra = {"Average Current": actual_current_str} 167 if "continuous_traffic" in tag: 168 self.dut.adb.shell(pmc_stop_iperf_client) 169 iperf_result = self.get_iperf_result() 170 asserts.assert_true(iperf_result.avg_rate, 171 "Failed to send iperf traffic", 172 extras=result_extra) 173 rate = "%.2fMB/s" % iperf_result.avg_rate 174 result_extra["Average Rate"] = rate 175 model = utils.trim_model_name(self.dut.model) 176 if self.threshold and (model in self.threshold) and ( 177 tag in self.threshold[model]): 178 acceptable_threshold = self.threshold[model][tag] 179 asserts.assert_true( 180 actual_current < acceptable_threshold, 181 ("Measured average current in [%s]: %s, which is " 182 "higher than acceptable threshold %.2fmA.") % ( 183 tag, actual_current_str, acceptable_threshold), 184 extras=result_extra) 185 asserts.explicit_pass("Measurement finished for %s." % tag, 186 extras=result_extra) 187 188 @test_tracker_info(uuid="99ed6d06-ad07-4650-8434-0ac9d856fafa") 189 def test_power_wifi_off(self): 190 wutils.wifi_toggle_state(self.dut, False) 191 self.measure_and_process_result() 192 193 @test_tracker_info(uuid="086db8fd-4040-45ac-8934-49b4d84413fc") 194 def test_power_wifi_on_idle(self): 195 wutils.wifi_toggle_state(self.dut, True) 196 self.measure_and_process_result() 197 198 @test_tracker_info(uuid="031516d9-b0f5-4f21-bc8b-078258852325") 199 def test_power_disconnected_connectivity_scan(self): 200 try: 201 self.dut.adb.shell(pmc_interval_cmd % self.scan_interval) 202 self.dut.adb.shell(pmc_start_connect_scan_cmd) 203 self.log.info("Started connectivity scan.") 204 self.measure_and_process_result() 205 finally: 206 self.dut.adb.shell(pmc_stop_connect_scan_cmd) 207 self.log.info("Stoped connectivity scan.") 208 209 @test_tracker_info(uuid="5e1f92d7-a79e-459c-aff0-d4acba3adee4") 210 def test_power_connected_2g_idle(self): 211 wutils.reset_wifi(self.dut) 212 self.dut.ed.clear_all_events() 213 wutils.wifi_connect(self.dut, self.network_2g) 214 self.measure_and_process_result() 215 216 @test_tracker_info(uuid="e2b4ab89-420e-4560-a08b-d3bf4336f05d") 217 def test_power_connected_2g_continuous_traffic(self): 218 try: 219 wutils.reset_wifi(self.dut) 220 self.dut.ed.clear_all_events() 221 wutils.wifi_connect(self.dut, self.network_2g) 222 self.iperf_server.start() 223 self.dut.adb.shell(pmc_start_iperf_client) 224 self.log.info("Started iperf traffic.") 225 self.measure_and_process_result() 226 finally: 227 self.iperf_server.stop() 228 self.log.info("Stopped iperf traffic.") 229 230 @test_tracker_info(uuid="a9517306-b967-494e-b471-84de58df8f1b") 231 def test_power_connected_5g_idle(self): 232 wutils.reset_wifi(self.dut) 233 self.dut.ed.clear_all_events() 234 wutils.wifi_connect(self.dut, self.network_5g) 235 self.measure_and_process_result() 236 237 @test_tracker_info(uuid="816716b3-a90b-4835-84b8-d8d761ebfba9") 238 def test_power_connected_5g_continuous_traffic(self): 239 try: 240 wutils.reset_wifi(self.dut) 241 self.dut.ed.clear_all_events() 242 wutils.wifi_connect(self.dut, self.network_5g) 243 self.iperf_server.start() 244 self.dut.adb.shell(pmc_start_iperf_client) 245 self.log.info("Started iperf traffic.") 246 self.measure_and_process_result() 247 finally: 248 self.iperf_server.stop() 249 self.log.info("Stopped iperf traffic.") 250 251 @test_tracker_info(uuid="e2d08e4e-7863-4554-af63-64d41ab0976a") 252 def test_power_gscan_three_2g_channels(self): 253 try: 254 self.dut.adb.shell(pmc_interval_cmd % self.scan_interval) 255 self.dut.adb.shell(pmc_start_gscan_specific_channels_cmd) 256 self.log.info("Started gscan for 2G channels 1, 6, and 11.") 257 self.measure_and_process_result() 258 finally: 259 self.dut.adb.shell(pmc_stop_gscan_cmd) 260 self.log.info("Stopped gscan.") 261 262 @test_tracker_info(uuid="0095b7e7-94b9-4cd9-912f-51971949748b") 263 def test_power_gscan_all_channels_no_dfs(self): 264 try: 265 self.dut.adb.shell(pmc_interval_cmd % self.scan_interval) 266 self.dut.adb.shell(pmc_start_gscan_no_dfs_cmd) 267 self.log.info("Started gscan for all non-DFS channels.") 268 self.measure_and_process_result() 269 finally: 270 self.dut.adb.shell(pmc_stop_gscan_cmd) 271 self.log.info("Stopped gscan.") 272 273 @test_tracker_info(uuid="263d1b68-8eb0-4e7f-99d4-3ca23ca359ce") 274 def test_power_connected_2g_gscan_all_channels_no_dfs(self): 275 try: 276 wutils.wifi_connect(self.dut, self.network_2g) 277 self.dut.adb.shell(pmc_interval_cmd % self.scan_interval) 278 self.dut.adb.shell(pmc_start_gscan_no_dfs_cmd) 279 self.log.info("Started gscan for all non-DFS channels.") 280 self.measure_and_process_result() 281 finally: 282 self.dut.adb.shell(pmc_stop_gscan_cmd) 283 self.log.info("Stopped gscan.") 284 285 @test_tracker_info(uuid="aad1a39d-01f9-4fa5-a23a-b85d54210f3c") 286 def test_power_connected_5g_gscan_all_channels_no_dfs(self): 287 try: 288 wutils.wifi_connect(self.dut, self.network_5g) 289 self.dut.adb.shell(pmc_interval_cmd % self.scan_interval) 290 self.dut.adb.shell(pmc_start_gscan_no_dfs_cmd) 291 self.log.info("Started gscan for all non-DFS channels.") 292 self.measure_and_process_result() 293 finally: 294 self.dut.adb.shell(pmc_stop_gscan_cmd) 295 self.log.info("Stopped gscan.") 296 297 @test_tracker_info(uuid="8f72cd5f-1c66-4ced-92d9-b7ebadf76424") 298 def test_power_auto_reconnect(self): 299 """ 300 Steps: 301 1. Connect to network, wait for three minutes. 302 2. Attenuate AP away, wait for one minute. 303 3. Make AP reappear, wait for three minutes for the device to 304 reconnect to the Wi-Fi network. 305 """ 306 self.attn.set_atten(0) 307 wutils.wifi_connect(self.dut, self.network_2g) 308 309 def attn_control(): 310 for i in range(7): 311 self.log.info("Iteration %s: Idle 3min after AP appeared.", i) 312 time.sleep(3 * 60) 313 self.attn.set_atten(90) 314 self.log.info("Iteration %s: Idle 1min after AP disappeared.", 315 i) 316 time.sleep(60) 317 self.attn.set_atten(0) 318 319 t = threading.Thread(target=attn_control) 320 t.start() 321 try: 322 self.measure_and_process_result() 323 finally: 324 t.join() 325 326 @test_tracker_info(uuid="a6db5964-3c68-47fa-b4c9-49f880549031") 327 def test_power_screen_on_wifi_off(self): 328 self.duration = 10 * 60 329 self.offset = 4 * 60 330 wutils.wifi_toggle_state(self.dut, False) 331 try: 332 self.dut.adb.shell(pmc_turn_screen_on) 333 self.measure_and_process_result() 334 finally: 335 self.dut.adb.shell(pmc_turn_screen_off) 336 337 @test_tracker_info(uuid="230d667a-aa42-4123-9dae-2036429ed574") 338 def test_power_screen_on_wifi_connected_2g_idle(self): 339 self.duration = 10 * 60 340 self.offset = 4 * 60 341 wutils.wifi_toggle_state(self.dut, True) 342 wutils.wifi_connect(self.dut, self.network_2g) 343 try: 344 self.dut.adb.shell(pmc_turn_screen_on) 345 self.measure_and_process_result() 346 finally: 347 self.dut.adb.shell(pmc_turn_screen_off) 348