1 /* 2 * Copyright (C) 2010, 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 */ 16 17 package com.android.connectivitymanagertest.stress; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.net.ConnectivityManager; 22 import android.net.NetworkInfo; 23 import android.net.NetworkInfo.State; 24 import android.net.wifi.ScanResult; 25 import android.net.wifi.WifiConfiguration; 26 import android.net.wifi.WifiManager; 27 import android.os.Bundle; 28 import android.os.Environment; 29 import android.os.PowerManager; 30 import android.os.SystemClock; 31 import android.provider.Settings; 32 import android.test.suitebuilder.annotation.LargeTest; 33 import android.util.Log; 34 35 import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner; 36 import com.android.connectivitymanagertest.ConnectivityManagerTestBase; 37 import com.android.connectivitymanagertest.WifiConfigurationHelper; 38 39 import java.io.BufferedWriter; 40 import java.io.File; 41 import java.io.FileWriter; 42 import java.io.IOException; 43 import java.util.List; 44 45 /** 46 * Stress Wi-Fi connection, scanning and reconnection after sleep. 47 * 48 * To run this stress test suite, type 49 * adb shell am instrument -e class com.android.connectivitymanagertest.stress.WifiStressTest 50 * -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner 51 */ 52 public class WifiStressTest extends ConnectivityManagerTestBase { 53 private final static long SCREEN_OFF_TIMER = 500; //500ms 54 /** 55 * Wi-Fi idle time for default sleep policy 56 */ 57 private final static long WIFI_IDLE_MS = 15 * 1000; 58 59 /** 60 * Delay after issuing wifi shutdown. 61 * The framework keep driver up for at leat 2 minutes to avoid problems 62 * that a quick shutdown could cause on wext driver and protentially 63 * on cfg based driver 64 */ 65 private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000; 66 67 private final static String OUTPUT_FILE = "WifiStressTestOutput.txt"; 68 private int mReconnectIterations; 69 private long mWifiSleepTime; 70 private int mScanIterations; 71 private String mSsid; 72 private String mPassword; 73 private ConnectivityManagerStressTestRunner mRunner; 74 private BufferedWriter mOutputWriter = null; 75 private boolean mWifiOnlyFlag; 76 77 public WifiStressTest() { 78 super(WifiStressTest.class.getSimpleName()); 79 } 80 81 @Override 82 protected void setUp() throws Exception { 83 super.setUp(); 84 85 mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation(); 86 mReconnectIterations = mRunner.getReconnectIterations(); 87 mSsid = mRunner.getReconnectSsid(); 88 mPassword = mRunner.getReconnectPassword(); 89 mScanIterations = mRunner.getScanIterations(); 90 mWifiSleepTime = mRunner.getSleepTime(); 91 mWifiOnlyFlag = mRunner.isWifiOnly(); 92 logv(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s)," 93 + "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid, 94 mPassword, mScanIterations, mWifiSleepTime)); 95 mOutputWriter = new BufferedWriter(new FileWriter(new File( 96 Environment.getExternalStorageDirectory(), OUTPUT_FILE), true)); 97 turnScreenOn(); 98 if (!mWifiManager.isWifiEnabled()) { 99 logv("Enable wi-fi before stress tests."); 100 if (!enableWifi()) { 101 tearDown(); 102 fail("enable wifi failed."); 103 } 104 sleep(SHORT_TIMEOUT, "Interruped while waiting for wifi on"); 105 } 106 } 107 108 @Override 109 protected void tearDown() throws Exception { 110 logv("tearDown()"); 111 if (mOutputWriter != null) { 112 mOutputWriter.close(); 113 } 114 super.tearDown(); 115 } 116 117 private void writeOutput(String s) { 118 logv("write message: " + s); 119 if (mOutputWriter == null) { 120 logv("no writer attached to file " + OUTPUT_FILE); 121 return; 122 } 123 try { 124 mOutputWriter.write(s + "\n"); 125 mOutputWriter.flush(); 126 } catch (IOException e) { 127 logv("failed to write output."); 128 } 129 } 130 131 private void sleep(long sometime, String errorMsg) { 132 try { 133 Thread.sleep(sometime); 134 } catch (InterruptedException e) { 135 fail(errorMsg); 136 } 137 } 138 139 /** 140 * Stress Wifi Scanning 141 * TODO: test the scanning quality for each frequency band 142 */ 143 @LargeTest 144 public void testWifiScanning() { 145 long scanTimeSum = 0, i, averageScanTime = -1; 146 int ssidAppearInScanResultsCount = 0; // count times of given ssid appear in scan results. 147 for (i = 1; i <= mScanIterations; i++) { 148 logv("testWifiScanning: iteration: " + i); 149 averageScanTime = scanTimeSum / i; 150 writeOutput(String.format("iteration %d out of %d", i, mScanIterations)); 151 writeOutput(String.format("average scanning time is %d", averageScanTime)); 152 writeOutput(String.format("ssid appear %d out of %d scan iterations", 153 ssidAppearInScanResultsCount, i)); 154 List<ScanResult> scanResultLocal = null; 155 // wait for a scan result 156 long start = 0; 157 synchronized (mWifiScanResultLock) { 158 start = SystemClock.uptimeMillis(); 159 assertTrue("start scan failed", mWifiManager.startScan()); 160 try { 161 mWifiScanResultLock.wait(WAIT_FOR_SCAN_RESULT); 162 } catch (InterruptedException e) { 163 // ignore 164 } 165 scanTimeSum += SystemClock.uptimeMillis() - start; 166 // save the scan result while in lock 167 scanResultLocal = mLastScanResult; 168 } 169 if (scanResultLocal == null || scanResultLocal.isEmpty()) { 170 fail("Scan results are empty "); 171 } 172 logv("size of scan result list: " + scanResultLocal.size()); 173 for (ScanResult sr : scanResultLocal) { 174 logv(String.format("scan result: " + sr.toString())); 175 if (mSsid.equals(sr.SSID)) { 176 ssidAppearInScanResultsCount += 1; 177 break; 178 } 179 } 180 } 181 Bundle result = new Bundle(); 182 result.putLong("actual-iterations", i - 1); 183 result.putLong("avg-scan-time", averageScanTime); 184 result.putInt("ap-discovered", ssidAppearInScanResultsCount); 185 getInstrumentation().sendStatus(Activity.RESULT_FIRST_USER, result); 186 if (i == mScanIterations + 1) { 187 writeOutput(String.format("iteration %d out of %d", i - 1, mScanIterations)); 188 writeOutput(String.format("average scanning time is %d", scanTimeSum / (i - 1))); 189 writeOutput(String.format("ssid appear %d out of %d scan iterations", 190 ssidAppearInScanResultsCount, i - 1)); 191 } 192 } 193 194 // Stress Wifi reconnection to secure net after sleep 195 @LargeTest 196 public void testWifiReconnectionAfterSleep() { 197 // set always scan to false 198 Settings.Global.putInt(mRunner.getContext().getContentResolver(), 199 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0); 200 // set wifi sleep policy to never on while in sleep 201 Settings.Global.putInt(mRunner.getContext().getContentResolver(), 202 Settings.Global.WIFI_SLEEP_POLICY, Settings.Global.WIFI_SLEEP_POLICY_DEFAULT); 203 // set idle timeout for wifi to 15s 204 Settings.Global.putLong(mRunner.getContext().getContentResolver(), 205 Settings.Global.WIFI_IDLE_MS, WIFI_IDLE_MS); 206 207 WifiConfiguration config; 208 if (mPassword == null) { 209 config = WifiConfigurationHelper.createOpenConfig(mSsid); 210 } else { 211 config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword); 212 } 213 214 assertTrue("Failed to connect to Wi-Fi network: " + mSsid, 215 connectToWifiWithConfiguration(config)); 216 assertTrue("wifi not connected", waitForNetworkState(ConnectivityManager.TYPE_WIFI, 217 State.CONNECTED, WIFI_CONNECTION_TIMEOUT)); 218 // Run ping test to verify the data connection 219 assertTrue("Wi-Fi is connected, but no data connection.", pingTest()); 220 221 long i, sum = 0, avgReconnectTime = 0; 222 for (i = 1; i <= mReconnectIterations; i++) { 223 // 1. Put device into sleep mode 224 // 2. Wait for the device to sleep for sometime, verify wi-fi is off and mobile is on. 225 // 3. Maintain the sleep mode for some time, 226 // 4. Verify the Wi-Fi is still off, and data is on 227 // 5. Wake up the device, verify Wi-Fi is enabled and connected. 228 writeOutput(String.format("iteration %d out of %d", 229 i, mReconnectIterations)); 230 logv("iteration: " + i); 231 turnScreenOff(); 232 // Use clock time since boot for intervals. 233 long start = SystemClock.uptimeMillis(); 234 PowerManager pm = 235 (PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE); 236 while (pm.isInteractive() && 237 ((SystemClock.uptimeMillis() - start) < SCREEN_OFF_TIMER)) { 238 SystemClock.sleep(100); 239 } 240 assertFalse("screen still on", pm.isInteractive()); 241 // wait for WiFi timeout 242 SystemClock.sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY); 243 // below check temporarily disabled due to bug in ConnectivityManager return 244 // assertTrue("Wait for Wi-Fi to idle timeout", 245 // waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, 246 // 6 * SHORT_TIMEOUT)); 247 if (mWifiOnlyFlag) { 248 assertTrue("expected wifi disconnect, still has active connection", 249 waitUntilNoActiveNetworkConnection(2 * LONG_TIMEOUT)); 250 } else { 251 // use long timeout as the pppd startup may take several retries. 252 assertTrue("no fallback on mobile or wifi didn't disconnect", 253 waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, 254 2 * LONG_TIMEOUT)); 255 } 256 SystemClock.sleep(mWifiSleepTime); 257 // verify the wi-fi is still off and either we have no connectivity or fallback on mobile 258 if (mWifiOnlyFlag) { 259 NetworkInfo ni = mCm.getActiveNetworkInfo(); 260 if (ni != null) { 261 Log.e(mLogTag, "has active network while in wifi sleep: " + ni.toString()); 262 fail("active network detected"); 263 } 264 } else { 265 assertEquals("mobile not connected", State.CONNECTED, 266 mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState()); 267 assertTrue("no connectivity over mobile", pingTest()); 268 } 269 270 // Turn screen on again 271 turnScreenOn(); 272 // Measure the time for Wi-Fi to get connected 273 long startTime = SystemClock.uptimeMillis(); 274 assertTrue("screen on: wifi not enabled before timeout", 275 waitForWifiState(WifiManager.WIFI_STATE_ENABLED, SHORT_TIMEOUT)); 276 assertTrue("screen on: wifi not connected before timeout", 277 waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, 278 LONG_TIMEOUT)); 279 long connectionTime = SystemClock.uptimeMillis() - startTime; 280 sum += connectionTime; 281 avgReconnectTime = sum / i; 282 logv("average reconnection time is: " + avgReconnectTime); 283 284 assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest()); 285 } 286 Bundle result = new Bundle(); 287 result.putLong("actual-iterations", i - 1); 288 result.putLong("avg-reconnect-time", avgReconnectTime); 289 getInstrumentation().sendStatus(Activity.RESULT_FIRST_USER, result); 290 if (i == mReconnectIterations + 1) { 291 writeOutput(String.format("iteration %d out of %d", 292 i - 1, mReconnectIterations)); 293 } 294 } 295 } 296