1# 2# Copyright 2022 - The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import os 17import time 18 19from acts import asserts 20from acts import base_test 21from acts import utils 22from acts import signals 23from acts import test_runner 24from acts.controllers import adb 25from acts.test_decorators import test_tracker_info 26from acts_contrib.test_utils.net import net_test_utils as nutils 27from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existence 28from acts_contrib.test_utils.tel.tel_test_utils import _generate_file_directory_and_file_name 29from acts_contrib.test_utils.wifi import wifi_test_utils as wutils 30from acts_contrib.test_utils.net.connectivity_const import MULTIPATH_PREFERENCE_NONE as NONE 31from acts_contrib.test_utils.net.connectivity_const import MULTIPATH_PREFERENCE_HANDOVER as HANDOVER 32from acts_contrib.test_utils.net.connectivity_const import MULTIPATH_PREFERENCE_RELIABILITY as RELIABILITY 33from acts_contrib.test_utils.net.connectivity_const import MULTIPATH_PREFERENCE_PERFORMANCE as PERFORMANCE 34 35DOWNLOAD_PATH = "/sdcard/Download/" 36RELIABLE = RELIABILITY | HANDOVER 37TIMEOUT = 6 38 39 40class DataCostTest(base_test.BaseTestClass): 41 """ Tests for Wifi Tethering """ 42 43 def setup_class(self): 44 """ Setup devices for tethering and unpack params """ 45 46 req_params = ("wifi_network", "download_file") 47 self.unpack_userparams(req_params) 48 49 for ad in self.android_devices: 50 nutils.verify_lte_data_and_tethering_supported(ad) 51 52 self.tcpdump_pid = None 53 54 def teardown_class(self): 55 """ Reset settings to default """ 56 for ad in self.android_devices: 57 sub_id = str(ad.droid.telephonyGetSubscriberId()) 58 ad.droid.connectivityFactoryResetNetworkPolicies(sub_id) 59 ad.droid.connectivitySetDataWarningLimit(sub_id, -1) 60 wutils.reset_wifi(ad) 61 62 def teardown_test(self): 63 if self.tcpdump_pid: 64 nutils.stop_tcpdump(self.dut, self.tcpdump_pid, self.test_name) 65 self.tcpdump_pid = None 66 67 def on_fail(self, test_name, begin_time): 68 self.dut.take_bug_report(test_name, begin_time) 69 dumpsys_info = self.dut.adb.shell("dumpsys netstats --uid") 70 self.dut.log.info(dumpsys_info) 71 72 """ Helper functions """ 73 74 def _clear_netstats(self, ad): 75 """ Clear netstats stored on device 76 77 Args: 78 ad: Android device object 79 """ 80 ad.log.info("Clear netstats record.") 81 ad.adb.shell("if [ $(ls /data/system/netstats/) ]; then rm /data/system/netstats/*; fi") 82 asserts.assert_equal("", ad.adb.shell("ls /data/system/netstats/"), 83 "Fail to clear netstats.") 84 ad.reboot() 85 time.sleep(30) 86 nutils.verify_lte_data_and_tethering_supported(ad) 87 self._check_multipath_preference_from_dumpsys(ad) 88 89 def _check_multipath_preference_from_dumpsys(self, ad): 90 """ Check cell multipath_preference from dumpsys 91 92 Args: 93 ad: Android device object 94 """ 95 try: 96 out = ad.adb.shell("dumpsys connectivity | grep budget") 97 except TimeoutError: 98 ad.log.warning("Fail to get status from dumpsys.") 99 out = "" 100 ad.log.info("MultipathPolicyTracker: %s" % out) 101 if out: 102 asserts.assert_true( 103 "HANDOVER|RELIABILITY" in out, 104 "Cell multipath preference should be HANDOVER|RELIABILITY.") 105 106 def _get_total_data_usage_for_device(self, ad, conn_type, sub_id): 107 """ Get total data usage in MB for device 108 109 Args: 110 ad: Android device object 111 conn_type: MOBILE/WIFI data usage 112 sub_id: subscription id 113 114 Returns: 115 Data usage in MB 116 """ 117 # end time should be in milli seconds and at least 2 hours more than the 118 # actual end time. NetStats:bucket is of size 2 hours and to ensure to 119 # get the most recent data usage, end_time should be +2hours 120 end_time = int(time.time() * 1000) + 2 * 1000 * 60 * 60 121 data_usage = ad.droid.connectivityQuerySummaryForDevice( 122 conn_type, sub_id, 0, end_time) 123 data_usage /= 1000.0 * 1000.0 # convert data_usage to MB 124 self.log.info("Total data usage is: %s" % data_usage) 125 return data_usage 126 127 def _check_if_multipath_preference_valid(self, val, exp): 128 """ Check if multipath value is same as expected 129 130 Args: 131 val: multipath preference for the network 132 exp: expected multipath preference value 133 """ 134 if exp == NONE: 135 asserts.assert_true(val == exp, "Multipath value should be 0") 136 else: 137 asserts.assert_true(val >= exp, 138 "Multipath value should be at least %s" % exp) 139 140 def _verify_multipath_preferences(self, ad, wifi_pref, cell_pref, 141 wifi_network, cell_network): 142 """ Verify mutlipath preferences for wifi and cell networks 143 144 Args: 145 ad: Android device object 146 wifi_pref: Expected multipath value for wifi network 147 cell_pref: Expected multipath value for cell network 148 wifi_network: Wifi network id on the device 149 cell_network: Cell network id on the device 150 """ 151 wifi_multipath = \ 152 ad.droid.connectivityGetMultipathPreferenceForNetwork(wifi_network) 153 cell_multipath = \ 154 ad.droid.connectivityGetMultipathPreferenceForNetwork(cell_network) 155 self.log.info("WiFi multipath preference: %s" % wifi_multipath) 156 self.log.info("Cell multipath preference: %s" % cell_multipath) 157 self.log.info("Checking multipath preference for wifi") 158 self._check_if_multipath_preference_valid(wifi_multipath, wifi_pref) 159 self.log.info("Checking multipath preference for cell") 160 self._check_if_multipath_preference_valid(cell_multipath, cell_pref) 161 162 """ Test Cases """ 163 164 @test_tracker_info(uuid="e86c8108-3e84-4668-bae4-e5d2c8c27910") 165 def test_multipath_preference_low_data_limit(self): 166 """ Verify multipath preference when mobile data limit is low 167 168 Steps: 169 1. DUT has WiFi and LTE data 170 2. Set mobile data usage limit to low value 171 3. Verify that multipath preference is 0 for cell network 172 """ 173 # set vars 174 ad = self.android_devices[0] 175 self.dut = ad 176 self._clear_netstats(ad) 177 utils.sync_device_time(ad) 178 self.tcpdump_pid = nutils.start_tcpdump(ad, self.test_name) 179 180 sub_id = str(ad.droid.telephonyGetSubscriberId()) 181 cell_network = ad.droid.connectivityGetActiveNetwork() 182 self.log.info("cell network %s" % cell_network) 183 wutils.wifi_connect(ad, self.wifi_network) 184 wifi_network = ad.droid.connectivityGetActiveNetwork() 185 self.log.info("wifi network %s" % wifi_network) 186 187 # verify mulipath preference values 188 self._verify_multipath_preferences(ad, RELIABLE, RELIABLE, 189 wifi_network, cell_network) 190 191 # set low data limit on mobile data 192 total_pre = self._get_total_data_usage_for_device(ad, 0, sub_id) 193 self.log.info("Setting data usage limit to %sMB" % (total_pre + 5)) 194 ad.droid.connectivitySetDataUsageLimit( 195 sub_id, int((total_pre + 5) * 1000.0 * 1000.0)) 196 self.log.info("Setting data warning limit to %sMB" % (total_pre + 5)) 197 ad.droid.connectivitySetDataWarningLimit( 198 sub_id, int((total_pre + 5) * 1000.0 * 1000.0)) 199 200 # verify multipath preference values 201 curr_time = time.time() 202 while time.time() < curr_time + TIMEOUT: 203 try: 204 self._verify_multipath_preferences(ad, RELIABLE, NONE, 205 wifi_network, cell_network) 206 return True 207 except signals.TestFailure as e: 208 self.log.debug("%s" % e) 209 time.sleep(1) 210 return False 211 212 @test_tracker_info(uuid="a2781411-d880-476a-9f40-2c67e0f97db9") 213 def test_multipath_preference_data_download(self): 214 """ Verify multipath preference when large file is downloaded 215 216 Steps: 217 1. DUT has WiFi and LTE data 218 2. WiFi is active network 219 3. Download large file over cell network 220 4. Verify multipath preference on cell network is 0 221 """ 222 # set vars 223 ad = self.android_devices[1] 224 self.dut = ad 225 self._clear_netstats(ad) 226 utils.sync_device_time(ad) 227 self.tcpdump_pid = nutils.start_tcpdump(ad, self.test_name) 228 229 cell_network = ad.droid.connectivityGetActiveNetwork() 230 self.log.info("cell network %s" % cell_network) 231 wutils.wifi_connect(ad, self.wifi_network) 232 wifi_network = ad.droid.connectivityGetActiveNetwork() 233 self.log.info("wifi network %s" % wifi_network) 234 235 # verify multipath preference for wifi and cell networks 236 self._verify_multipath_preferences(ad, RELIABLE, RELIABLE, 237 wifi_network, cell_network) 238 239 # download file with cell network 240 ad.droid.connectivityNetworkOpenConnection(cell_network, 241 self.download_file) 242 file_folder, file_name = _generate_file_directory_and_file_name( 243 self.download_file, DOWNLOAD_PATH) 244 file_path = os.path.join(file_folder, file_name) 245 self.log.info("File path: %s" % file_path) 246 if _check_file_existence(ad, file_path): 247 self.log.info("File exists. Removing file %s" % file_name) 248 ad.adb.shell("rm -rf %s%s" % (DOWNLOAD_PATH, file_name)) 249 250 # verify multipath preference values 251 curr_time = time.time() 252 while time.time() < curr_time + TIMEOUT: 253 try: 254 self._verify_multipath_preferences(ad, RELIABLE, NONE, 255 wifi_network, cell_network) 256 return True 257 except signals.TestFailure as e: 258 self.log.debug("%s" % e) 259 time.sleep(1) 260 return False 261 262 # TODO gmoturu@: Need to add tests that use the mobility rig and test when 263 # the WiFi signal is poor and data signal is good. 264