ConnectivityManagerTestBase.java revision 86e15557c52e2847d2adc8495a281dcf0239506e
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 17package com.android.connectivitymanagertest; 18 19import android.app.KeyguardManager; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.net.ConnectivityManager; 25import android.net.NetworkInfo; 26import android.net.NetworkInfo.State; 27import android.net.wifi.ScanResult; 28import android.net.wifi.WifiConfiguration; 29import android.net.wifi.WifiManager; 30import android.os.PowerManager; 31import android.os.SystemClock; 32import android.test.InstrumentationTestCase; 33import android.util.Log; 34import android.view.KeyEvent; 35 36import java.io.IOException; 37import java.net.UnknownHostException; 38import java.util.List; 39 40 41/** 42 * Base InstrumentationTestCase for Connectivity Manager (CM) test suite 43 * 44 * It registers connectivity manager broadcast and WiFi broadcast to provide 45 * network connectivity information, also provides a set of utility functions 46 * to modify and verify connectivity states. 47 * 48 * A CM test case should extend this base class. 49 */ 50public class ConnectivityManagerTestBase extends InstrumentationTestCase { 51 52 private static final String PING_IP_ADDR = "8.8.8.8"; 53 54 protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds 55 protected static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds 56 protected static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds 57 protected static final long LONG_TIMEOUT = 2 * 60 * 1000; // 2 minutes 58 protected static final long WIFI_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes 59 // 2 minutes timer between wifi stop and start 60 protected static final long WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; // 2 minutes 61 // Set ping test timer to be 3 minutes 62 protected static final long PING_TIMER = 3 * 60 *1000; // 3 minutes 63 protected static final int SUCCESS = 0; // for Wifi tethering state change 64 protected static final int FAILURE = 1; 65 protected static final int INIT = -1; 66 67 protected final String mLogTag; 68 69 private ConnectivityReceiver mConnectivityReceiver = null; 70 private WifiReceiver mWifiReceiver = null; 71 72 private long mLastConnectivityChangeTime = -1; 73 protected ConnectivityManager mCm; 74 private Context mContext; 75 protected List<ScanResult> mLastScanResult; 76 protected Object mWifiScanResultLock = new Object(); 77 78 /* Control Wifi States */ 79 public WifiManager mWifiManager; 80 81 public ConnectivityManagerTestBase(String logTag) { 82 super(); 83 mLogTag = logTag; 84 } 85 86 protected long getLastConnectivityChangeTime() { 87 return mLastConnectivityChangeTime; 88 } 89 90 /** 91 * A wrapper of a broadcast receiver which provides network connectivity information 92 * for all kinds of network: wifi, mobile, etc. 93 */ 94 private class ConnectivityReceiver extends BroadcastReceiver { 95 @Override 96 public void onReceive(Context context, Intent intent) { 97 mLastConnectivityChangeTime = SystemClock.uptimeMillis(); 98 logv("ConnectivityReceiver: " + intent); 99 String action = intent.getAction(); 100 if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 101 Log.v("ConnectivityReceiver", "onReceive() called with " + intent); 102 } 103 } 104 } 105 106 private class WifiReceiver extends BroadcastReceiver { 107 @Override 108 public void onReceive(Context context, Intent intent) { 109 String action = intent.getAction(); 110 Log.v("WifiReceiver", "onReceive() is calleld with " + intent); 111 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 112 logv("scan results are available"); 113 synchronized (mWifiScanResultLock) { 114 mLastScanResult = mWifiManager.getScanResults(); 115 mWifiScanResultLock.notifyAll(); 116 } 117 } 118 } 119 } 120 121 @Override 122 protected void setUp() throws Exception { 123 mLastScanResult = null; 124 mContext = getInstrumentation().getContext(); 125 126 // Get an instance of ConnectivityManager 127 mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 128 // Get an instance of WifiManager 129 mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE); 130 131 if (mWifiManager.isWifiApEnabled()) { 132 // if soft AP is enabled, disable it 133 mWifiManager.setWifiApEnabled(null, false); 134 logv("Disable soft ap"); 135 } 136 137 // register a connectivity receiver for CONNECTIVITY_ACTION; 138 mConnectivityReceiver = new ConnectivityReceiver(); 139 mContext.registerReceiver(mConnectivityReceiver, 140 new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 141 142 mWifiReceiver = new WifiReceiver(); 143 IntentFilter mIntentFilter = new IntentFilter(); 144 mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 145 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 146 mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 147 mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 148 mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 149 mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); 150 mContext.registerReceiver(mWifiReceiver, mIntentFilter); 151 152 logv("Clear Wifi before we start the test."); 153 removeConfiguredNetworksAndDisableWifi(); 154 } 155 156 // wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, 157 // DISCONNECTED, UNKNOWN 158 protected boolean waitForNetworkState(int networkType, State expectedState, long timeout) { 159 long startTime = SystemClock.uptimeMillis(); 160 while (true) { 161 NetworkInfo ni = mCm.getNetworkInfo(networkType); 162 if (ni != null && expectedState.equals(ni.getState())) { 163 logv("waitForNetworkState success: %s", ni); 164 return true; 165 } 166 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 167 logv("waitForNetworkState timeout: %s", ni); 168 return false; 169 } 170 logv("waitForNetworkState interim: %s", ni); 171 SystemClock.sleep(SHORT_TIMEOUT); 172 } 173 } 174 175 // wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED, 176 // WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN 177 protected boolean waitForWifiState(int expectedState, long timeout) { 178 long startTime = SystemClock.uptimeMillis(); 179 while (true) { 180 int state = mWifiManager.getWifiState(); 181 if (state == expectedState) { 182 logv("waitForWifiState success: state=" + state); 183 return true; 184 } 185 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 186 logv("waitForWifiState timeout: expected=%d, actual=%d", expectedState, state); 187 return false; 188 } 189 logv("waitForWifiState interim: expected=%d, actual=%d", expectedState, state); 190 SystemClock.sleep(SHORT_TIMEOUT); 191 } 192 } 193 194 // Wait for Wifi AP state: WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, 195 // WIFI_AP_STATE_ENABLED, WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN 196 protected boolean waitForWifiApState(int expectedState, long timeout) { 197 long startTime = SystemClock.uptimeMillis(); 198 while (true) { 199 int state = mWifiManager.getWifiApState(); 200 if (state == expectedState) { 201 logv("waitForWifiAPState success: state=" + state); 202 return true; 203 } 204 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 205 logv(String.format("waitForWifiAPState timeout: expected=%d, actual=%d", 206 expectedState, state)); 207 return false; 208 } 209 logv(String.format("waitForWifiAPState interim: expected=%d, actual=%d", 210 expectedState, state)); 211 SystemClock.sleep(SHORT_TIMEOUT); 212 } 213 } 214 215 /** 216 * Wait for the wifi tethering result: 217 * @param timeout is the maximum waiting time 218 * @return SUCCESS if tethering result is successful 219 * FAILURE if tethering result returns error. 220 */ 221 protected boolean waitForTetherStateChange(long timeout) { 222 long startTime = SystemClock.uptimeMillis(); 223 String[] wifiRegexes = mCm.getTetherableWifiRegexs(); 224 while (true) { 225 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 226 return false; 227 } 228 String[] active = mCm.getTetheredIfaces(); 229 String[] error = mCm.getTetheringErroredIfaces(); 230 for (String iface: active) { 231 for (String regex: wifiRegexes) { 232 if (iface.matches(regex)) { 233 return true; 234 } 235 } 236 } 237 for (String iface: error) { 238 for (String regex: wifiRegexes) { 239 if (iface.matches(regex)) { 240 return false; 241 } 242 } 243 } 244 SystemClock.sleep(SHORT_TIMEOUT); 245 } 246 } 247 248 // Return true if device is currently connected to mobile network 249 protected boolean isConnectedToMobile() { 250 return (mCm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_MOBILE); 251 } 252 253 // Return true if device is currently connected to Wifi 254 protected boolean isConnectedToWifi() { 255 return (mCm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI); 256 } 257 258 protected boolean enableWifi() { 259 return mWifiManager.setWifiEnabled(true); 260 } 261 262 // Turn screen off 263 protected void turnScreenOff() { 264 logv("Turn screen off"); 265 PowerManager pm = 266 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 267 pm.goToSleep(SystemClock.uptimeMillis()); 268 } 269 270 // Turn screen on 271 protected void turnScreenOn() { 272 logv("Turn screen on"); 273 PowerManager pm = 274 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 275 pm.wakeUp(SystemClock.uptimeMillis()); 276 // disable lock screen 277 KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 278 if (km.inKeyguardRestrictedInputMode()) { 279 sendKeys(KeyEvent.KEYCODE_MENU); 280 } 281 } 282 283 /** 284 * @param pingServerList a list of servers that can be used for ping test, can be null 285 * @return true if the ping test is successful, false otherwise. 286 */ 287 protected boolean pingTest(String[] pingServerList) { 288 String[] hostList = {"www.google.com", "www.yahoo.com", 289 "www.bing.com", "www.facebook.com", "www.ask.com"}; 290 if (pingServerList != null) { 291 hostList = pingServerList; 292 } 293 294 long startTime = System.currentTimeMillis(); 295 while ((System.currentTimeMillis() - startTime) < PING_TIMER) { 296 try { 297 // assume the chance that all servers are down is very small 298 for (int i = 0; i < hostList.length; i++ ) { 299 String host = hostList[i]; 300 logv("Start ping test, ping " + host); 301 Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host); 302 int status = p.waitFor(); 303 if (status == 0) { 304 // if any of the ping test is successful, return true 305 return true; 306 } 307 } 308 } catch (UnknownHostException e) { 309 logv("Ping test Fail: Unknown Host"); 310 } catch (IOException e) { 311 logv("Ping test Fail: IOException"); 312 } catch (InterruptedException e) { 313 logv("Ping test Fail: InterruptedException"); 314 } 315 } 316 // ping test timeout 317 return false; 318 } 319 320 /** 321 * Associate the device to given SSID 322 * If the device is already associated with a WiFi, disconnect and forget it, 323 * We don't verify whether the connection is successful or not, leave this to the test 324 */ 325 protected boolean connectToWifi(String ssid, String password) { 326 WifiConfiguration config; 327 if (password == null) { 328 config = WifiConfigurationHelper.createOpenConfig(ssid); 329 } else { 330 config = WifiConfigurationHelper.createPskConfig(ssid, password); 331 } 332 return connectToWifiWithConfiguration(config); 333 } 334 335 /** 336 * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration 337 * is pure string, we need to convert it to quoted string. 338 */ 339 protected boolean connectToWifiWithConfiguration(WifiConfiguration config) { 340 // If Wifi is not enabled, enable it 341 if (!mWifiManager.isWifiEnabled()) { 342 logv("Wifi is not enabled, enable it"); 343 mWifiManager.setWifiEnabled(true); 344 // wait for the wifi state change before start scanning. 345 if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT)) { 346 logv("wait for WIFI_STATE_ENABLED failed"); 347 return false; 348 } 349 } 350 351 // Save network configuration and connect to network without scanning 352 mWifiManager.connect(config, 353 new WifiManager.ActionListener() { 354 @Override 355 public void onSuccess() { 356 } 357 358 @Override 359 public void onFailure(int reason) { 360 logv("connect failure " + reason); 361 } 362 }); 363 return true; 364 } 365 366 /* 367 * Disconnect from the current AP and remove configured networks. 368 */ 369 protected boolean disconnectAP() { 370 // remove saved networks 371 if (!mWifiManager.isWifiEnabled()) { 372 logv("Enabled wifi before remove configured networks"); 373 mWifiManager.setWifiEnabled(true); 374 SystemClock.sleep(SHORT_TIMEOUT); 375 } 376 377 List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks(); 378 if (wifiConfigList == null) { 379 logv("no configuration list is null"); 380 return true; 381 } 382 logv("size of wifiConfigList: " + wifiConfigList.size()); 383 for (WifiConfiguration wifiConfig: wifiConfigList) { 384 logv("remove wifi configuration: " + wifiConfig.networkId); 385 int netId = wifiConfig.networkId; 386 mWifiManager.forget(netId, new WifiManager.ActionListener() { 387 @Override 388 public void onSuccess() { 389 } 390 391 @Override 392 public void onFailure(int reason) { 393 logv("Failed to forget " + reason); 394 } 395 }); 396 } 397 return true; 398 } 399 /** 400 * Disable Wifi 401 * @return true if Wifi is disabled successfully 402 */ 403 protected boolean disableWifi() { 404 return mWifiManager.setWifiEnabled(false); 405 } 406 407 /** 408 * Remove configured networks and disable wifi 409 */ 410 protected boolean removeConfiguredNetworksAndDisableWifi() { 411 if (!disconnectAP()) { 412 return false; 413 } 414 SystemClock.sleep(SHORT_TIMEOUT); 415 if (!mWifiManager.setWifiEnabled(false)) { 416 return false; 417 } 418 SystemClock.sleep(SHORT_TIMEOUT); 419 return true; 420 } 421 422 protected static String convertToQuotedString(String string) { 423 return "\"" + string + "\""; 424 } 425 426 protected boolean waitForActiveNetworkConnection(long timeout) { 427 long startTime = SystemClock.uptimeMillis(); 428 while (true) { 429 NetworkInfo ni = mCm.getActiveNetworkInfo(); 430 if (ni != null && ni.isConnected()) { 431 return true; 432 } 433 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 434 logv("waitForActiveNetworkConnection timeout: %s", ni); 435 return false; 436 } 437 logv("waitForActiveNetworkConnection interim: %s", ni); 438 SystemClock.sleep(SHORT_TIMEOUT); 439 } 440 } 441 442 protected boolean waitUntilNoActiveNetworkConnection(long timeout) { 443 long startTime = SystemClock.uptimeMillis(); 444 while (true) { 445 NetworkInfo ni = mCm.getActiveNetworkInfo(); 446 if (ni == null) { 447 return true; 448 } 449 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 450 logv("waitForActiveNetworkConnection timeout: %s", ni); 451 return false; 452 } 453 logv("waitForActiveNetworkConnection interim: %s", ni); 454 SystemClock.sleep(SHORT_TIMEOUT); 455 } 456 } 457 458 // use ping request against Google public DNS to verify connectivity 459 protected boolean checkNetworkConnectivity() { 460 assertTrue("no active network connection", waitForActiveNetworkConnection(LONG_TIMEOUT)); 461 try { 462 Process proc = Runtime.getRuntime().exec(new String[]{ 463 "/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR}); 464 return proc.waitFor() == 0; 465 } catch (InterruptedException | IOException e) { 466 Log.e(mLogTag, "Ping failed", e); 467 } 468 return false; 469 } 470 471 @Override 472 protected void tearDown() throws Exception{ 473 //Unregister receiver 474 if (mConnectivityReceiver != null) { 475 mContext.unregisterReceiver(mConnectivityReceiver); 476 } 477 if (mWifiReceiver != null) { 478 mContext.unregisterReceiver(mWifiReceiver); 479 } 480 super.tearDown(); 481 } 482 483 protected void logv(String format, Object... args) { 484 Log.v(mLogTag, String.format(format, args)); 485 } 486 487 /** 488 * Connect to the provided Wi-Fi network 489 * @param config is the network configuration 490 * @throws AssertionError if fails to associate and connect to wifi ap 491 */ 492 protected void connectToWifi(WifiConfiguration config) { 493 // step 1: connect to the test access point 494 assertTrue("failed to associate with " + config.SSID, 495 connectToWifiWithConfiguration(config)); 496 497 // step 2: verify Wifi state and network state; 498 assertTrue("wifi state not connected with " + config.SSID, 499 waitForNetworkState(ConnectivityManager.TYPE_WIFI, 500 State.CONNECTED, WIFI_CONNECTION_TIMEOUT)); 501 502 // step 3: verify the current connected network is the given SSID 503 assertNotNull("no active wifi info", mWifiManager.getConnectionInfo()); 504 assertEquals("SSID mismatch", config.SSID, mWifiManager.getConnectionInfo().getSSID()); 505 } 506} 507