1 /* 2 * Copyright (C) 2009 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 android.net.cts; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 21 22 import android.app.PendingIntent; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.PackageManager; 29 import android.net.ConnectivityManager; 30 import android.net.ConnectivityManager.NetworkCallback; 31 import android.net.Network; 32 import android.net.NetworkCapabilities; 33 import android.net.NetworkConfig; 34 import android.net.NetworkInfo; 35 import android.net.NetworkInfo.DetailedState; 36 import android.net.NetworkInfo.State; 37 import android.net.NetworkRequest; 38 import android.net.wifi.WifiManager; 39 import android.os.SystemProperties; 40 import android.system.Os; 41 import android.system.OsConstants; 42 import android.test.AndroidTestCase; 43 import android.util.Log; 44 45 import com.android.internal.telephony.PhoneConstants; 46 47 import java.io.InputStream; 48 import java.io.IOException; 49 import java.io.OutputStream; 50 import java.net.Socket; 51 import java.net.InetSocketAddress; 52 import java.util.HashMap; 53 import java.util.concurrent.CountDownLatch; 54 import java.util.concurrent.LinkedBlockingQueue; 55 import java.util.concurrent.TimeUnit; 56 57 public class ConnectivityManagerTest extends AndroidTestCase { 58 59 private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); 60 61 private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI"; 62 63 public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; 64 public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; 65 66 private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 67 private static final String TEST_HOST = "connectivitycheck.gstatic.com"; 68 private static final int SOCKET_TIMEOUT_MS = 2000; 69 private static final int SEND_BROADCAST_TIMEOUT = 30000; 70 private static final int HTTP_PORT = 80; 71 private static final String HTTP_REQUEST = 72 "GET /generate_204 HTTP/1.0\r\n" + 73 "Host: " + TEST_HOST + "\r\n" + 74 "Connection: keep-alive\r\n\r\n"; 75 76 // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. 77 private static final String NETWORK_CALLBACK_ACTION = 78 "ConnectivityManagerTest.NetworkCallbackAction"; 79 80 // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen 81 public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT = 82 "android.net.cts.appForApi23.getWifiConnectivityActionCount"; 83 84 // device could have only one interface: data, wifi. 85 private static final int MIN_NUM_NETWORK_TYPES = 1; 86 87 private Context mContext; 88 private ConnectivityManager mCm; 89 private WifiManager mWifiManager; 90 private PackageManager mPackageManager; 91 private final HashMap<Integer, NetworkConfig> mNetworks = 92 new HashMap<Integer, NetworkConfig>(); 93 94 @Override setUp()95 protected void setUp() throws Exception { 96 super.setUp(); 97 mContext = getContext(); 98 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 99 mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 100 mPackageManager = mContext.getPackageManager(); 101 102 // Get com.android.internal.R.array.networkAttributes 103 int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android"); 104 String[] naStrings = mContext.getResources().getStringArray(resId); 105 //TODO: What is the "correct" way to determine if this is a wifi only device? 106 boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); 107 for (String naString : naStrings) { 108 try { 109 NetworkConfig n = new NetworkConfig(naString); 110 if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) { 111 continue; 112 } 113 mNetworks.put(n.type, n); 114 } catch (Exception e) {} 115 } 116 } 117 testIsNetworkTypeValid()118 public void testIsNetworkTypeValid() { 119 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); 120 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); 121 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS)); 122 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL)); 123 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN)); 124 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI)); 125 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX)); 126 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH)); 127 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY)); 128 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET)); 129 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA)); 130 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS)); 131 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS)); 132 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P)); 133 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA)); 134 assertFalse(mCm.isNetworkTypeValid(-1)); 135 assertTrue(mCm.isNetworkTypeValid(0)); 136 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE)); 137 assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1)); 138 139 NetworkInfo[] ni = mCm.getAllNetworkInfo(); 140 141 for (NetworkInfo n: ni) { 142 assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType())); 143 } 144 145 } 146 testSetNetworkPreference()147 public void testSetNetworkPreference() { 148 // getNetworkPreference() and setNetworkPreference() are both deprecated so they do 149 // not preform any action. Verify they are at least still callable. 150 mCm.setNetworkPreference(mCm.getNetworkPreference()); 151 } 152 testGetActiveNetworkInfo()153 public void testGetActiveNetworkInfo() { 154 NetworkInfo ni = mCm.getActiveNetworkInfo(); 155 156 assertNotNull("You must have an active network connection to complete CTS", ni); 157 assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); 158 assertTrue(ni.getState() == State.CONNECTED); 159 } 160 testGetActiveNetwork()161 public void testGetActiveNetwork() { 162 Network network = mCm.getActiveNetwork(); 163 assertNotNull("You must have an active network connection to complete CTS", network); 164 165 NetworkInfo ni = mCm.getNetworkInfo(network); 166 assertNotNull("Network returned from getActiveNetwork was invalid", ni); 167 168 // Similar to testGetActiveNetworkInfo above. 169 assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); 170 assertTrue(ni.getState() == State.CONNECTED); 171 } 172 testGetNetworkInfo()173 public void testGetNetworkInfo() { 174 for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { 175 if (isSupported(type)) { 176 NetworkInfo ni = mCm.getNetworkInfo(type); 177 assertTrue("Info shouldn't be null for " + type, ni != null); 178 State state = ni.getState(); 179 assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal() 180 && state.ordinal() >= State.CONNECTING.ordinal()); 181 DetailedState ds = ni.getDetailedState(); 182 assertTrue("Bad detailed state for " + type, 183 DetailedState.FAILED.ordinal() >= ds.ordinal() 184 && ds.ordinal() >= DetailedState.IDLE.ordinal()); 185 } else { 186 assertNull("Info should be null for " + type, mCm.getNetworkInfo(type)); 187 } 188 } 189 } 190 testGetAllNetworkInfo()191 public void testGetAllNetworkInfo() { 192 NetworkInfo[] ni = mCm.getAllNetworkInfo(); 193 assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); 194 for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 195 int desiredFoundCount = (isSupported(type) ? 1 : 0); 196 int foundCount = 0; 197 for (NetworkInfo i : ni) { 198 if (i.getType() == type) foundCount++; 199 } 200 if (foundCount != desiredFoundCount) { 201 Log.e(TAG, "failure in testGetAllNetworkInfo. Dump of returned NetworkInfos:"); 202 for (NetworkInfo networkInfo : ni) Log.e(TAG, " " + networkInfo); 203 } 204 assertTrue("Unexpected foundCount of " + foundCount + " for type " + type, 205 foundCount == desiredFoundCount); 206 } 207 } 208 assertStartUsingNetworkFeatureUnsupported(int networkType, String feature)209 private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) { 210 try { 211 mCm.startUsingNetworkFeature(networkType, feature); 212 fail("startUsingNetworkFeature is no longer supported in the current API version"); 213 } catch (UnsupportedOperationException expected) {} 214 } 215 assertStopUsingNetworkFeatureUnsupported(int networkType, String feature)216 private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) { 217 try { 218 mCm.startUsingNetworkFeature(networkType, feature); 219 fail("stopUsingNetworkFeature is no longer supported in the current API version"); 220 } catch (UnsupportedOperationException expected) {} 221 } 222 assertRequestRouteToHostUnsupported(int networkType, int hostAddress)223 private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) { 224 try { 225 mCm.requestRouteToHost(networkType, hostAddress); 226 fail("requestRouteToHost is no longer supported in the current API version"); 227 } catch (UnsupportedOperationException expected) {} 228 } 229 testStartUsingNetworkFeature()230 public void testStartUsingNetworkFeature() { 231 232 final String invalidateFeature = "invalidateFeature"; 233 final String mmsFeature = "enableMMS"; 234 final int failureCode = -1; 235 final int wifiOnlyStartFailureCode = PhoneConstants.APN_REQUEST_FAILED; 236 final int wifiOnlyStopFailureCode = -1; 237 238 assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); 239 assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); 240 assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature); 241 } 242 isSupported(int networkType)243 private boolean isSupported(int networkType) { 244 // Change-Id I02eb5f22737720095f646f8db5c87fd66da129d6 added VPN support 245 // to all devices directly in software, independent of any external 246 // configuration. 247 return mNetworks.containsKey(networkType) || 248 (networkType == ConnectivityManager.TYPE_VPN); 249 } 250 testIsNetworkSupported()251 public void testIsNetworkSupported() { 252 for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 253 boolean supported = mCm.isNetworkSupported(type); 254 if (isSupported(type)) { 255 assertTrue(supported); 256 } else { 257 assertFalse(supported); 258 } 259 } 260 } 261 testRequestRouteToHost()262 public void testRequestRouteToHost() { 263 for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 264 assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); 265 } 266 } 267 testTest()268 public void testTest() { 269 mCm.getBackgroundDataSetting(); 270 } 271 makeWifiNetworkRequest()272 private NetworkRequest makeWifiNetworkRequest() { 273 return new NetworkRequest.Builder() 274 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 275 .build(); 276 } 277 278 /** 279 * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to 280 * see if we get a callback for the TRANSPORT_WIFI transport type being available. 281 * 282 * <p>In order to test that a NetworkCallback occurs, we need some change in the network 283 * state (either a transport or capability is now available). The most straightforward is 284 * WiFi. We could add a version that uses the telephony data connection but it's not clear 285 * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). 286 */ testRegisterNetworkCallback()287 public void testRegisterNetworkCallback() { 288 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { 289 Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); 290 return; 291 } 292 293 // We will register for a WIFI network being available or lost. 294 final TestNetworkCallback callback = new TestNetworkCallback(); 295 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 296 297 final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback(); 298 mCm.registerDefaultNetworkCallback(defaultTrackingCallback); 299 300 final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); 301 Network wifiNetwork = null; 302 303 try { 304 // Make sure WiFi is connected to an access point to start with. 305 if (!previousWifiEnabledState) { 306 connectToWifi(); 307 } 308 309 // Now we should expect to get a network callback about availability of the wifi 310 // network even if it was already connected as a state-based action when the callback 311 // is registered. 312 wifiNetwork = callback.waitForAvailable(); 313 assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI", 314 wifiNetwork); 315 316 assertNotNull("Did not receive NetworkCallback.onAvailable for any default network", 317 defaultTrackingCallback.waitForAvailable()); 318 } catch (InterruptedException e) { 319 fail("Broadcast receiver or NetworkCallback wait was interrupted."); 320 } finally { 321 mCm.unregisterNetworkCallback(callback); 322 mCm.unregisterNetworkCallback(defaultTrackingCallback); 323 324 // Return WiFi to its original enabled/disabled state. 325 if (!previousWifiEnabledState) { 326 disconnectFromWifi(wifiNetwork); 327 } 328 } 329 } 330 331 /** 332 * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to 333 * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead 334 * of a {@code NetworkCallback}. 335 */ testRegisterNetworkCallback_withPendingIntent()336 public void testRegisterNetworkCallback_withPendingIntent() { 337 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) { 338 Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); 339 return; 340 } 341 342 // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined 343 // action, NETWORK_CALLBACK_ACTION. 344 IntentFilter filter = new IntentFilter(); 345 filter.addAction(NETWORK_CALLBACK_ACTION); 346 347 ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( 348 ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); 349 mContext.registerReceiver(receiver, filter); 350 351 // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. 352 Intent intent = new Intent(NETWORK_CALLBACK_ACTION); 353 PendingIntent pendingIntent = PendingIntent.getBroadcast( 354 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); 355 356 // We will register for a WIFI network being available or lost. 357 mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent); 358 359 final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); 360 361 try { 362 // Make sure WiFi is connected to an access point to start with. 363 if (!previousWifiEnabledState) { 364 connectToWifi(); 365 } 366 367 // Now we expect to get the Intent delivered notifying of the availability of the wifi 368 // network even if it was already connected as a state-based action when the callback 369 // is registered. 370 assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI", 371 receiver.waitForState()); 372 } catch (InterruptedException e) { 373 fail("Broadcast receiver or NetworkCallback wait was interrupted."); 374 } finally { 375 mCm.unregisterNetworkCallback(pendingIntent); 376 pendingIntent.cancel(); 377 mContext.unregisterReceiver(receiver); 378 379 // Return WiFi to its original enabled/disabled state. 380 if (!previousWifiEnabledState) { 381 disconnectFromWifi(null); 382 } 383 } 384 } 385 386 /** 387 * Tests reporting of connectivity changed. 388 */ testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent()389 public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() { 390 ConnectivityReceiver.prepare(); 391 392 toggleWifi(); 393 394 // The connectivity broadcast has been sent; push through a terminal broadcast 395 // to wait for in the receive to confirm it didn't see the connectivity change. 396 Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); 397 finalIntent.setClass(mContext, ConnectivityReceiver.class); 398 mContext.sendBroadcast(finalIntent); 399 assertFalse(ConnectivityReceiver.waitForBroadcast()); 400 } 401 testConnectivityChanged_whenRegistered_shouldReceiveIntent()402 public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() { 403 ConnectivityReceiver.prepare(); 404 ConnectivityReceiver receiver = new ConnectivityReceiver(); 405 IntentFilter filter = new IntentFilter(); 406 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 407 mContext.registerReceiver(receiver, filter); 408 409 toggleWifi(); 410 Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); 411 finalIntent.setClass(mContext, ConnectivityReceiver.class); 412 mContext.sendBroadcast(finalIntent); 413 414 assertTrue(ConnectivityReceiver.waitForBroadcast()); 415 } 416 testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()417 public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent() 418 throws InterruptedException { 419 Intent startIntent = new Intent(); 420 startIntent.setComponent(new ComponentName("android.net.cts.appForApi23", 421 "android.net.cts.appForApi23.ConnectivityListeningActivity")); 422 mContext.startActivity(startIntent); 423 424 toggleWifi(); 425 426 Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT); 427 assertEquals(2, sendOrderedBroadcastAndReturnResultCode( 428 getConnectivityCount, SEND_BROADCAST_TIMEOUT)); 429 } 430 sendOrderedBroadcastAndReturnResultCode( Intent intent, int timeoutMs)431 private int sendOrderedBroadcastAndReturnResultCode( 432 Intent intent, int timeoutMs) throws InterruptedException { 433 final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>(1); 434 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { 435 @Override 436 public void onReceive(Context context, Intent intent) { 437 result.offer(getResultCode()); 438 } 439 }, null, 0, null, null); 440 441 Integer resultCode = result.poll(timeoutMs, TimeUnit.MILLISECONDS); 442 assertNotNull("Timed out (more than " + timeoutMs + 443 " milliseconds) waiting for result code for broadcast", resultCode); 444 return resultCode; 445 } 446 447 // Toggle WiFi twice, leaving it in the state it started in toggleWifi()448 private void toggleWifi() { 449 if (mWifiManager.isWifiEnabled()) { 450 Network wifiNetwork = getWifiNetwork(); 451 disconnectFromWifi(wifiNetwork); 452 connectToWifi(); 453 } else { 454 connectToWifi(); 455 Network wifiNetwork = getWifiNetwork(); 456 disconnectFromWifi(wifiNetwork); 457 } 458 } 459 460 /** Enable WiFi and wait for it to become connected to a network. */ connectToWifi()461 private Network connectToWifi() { 462 final TestNetworkCallback callback = new TestNetworkCallback(); 463 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 464 Network wifiNetwork = null; 465 466 ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( 467 ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); 468 IntentFilter filter = new IntentFilter(); 469 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 470 mContext.registerReceiver(receiver, filter); 471 472 boolean connected = false; 473 try { 474 assertTrue(mWifiManager.setWifiEnabled(true)); 475 // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. 476 wifiNetwork = callback.waitForAvailable(); 477 assertNotNull(wifiNetwork); 478 connected = receiver.waitForState(); 479 } catch (InterruptedException ex) { 480 fail("connectToWifi was interrupted"); 481 } finally { 482 mCm.unregisterNetworkCallback(callback); 483 mContext.unregisterReceiver(receiver); 484 } 485 486 assertTrue("Wifi must be configured to connect to an access point for this test.", 487 connected); 488 return wifiNetwork; 489 } 490 getBoundSocket(Network network, String host, int port)491 private Socket getBoundSocket(Network network, String host, int port) throws IOException { 492 InetSocketAddress addr = new InetSocketAddress(host, port); 493 Socket s = network.getSocketFactory().createSocket(); 494 try { 495 s.setSoTimeout(SOCKET_TIMEOUT_MS); 496 s.connect(addr, SOCKET_TIMEOUT_MS); 497 } catch (IOException e) { 498 s.close(); 499 throw e; 500 } 501 return s; 502 } 503 testHttpRequest(Socket s)504 private void testHttpRequest(Socket s) throws IOException { 505 OutputStream out = s.getOutputStream(); 506 InputStream in = s.getInputStream(); 507 508 final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); 509 byte[] responseBytes = new byte[4096]; 510 out.write(requestBytes); 511 in.read(responseBytes); 512 assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); 513 } 514 515 /** Disable WiFi and wait for it to become disconnected from the network. */ disconnectFromWifi(Network wifiNetworkToCheck)516 private void disconnectFromWifi(Network wifiNetworkToCheck) { 517 final TestNetworkCallback callback = new TestNetworkCallback(); 518 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 519 Network lostWifiNetwork = null; 520 521 ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( 522 ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); 523 IntentFilter filter = new IntentFilter(); 524 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 525 mContext.registerReceiver(receiver, filter); 526 527 // Assert that we can establish a TCP connection on wifi. 528 Socket wifiBoundSocket = null; 529 if (wifiNetworkToCheck != null) { 530 try { 531 wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); 532 testHttpRequest(wifiBoundSocket); 533 } catch (IOException e) { 534 fail("HTTP request before wifi disconnected failed with: " + e); 535 } 536 } 537 538 boolean disconnected = false; 539 try { 540 assertTrue(mWifiManager.setWifiEnabled(false)); 541 // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. 542 lostWifiNetwork = callback.waitForLost(); 543 assertNotNull(lostWifiNetwork); 544 disconnected = receiver.waitForState(); 545 } catch (InterruptedException ex) { 546 fail("disconnectFromWifi was interrupted"); 547 } finally { 548 mCm.unregisterNetworkCallback(callback); 549 mContext.unregisterReceiver(receiver); 550 } 551 552 assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); 553 554 // Check that the socket is closed when wifi disconnects. 555 if (wifiBoundSocket != null) { 556 try { 557 testHttpRequest(wifiBoundSocket); 558 fail("HTTP request should not succeed after wifi disconnects"); 559 } catch (IOException expected) { 560 assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); 561 } 562 } 563 } 564 565 /** 566 * Receiver that captures the last connectivity change's network type and state. Recognizes 567 * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. 568 */ 569 private class ConnectivityActionReceiver extends BroadcastReceiver { 570 571 private final CountDownLatch mReceiveLatch = new CountDownLatch(1); 572 573 private final int mNetworkType; 574 private final NetworkInfo.State mNetState; 575 ConnectivityActionReceiver(int networkType, NetworkInfo.State netState)576 ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { 577 mNetworkType = networkType; 578 mNetState = netState; 579 } 580 onReceive(Context context, Intent intent)581 public void onReceive(Context context, Intent intent) { 582 String action = intent.getAction(); 583 NetworkInfo networkInfo = null; 584 585 // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable 586 // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is 587 // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. 588 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { 589 networkInfo = intent.getExtras() 590 .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); 591 assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); 592 } else if (NETWORK_CALLBACK_ACTION.equals(action)) { 593 Network network = intent.getExtras() 594 .getParcelable(ConnectivityManager.EXTRA_NETWORK); 595 assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); 596 networkInfo = mCm.getNetworkInfo(network); 597 if (networkInfo == null) { 598 // When disconnecting, it seems like we get an intent sent with an invalid 599 // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), 600 // it is invalid. Ignore these. 601 Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " 602 + "invalid network"); 603 return; 604 } 605 } else { 606 fail("ConnectivityActionReceiver received unxpected intent action: " + action); 607 } 608 609 assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); 610 int networkType = networkInfo.getType(); 611 State networkState = networkInfo.getState(); 612 Log.i(TAG, "Network type: " + networkType + " state: " + networkState); 613 if (networkType == mNetworkType && networkInfo.getState() == mNetState) { 614 mReceiveLatch.countDown(); 615 } 616 } 617 waitForState()618 public boolean waitForState() throws InterruptedException { 619 return mReceiveLatch.await(30, TimeUnit.SECONDS); 620 } 621 } 622 623 /** 624 * Callback used in testRegisterNetworkCallback that allows caller to block on 625 * {@code onAvailable}. 626 */ 627 private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { 628 private final CountDownLatch mAvailableLatch = new CountDownLatch(1); 629 private final CountDownLatch mLostLatch = new CountDownLatch(1); 630 631 public Network currentNetwork; 632 public Network lastLostNetwork; 633 waitForAvailable()634 public Network waitForAvailable() throws InterruptedException { 635 return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; 636 } 637 waitForLost()638 public Network waitForLost() throws InterruptedException { 639 return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; 640 } 641 642 @Override onAvailable(Network network)643 public void onAvailable(Network network) { 644 currentNetwork = network; 645 mAvailableLatch.countDown(); 646 } 647 648 @Override onLost(Network network)649 public void onLost(Network network) { 650 lastLostNetwork = network; 651 if (network.equals(currentNetwork)) { 652 currentNetwork = null; 653 } 654 mLostLatch.countDown(); 655 } 656 } 657 getWifiNetwork()658 private Network getWifiNetwork() { 659 TestNetworkCallback callback = new TestNetworkCallback(); 660 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 661 Network network = null; 662 try { 663 network = callback.waitForAvailable(); 664 } catch (InterruptedException e) { 665 fail("NetworkCallback wait was interrupted."); 666 } finally { 667 mCm.unregisterNetworkCallback(callback); 668 } 669 assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); 670 return network; 671 } 672 673 /** Verify restricted networks cannot be requested. */ testRestrictedNetworks()674 public void testRestrictedNetworks() { 675 // Verify we can request unrestricted networks: 676 NetworkRequest request = new NetworkRequest.Builder() 677 .addCapability(NET_CAPABILITY_INTERNET).build(); 678 NetworkCallback callback = new NetworkCallback(); 679 mCm.requestNetwork(request, callback); 680 mCm.unregisterNetworkCallback(callback); 681 // Verify we cannot request restricted networks: 682 request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build(); 683 callback = new NetworkCallback(); 684 try { 685 mCm.requestNetwork(request, callback); 686 fail("No exception thrown when restricted network requested."); 687 } catch (SecurityException expected) {} 688 } 689 } 690