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.Manifest.permission.CONNECTIVITY_INTERNAL; 20 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; 21 import static android.Manifest.permission.NETWORK_SETTINGS; 22 import static android.Manifest.permission.READ_DEVICE_CONFIG; 23 import static android.content.pm.PackageManager.FEATURE_BLUETOOTH; 24 import static android.content.pm.PackageManager.FEATURE_ETHERNET; 25 import static android.content.pm.PackageManager.FEATURE_TELEPHONY; 26 import static android.content.pm.PackageManager.FEATURE_USB_HOST; 27 import static android.content.pm.PackageManager.FEATURE_WATCH; 28 import static android.content.pm.PackageManager.FEATURE_WIFI; 29 import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT; 30 import static android.content.pm.PackageManager.GET_PERMISSIONS; 31 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 32 import static android.net.ConnectivityManager.EXTRA_NETWORK; 33 import static android.net.ConnectivityManager.EXTRA_NETWORK_REQUEST; 34 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; 35 import static android.net.ConnectivityManager.TYPE_BLUETOOTH; 36 import static android.net.ConnectivityManager.TYPE_ETHERNET; 37 import static android.net.ConnectivityManager.TYPE_MOBILE_CBS; 38 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; 39 import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY; 40 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; 41 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; 42 import static android.net.ConnectivityManager.TYPE_MOBILE_IA; 43 import static android.net.ConnectivityManager.TYPE_MOBILE_IMS; 44 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; 45 import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; 46 import static android.net.ConnectivityManager.TYPE_PROXY; 47 import static android.net.ConnectivityManager.TYPE_VPN; 48 import static android.net.ConnectivityManager.TYPE_WIFI_P2P; 49 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; 50 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; 51 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 52 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; 53 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 54 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; 55 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 56 import static android.net.NetworkCapabilities.TRANSPORT_TEST; 57 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 58 import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; 59 import static android.net.cts.util.CtsNetUtils.HTTP_PORT; 60 import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION; 61 import static android.net.cts.util.CtsNetUtils.TEST_HOST; 62 import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; 63 import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; 64 import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL; 65 import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL; 66 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; 67 import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; 68 import static android.system.OsConstants.AF_INET; 69 import static android.system.OsConstants.AF_INET6; 70 import static android.system.OsConstants.AF_UNSPEC; 71 72 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; 73 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 74 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 75 import static com.android.modules.utils.build.SdkLevel.isAtLeastS; 76 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN; 77 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE; 78 import static com.android.testutils.MiscAsserts.assertThrows; 79 import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork; 80 import static com.android.testutils.TestPermissionUtil.runAsShell; 81 82 import static org.junit.Assert.assertArrayEquals; 83 import static org.junit.Assert.assertEquals; 84 import static org.junit.Assert.assertFalse; 85 import static org.junit.Assert.assertNotEquals; 86 import static org.junit.Assert.assertNotNull; 87 import static org.junit.Assert.assertNotSame; 88 import static org.junit.Assert.assertNull; 89 import static org.junit.Assert.assertTrue; 90 import static org.junit.Assert.fail; 91 import static org.junit.Assume.assumeTrue; 92 93 import android.annotation.NonNull; 94 import android.app.Instrumentation; 95 import android.app.PendingIntent; 96 import android.app.UiAutomation; 97 import android.content.BroadcastReceiver; 98 import android.content.ContentResolver; 99 import android.content.Context; 100 import android.content.Intent; 101 import android.content.IntentFilter; 102 import android.content.pm.PackageInfo; 103 import android.content.pm.PackageManager; 104 import android.content.res.Resources; 105 import android.net.ConnectivityManager; 106 import android.net.ConnectivityManager.NetworkCallback; 107 import android.net.ConnectivitySettingsManager; 108 import android.net.InetAddresses; 109 import android.net.IpSecManager; 110 import android.net.IpSecManager.UdpEncapsulationSocket; 111 import android.net.LinkAddress; 112 import android.net.LinkProperties; 113 import android.net.Network; 114 import android.net.NetworkAgent; 115 import android.net.NetworkAgentConfig; 116 import android.net.NetworkCapabilities; 117 import android.net.NetworkInfo; 118 import android.net.NetworkInfo.DetailedState; 119 import android.net.NetworkInfo.State; 120 import android.net.NetworkProvider; 121 import android.net.NetworkRequest; 122 import android.net.NetworkScore; 123 import android.net.NetworkSpecifier; 124 import android.net.NetworkStateSnapshot; 125 import android.net.NetworkUtils; 126 import android.net.OemNetworkPreferences; 127 import android.net.ProxyInfo; 128 import android.net.SocketKeepalive; 129 import android.net.TelephonyNetworkSpecifier; 130 import android.net.TestNetworkInterface; 131 import android.net.TestNetworkManager; 132 import android.net.Uri; 133 import android.net.cts.util.CtsNetUtils; 134 import android.net.cts.util.CtsTetheringUtils; 135 import android.net.util.KeepaliveUtils; 136 import android.net.wifi.WifiManager; 137 import android.os.Binder; 138 import android.os.Build; 139 import android.os.Handler; 140 import android.os.Looper; 141 import android.os.MessageQueue; 142 import android.os.Process; 143 import android.os.SystemClock; 144 import android.os.SystemProperties; 145 import android.os.UserHandle; 146 import android.os.VintfRuntimeInfo; 147 import android.platform.test.annotations.AppModeFull; 148 import android.provider.DeviceConfig; 149 import android.provider.Settings; 150 import android.telephony.SubscriptionManager; 151 import android.telephony.TelephonyManager; 152 import android.text.TextUtils; 153 import android.util.ArraySet; 154 import android.util.Log; 155 import android.util.Pair; 156 import android.util.Range; 157 158 import androidx.test.InstrumentationRegistry; 159 import androidx.test.runner.AndroidJUnit4; 160 161 import com.android.internal.util.ArrayUtils; 162 import com.android.modules.utils.build.SdkLevel; 163 import com.android.networkstack.apishim.ConnectivityManagerShimImpl; 164 import com.android.networkstack.apishim.ConstantsShim; 165 import com.android.networkstack.apishim.NetworkInformationShimImpl; 166 import com.android.networkstack.apishim.common.ConnectivityManagerShim; 167 import com.android.testutils.CompatUtil; 168 import com.android.testutils.DevSdkIgnoreRule; 169 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 170 import com.android.testutils.DevSdkIgnoreRuleKt; 171 import com.android.testutils.RecorderCallback.CallbackEntry; 172 import com.android.testutils.SkipPresubmit; 173 import com.android.testutils.TestHttpServer; 174 import com.android.testutils.TestNetworkTracker; 175 import com.android.testutils.TestableNetworkCallback; 176 177 import junit.framework.AssertionFailedError; 178 179 import libcore.io.Streams; 180 181 import org.junit.After; 182 import org.junit.Before; 183 import org.junit.Rule; 184 import org.junit.Test; 185 import org.junit.runner.RunWith; 186 187 import java.io.FileDescriptor; 188 import java.io.IOException; 189 import java.io.InputStream; 190 import java.io.InputStreamReader; 191 import java.io.OutputStream; 192 import java.net.HttpURLConnection; 193 import java.net.Inet4Address; 194 import java.net.Inet6Address; 195 import java.net.InetAddress; 196 import java.net.InetSocketAddress; 197 import java.net.MalformedURLException; 198 import java.net.Socket; 199 import java.net.URL; 200 import java.net.UnknownHostException; 201 import java.nio.charset.StandardCharsets; 202 import java.util.ArrayList; 203 import java.util.Collection; 204 import java.util.List; 205 import java.util.Objects; 206 import java.util.Set; 207 import java.util.concurrent.CompletableFuture; 208 import java.util.concurrent.CountDownLatch; 209 import java.util.concurrent.Executor; 210 import java.util.concurrent.ExecutorService; 211 import java.util.concurrent.Executors; 212 import java.util.concurrent.LinkedBlockingQueue; 213 import java.util.concurrent.TimeUnit; 214 import java.util.concurrent.TimeoutException; 215 import java.util.concurrent.atomic.AtomicInteger; 216 import java.util.function.Supplier; 217 import java.util.regex.Matcher; 218 import java.util.regex.Pattern; 219 220 import fi.iki.elonen.NanoHTTPD.Method; 221 import fi.iki.elonen.NanoHTTPD.Response.IStatus; 222 import fi.iki.elonen.NanoHTTPD.Response.Status; 223 224 @RunWith(AndroidJUnit4.class) 225 public class ConnectivityManagerTest { 226 @Rule 227 public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); 228 229 private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); 230 231 public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE; 232 public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; 233 234 private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 235 private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; 236 private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500; 237 private static final int MAX_KEEPALIVE_RETRY_COUNT = 3; 238 private static final int MIN_KEEPALIVE_INTERVAL = 10; 239 240 private static final int NETWORK_CALLBACK_TIMEOUT_MS = 30_000; 241 private static final int NO_CALLBACK_TIMEOUT_MS = 100; 242 private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; 243 private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; 244 // device could have only one interface: data, wifi. 245 private static final int MIN_NUM_NETWORK_TYPES = 1; 246 247 // Airplane Mode BroadcastReceiver Timeout 248 private static final long AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 10_000L; 249 250 // Timeout for applying uids allowed on restricted networks 251 private static final long APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS = 3_000L; 252 253 // Minimum supported keepalive counts for wifi and cellular. 254 public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1; 255 public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3; 256 257 private static final String NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME = 258 "config_networkMeteredMultipathPreference"; 259 private static final String KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME = 260 "config_allowedUnprivilegedKeepalivePerUid"; 261 private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME = 262 "config_reservedPrivilegedKeepaliveSlots"; 263 264 private static final LinkAddress TEST_LINKADDR = new LinkAddress( 265 InetAddresses.parseNumericAddress("2001:db8::8"), 64); 266 267 private static final int AIRPLANE_MODE_OFF = 0; 268 private static final int AIRPLANE_MODE_ON = 1; 269 270 private static final String TEST_HTTPS_URL_PATH = "/https_path"; 271 private static final String TEST_HTTP_URL_PATH = "/http_path"; 272 private static final String LOCALHOST_HOSTNAME = "localhost"; 273 // Re-connecting to the AP, obtaining an IP address, revalidating can take a long time 274 private static final long WIFI_CONNECT_TIMEOUT_MS = 60_000L; 275 276 private Context mContext; 277 private Instrumentation mInstrumentation; 278 private ConnectivityManager mCm; 279 private ConnectivityManagerShim mCmShim; 280 private WifiManager mWifiManager; 281 private PackageManager mPackageManager; 282 private final ArraySet<Integer> mNetworkTypes = new ArraySet<>(); 283 private UiAutomation mUiAutomation; 284 private CtsNetUtils mCtsNetUtils; 285 286 // Used for cleanup purposes. 287 private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>(); 288 289 private final TestHttpServer mHttpServer = new TestHttpServer(LOCALHOST_HOSTNAME); 290 291 @Before setUp()292 public void setUp() throws Exception { 293 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 294 mContext = mInstrumentation.getContext(); 295 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 296 mCmShim = ConnectivityManagerShimImpl.newInstance(mContext); 297 mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 298 mPackageManager = mContext.getPackageManager(); 299 mCtsNetUtils = new CtsNetUtils(mContext); 300 301 if (DevSdkIgnoreRuleKt.isDevSdkInRange(null /* minExclusive */, 302 Build.VERSION_CODES.R /* maxInclusive */)) { 303 addLegacySupportedNetworkTypes(); 304 } else { 305 addSupportedNetworkTypes(); 306 } 307 308 mUiAutomation = mInstrumentation.getUiAutomation(); 309 310 assertNotNull("CTS requires a working Internet connection", mCm.getActiveNetwork()); 311 } 312 addLegacySupportedNetworkTypes()313 private void addLegacySupportedNetworkTypes() { 314 // Network type support as expected for android R- 315 // Get com.android.internal.R.array.networkAttributes 316 int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android"); 317 String[] naStrings = mContext.getResources().getStringArray(resId); 318 boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); 319 for (String naString : naStrings) { 320 try { 321 final String[] splitConfig = naString.split(","); 322 // Format was name,type,radio,priority,restoreTime,dependencyMet 323 final int type = Integer.parseInt(splitConfig[1]); 324 if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(type)) { 325 continue; 326 } 327 mNetworkTypes.add(type); 328 } catch (Exception e) {} 329 } 330 } 331 addSupportedNetworkTypes()332 private void addSupportedNetworkTypes() { 333 final PackageManager pm = mContext.getPackageManager(); 334 if (pm.hasSystemFeature(FEATURE_WIFI)) { 335 mNetworkTypes.add(TYPE_WIFI); 336 } 337 if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) { 338 mNetworkTypes.add(TYPE_WIFI_P2P); 339 } 340 if (mContext.getSystemService(TelephonyManager.class).isDataCapable()) { 341 mNetworkTypes.add(TYPE_MOBILE); 342 mNetworkTypes.add(TYPE_MOBILE_MMS); 343 mNetworkTypes.add(TYPE_MOBILE_SUPL); 344 mNetworkTypes.add(TYPE_MOBILE_DUN); 345 mNetworkTypes.add(TYPE_MOBILE_HIPRI); 346 mNetworkTypes.add(TYPE_MOBILE_FOTA); 347 mNetworkTypes.add(TYPE_MOBILE_IMS); 348 mNetworkTypes.add(TYPE_MOBILE_CBS); 349 mNetworkTypes.add(TYPE_MOBILE_IA); 350 mNetworkTypes.add(TYPE_MOBILE_EMERGENCY); 351 } 352 if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) { 353 mNetworkTypes.add(TYPE_BLUETOOTH); 354 } 355 if (pm.hasSystemFeature(FEATURE_WATCH)) { 356 mNetworkTypes.add(TYPE_PROXY); 357 } 358 if (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) { 359 mNetworkTypes.add(TYPE_ETHERNET); 360 } 361 mNetworkTypes.add(TYPE_VPN); 362 } 363 364 @After tearDown()365 public void tearDown() throws Exception { 366 // Release any NetworkRequests filed to connect mobile data. 367 if (mCtsNetUtils.cellConnectAttempted()) { 368 mCtsNetUtils.disconnectFromCell(); 369 } 370 371 if (TestUtils.shouldTestSApis()) { 372 runWithShellPermissionIdentity( 373 () -> mCmShim.setRequireVpnForUids(false, mVpnRequiredUidRanges), 374 NETWORK_SETTINGS); 375 } 376 377 // All tests in this class require a working Internet connection as they start. Make 378 // sure there is still one as they end that's ready to use for the next test to use. 379 final TestNetworkCallback callback = new TestNetworkCallback(); 380 mCm.registerDefaultNetworkCallback(callback); 381 try { 382 assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable()); 383 } finally { 384 mCm.unregisterNetworkCallback(callback); 385 } 386 } 387 388 @Test testIsNetworkTypeValid()389 public void testIsNetworkTypeValid() { 390 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); 391 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); 392 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS)); 393 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL)); 394 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN)); 395 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI)); 396 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX)); 397 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH)); 398 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY)); 399 assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET)); 400 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA)); 401 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS)); 402 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS)); 403 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P)); 404 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA)); 405 assertFalse(mCm.isNetworkTypeValid(-1)); 406 assertTrue(mCm.isNetworkTypeValid(0)); 407 assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE)); 408 assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1)); 409 410 NetworkInfo[] ni = mCm.getAllNetworkInfo(); 411 412 for (NetworkInfo n: ni) { 413 assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType())); 414 } 415 416 } 417 418 @Test testSetNetworkPreference()419 public void testSetNetworkPreference() { 420 // getNetworkPreference() and setNetworkPreference() are both deprecated so they do 421 // not preform any action. Verify they are at least still callable. 422 mCm.setNetworkPreference(mCm.getNetworkPreference()); 423 } 424 425 @Test testGetActiveNetworkInfo()426 public void testGetActiveNetworkInfo() { 427 NetworkInfo ni = mCm.getActiveNetworkInfo(); 428 429 assertNotNull("You must have an active network connection to complete CTS", ni); 430 assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); 431 assertTrue(ni.getState() == State.CONNECTED); 432 } 433 434 @Test testGetActiveNetwork()435 public void testGetActiveNetwork() { 436 Network network = mCm.getActiveNetwork(); 437 assertNotNull("You must have an active network connection to complete CTS", network); 438 439 NetworkInfo ni = mCm.getNetworkInfo(network); 440 assertNotNull("Network returned from getActiveNetwork was invalid", ni); 441 442 // Similar to testGetActiveNetworkInfo above. 443 assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType())); 444 assertTrue(ni.getState() == State.CONNECTED); 445 } 446 447 @Test testGetNetworkInfo()448 public void testGetNetworkInfo() { 449 for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { 450 if (shouldBeSupported(type)) { 451 NetworkInfo ni = mCm.getNetworkInfo(type); 452 assertTrue("Info shouldn't be null for " + type, ni != null); 453 State state = ni.getState(); 454 assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal() 455 && state.ordinal() >= State.CONNECTING.ordinal()); 456 DetailedState ds = ni.getDetailedState(); 457 assertTrue("Bad detailed state for " + type, 458 DetailedState.FAILED.ordinal() >= ds.ordinal() 459 && ds.ordinal() >= DetailedState.IDLE.ordinal()); 460 } else { 461 assertNull("Info should be null for " + type, mCm.getNetworkInfo(type)); 462 } 463 } 464 } 465 466 @Test testGetAllNetworkInfo()467 public void testGetAllNetworkInfo() { 468 NetworkInfo[] ni = mCm.getAllNetworkInfo(); 469 assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); 470 for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 471 int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0); 472 int foundCount = 0; 473 for (NetworkInfo i : ni) { 474 if (i.getType() == type) foundCount++; 475 } 476 if (foundCount != desiredFoundCount) { 477 Log.e(TAG, "failure in testGetAllNetworkInfo. Dump of returned NetworkInfos:"); 478 for (NetworkInfo networkInfo : ni) Log.e(TAG, " " + networkInfo); 479 } 480 assertTrue("Unexpected foundCount of " + foundCount + " for type " + type, 481 foundCount == desiredFoundCount); 482 } 483 } 484 getSubscriberIdForCellNetwork(Network cellNetwork)485 private String getSubscriberIdForCellNetwork(Network cellNetwork) { 486 final NetworkCapabilities cellCaps = mCm.getNetworkCapabilities(cellNetwork); 487 final NetworkSpecifier specifier = cellCaps.getNetworkSpecifier(); 488 assertTrue(specifier instanceof TelephonyNetworkSpecifier); 489 // Get subscription from Telephony network specifier. 490 final int subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); 491 assertNotEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, subId); 492 493 // Get subscriber Id from telephony manager. 494 final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 495 return runWithShellPermissionIdentity(() -> tm.getSubscriberId(subId), 496 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 497 } 498 499 @AppModeFull(reason = "Cannot request network in instant app mode") 500 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 501 @Test testGetAllNetworkStateSnapshots()502 public void testGetAllNetworkStateSnapshots() 503 throws InterruptedException { 504 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); 505 // Make sure cell is active to retrieve IMSI for verification in later step. 506 final Network cellNetwork = mCtsNetUtils.connectToCell(); 507 final String subscriberId = getSubscriberIdForCellNetwork(cellNetwork); 508 assertFalse(TextUtils.isEmpty(subscriberId)); 509 510 // Verify the API cannot be called without proper permission. 511 assertThrows(SecurityException.class, () -> mCm.getAllNetworkStateSnapshots()); 512 513 // Get all networks, verify the result of getAllNetworkStateSnapshots matches the result 514 // got from other APIs. 515 final Network[] networks = mCm.getAllNetworks(); 516 assertGreaterOrEqual(networks.length, 1); 517 final List<NetworkStateSnapshot> snapshots = runWithShellPermissionIdentity( 518 () -> mCm.getAllNetworkStateSnapshots(), NETWORK_SETTINGS); 519 assertEquals(networks.length, snapshots.size()); 520 for (final Network network : networks) { 521 // Can't use a lambda because it will cause the test to crash on R with 522 // NoClassDefFoundError. 523 NetworkStateSnapshot snapshot = null; 524 for (NetworkStateSnapshot item : snapshots) { 525 if (item.getNetwork().equals(network)) { 526 snapshot = item; 527 break; 528 } 529 } 530 assertNotNull(snapshot); 531 final NetworkCapabilities caps = 532 Objects.requireNonNull(mCm.getNetworkCapabilities(network)); 533 // Redact specifier of the capabilities of the snapshot before comparing since 534 // the result returned from getNetworkCapabilities always get redacted. 535 final NetworkSpecifier snapshotCapSpecifier = 536 snapshot.getNetworkCapabilities().getNetworkSpecifier(); 537 final NetworkSpecifier redactedSnapshotCapSpecifier = 538 snapshotCapSpecifier == null ? null : snapshotCapSpecifier.redact(); 539 assertEquals("", caps.describeImmutableDifferences( 540 snapshot.getNetworkCapabilities() 541 .setNetworkSpecifier(redactedSnapshotCapSpecifier))); 542 assertEquals(mCm.getLinkProperties(network), snapshot.getLinkProperties()); 543 assertEquals(mCm.getNetworkInfo(network).getType(), snapshot.getLegacyType()); 544 545 if (network.equals(cellNetwork)) { 546 assertEquals(subscriberId, snapshot.getSubscriberId()); 547 } 548 } 549 } 550 551 /** 552 * Tests that connections can be opened on WiFi and cellphone networks, 553 * and that they are made from different IP addresses. 554 */ 555 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 556 @Test 557 @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks") testOpenConnection()558 public void testOpenConnection() throws Exception { 559 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 560 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); 561 562 Network wifiNetwork = mCtsNetUtils.connectToWifi(); 563 Network cellNetwork = mCtsNetUtils.connectToCell(); 564 // This server returns the requestor's IP address as the response body. 565 URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text"); 566 String wifiAddressString = httpGet(wifiNetwork, url); 567 String cellAddressString = httpGet(cellNetwork, url); 568 569 assertFalse(String.format("Same address '%s' on two different networks (%s, %s)", 570 wifiAddressString, wifiNetwork, cellNetwork), 571 wifiAddressString.equals(cellAddressString)); 572 573 // Verify that the IP addresses that the requests appeared to come from are actually on the 574 // respective networks. 575 assertOnNetwork(wifiAddressString, wifiNetwork); 576 assertOnNetwork(cellAddressString, cellNetwork); 577 578 assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork)); 579 } 580 581 /** 582 * Performs a HTTP GET to the specified URL on the specified Network, and returns 583 * the response body decoded as UTF-8. 584 */ httpGet(Network network, URL httpUrl)585 private static String httpGet(Network network, URL httpUrl) throws IOException { 586 HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl); 587 try { 588 InputStream inputStream = connection.getInputStream(); 589 return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); 590 } finally { 591 connection.disconnect(); 592 } 593 } 594 assertOnNetwork(String adressString, Network network)595 private void assertOnNetwork(String adressString, Network network) throws UnknownHostException { 596 InetAddress address = InetAddress.getByName(adressString); 597 LinkProperties linkProperties = mCm.getLinkProperties(network); 598 // To make sure that the request went out on the right network, check that 599 // the IP address seen by the server is assigned to the expected network. 600 // We can only do this for IPv6 addresses, because in IPv4 we will likely 601 // have a private IPv4 address, and that won't match what the server sees. 602 if (address instanceof Inet6Address) { 603 assertContains(linkProperties.getAddresses(), address); 604 } 605 } 606 assertContains(Collection<T> collection, T element)607 private static<T> void assertContains(Collection<T> collection, T element) { 608 assertTrue(element + " not found in " + collection, collection.contains(element)); 609 } 610 assertStartUsingNetworkFeatureUnsupported(int networkType, String feature)611 private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) { 612 try { 613 mCm.startUsingNetworkFeature(networkType, feature); 614 fail("startUsingNetworkFeature is no longer supported in the current API version"); 615 } catch (UnsupportedOperationException expected) {} 616 } 617 assertStopUsingNetworkFeatureUnsupported(int networkType, String feature)618 private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) { 619 try { 620 mCm.startUsingNetworkFeature(networkType, feature); 621 fail("stopUsingNetworkFeature is no longer supported in the current API version"); 622 } catch (UnsupportedOperationException expected) {} 623 } 624 assertRequestRouteToHostUnsupported(int networkType, int hostAddress)625 private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) { 626 try { 627 mCm.requestRouteToHost(networkType, hostAddress); 628 fail("requestRouteToHost is no longer supported in the current API version"); 629 } catch (UnsupportedOperationException expected) {} 630 } 631 632 @Test testStartUsingNetworkFeature()633 public void testStartUsingNetworkFeature() { 634 635 final String invalidateFeature = "invalidateFeature"; 636 final String mmsFeature = "enableMMS"; 637 638 assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); 639 assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature); 640 assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature); 641 } 642 shouldEthernetBeSupported()643 private boolean shouldEthernetBeSupported() { 644 // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies. 645 // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on 646 // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or 647 // if the device can be a USB host and thus can use USB Ethernet adapters. 648 // 649 // Note that this test this will still fail in instant mode if a device supports Ethernet 650 // via other hardware means. We are not currently aware of any such device. 651 return (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) || 652 mPackageManager.hasSystemFeature(FEATURE_ETHERNET) || 653 mPackageManager.hasSystemFeature(FEATURE_USB_HOST); 654 } 655 shouldBeSupported(int networkType)656 private boolean shouldBeSupported(int networkType) { 657 return mNetworkTypes.contains(networkType) 658 || (networkType == ConnectivityManager.TYPE_VPN) 659 || (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported()); 660 } 661 662 @Test testIsNetworkSupported()663 public void testIsNetworkSupported() { 664 for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 665 boolean supported = mCm.isNetworkSupported(type); 666 if (shouldBeSupported(type)) { 667 assertTrue("Network type " + type + " should be supported", supported); 668 } else { 669 assertFalse("Network type " + type + " should not be supported", supported); 670 } 671 } 672 } 673 674 @Test testRequestRouteToHost()675 public void testRequestRouteToHost() { 676 for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 677 assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); 678 } 679 } 680 681 @Test testTest()682 public void testTest() { 683 mCm.getBackgroundDataSetting(); 684 } 685 makeDefaultRequest()686 private NetworkRequest makeDefaultRequest() { 687 // Make a request that is similar to the way framework tracks the system 688 // default network. 689 return new NetworkRequest.Builder() 690 .clearCapabilities() 691 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 692 .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 693 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) 694 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 695 .build(); 696 } 697 makeWifiNetworkRequest()698 private NetworkRequest makeWifiNetworkRequest() { 699 return new NetworkRequest.Builder() 700 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 701 .addCapability(NET_CAPABILITY_INTERNET) 702 .build(); 703 } 704 makeCellNetworkRequest()705 private NetworkRequest makeCellNetworkRequest() { 706 return new NetworkRequest.Builder() 707 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 708 .addCapability(NET_CAPABILITY_INTERNET) 709 .build(); 710 } 711 712 @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") 713 @Test @IgnoreUpTo(Build.VERSION_CODES.Q) testIsPrivateDnsBroken()714 public void testIsPrivateDnsBroken() throws InterruptedException { 715 final String invalidPrivateDnsServer = "invalidhostname.example.com"; 716 final String goodPrivateDnsServer = "dns.google"; 717 mCtsNetUtils.storePrivateDnsSetting(); 718 final TestableNetworkCallback cb = new TestableNetworkCallback(); 719 mCm.registerNetworkCallback(makeWifiNetworkRequest(), cb); 720 try { 721 // Verifying the good private DNS sever 722 mCtsNetUtils.setPrivateDnsStrictMode(goodPrivateDnsServer); 723 final Network networkForPrivateDns = mCtsNetUtils.ensureWifiConnected(); 724 cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS, 725 entry -> (!((CallbackEntry.CapabilitiesChanged) entry).getCaps() 726 .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork())); 727 728 // Verifying the broken private DNS sever 729 mCtsNetUtils.setPrivateDnsStrictMode(invalidPrivateDnsServer); 730 cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS, 731 entry -> (((CallbackEntry.CapabilitiesChanged) entry).getCaps() 732 .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork())); 733 } finally { 734 mCtsNetUtils.restorePrivateDnsSetting(); 735 // Toggle wifi to make sure it is re-validated 736 reconnectWifi(); 737 } 738 } 739 740 /** 741 * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to 742 * see if we get a callback for the TRANSPORT_WIFI transport type being available. 743 * 744 * <p>In order to test that a NetworkCallback occurs, we need some change in the network 745 * state (either a transport or capability is now available). The most straightforward is 746 * WiFi. We could add a version that uses the telephony data connection but it's not clear 747 * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). 748 */ 749 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 750 @Test testRegisterNetworkCallback()751 public void testRegisterNetworkCallback() { 752 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 753 754 // We will register for a WIFI network being available or lost. 755 final TestNetworkCallback callback = new TestNetworkCallback(); 756 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 757 758 final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback(); 759 mCm.registerDefaultNetworkCallback(defaultTrackingCallback); 760 761 final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback(); 762 final TestNetworkCallback perUidCallback = new TestNetworkCallback(); 763 final TestNetworkCallback bestMatchingCallback = new TestNetworkCallback(); 764 final Handler h = new Handler(Looper.getMainLooper()); 765 if (TestUtils.shouldTestSApis()) { 766 runWithShellPermissionIdentity(() -> { 767 mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, h); 768 mCmShim.registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h); 769 }, NETWORK_SETTINGS); 770 mCm.registerBestMatchingNetworkCallback(makeDefaultRequest(), bestMatchingCallback, h); 771 } 772 773 Network wifiNetwork = null; 774 775 try { 776 mCtsNetUtils.ensureWifiConnected(); 777 778 // Now we should expect to get a network callback about availability of the wifi 779 // network even if it was already connected as a state-based action when the callback 780 // is registered. 781 wifiNetwork = callback.waitForAvailable(); 782 assertNotNull("Did not receive onAvailable for TRANSPORT_WIFI request", 783 wifiNetwork); 784 785 final Network defaultNetwork = defaultTrackingCallback.waitForAvailable(); 786 assertNotNull("Did not receive onAvailable on default network callback", 787 defaultNetwork); 788 789 if (TestUtils.shouldTestSApis()) { 790 assertNotNull("Did not receive onAvailable on system default network callback", 791 systemDefaultCallback.waitForAvailable()); 792 final Network perUidNetwork = perUidCallback.waitForAvailable(); 793 assertNotNull("Did not receive onAvailable on per-UID default network callback", 794 perUidNetwork); 795 assertEquals(defaultNetwork, perUidNetwork); 796 final Network bestMatchingNetwork = bestMatchingCallback.waitForAvailable(); 797 assertNotNull("Did not receive onAvailable on best matching network callback", 798 bestMatchingNetwork); 799 assertEquals(defaultNetwork, bestMatchingNetwork); 800 } 801 802 } catch (InterruptedException e) { 803 fail("Broadcast receiver or NetworkCallback wait was interrupted."); 804 } finally { 805 mCm.unregisterNetworkCallback(callback); 806 mCm.unregisterNetworkCallback(defaultTrackingCallback); 807 if (TestUtils.shouldTestSApis()) { 808 mCm.unregisterNetworkCallback(systemDefaultCallback); 809 mCm.unregisterNetworkCallback(perUidCallback); 810 mCm.unregisterNetworkCallback(bestMatchingCallback); 811 } 812 } 813 } 814 815 /** 816 * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to 817 * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead 818 * of a {@code NetworkCallback}. 819 */ 820 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 821 @Test testRegisterNetworkCallback_withPendingIntent()822 public void testRegisterNetworkCallback_withPendingIntent() { 823 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 824 825 // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined 826 // action, NETWORK_CALLBACK_ACTION. 827 final IntentFilter filter = new IntentFilter(); 828 filter.addAction(NETWORK_CALLBACK_ACTION); 829 830 final ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( 831 mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); 832 mContext.registerReceiver(receiver, filter); 833 834 // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. 835 final Intent intent = new Intent(NETWORK_CALLBACK_ACTION) 836 .setPackage(mContext.getPackageName()); 837 // While ConnectivityService would put extra info such as network or request id before 838 // broadcasting the inner intent. The MUTABLE flag needs to be added accordingly. 839 // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+ or 840 // shims. 841 final int pendingIntentFlagMutable = 1 << 25; 842 final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0 /*requestCode*/, 843 intent, PendingIntent.FLAG_CANCEL_CURRENT | pendingIntentFlagMutable); 844 845 // We will register for a WIFI network being available or lost. 846 mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent); 847 848 try { 849 mCtsNetUtils.ensureWifiConnected(); 850 851 // Now we expect to get the Intent delivered notifying of the availability of the wifi 852 // network even if it was already connected as a state-based action when the callback 853 // is registered. 854 assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI", 855 receiver.waitForState()); 856 } catch (InterruptedException e) { 857 fail("Broadcast receiver or NetworkCallback wait was interrupted."); 858 } finally { 859 mCm.unregisterNetworkCallback(pendingIntent); 860 pendingIntent.cancel(); 861 mContext.unregisterReceiver(receiver); 862 } 863 } 864 runIdenticalPendingIntentsRequestTest(boolean useListen)865 private void runIdenticalPendingIntentsRequestTest(boolean useListen) throws Exception { 866 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 867 868 // Disconnect before registering callbacks, reconnect later to fire them 869 mCtsNetUtils.ensureWifiDisconnected(null); 870 871 final NetworkRequest firstRequest = makeWifiNetworkRequest(); 872 final NetworkRequest secondRequest = new NetworkRequest(firstRequest); 873 // Will match wifi or test, since transports are ORed; but there should only be wifi 874 secondRequest.networkCapabilities.addTransportType(TRANSPORT_TEST); 875 876 PendingIntent firstIntent = null; 877 PendingIntent secondIntent = null; 878 BroadcastReceiver receiver = null; 879 880 // Avoid receiving broadcasts from other runs by appending a timestamp 881 final String broadcastAction = NETWORK_CALLBACK_ACTION + System.currentTimeMillis(); 882 try { 883 // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+ 884 // Intent is mutable to receive EXTRA_NETWORK_REQUEST from ConnectivityService 885 final int pendingIntentFlagMutable = 1 << 25; 886 final String extraBoolKey = "extra_bool"; 887 firstIntent = PendingIntent.getBroadcast(mContext, 888 0 /* requestCode */, 889 new Intent(broadcastAction).putExtra(extraBoolKey, false), 890 PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable); 891 892 if (useListen) { 893 mCm.registerNetworkCallback(firstRequest, firstIntent); 894 } else { 895 mCm.requestNetwork(firstRequest, firstIntent); 896 } 897 898 // Second intent equals the first as per filterEquals (extras don't count), so first 899 // intent will be updated with the new extras 900 secondIntent = PendingIntent.getBroadcast(mContext, 901 0 /* requestCode */, 902 new Intent(broadcastAction).putExtra(extraBoolKey, true), 903 PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable); 904 905 // Because secondIntent.intentFilterEquals the first, the request should be replaced 906 if (useListen) { 907 mCm.registerNetworkCallback(secondRequest, secondIntent); 908 } else { 909 mCm.requestNetwork(secondRequest, secondIntent); 910 } 911 912 final IntentFilter filter = new IntentFilter(); 913 filter.addAction(broadcastAction); 914 915 final CompletableFuture<Network> networkFuture = new CompletableFuture<>(); 916 final AtomicInteger receivedCount = new AtomicInteger(0); 917 receiver = new BroadcastReceiver() { 918 @Override 919 public void onReceive(Context context, Intent intent) { 920 final NetworkRequest request = intent.getParcelableExtra(EXTRA_NETWORK_REQUEST); 921 assertPendingIntentRequestMatches(request, secondRequest, useListen); 922 receivedCount.incrementAndGet(); 923 networkFuture.complete(intent.getParcelableExtra(EXTRA_NETWORK)); 924 } 925 }; 926 mContext.registerReceiver(receiver, filter); 927 928 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 929 try { 930 assertEquals(wifiNetwork, networkFuture.get( 931 NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 932 } catch (TimeoutException e) { 933 throw new AssertionError("PendingIntent not received for " + secondRequest, e); 934 } 935 936 // Sleep for a small amount of time to try to check that only one callback is ever 937 // received (so the first callback was really unregistered). This does not guarantee 938 // that the test will fail if it runs very slowly, but it should at least be very 939 // noticeably flaky. 940 Thread.sleep(NO_CALLBACK_TIMEOUT_MS); 941 942 // For R- frameworks, listens will receive duplicated callbacks. See b/189868426. 943 if (isAtLeastS() || !useListen) { 944 assertEquals("PendingIntent should only be received once", 1, receivedCount.get()); 945 } 946 } finally { 947 if (firstIntent != null) mCm.unregisterNetworkCallback(firstIntent); 948 if (secondIntent != null) mCm.unregisterNetworkCallback(secondIntent); 949 if (receiver != null) mContext.unregisterReceiver(receiver); 950 mCtsNetUtils.ensureWifiConnected(); 951 } 952 } 953 assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed, boolean useListen)954 private void assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed, 955 boolean useListen) { 956 assertArrayEquals(filed.networkCapabilities.getCapabilities(), 957 broadcasted.networkCapabilities.getCapabilities()); 958 // For R- frameworks, listens will receive duplicated callbacks. See b/189868426. 959 if (!isAtLeastS() && useListen) return; 960 assertArrayEquals(filed.networkCapabilities.getTransportTypes(), 961 broadcasted.networkCapabilities.getTransportTypes()); 962 } 963 964 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 965 @Test testRegisterNetworkRequest_identicalPendingIntents()966 public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception { 967 runIdenticalPendingIntentsRequestTest(false /* useListen */); 968 } 969 970 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 971 @Test testRegisterNetworkCallback_identicalPendingIntents()972 public void testRegisterNetworkCallback_identicalPendingIntents() throws Exception { 973 runIdenticalPendingIntentsRequestTest(true /* useListen */); 974 } 975 976 /** 977 * Exercises the requestNetwork with NetworkCallback API. This checks to 978 * see if we get a callback for an INTERNET request. 979 */ 980 @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") 981 @Test testRequestNetworkCallback()982 public void testRequestNetworkCallback() { 983 final TestNetworkCallback callback = new TestNetworkCallback(); 984 mCm.requestNetwork(new NetworkRequest.Builder() 985 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 986 .build(), callback); 987 988 try { 989 // Wait to get callback for availability of internet 990 Network internetNetwork = callback.waitForAvailable(); 991 assertNotNull("Did not receive NetworkCallback#onAvailable for INTERNET", 992 internetNetwork); 993 } catch (InterruptedException e) { 994 fail("NetworkCallback wait was interrupted."); 995 } finally { 996 mCm.unregisterNetworkCallback(callback); 997 } 998 } 999 1000 /** 1001 * Exercises the requestNetwork with NetworkCallback API with timeout - expected to 1002 * fail. Use WIFI and switch Wi-Fi off. 1003 */ 1004 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1005 @Test testRequestNetworkCallback_onUnavailable()1006 public void testRequestNetworkCallback_onUnavailable() { 1007 final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); 1008 if (previousWifiEnabledState) { 1009 mCtsNetUtils.ensureWifiDisconnected(null); 1010 } 1011 1012 final TestNetworkCallback callback = new TestNetworkCallback(); 1013 mCm.requestNetwork(new NetworkRequest.Builder() 1014 .addTransportType(TRANSPORT_WIFI) 1015 .build(), callback, 100); 1016 1017 try { 1018 // Wait to get callback for unavailability of requested network 1019 assertTrue("Did not receive NetworkCallback#onUnavailable", 1020 callback.waitForUnavailable()); 1021 } catch (InterruptedException e) { 1022 fail("NetworkCallback wait was interrupted."); 1023 } finally { 1024 mCm.unregisterNetworkCallback(callback); 1025 if (previousWifiEnabledState) { 1026 mCtsNetUtils.connectToWifi(); 1027 } 1028 } 1029 } 1030 getFirstV4Address(Network network)1031 private InetAddress getFirstV4Address(Network network) { 1032 LinkProperties linkProperties = mCm.getLinkProperties(network); 1033 for (InetAddress address : linkProperties.getAddresses()) { 1034 if (address instanceof Inet4Address) { 1035 return address; 1036 } 1037 } 1038 return null; 1039 } 1040 1041 /** 1042 * Checks that enabling/disabling wifi causes CONNECTIVITY_ACTION broadcasts. 1043 */ 1044 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1045 @Test testToggleWifiConnectivityAction()1046 public void testToggleWifiConnectivityAction() { 1047 // toggleWifi calls connectToWifi and disconnectFromWifi, which both wait for 1048 // CONNECTIVITY_ACTION broadcasts. 1049 mCtsNetUtils.toggleWifi(); 1050 } 1051 1052 /** Verify restricted networks cannot be requested. */ 1053 @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") 1054 @Test testRestrictedNetworks()1055 public void testRestrictedNetworks() { 1056 // Verify we can request unrestricted networks: 1057 NetworkRequest request = new NetworkRequest.Builder() 1058 .addCapability(NET_CAPABILITY_INTERNET).build(); 1059 NetworkCallback callback = new NetworkCallback(); 1060 mCm.requestNetwork(request, callback); 1061 mCm.unregisterNetworkCallback(callback); 1062 // Verify we cannot request restricted networks: 1063 request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build(); 1064 callback = new NetworkCallback(); 1065 try { 1066 mCm.requestNetwork(request, callback); 1067 fail("No exception thrown when restricted network requested."); 1068 } catch (SecurityException expected) {} 1069 } 1070 1071 // Returns "true", "false" or "none" getWifiMeteredStatus(String ssid)1072 private String getWifiMeteredStatus(String ssid) throws Exception { 1073 // Interestingly giving the SSID as an argument to list wifi-networks 1074 // only works iff the network in question has the "false" policy. 1075 // Also unfortunately runShellCommand does not pass the command to the interpreter 1076 // so it's not possible to | grep the ssid. 1077 final String command = "cmd netpolicy list wifi-networks"; 1078 final String policyString = runShellCommand(mInstrumentation, command); 1079 1080 final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$", 1081 Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString); 1082 if (!m.find()) { 1083 fail("Unexpected format from cmd netpolicy, policyString = " + policyString); 1084 } 1085 return m.group(1); 1086 } 1087 1088 // metered should be "true", "false" or "none" setWifiMeteredStatus(String ssid, String metered)1089 private void setWifiMeteredStatus(String ssid, String metered) throws Exception { 1090 final String setCommand = "cmd netpolicy set metered-network " + ssid + " " + metered; 1091 runShellCommand(mInstrumentation, setCommand); 1092 assertEquals(getWifiMeteredStatus(ssid), metered); 1093 } 1094 unquoteSSID(String ssid)1095 private String unquoteSSID(String ssid) { 1096 // SSID is returned surrounded by quotes if it can be decoded as UTF-8. 1097 // Otherwise it's guaranteed not to start with a quote. 1098 if (ssid.charAt(0) == '"') { 1099 return ssid.substring(1, ssid.length() - 1); 1100 } else { 1101 return ssid; 1102 } 1103 } 1104 waitForActiveNetworkMetered(final int targetTransportType, final boolean requestedMeteredness, final boolean useSystemDefault)1105 private void waitForActiveNetworkMetered(final int targetTransportType, 1106 final boolean requestedMeteredness, final boolean useSystemDefault) 1107 throws Exception { 1108 final CountDownLatch latch = new CountDownLatch(1); 1109 final NetworkCallback networkCallback = new NetworkCallback() { 1110 @Override 1111 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { 1112 if (!nc.hasTransport(targetTransportType)) return; 1113 1114 final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); 1115 if (metered == requestedMeteredness) { 1116 latch.countDown(); 1117 } 1118 } 1119 }; 1120 1121 try { 1122 // Registering a callback here guarantees onCapabilitiesChanged is called immediately 1123 // with the current setting. Therefore, if the setting has already been changed, 1124 // this method will return right away, and if not, it'll wait for the setting to change. 1125 if (useSystemDefault) { 1126 runWithShellPermissionIdentity(() -> 1127 mCmShim.registerSystemDefaultNetworkCallback(networkCallback, 1128 new Handler(Looper.getMainLooper())), 1129 NETWORK_SETTINGS); 1130 } else { 1131 mCm.registerDefaultNetworkCallback(networkCallback); 1132 } 1133 1134 // Changing meteredness on wifi involves reconnecting, which can take several seconds 1135 // (involves re-associating, DHCP...). 1136 if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1137 fail("Timed out waiting for active network metered status to change to " 1138 + requestedMeteredness + " ; network = " + mCm.getActiveNetwork()); 1139 } 1140 } finally { 1141 mCm.unregisterNetworkCallback(networkCallback); 1142 } 1143 } 1144 setWifiMeteredStatusAndWait(String ssid, boolean isMetered)1145 private void setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception { 1146 setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */); 1147 waitForActiveNetworkMetered(TRANSPORT_WIFI, 1148 isMetered /* requestedMeteredness */, 1149 true /* useSystemDefault */); 1150 } 1151 assertMultipathPreferenceIsEventually(Network network, int oldValue, int expectedValue)1152 private void assertMultipathPreferenceIsEventually(Network network, int oldValue, 1153 int expectedValue) { 1154 // Quick check : if oldValue == expectedValue, there is no way to guarantee the test 1155 // is not flaky. 1156 assertNotSame(oldValue, expectedValue); 1157 1158 for (int i = 0; i < NUM_TRIES_MULTIPATH_PREF_CHECK; ++i) { 1159 final int actualValue = mCm.getMultipathPreference(network); 1160 if (actualValue == expectedValue) { 1161 return; 1162 } 1163 if (actualValue != oldValue) { 1164 fail("Multipath preference is neither previous (" + oldValue 1165 + ") nor expected (" + expectedValue + ")"); 1166 } 1167 SystemClock.sleep(INTERVAL_MULTIPATH_PREF_CHECK_MS); 1168 } 1169 fail("Timed out waiting for multipath preference to change. expected = " 1170 + expectedValue + " ; actual = " + mCm.getMultipathPreference(network)); 1171 } 1172 getCurrentMeteredMultipathPreference(ContentResolver resolver)1173 private int getCurrentMeteredMultipathPreference(ContentResolver resolver) { 1174 final String rawMeteredPref = Settings.Global.getString(resolver, 1175 NETWORK_METERED_MULTIPATH_PREFERENCE); 1176 return TextUtils.isEmpty(rawMeteredPref) 1177 ? getIntResourceForName(NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME) 1178 : Integer.parseInt(rawMeteredPref); 1179 } 1180 findNextPrefValue(ContentResolver resolver)1181 private int findNextPrefValue(ContentResolver resolver) { 1182 // A bit of a nuclear hammer, but race conditions in CTS are bad. To be able to 1183 // detect a correct setting value without race conditions, the next pref must 1184 // be a valid value (range 0..3) that is different from the old setting of the 1185 // metered preference and from the unmetered preference. 1186 final int meteredPref = getCurrentMeteredMultipathPreference(resolver); 1187 final int unmeteredPref = ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED; 1188 if (0 != meteredPref && 0 != unmeteredPref) return 0; 1189 if (1 != meteredPref && 1 != unmeteredPref) return 1; 1190 return 2; 1191 } 1192 1193 /** 1194 * Verify that getMultipathPreference does return appropriate values 1195 * for metered and unmetered networks. 1196 */ 1197 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1198 @Test testGetMultipathPreference()1199 public void testGetMultipathPreference() throws Exception { 1200 final ContentResolver resolver = mContext.getContentResolver(); 1201 mCtsNetUtils.ensureWifiConnected(); 1202 final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); 1203 final String oldMeteredSetting = getWifiMeteredStatus(ssid); 1204 final String oldMeteredMultipathPreference = Settings.Global.getString( 1205 resolver, NETWORK_METERED_MULTIPATH_PREFERENCE); 1206 try { 1207 final int initialMeteredPreference = getCurrentMeteredMultipathPreference(resolver); 1208 int newMeteredPreference = findNextPrefValue(resolver); 1209 Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, 1210 Integer.toString(newMeteredPreference)); 1211 // Wifi meterness changes from unmetered to metered will disconnect and reconnect since 1212 // R. 1213 setWifiMeteredStatusAndWait(ssid, true); 1214 final Network network = mCtsNetUtils.ensureWifiConnected(); 1215 assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); 1216 assertEquals(mCm.getNetworkCapabilities(network).hasCapability( 1217 NET_CAPABILITY_NOT_METERED), false); 1218 assertMultipathPreferenceIsEventually(network, initialMeteredPreference, 1219 newMeteredPreference); 1220 1221 final int oldMeteredPreference = newMeteredPreference; 1222 newMeteredPreference = findNextPrefValue(resolver); 1223 Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, 1224 Integer.toString(newMeteredPreference)); 1225 assertEquals(mCm.getNetworkCapabilities(network).hasCapability( 1226 NET_CAPABILITY_NOT_METERED), false); 1227 assertMultipathPreferenceIsEventually(network, 1228 oldMeteredPreference, newMeteredPreference); 1229 1230 // No disconnect from unmetered to metered. 1231 setWifiMeteredStatusAndWait(ssid, false); 1232 assertEquals(mCm.getNetworkCapabilities(network).hasCapability( 1233 NET_CAPABILITY_NOT_METERED), true); 1234 assertMultipathPreferenceIsEventually(network, newMeteredPreference, 1235 ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED); 1236 } finally { 1237 Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, 1238 oldMeteredMultipathPreference); 1239 setWifiMeteredStatus(ssid, oldMeteredSetting); 1240 } 1241 } 1242 1243 // TODO: move the following socket keep alive test to dedicated test class. 1244 /** 1245 * Callback used in tcp keepalive offload that allows caller to wait callback fires. 1246 */ 1247 private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback { 1248 public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; 1249 1250 public static class CallbackValue { 1251 public final CallbackType callbackType; 1252 public final int error; 1253 CallbackValue(final CallbackType type, final int error)1254 private CallbackValue(final CallbackType type, final int error) { 1255 this.callbackType = type; 1256 this.error = error; 1257 } 1258 1259 public static class OnStartedCallback extends CallbackValue { OnStartedCallback()1260 OnStartedCallback() { super(CallbackType.ON_STARTED, 0); } 1261 } 1262 1263 public static class OnStoppedCallback extends CallbackValue { OnStoppedCallback()1264 OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); } 1265 } 1266 1267 public static class OnErrorCallback extends CallbackValue { OnErrorCallback(final int error)1268 OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); } 1269 } 1270 1271 @Override equals(Object o)1272 public boolean equals(Object o) { 1273 return o.getClass() == this.getClass() 1274 && this.callbackType == ((CallbackValue) o).callbackType 1275 && this.error == ((CallbackValue) o).error; 1276 } 1277 1278 @Override toString()1279 public String toString() { 1280 return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error); 1281 } 1282 } 1283 1284 private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>(); 1285 1286 @Override onStarted()1287 public void onStarted() { 1288 mCallbacks.add(new CallbackValue.OnStartedCallback()); 1289 } 1290 1291 @Override onStopped()1292 public void onStopped() { 1293 mCallbacks.add(new CallbackValue.OnStoppedCallback()); 1294 } 1295 1296 @Override onError(final int error)1297 public void onError(final int error) { 1298 mCallbacks.add(new CallbackValue.OnErrorCallback(error)); 1299 } 1300 pollCallback()1301 public CallbackValue pollCallback() { 1302 try { 1303 return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS, 1304 TimeUnit.MILLISECONDS); 1305 } catch (InterruptedException e) { 1306 fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms"); 1307 } 1308 return null; 1309 } expectCallback(CallbackValue expectedCallback)1310 private void expectCallback(CallbackValue expectedCallback) { 1311 final CallbackValue actualCallback = pollCallback(); 1312 assertEquals(expectedCallback, actualCallback); 1313 } 1314 expectStarted()1315 public void expectStarted() { 1316 expectCallback(new CallbackValue.OnStartedCallback()); 1317 } 1318 expectStopped()1319 public void expectStopped() { 1320 expectCallback(new CallbackValue.OnStoppedCallback()); 1321 } 1322 expectError(int error)1323 public void expectError(int error) { 1324 expectCallback(new CallbackValue.OnErrorCallback(error)); 1325 } 1326 } 1327 getAddrByName(final String hostname, final int family)1328 private InetAddress getAddrByName(final String hostname, final int family) throws Exception { 1329 final InetAddress[] allAddrs = InetAddress.getAllByName(hostname); 1330 for (InetAddress addr : allAddrs) { 1331 if (family == AF_INET && addr instanceof Inet4Address) return addr; 1332 1333 if (family == AF_INET6 && addr instanceof Inet6Address) return addr; 1334 1335 if (family == AF_UNSPEC) return addr; 1336 } 1337 return null; 1338 } 1339 getConnectedSocket(final Network network, final String host, final int port, final int family)1340 private Socket getConnectedSocket(final Network network, final String host, final int port, 1341 final int family) throws Exception { 1342 final Socket s = network.getSocketFactory().createSocket(); 1343 try { 1344 final InetAddress addr = getAddrByName(host, family); 1345 if (addr == null) fail("Fail to get destination address for " + family); 1346 1347 final InetSocketAddress sockAddr = new InetSocketAddress(addr, port); 1348 s.connect(sockAddr); 1349 } catch (Exception e) { 1350 s.close(); 1351 throw e; 1352 } 1353 return s; 1354 } 1355 getSupportedKeepalivesForNet(@onNull Network network)1356 private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception { 1357 final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); 1358 1359 // Get number of supported concurrent keepalives for testing network. 1360 final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); 1361 return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( 1362 keepalivesPerTransport, nc); 1363 } 1364 isTcpKeepaliveSupportedByKernel()1365 private static boolean isTcpKeepaliveSupportedByKernel() { 1366 final String kVersionString = VintfRuntimeInfo.getKernelVersion(); 1367 return compareMajorMinorVersion(kVersionString, "4.8") >= 0; 1368 } 1369 getVersionFromString(String version)1370 private static Pair<Integer, Integer> getVersionFromString(String version) { 1371 // Only gets major and minor number of the version string. 1372 final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); 1373 final Matcher m = versionPattern.matcher(version); 1374 if (m.matches()) { 1375 final int major = Integer.parseInt(m.group(1)); 1376 final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); 1377 return new Pair<>(major, minor); 1378 } else { 1379 return new Pair<>(0, 0); 1380 } 1381 } 1382 1383 // TODO: Move to util class. compareMajorMinorVersion(final String s1, final String s2)1384 private static int compareMajorMinorVersion(final String s1, final String s2) { 1385 final Pair<Integer, Integer> v1 = getVersionFromString(s1); 1386 final Pair<Integer, Integer> v2 = getVersionFromString(s2); 1387 1388 if (v1.first == v2.first) { 1389 return Integer.compare(v1.second, v2.second); 1390 } else { 1391 return Integer.compare(v1.first, v2.first); 1392 } 1393 } 1394 1395 /** 1396 * Verifies that version string compare logic returns expected result for various cases. 1397 * Note that only major and minor number are compared. 1398 */ 1399 @Test testMajorMinorVersionCompare()1400 public void testMajorMinorVersionCompare() { 1401 assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); 1402 assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); 1403 assertEquals(1, compareMajorMinorVersion("5.0", "4.8")); 1404 assertEquals(1, compareMajorMinorVersion("5", "4.8")); 1405 assertEquals(0, compareMajorMinorVersion("5", "5.0")); 1406 assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8")); 1407 assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8")); 1408 assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8")); 1409 assertEquals(0, compareMajorMinorVersion("4.8", "4.8")); 1410 assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0")); 1411 assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8")); 1412 } 1413 1414 /** 1415 * Verifies that the keepalive API cannot create any keepalive when the maximum number of 1416 * keepalives is set to 0. 1417 */ 1418 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1419 @Test testKeepaliveWifiUnsupported()1420 public void testKeepaliveWifiUnsupported() throws Exception { 1421 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1422 1423 final Network network = mCtsNetUtils.ensureWifiConnected(); 1424 if (getSupportedKeepalivesForNet(network) != 0) return; 1425 final InetAddress srcAddr = getFirstV4Address(network); 1426 assumeTrue("This test requires native IPv4", srcAddr != null); 1427 1428 runWithShellPermissionIdentity(() -> { 1429 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0)); 1430 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); 1431 }); 1432 } 1433 1434 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1435 @Test 1436 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") testCreateTcpKeepalive()1437 public void testCreateTcpKeepalive() throws Exception { 1438 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1439 1440 final Network network = mCtsNetUtils.ensureWifiConnected(); 1441 if (getSupportedKeepalivesForNet(network) == 0) return; 1442 final InetAddress srcAddr = getFirstV4Address(network); 1443 assumeTrue("This test requires native IPv4", srcAddr != null); 1444 1445 // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support 1446 // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive 1447 // needs to be supported except if the kernel doesn't support it. 1448 if (!isTcpKeepaliveSupportedByKernel()) { 1449 // Verify that the callback result is expected. 1450 runWithShellPermissionIdentity(() -> { 1451 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); 1452 }); 1453 Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " 1454 + VintfRuntimeInfo.getKernelVersion()); 1455 return; 1456 } 1457 1458 final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); 1459 // So far only ipv4 tcp keepalive offload is supported. 1460 // TODO: add test case for ipv6 tcp keepalive offload when it is supported. 1461 try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, AF_INET)) { 1462 1463 // Should able to start keep alive offload when socket is idle. 1464 final Executor executor = mContext.getMainExecutor(); 1465 final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); 1466 1467 mUiAutomation.adoptShellPermissionIdentity(); 1468 try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { 1469 sk.start(MIN_KEEPALIVE_INTERVAL); 1470 callback.expectStarted(); 1471 1472 // App should not able to write during keepalive offload. 1473 final OutputStream out = s.getOutputStream(); 1474 try { 1475 out.write(requestBytes); 1476 fail("Should not able to write"); 1477 } catch (IOException e) { } 1478 // App should not able to read during keepalive offload. 1479 final InputStream in = s.getInputStream(); 1480 byte[] responseBytes = new byte[4096]; 1481 try { 1482 in.read(responseBytes); 1483 fail("Should not able to read"); 1484 } catch (IOException e) { } 1485 1486 // Stop. 1487 sk.stop(); 1488 callback.expectStopped(); 1489 } finally { 1490 mUiAutomation.dropShellPermissionIdentity(); 1491 } 1492 1493 // Ensure socket is still connected. 1494 assertTrue(s.isConnected()); 1495 assertFalse(s.isClosed()); 1496 1497 // Let socket be not idle. 1498 try { 1499 final OutputStream out = s.getOutputStream(); 1500 out.write(requestBytes); 1501 } catch (IOException e) { 1502 fail("Failed to write data " + e); 1503 } 1504 // Make sure response data arrives. 1505 final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue(); 1506 final FileDescriptor fd = s.getFileDescriptor$(); 1507 final CountDownLatch mOnReceiveLatch = new CountDownLatch(1); 1508 fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> { 1509 mOnReceiveLatch.countDown(); 1510 return 0; // Unregister listener. 1511 }); 1512 if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) { 1513 fdHandlerQueue.removeOnFileDescriptorEventListener(fd); 1514 fail("Timeout: no response data"); 1515 } 1516 1517 // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue 1518 // that has not been read. 1519 mUiAutomation.adoptShellPermissionIdentity(); 1520 try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { 1521 sk.start(MIN_KEEPALIVE_INTERVAL); 1522 callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); 1523 } finally { 1524 mUiAutomation.dropShellPermissionIdentity(); 1525 } 1526 } 1527 } 1528 createConcurrentKeepalivesOfType( int requestCount, @NonNull TestSocketKeepaliveCallback callback, Supplier<SocketKeepalive> kaFactory)1529 private ArrayList<SocketKeepalive> createConcurrentKeepalivesOfType( 1530 int requestCount, @NonNull TestSocketKeepaliveCallback callback, 1531 Supplier<SocketKeepalive> kaFactory) { 1532 final ArrayList<SocketKeepalive> kalist = new ArrayList<>(); 1533 1534 int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT; 1535 1536 // Test concurrent keepalives with the given supplier. 1537 while (kalist.size() < requestCount) { 1538 final SocketKeepalive ka = kaFactory.get(); 1539 ka.start(MIN_KEEPALIVE_INTERVAL); 1540 TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); 1541 assertNotNull(cv); 1542 if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { 1543 if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { 1544 // Unsupported. 1545 break; 1546 } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { 1547 // Limit reached or temporary unavailable due to stopped slot is not yet 1548 // released. 1549 if (remainingRetries > 0) { 1550 SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS); 1551 remainingRetries--; 1552 continue; 1553 } 1554 break; 1555 } 1556 } 1557 if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { 1558 kalist.add(ka); 1559 } else { 1560 fail("Unexpected error when creating " + (kalist.size() + 1) + " " 1561 + ka.getClass().getSimpleName() + ": " + cv); 1562 } 1563 } 1564 1565 return kalist; 1566 } 1567 createConcurrentNattSocketKeepalives( @onNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1568 private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives( 1569 @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount, 1570 @NonNull TestSocketKeepaliveCallback callback) throws Exception { 1571 1572 final Executor executor = mContext.getMainExecutor(); 1573 1574 // Initialize a real NaT-T socket. 1575 final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); 1576 final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); 1577 final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); 1578 assertNotNull(srcAddr); 1579 assertNotNull(dstAddr); 1580 1581 // Test concurrent Nat-T keepalives. 1582 final ArrayList<SocketKeepalive> result = createConcurrentKeepalivesOfType(requestCount, 1583 callback, () -> mCm.createSocketKeepalive(network, nattSocket, 1584 srcAddr, dstAddr, executor, callback)); 1585 1586 nattSocket.close(); 1587 return result; 1588 } 1589 createConcurrentTcpSocketKeepalives( @onNull Network network, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1590 private @NonNull ArrayList<SocketKeepalive> createConcurrentTcpSocketKeepalives( 1591 @NonNull Network network, int requestCount, 1592 @NonNull TestSocketKeepaliveCallback callback) { 1593 final Executor executor = mContext.getMainExecutor(); 1594 1595 // Create concurrent TCP keepalives. 1596 return createConcurrentKeepalivesOfType(requestCount, callback, () -> { 1597 // Assert that TCP connections can be established. The file descriptor of tcp 1598 // sockets will be duplicated and kept valid in service side if the keepalives are 1599 // successfully started. 1600 try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, 1601 AF_INET)) { 1602 return mCm.createSocketKeepalive(network, tcpSocket, executor, callback); 1603 } catch (Exception e) { 1604 fail("Unexpected error when creating TCP socket: " + e); 1605 } 1606 return null; 1607 }); 1608 } 1609 1610 /** 1611 * Creates concurrent keepalives until the specified counts of each type of keepalives are 1612 * reached or the expected error callbacks are received for each type of keepalives. 1613 * 1614 * @return the total number of keepalives created. 1615 */ 1616 private int createConcurrentSocketKeepalives( 1617 @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount) 1618 throws Exception { 1619 final ArrayList<SocketKeepalive> kalist = new ArrayList<>(); 1620 final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); 1621 1622 kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback)); 1623 kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); 1624 1625 final int ret = kalist.size(); 1626 1627 // Clean up. 1628 for (final SocketKeepalive ka : kalist) { 1629 ka.stop(); 1630 callback.expectStopped(); 1631 } 1632 kalist.clear(); 1633 1634 return ret; 1635 } 1636 1637 /** 1638 * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't 1639 * get leaked after iterations. 1640 */ 1641 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1642 @Test 1643 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") 1644 public void testSocketKeepaliveLimitWifi() throws Exception { 1645 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1646 1647 final Network network = mCtsNetUtils.ensureWifiConnected(); 1648 final int supported = getSupportedKeepalivesForNet(network); 1649 if (supported == 0) { 1650 return; 1651 } 1652 final InetAddress srcAddr = getFirstV4Address(network); 1653 assumeTrue("This test requires native IPv4", srcAddr != null); 1654 1655 runWithShellPermissionIdentity(() -> { 1656 // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. 1657 assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); 1658 1659 // Verifies that Nat-T keepalives can be established. 1660 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1661 supported + 1, 0)); 1662 // Verifies that keepalives don't get leaked in second round. 1663 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, 1664 0)); 1665 }); 1666 1667 // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support 1668 // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. 1669 if (!isTcpKeepaliveSupportedByKernel()) return; 1670 1671 runWithShellPermissionIdentity(() -> { 1672 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, 1673 supported + 1)); 1674 1675 // Verifies that different types can be established at the same time. 1676 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1677 supported / 2, supported - supported / 2)); 1678 1679 // Verifies that keepalives don't get leaked in second round. 1680 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, 1681 supported)); 1682 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1683 supported / 2, supported - supported / 2)); 1684 }); 1685 } 1686 1687 /** 1688 * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and 1689 * don't get leaked after iterations. 1690 */ 1691 @AppModeFull(reason = "Cannot request network in instant app mode") 1692 @Test 1693 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") 1694 public void testSocketKeepaliveLimitTelephony() throws Exception { 1695 if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { 1696 Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" 1697 + " supports telephony"); 1698 return; 1699 } 1700 1701 final int firstSdk = SdkLevel.isAtLeastS() 1702 ? Build.VERSION.DEVICE_INITIAL_SDK_INT 1703 // FIRST_SDK_INT was a @TestApi field renamed to DEVICE_INITIAL_SDK_INT in S 1704 : Build.VERSION.class.getField("FIRST_SDK_INT").getInt(null); 1705 if (firstSdk < Build.VERSION_CODES.Q) { 1706 Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching" 1707 + " before Q: " + firstSdk); 1708 return; 1709 } 1710 1711 final Network network = mCtsNetUtils.connectToCell(); 1712 final int supported = getSupportedKeepalivesForNet(network); 1713 final InetAddress srcAddr = getFirstV4Address(network); 1714 assumeTrue("This test requires native IPv4", srcAddr != null); 1715 1716 runWithShellPermissionIdentity(() -> { 1717 // Verifies that the supported keepalive slots meet minimum requirement. 1718 assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); 1719 // Verifies that Nat-T keepalives can be established. 1720 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1721 supported + 1, 0)); 1722 // Verifies that keepalives don't get leaked in second round. 1723 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, 1724 0)); 1725 }); 1726 } 1727 1728 private int getIntResourceForName(@NonNull String resName) { 1729 final Resources r = mContext.getResources(); 1730 final int resId = r.getIdentifier(resName, "integer", "android"); 1731 return r.getInteger(resId); 1732 } 1733 1734 /** 1735 * Verifies that the keepalive slots are limited as customized for unprivileged requests. 1736 */ 1737 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1738 @Test 1739 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") 1740 public void testSocketKeepaliveUnprivileged() throws Exception { 1741 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1742 1743 final Network network = mCtsNetUtils.ensureWifiConnected(); 1744 final int supported = getSupportedKeepalivesForNet(network); 1745 if (supported == 0) { 1746 return; 1747 } 1748 final InetAddress srcAddr = getFirstV4Address(network); 1749 assumeTrue("This test requires native IPv4", srcAddr != null); 1750 1751 // Resource ID might be shifted on devices that compiled with different symbols. 1752 // Thus, resolve ID at runtime is needed. 1753 final int allowedUnprivilegedPerUid = 1754 getIntResourceForName(KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME); 1755 final int reservedPrivilegedSlots = 1756 getIntResourceForName(KEEPALIVE_RESERVED_PER_SLOT_RES_NAME); 1757 // Verifies that unprivileged request per uid cannot exceed the limit customized in the 1758 // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test 1759 // does not apply to TCP. 1760 assertGreaterOrEqual(supported, reservedPrivilegedSlots); 1761 assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); 1762 final int expectedUnprivileged = 1763 Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); 1764 assertEquals(expectedUnprivileged, 1765 createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0)); 1766 } 1767 1768 private static void assertGreaterOrEqual(long greater, long lesser) { 1769 assertTrue("" + greater + " expected to be greater than or equal to " + lesser, 1770 greater >= lesser); 1771 } 1772 1773 /** 1774 * Verifies that apps are not allowed to access restricted networks even if they declare the 1775 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests. 1776 * See. b/144679405. 1777 */ 1778 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1779 @Test 1780 public void testRestrictedNetworkPermission() throws Exception { 1781 // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. 1782 final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), 1783 GET_PERMISSIONS); 1784 final int index = ArrayUtils.indexOf( 1785 app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS); 1786 assertTrue(index >= 0); 1787 assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED); 1788 1789 // Ensure that NetworkUtils.queryUserAccess always returns false since this package should 1790 // not have netd system permission to call this function. 1791 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 1792 assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId)); 1793 1794 // Ensure that this package cannot bind to any restricted network that's currently 1795 // connected. 1796 Network[] networks = mCm.getAllNetworks(); 1797 for (Network network : networks) { 1798 NetworkCapabilities nc = mCm.getNetworkCapabilities(network); 1799 if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { 1800 try { 1801 network.bindSocket(new Socket()); 1802 fail("Bind to restricted network " + network + " unexpectedly succeeded"); 1803 } catch (IOException expected) {} 1804 } 1805 } 1806 } 1807 1808 /** 1809 * Verifies that apps are allowed to call setAirplaneMode if they declare 1810 * NETWORK_AIRPLANE_MODE permission in their manifests. 1811 * See b/145164696. 1812 */ 1813 @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps") 1814 @Test 1815 public void testSetAirplaneMode() throws Exception{ 1816 final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI); 1817 final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 1818 // store the current state of airplane mode 1819 final boolean isAirplaneModeEnabled = isAirplaneModeEnabled(); 1820 final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); 1821 final TestableNetworkCallback telephonyCb = new TestableNetworkCallback(); 1822 // disable airplane mode to reach a known state 1823 runShellCommand("cmd connectivity airplane-mode disable"); 1824 // Verify that networks are available as expected if wifi or cell is supported. Continue the 1825 // test if none of them are supported since test should still able to verify the permission 1826 // mechanism. 1827 if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb); 1828 if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb); 1829 1830 try { 1831 // Verify we cannot set Airplane Mode without correct permission: 1832 try { 1833 setAndVerifyAirplaneMode(true); 1834 fail("SecurityException should have been thrown when setAirplaneMode was called" 1835 + "without holding permission NETWORK_AIRPLANE_MODE."); 1836 } catch (SecurityException expected) {} 1837 1838 // disable airplane mode again to reach a known state 1839 runShellCommand("cmd connectivity airplane-mode disable"); 1840 1841 // adopt shell permission which holds NETWORK_AIRPLANE_MODE 1842 mUiAutomation.adoptShellPermissionIdentity(); 1843 1844 // Verify we can enable Airplane Mode with correct permission: 1845 try { 1846 setAndVerifyAirplaneMode(true); 1847 } catch (SecurityException e) { 1848 fail("SecurityException should not have been thrown when setAirplaneMode(true) was" 1849 + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); 1850 } 1851 // Verify that the enabling airplane mode takes effect as expected to prevent flakiness 1852 // caused by fast airplane mode switches. Ensure network lost before turning off 1853 // airplane mode. 1854 if (supportWifi) waitForLost(wifiCb); 1855 if (supportTelephony) waitForLost(telephonyCb); 1856 1857 // Verify we can disable Airplane Mode with correct permission: 1858 try { 1859 setAndVerifyAirplaneMode(false); 1860 } catch (SecurityException e) { 1861 fail("SecurityException should not have been thrown when setAirplaneMode(false) was" 1862 + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); 1863 } 1864 // Verify that turning airplane mode off takes effect as expected. 1865 if (supportWifi) waitForAvailable(wifiCb); 1866 if (supportTelephony) waitForAvailable(telephonyCb); 1867 } finally { 1868 if (supportWifi) mCm.unregisterNetworkCallback(wifiCb); 1869 if (supportTelephony) mCm.unregisterNetworkCallback(telephonyCb); 1870 // Restore the previous state of airplane mode and permissions: 1871 runShellCommand("cmd connectivity airplane-mode " 1872 + (isAirplaneModeEnabled ? "enable" : "disable")); 1873 mUiAutomation.dropShellPermissionIdentity(); 1874 } 1875 } 1876 1877 private void requestAndWaitForAvailable(@NonNull final NetworkRequest request, 1878 @NonNull final TestableNetworkCallback cb) { 1879 mCm.registerNetworkCallback(request, cb); 1880 waitForAvailable(cb); 1881 } 1882 1883 private void waitForAvailable(@NonNull final TestableNetworkCallback cb) { 1884 cb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 1885 c -> c instanceof CallbackEntry.Available); 1886 } 1887 1888 private void waitForAvailable( 1889 @NonNull final TestableNetworkCallback cb, final int expectedTransport) { 1890 cb.eventuallyExpect( 1891 CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 1892 entry -> { 1893 final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork()); 1894 return nc.hasTransport(expectedTransport); 1895 } 1896 ); 1897 } 1898 1899 private void waitForAvailable( 1900 @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) { 1901 cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */, 1902 true /* validated */, 1903 false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS); 1904 } 1905 1906 private void waitForLost(@NonNull final TestableNetworkCallback cb) { 1907 cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS, 1908 c -> c instanceof CallbackEntry.Lost); 1909 } 1910 1911 private void setAndVerifyAirplaneMode(Boolean expectedResult) 1912 throws Exception { 1913 final CompletableFuture<Boolean> actualResult = new CompletableFuture(); 1914 BroadcastReceiver receiver = new BroadcastReceiver() { 1915 @Override 1916 public void onReceive(Context context, Intent intent) { 1917 // The defaultValue of getExtraBoolean should be the opposite of what is 1918 // expected, thus ensuring a test failure if the extra is absent. 1919 actualResult.complete(intent.getBooleanExtra("state", !expectedResult)); 1920 } 1921 }; 1922 try { 1923 mContext.registerReceiver(receiver, 1924 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 1925 mCm.setAirplaneMode(expectedResult); 1926 final String msg = "Setting Airplane Mode failed,"; 1927 assertEquals(msg, expectedResult, actualResult.get(AIRPLANE_MODE_CHANGE_TIMEOUT_MS, 1928 TimeUnit.MILLISECONDS)); 1929 } finally { 1930 mContext.unregisterReceiver(receiver); 1931 } 1932 } 1933 1934 private static boolean isAirplaneModeEnabled() { 1935 return runShellCommand("cmd connectivity airplane-mode") 1936 .trim().equals("enabled"); 1937 } 1938 1939 @Test 1940 public void testGetCaptivePortalServerUrl() { 1941 final String permission = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q 1942 ? CONNECTIVITY_INTERNAL 1943 : NETWORK_SETTINGS; 1944 final String url = runAsShell(permission, mCm::getCaptivePortalServerUrl); 1945 assertNotNull("getCaptivePortalServerUrl must not be null", url); 1946 try { 1947 final URL parsedUrl = new URL(url); 1948 // As per the javadoc, the URL must be HTTP 1949 assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol()); 1950 } catch (MalformedURLException e) { 1951 throw new AssertionFailedError("Captive portal server URL is invalid: " + e); 1952 } 1953 } 1954 1955 /** 1956 * Verifies that apps are forbidden from getting ssid information from 1957 * {@Code NetworkCapabilities} if they do not hold NETWORK_SETTINGS permission. 1958 * See b/161370134. 1959 */ 1960 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1961 @Test 1962 public void testSsidInNetworkCapabilities() throws Exception { 1963 assumeTrue("testSsidInNetworkCapabilities cannot execute unless device supports WiFi", 1964 mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1965 1966 final Network network = mCtsNetUtils.ensureWifiConnected(); 1967 final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); 1968 assertNotNull("Ssid getting from WifiManager is null", ssid); 1969 // This package should have no NETWORK_SETTINGS permission. Verify that no ssid is contained 1970 // in the NetworkCapabilities. 1971 verifySsidFromQueriedNetworkCapabilities(network, ssid, false /* hasSsid */); 1972 verifySsidFromCallbackNetworkCapabilities(ssid, false /* hasSsid */); 1973 // Adopt shell permission to allow to get ssid information. 1974 runWithShellPermissionIdentity(() -> { 1975 verifySsidFromQueriedNetworkCapabilities(network, ssid, true /* hasSsid */); 1976 verifySsidFromCallbackNetworkCapabilities(ssid, true /* hasSsid */); 1977 }); 1978 } 1979 1980 private void verifySsidFromQueriedNetworkCapabilities(@NonNull Network network, 1981 @NonNull String ssid, boolean hasSsid) throws Exception { 1982 // Verify if ssid is contained in NetworkCapabilities queried from ConnectivityManager. 1983 final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); 1984 assertNotNull("NetworkCapabilities of the network is null", nc); 1985 assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find()); 1986 } 1987 1988 private void verifySsidFromCallbackNetworkCapabilities(@NonNull String ssid, boolean hasSsid) 1989 throws Exception { 1990 final CompletableFuture<NetworkCapabilities> foundNc = new CompletableFuture(); 1991 final NetworkCallback callback = new NetworkCallback() { 1992 @Override 1993 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { 1994 foundNc.complete(nc); 1995 } 1996 }; 1997 try { 1998 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 1999 // Registering a callback here guarantees onCapabilitiesChanged is called immediately 2000 // because WiFi network should be connected. 2001 final NetworkCapabilities nc = 2002 foundNc.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 2003 // Verify if ssid is contained in the NetworkCapabilities received from callback. 2004 assertNotNull("NetworkCapabilities of the network is null", nc); 2005 assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find()); 2006 } finally { 2007 mCm.unregisterNetworkCallback(callback); 2008 } 2009 } 2010 2011 /** 2012 * Verify background request can only be requested when acquiring 2013 * {@link android.Manifest.permission.NETWORK_SETTINGS}. 2014 */ 2015 @AppModeFull(reason = "Instant apps cannot create test networks") 2016 @Test 2017 public void testRequestBackgroundNetwork() { 2018 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2019 // shims, and @IgnoreUpTo does not check that. 2020 assumeTrue(TestUtils.shouldTestSApis()); 2021 2022 // Create a tun interface. Use the returned interface name as the specifier to create 2023 // a test network request. 2024 final TestNetworkManager tnm = runWithShellPermissionIdentity(() -> 2025 mContext.getSystemService(TestNetworkManager.class), 2026 android.Manifest.permission.MANAGE_TEST_NETWORKS); 2027 final TestNetworkInterface testNetworkInterface = runWithShellPermissionIdentity(() -> 2028 tnm.createTunInterface(new LinkAddress[]{TEST_LINKADDR}), 2029 android.Manifest.permission.MANAGE_TEST_NETWORKS, 2030 android.Manifest.permission.NETWORK_SETTINGS); 2031 assertNotNull(testNetworkInterface); 2032 2033 final NetworkRequest testRequest = new NetworkRequest.Builder() 2034 .addTransportType(TRANSPORT_TEST) 2035 // Test networks do not have NOT_VPN or TRUSTED capabilities by default 2036 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) 2037 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 2038 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier( 2039 testNetworkInterface.getInterfaceName())) 2040 .build(); 2041 2042 // Verify background network cannot be requested without NETWORK_SETTINGS permission. 2043 final TestableNetworkCallback callback = new TestableNetworkCallback(); 2044 final Handler handler = new Handler(Looper.getMainLooper()); 2045 assertThrows(SecurityException.class, 2046 () -> mCmShim.requestBackgroundNetwork(testRequest, callback, handler)); 2047 2048 Network testNetwork = null; 2049 try { 2050 // Request background test network via Shell identity which has NETWORK_SETTINGS 2051 // permission granted. 2052 runWithShellPermissionIdentity( 2053 () -> mCmShim.requestBackgroundNetwork(testRequest, callback, handler), 2054 new String[] { android.Manifest.permission.NETWORK_SETTINGS }); 2055 2056 // Register the test network agent which has no foreground request associated to it. 2057 // And verify it can satisfy the background network request just fired. 2058 final Binder binder = new Binder(); 2059 runWithShellPermissionIdentity(() -> 2060 tnm.setupTestNetwork(testNetworkInterface.getInterfaceName(), binder), 2061 new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS, 2062 android.Manifest.permission.NETWORK_SETTINGS }); 2063 waitForAvailable(callback); 2064 testNetwork = callback.getLastAvailableNetwork(); 2065 assertNotNull(testNetwork); 2066 2067 // The test network that has just connected is a foreground network, 2068 // non-listen requests will get available callback before it can be put into 2069 // background if no foreground request can be satisfied. Thus, wait for a short 2070 // period is needed to let foreground capability go away. 2071 callback.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, 2072 NETWORK_CALLBACK_TIMEOUT_MS, 2073 c -> c instanceof CallbackEntry.CapabilitiesChanged 2074 && !((CallbackEntry.CapabilitiesChanged) c).getCaps() 2075 .hasCapability(NET_CAPABILITY_FOREGROUND)); 2076 final NetworkCapabilities nc = mCm.getNetworkCapabilities(testNetwork); 2077 assertFalse("expected background network, but got " + nc, 2078 nc.hasCapability(NET_CAPABILITY_FOREGROUND)); 2079 } finally { 2080 final Network n = testNetwork; 2081 runWithShellPermissionIdentity(() -> { 2082 if (null != n) { 2083 tnm.teardownTestNetwork(n); 2084 callback.eventuallyExpect(CallbackEntry.LOST, 2085 NETWORK_CALLBACK_TIMEOUT_MS, 2086 lost -> n.equals(lost.getNetwork())); 2087 } 2088 testNetworkInterface.getFileDescriptor().close(); 2089 }, new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS }); 2090 mCm.unregisterNetworkCallback(callback); 2091 } 2092 } 2093 2094 private class DetailedBlockedStatusCallback extends TestableNetworkCallback { 2095 public void expectAvailableCallbacks(Network network) { 2096 super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */, 2097 BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS); 2098 } 2099 public void expectBlockedStatusCallback(Network network, int blockedStatus) { 2100 super.expectBlockedStatusCallback(blockedStatus, network, NETWORK_CALLBACK_TIMEOUT_MS); 2101 } 2102 public void onBlockedStatusChanged(Network network, int blockedReasons) { 2103 getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons)); 2104 } 2105 } 2106 2107 private void setRequireVpnForUids(boolean requireVpn, Collection<Range<Integer>> ranges) 2108 throws Exception { 2109 mCmShim.setRequireVpnForUids(requireVpn, ranges); 2110 for (Range<Integer> range : ranges) { 2111 if (requireVpn) { 2112 mVpnRequiredUidRanges.add(range); 2113 } else { 2114 assertTrue(mVpnRequiredUidRanges.remove(range)); 2115 } 2116 } 2117 } 2118 2119 private void doTestBlockedStatusCallback() throws Exception { 2120 final DetailedBlockedStatusCallback myUidCallback = new DetailedBlockedStatusCallback(); 2121 final DetailedBlockedStatusCallback otherUidCallback = new DetailedBlockedStatusCallback(); 2122 2123 final int myUid = Process.myUid(); 2124 final int otherUid = UserHandle.getUid(5, Process.FIRST_APPLICATION_UID); 2125 final Handler handler = new Handler(Looper.getMainLooper()); 2126 mCm.registerDefaultNetworkCallback(myUidCallback, handler); 2127 mCmShim.registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, handler); 2128 2129 final Network defaultNetwork = mCm.getActiveNetwork(); 2130 final List<DetailedBlockedStatusCallback> allCallbacks = 2131 List.of(myUidCallback, otherUidCallback); 2132 for (DetailedBlockedStatusCallback callback : allCallbacks) { 2133 callback.expectAvailableCallbacks(defaultNetwork); 2134 } 2135 2136 final Range<Integer> myUidRange = new Range<>(myUid, myUid); 2137 final Range<Integer> otherUidRange = new Range<>(otherUid, otherUid); 2138 2139 setRequireVpnForUids(true, List.of(myUidRange)); 2140 myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN); 2141 otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2142 2143 setRequireVpnForUids(true, List.of(myUidRange, otherUidRange)); 2144 myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2145 otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN); 2146 2147 // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not 2148 // unblock myUid because it was added to the blocked ranges twice. 2149 setRequireVpnForUids(false, List.of(myUidRange)); 2150 myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2151 otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2152 2153 setRequireVpnForUids(false, List.of(myUidRange, otherUidRange)); 2154 myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); 2155 otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); 2156 2157 myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2158 otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2159 } 2160 2161 @Test 2162 public void testBlockedStatusCallback() { 2163 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2164 // shims, and @IgnoreUpTo does not check that. 2165 assumeTrue(TestUtils.shouldTestSApis()); 2166 runWithShellPermissionIdentity(() -> doTestBlockedStatusCallback(), NETWORK_SETTINGS); 2167 } 2168 2169 private void doTestLegacyLockdownEnabled() throws Exception { 2170 NetworkInfo info = mCm.getActiveNetworkInfo(); 2171 assertNotNull(info); 2172 assertEquals(DetailedState.CONNECTED, info.getDetailedState()); 2173 2174 try { 2175 mCmShim.setLegacyLockdownVpnEnabled(true); 2176 2177 // setLegacyLockdownVpnEnabled is asynchronous and only takes effect when the 2178 // ConnectivityService handler thread processes it. Ensure it has taken effect by doing 2179 // something that blocks until the handler thread is idle. 2180 final TestableNetworkCallback callback = new TestableNetworkCallback(); 2181 mCm.registerDefaultNetworkCallback(callback); 2182 waitForAvailable(callback); 2183 mCm.unregisterNetworkCallback(callback); 2184 2185 // Test one of the effects of setLegacyLockdownVpnEnabled: the fact that any NetworkInfo 2186 // in state CONNECTED is degraded to CONNECTING if the legacy VPN is not connected. 2187 info = mCm.getActiveNetworkInfo(); 2188 assertNotNull(info); 2189 assertEquals(DetailedState.CONNECTING, info.getDetailedState()); 2190 } finally { 2191 mCmShim.setLegacyLockdownVpnEnabled(false); 2192 } 2193 } 2194 2195 @Test 2196 public void testLegacyLockdownEnabled() { 2197 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2198 // shims, and @IgnoreUpTo does not check that. 2199 assumeTrue(TestUtils.shouldTestSApis()); 2200 runWithShellPermissionIdentity(() -> doTestLegacyLockdownEnabled(), NETWORK_SETTINGS); 2201 } 2202 2203 @Test 2204 public void testGetCapabilityCarrierName() { 2205 assumeTrue(TestUtils.shouldTestSApis()); 2206 assertEquals("ENTERPRISE", NetworkInformationShimImpl.newInstance() 2207 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_ENTERPRISE)); 2208 assertNull(NetworkInformationShimImpl.newInstance() 2209 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_NOT_VCN_MANAGED)); 2210 } 2211 2212 @Test 2213 public void testSetGlobalProxy() { 2214 assumeTrue(TestUtils.shouldTestSApis()); 2215 // Behavior is verified in gts. Verify exception thrown w/o permission. 2216 assertThrows(SecurityException.class, () -> mCm.setGlobalProxy( 2217 ProxyInfo.buildDirectProxy("example.com" /* host */, 8080 /* port */))); 2218 } 2219 2220 @Test 2221 public void testFactoryResetWithoutPermission() { 2222 assumeTrue(TestUtils.shouldTestSApis()); 2223 assertThrows(SecurityException.class, () -> mCm.factoryReset()); 2224 } 2225 2226 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 2227 @Test 2228 public void testFactoryReset() throws Exception { 2229 assumeTrue(TestUtils.shouldTestSApis()); 2230 2231 // Store current settings. 2232 final int curAvoidBadWifi = 2233 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext); 2234 final int curPrivateDnsMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext); 2235 2236 TestTetheringEventCallback tetherEventCallback = null; 2237 final CtsTetheringUtils tetherUtils = new CtsTetheringUtils(mContext); 2238 try { 2239 tetherEventCallback = tetherUtils.registerTetheringEventCallback(); 2240 // Adopt for NETWORK_SETTINGS permission. 2241 mUiAutomation.adoptShellPermissionIdentity(); 2242 // start tethering 2243 tetherEventCallback.assumeWifiTetheringSupported(mContext); 2244 tetherUtils.startWifiTethering(tetherEventCallback); 2245 // Update setting to verify the behavior. 2246 mCm.setAirplaneMode(true); 2247 ConnectivitySettingsManager.setPrivateDnsMode(mContext, 2248 ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF); 2249 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, 2250 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE); 2251 assertEquals(AIRPLANE_MODE_ON, Settings.Global.getInt( 2252 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON)); 2253 // Verify factoryReset 2254 mCm.factoryReset(); 2255 verifySettings(AIRPLANE_MODE_OFF, 2256 ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, 2257 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT); 2258 2259 tetherEventCallback.expectNoTetheringActive(); 2260 } finally { 2261 // Restore settings. 2262 mCm.setAirplaneMode(false); 2263 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, curAvoidBadWifi); 2264 ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode); 2265 if (tetherEventCallback != null) { 2266 tetherUtils.unregisterTetheringEventCallback(tetherEventCallback); 2267 } 2268 tetherUtils.stopAllTethering(); 2269 mUiAutomation.dropShellPermissionIdentity(); 2270 } 2271 } 2272 2273 /** 2274 * Verify that {@link ConnectivityManager#setProfileNetworkPreference} cannot be called 2275 * without required NETWORK_STACK permissions. 2276 */ 2277 @Test 2278 public void testSetProfileNetworkPreference_NoPermission() { 2279 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2280 // shims, and @IgnoreUpTo does not check that. 2281 assumeTrue(TestUtils.shouldTestSApis()); 2282 assertThrows(SecurityException.class, () -> mCm.setProfileNetworkPreference( 2283 UserHandle.of(0), PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null /* executor */, 2284 null /* listener */)); 2285 } 2286 2287 @Test 2288 public void testSystemReady() { 2289 assumeTrue(TestUtils.shouldTestSApis()); 2290 assertThrows(SecurityException.class, () -> mCm.systemReady()); 2291 } 2292 2293 @Test 2294 public void testGetIpSecNetIdRange() { 2295 assumeTrue(TestUtils.shouldTestSApis()); 2296 // The lower refers to ConnectivityManager.TUN_INTF_NETID_START. 2297 final long lower = 64512; 2298 // The upper refers to ConnectivityManager.TUN_INTF_NETID_START 2299 // + ConnectivityManager.TUN_INTF_NETID_RANGE - 1 2300 final long upper = 65535; 2301 assertEquals(lower, (long) ConnectivityManager.getIpSecNetIdRange().getLower()); 2302 assertEquals(upper, (long) ConnectivityManager.getIpSecNetIdRange().getUpper()); 2303 } 2304 2305 private void verifySettings(int expectedAirplaneMode, int expectedPrivateDnsMode, 2306 int expectedAvoidBadWifi) throws Exception { 2307 assertEquals(expectedAirplaneMode, Settings.Global.getInt( 2308 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON)); 2309 assertEquals(expectedPrivateDnsMode, 2310 ConnectivitySettingsManager.getPrivateDnsMode(mContext)); 2311 assertEquals(expectedAvoidBadWifi, 2312 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext)); 2313 } 2314 2315 /** 2316 * Verify that per-app OEM network preference functions as expected for network preference TEST. 2317 * For specified apps, validate networks are prioritized in order: unmetered, TEST transport, 2318 * default network. 2319 */ 2320 @AppModeFull(reason = "Instant apps cannot create test networks") 2321 @Test 2322 public void testSetOemNetworkPreferenceForTestPref() throws Exception { 2323 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2324 // shims, and @IgnoreUpTo does not check that. 2325 assumeTrue(TestUtils.shouldTestSApis()); 2326 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 2327 2328 final TestNetworkTracker tnt = callWithShellPermissionIdentity( 2329 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS)); 2330 final TestableNetworkCallback defaultCallback = new TestableNetworkCallback(); 2331 final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback(); 2332 2333 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2334 final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity( 2335 () -> mCm.getNetworkCapabilities(wifiNetwork)); 2336 final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid()); 2337 final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered(); 2338 2339 try { 2340 // This network will be used for unmetered. 2341 setWifiMeteredStatusAndWait(ssid, false /* isMetered */); 2342 2343 setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST); 2344 registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2345 2346 // Validate that an unmetered network is used over other networks. 2347 waitForAvailable(defaultCallback, wifiNetwork); 2348 waitForAvailable(systemDefaultCallback, wifiNetwork); 2349 2350 // Validate when setting unmetered to metered, unmetered is lost and replaced by the 2351 // network with the TEST transport. 2352 setWifiMeteredStatusAndWait(ssid, true /* isMetered */); 2353 defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork, 2354 NETWORK_CALLBACK_TIMEOUT_MS); 2355 waitForAvailable(defaultCallback, tnt.getNetwork()); 2356 // Depending on if this device has cellular connectivity or not, multiple available 2357 // callbacks may be received. Eventually, metered Wi-Fi should be the final available 2358 // callback in any case therefore confirm its receipt before continuing to assure the 2359 // system is in the expected state. 2360 waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI); 2361 } finally { 2362 // Validate that removing the test network will fallback to the default network. 2363 runWithShellPermissionIdentity(tnt::teardown); 2364 defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork(), 2365 NETWORK_CALLBACK_TIMEOUT_MS); 2366 waitForAvailable(defaultCallback); 2367 2368 setWifiMeteredStatusAndWait(ssid, oldMeteredValue); 2369 2370 // Cleanup any prior test state from setOemNetworkPreference 2371 clearOemNetworkPreference(); 2372 unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2373 } 2374 } 2375 2376 /** 2377 * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY. 2378 * For specified apps, validate that only TEST transport type networks are used. 2379 */ 2380 @AppModeFull(reason = "Instant apps cannot create test networks") 2381 @Test 2382 public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception { 2383 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2384 // shims, and @IgnoreUpTo does not check that. 2385 assumeTrue(TestUtils.shouldTestSApis()); 2386 2387 final TestNetworkTracker tnt = callWithShellPermissionIdentity( 2388 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS)); 2389 final TestableNetworkCallback defaultCallback = new TestableNetworkCallback(); 2390 final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback(); 2391 2392 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2393 2394 try { 2395 setOemNetworkPreferenceForMyPackage( 2396 OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY); 2397 registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2398 waitForAvailable(defaultCallback, tnt.getNetwork()); 2399 waitForAvailable(systemDefaultCallback, wifiNetwork); 2400 } finally { 2401 runWithShellPermissionIdentity(tnt::teardown); 2402 defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork(), 2403 NETWORK_CALLBACK_TIMEOUT_MS); 2404 2405 // This network preference should only ever use the test network therefore available 2406 // should not trigger when the test network goes down (e.g. switch to cellular). 2407 defaultCallback.assertNoCallback(); 2408 // The system default should still be connected to Wi-fi 2409 assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork()); 2410 2411 // Cleanup any prior test state from setOemNetworkPreference 2412 clearOemNetworkPreference(); 2413 2414 // The default (non-test) network should be available as the network pref was cleared. 2415 waitForAvailable(defaultCallback); 2416 unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2417 } 2418 } 2419 2420 private void unregisterTestOemNetworkPreferenceCallbacks( 2421 @NonNull final TestableNetworkCallback defaultCallback, 2422 @NonNull final TestableNetworkCallback systemDefaultCallback) { 2423 mCm.unregisterNetworkCallback(defaultCallback); 2424 mCm.unregisterNetworkCallback(systemDefaultCallback); 2425 } 2426 2427 private void registerTestOemNetworkPreferenceCallbacks( 2428 @NonNull final TestableNetworkCallback defaultCallback, 2429 @NonNull final TestableNetworkCallback systemDefaultCallback) { 2430 mCm.registerDefaultNetworkCallback(defaultCallback); 2431 runWithShellPermissionIdentity(() -> 2432 mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, 2433 new Handler(Looper.getMainLooper())), NETWORK_SETTINGS); 2434 } 2435 2436 private static final class OnCompleteListenerCallback { 2437 final CompletableFuture<Object> mDone = new CompletableFuture<>(); 2438 2439 public void onComplete() { 2440 mDone.complete(new Object()); 2441 } 2442 2443 void expectOnComplete() throws Exception { 2444 try { 2445 mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 2446 } catch (TimeoutException e) { 2447 fail("Expected onComplete() not received after " 2448 + NETWORK_CALLBACK_TIMEOUT_MS + " ms"); 2449 } 2450 } 2451 } 2452 2453 private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception { 2454 final OemNetworkPreferences pref = new OemNetworkPreferences.Builder() 2455 .addNetworkPreference(mContext.getPackageName(), networkPref) 2456 .build(); 2457 final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback(); 2458 mUiAutomation.adoptShellPermissionIdentity(); 2459 try { 2460 mCm.setOemNetworkPreference( 2461 pref, mContext.getMainExecutor(), oemPrefListener::onComplete); 2462 } finally { 2463 mUiAutomation.dropShellPermissionIdentity(); 2464 } 2465 oemPrefListener.expectOnComplete(); 2466 } 2467 2468 /** 2469 * This will clear the OEM network preference on the device. As there is currently no way of 2470 * getting the existing preference, if this is executed while an existing preference is in 2471 * place, that preference will need to be reapplied after executing this test. 2472 * @throws Exception 2473 */ 2474 private void clearOemNetworkPreference() throws Exception { 2475 final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build(); 2476 final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback(); 2477 mUiAutomation.adoptShellPermissionIdentity(); 2478 try { 2479 mCm.setOemNetworkPreference( 2480 clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete); 2481 } finally { 2482 mUiAutomation.dropShellPermissionIdentity(); 2483 } 2484 oemPrefListener.expectOnComplete(); 2485 } 2486 2487 @Test 2488 public void testSetAcceptPartialConnectivity_NoPermission_GetException() { 2489 assumeTrue(TestUtils.shouldTestSApis()); 2490 assertThrows(SecurityException.class, () -> mCm.setAcceptPartialConnectivity( 2491 mCm.getActiveNetwork(), false /* accept */ , false /* always */)); 2492 } 2493 2494 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2495 @Test 2496 public void testAcceptPartialConnectivity_validatedNetwork() throws Exception { 2497 assumeTrue(TestUtils.shouldTestSApis()); 2498 assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" 2499 + " unless device supports WiFi", 2500 mPackageManager.hasSystemFeature(FEATURE_WIFI)); 2501 2502 try { 2503 // Wait for partial connectivity to be detected on the network 2504 final Network network = preparePartialConnectivity(); 2505 2506 runAsShell(NETWORK_SETTINGS, () -> { 2507 // The always bit is verified in NetworkAgentTest 2508 mCm.setAcceptPartialConnectivity(network, true /* accept */, false /* always */); 2509 }); 2510 2511 // Accept partial connectivity network should result in a validated network 2512 expectNetworkHasCapability(network, NET_CAPABILITY_VALIDATED, WIFI_CONNECT_TIMEOUT_MS); 2513 } finally { 2514 resetValidationConfig(); 2515 // Reconnect wifi to reset the wifi status 2516 reconnectWifi(); 2517 } 2518 } 2519 2520 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2521 @Test 2522 public void testRejectPartialConnectivity_TearDownNetwork() throws Exception { 2523 assumeTrue(TestUtils.shouldTestSApis()); 2524 assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" 2525 + " unless device supports WiFi", 2526 mPackageManager.hasSystemFeature(FEATURE_WIFI)); 2527 2528 final TestNetworkCallback cb = new TestNetworkCallback(); 2529 try { 2530 // Wait for partial connectivity to be detected on the network 2531 final Network network = preparePartialConnectivity(); 2532 2533 mCm.requestNetwork(makeWifiNetworkRequest(), cb); 2534 runAsShell(NETWORK_SETTINGS, () -> { 2535 // The always bit is verified in NetworkAgentTest 2536 mCm.setAcceptPartialConnectivity(network, false /* accept */, false /* always */); 2537 }); 2538 // Reject partial connectivity network should cause the network being torn down 2539 assertEquals(network, cb.waitForLost()); 2540 } finally { 2541 mCm.unregisterNetworkCallback(cb); 2542 resetValidationConfig(); 2543 // Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot 2544 // apply here. Thus, turn off wifi first and restart to restore. 2545 runShellCommand("svc wifi disable"); 2546 mCtsNetUtils.ensureWifiConnected(); 2547 } 2548 } 2549 2550 @Test 2551 public void testSetAcceptUnvalidated_NoPermission_GetException() { 2552 assumeTrue(TestUtils.shouldTestSApis()); 2553 assertThrows(SecurityException.class, () -> mCm.setAcceptUnvalidated( 2554 mCm.getActiveNetwork(), false /* accept */ , false /* always */)); 2555 } 2556 2557 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2558 @Test 2559 public void testRejectUnvalidated_TearDownNetwork() throws Exception { 2560 assumeTrue(TestUtils.shouldTestSApis()); 2561 final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) 2562 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 2563 assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" 2564 + " unless device supports WiFi and telephony", canRunTest); 2565 2566 final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); 2567 try { 2568 // Ensure at least one default network candidate connected. 2569 mCtsNetUtils.connectToCell(); 2570 2571 final Network wifiNetwork = prepareUnvalidatedNetwork(); 2572 // Default network should not be wifi ,but checking that wifi is not the default doesn't 2573 // guarantee that it won't become the default in the future. 2574 assertNotEquals(wifiNetwork, mCm.getActiveNetwork()); 2575 2576 mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); 2577 runAsShell(NETWORK_SETTINGS, () -> { 2578 mCm.setAcceptUnvalidated(wifiNetwork, false /* accept */, false /* always */); 2579 }); 2580 waitForLost(wifiCb); 2581 } finally { 2582 mCm.unregisterNetworkCallback(wifiCb); 2583 resetValidationConfig(); 2584 /// Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot 2585 // apply here. Thus, turn off wifi first and restart to restore. 2586 runShellCommand("svc wifi disable"); 2587 mCtsNetUtils.ensureWifiConnected(); 2588 } 2589 } 2590 2591 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2592 @Test 2593 public void testSetAvoidUnvalidated() throws Exception { 2594 assumeTrue(TestUtils.shouldTestSApis()); 2595 // TODO: Allow in debuggable ROM only. To be replaced by FabricatedOverlay 2596 assumeTrue(Build.isDebuggable()); 2597 final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) 2598 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 2599 assumeTrue("testSetAvoidUnvalidated cannot execute" 2600 + " unless device supports WiFi and telephony", canRunTest); 2601 2602 final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); 2603 final TestableNetworkCallback defaultCb = new TestableNetworkCallback(); 2604 final int previousAvoidBadWifi = 2605 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext); 2606 2607 allowBadWifi(); 2608 2609 final Network cellNetwork = mCtsNetUtils.connectToCell(); 2610 final Network wifiNetwork = prepareValidatedNetwork(); 2611 2612 mCm.registerDefaultNetworkCallback(defaultCb); 2613 mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); 2614 2615 try { 2616 // Verify wifi is the default network. 2617 defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2618 entry -> wifiNetwork.equals(entry.getNetwork())); 2619 wifiCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2620 entry -> wifiNetwork.equals(entry.getNetwork())); 2621 assertTrue(mCm.getNetworkCapabilities(wifiNetwork).hasCapability( 2622 NET_CAPABILITY_VALIDATED)); 2623 2624 // Configure response code for unvalidated network 2625 configTestServer(Status.INTERNAL_ERROR, Status.INTERNAL_ERROR); 2626 mCm.reportNetworkConnectivity(wifiNetwork, false); 2627 // Default network should stay on unvalidated wifi because avoid bad wifi is disabled. 2628 defaultCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, 2629 NETWORK_CALLBACK_TIMEOUT_MS, 2630 entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps() 2631 .hasCapability(NET_CAPABILITY_VALIDATED)); 2632 wifiCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, 2633 NETWORK_CALLBACK_TIMEOUT_MS, 2634 entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps() 2635 .hasCapability(NET_CAPABILITY_VALIDATED)); 2636 2637 runAsShell(NETWORK_SETTINGS, () -> { 2638 mCm.setAvoidUnvalidated(wifiNetwork); 2639 }); 2640 // Default network should be updated to validated cellular network. 2641 defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2642 entry -> cellNetwork.equals(entry.getNetwork())); 2643 // No update on wifi callback. 2644 wifiCb.assertNoCallback(); 2645 } finally { 2646 mCm.unregisterNetworkCallback(wifiCb); 2647 mCm.unregisterNetworkCallback(defaultCb); 2648 resetAvoidBadWifi(previousAvoidBadWifi); 2649 resetValidationConfig(); 2650 // Reconnect wifi to reset the wifi status 2651 reconnectWifi(); 2652 } 2653 } 2654 2655 private void resetAvoidBadWifi(int settingValue) { 2656 setTestAllowBadWifiResource(0 /* timeMs */); 2657 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, settingValue); 2658 } 2659 2660 private void allowBadWifi() { 2661 setTestAllowBadWifiResource( 2662 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS /* timeMs */); 2663 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, 2664 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE); 2665 } 2666 2667 private void setTestAllowBadWifiResource(long timeMs) { 2668 runAsShell(NETWORK_SETTINGS, () -> { 2669 mCm.setTestAllowBadWifiUntil(timeMs); 2670 }); 2671 } 2672 2673 private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout) 2674 throws Exception { 2675 final CompletableFuture<Network> future = new CompletableFuture(); 2676 final NetworkCallback cb = new NetworkCallback() { 2677 @Override 2678 public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) { 2679 if (n.equals(network) && nc.hasCapability(expectedNetCap)) { 2680 future.complete(network); 2681 } 2682 } 2683 }; 2684 2685 try { 2686 mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), cb); 2687 return future.get(timeout, TimeUnit.MILLISECONDS); 2688 } finally { 2689 mCm.unregisterNetworkCallback(cb); 2690 } 2691 } 2692 2693 private void resetValidationConfig() { 2694 NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); 2695 mHttpServer.stop(); 2696 } 2697 2698 private void prepareHttpServer() throws Exception { 2699 runAsShell(READ_DEVICE_CONFIG, () -> { 2700 // Verify that the test URLs are not normally set on the device, but do not fail if the 2701 // test URLs are set to what this test uses (URLs on localhost), in case the test was 2702 // interrupted manually and rerun. 2703 assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL); 2704 assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL); 2705 }); 2706 2707 NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); 2708 2709 mHttpServer.start(); 2710 } 2711 2712 private Network reconnectWifi() { 2713 mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); 2714 return mCtsNetUtils.ensureWifiConnected(); 2715 } 2716 2717 private Network prepareValidatedNetwork() throws Exception { 2718 prepareHttpServer(); 2719 configTestServer(Status.NO_CONTENT, Status.NO_CONTENT); 2720 // Disconnect wifi first then start wifi network with configuration. 2721 final Network wifiNetwork = reconnectWifi(); 2722 2723 return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_VALIDATED, 2724 WIFI_CONNECT_TIMEOUT_MS); 2725 } 2726 2727 private Network preparePartialConnectivity() throws Exception { 2728 prepareHttpServer(); 2729 // Configure response code for partial connectivity 2730 configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, 2731 Status.NO_CONTENT /* httpStatusCode */); 2732 // Disconnect wifi first then start wifi network with configuration. 2733 mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); 2734 final Network network = mCtsNetUtils.ensureWifiConnected(); 2735 2736 return expectNetworkHasCapability(network, NET_CAPABILITY_PARTIAL_CONNECTIVITY, 2737 WIFI_CONNECT_TIMEOUT_MS); 2738 } 2739 2740 private Network prepareUnvalidatedNetwork() throws Exception { 2741 prepareHttpServer(); 2742 // Configure response code for unvalidated network 2743 configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, 2744 Status.INTERNAL_ERROR /* httpStatusCode */); 2745 2746 // Disconnect wifi first then start wifi network with configuration. 2747 mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); 2748 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2749 return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_INTERNET, 2750 WIFI_CONNECT_TIMEOUT_MS); 2751 } 2752 2753 private String makeUrl(String path) { 2754 return "http://localhost:" + mHttpServer.getListeningPort() + path; 2755 } 2756 2757 private void assertEmptyOrLocalhostUrl(String urlKey) { 2758 final String url = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, urlKey); 2759 assertTrue(urlKey + " must not be set in production scenarios, current value= " + url, 2760 TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME.equals(Uri.parse(url).getHost())); 2761 } 2762 2763 private void configTestServer(IStatus httpsStatusCode, IStatus httpStatusCode) { 2764 mHttpServer.addResponse(new TestHttpServer.Request( 2765 TEST_HTTPS_URL_PATH, Method.GET, "" /* queryParameters */), 2766 httpsStatusCode, null /* locationHeader */, "" /* content */); 2767 mHttpServer.addResponse(new TestHttpServer.Request( 2768 TEST_HTTP_URL_PATH, Method.GET, "" /* queryParameters */), 2769 httpStatusCode, null /* locationHeader */, "" /* content */); 2770 NetworkValidationTestUtil.setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)); 2771 NetworkValidationTestUtil.setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)); 2772 NetworkValidationTestUtil.setUrlExpirationDeviceConfig( 2773 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS); 2774 } 2775 2776 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 2777 @Test 2778 public void testMobileDataPreferredUids() throws Exception { 2779 assumeTrue(TestUtils.shouldTestSApis()); 2780 final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) 2781 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 2782 assumeTrue("testMobileDataPreferredUidsWithCallback cannot execute" 2783 + " unless device supports both WiFi and telephony", canRunTest); 2784 2785 final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */); 2786 final Set<Integer> mobileDataPreferredUids = 2787 ConnectivitySettingsManager.getMobileDataPreferredUids(mContext); 2788 // CtsNetTestCases uid should not list in MOBILE_DATA_PREFERRED_UIDS setting because it just 2789 // installs to device. In case the uid is existed in setting mistakenly, try to remove the 2790 // uid and set correct uids to setting. 2791 mobileDataPreferredUids.remove(uid); 2792 ConnectivitySettingsManager.setMobileDataPreferredUids(mContext, mobileDataPreferredUids); 2793 2794 // For testing mobile data preferred uids feature, it needs both wifi and cell network. 2795 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2796 final Network cellNetwork = mCtsNetUtils.connectToCell(); 2797 final TestableNetworkCallback defaultTrackingCb = new TestableNetworkCallback(); 2798 final TestableNetworkCallback systemDefaultCb = new TestableNetworkCallback(); 2799 final Handler h = new Handler(Looper.getMainLooper()); 2800 runWithShellPermissionIdentity(() -> mCm.registerSystemDefaultNetworkCallback( 2801 systemDefaultCb, h), NETWORK_SETTINGS); 2802 mCm.registerDefaultNetworkCallback(defaultTrackingCb); 2803 2804 try { 2805 // CtsNetTestCases uid is not listed in MOBILE_DATA_PREFERRED_UIDS setting, so the 2806 // per-app default network should be same as system default network. 2807 waitForAvailable(systemDefaultCb, wifiNetwork); 2808 defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2809 entry -> wifiNetwork.equals(entry.getNetwork())); 2810 // Active network for CtsNetTestCases uid should be wifi now. 2811 assertEquals(wifiNetwork, mCm.getActiveNetwork()); 2812 2813 // Add CtsNetTestCases uid to MOBILE_DATA_PREFERRED_UIDS setting, then available per-app 2814 // default network callback should be received with cell network. 2815 final Set<Integer> newMobileDataPreferredUids = new ArraySet<>(mobileDataPreferredUids); 2816 newMobileDataPreferredUids.add(uid); 2817 ConnectivitySettingsManager.setMobileDataPreferredUids( 2818 mContext, newMobileDataPreferredUids); 2819 defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2820 entry -> cellNetwork.equals(entry.getNetwork())); 2821 // System default network doesn't change. 2822 systemDefaultCb.assertNoCallback(); 2823 // Active network for CtsNetTestCases uid should change to cell, too. 2824 assertEquals(cellNetwork, mCm.getActiveNetwork()); 2825 2826 // Remove CtsNetTestCases uid from MOBILE_DATA_PREFERRED_UIDS setting, then available 2827 // per-app default network callback should be received again with system default network 2828 newMobileDataPreferredUids.remove(uid); 2829 ConnectivitySettingsManager.setMobileDataPreferredUids( 2830 mContext, newMobileDataPreferredUids); 2831 defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2832 entry -> wifiNetwork.equals(entry.getNetwork())); 2833 // System default network still doesn't change. 2834 systemDefaultCb.assertNoCallback(); 2835 // Active network for CtsNetTestCases uid should change back to wifi. 2836 assertEquals(wifiNetwork, mCm.getActiveNetwork()); 2837 } finally { 2838 mCm.unregisterNetworkCallback(systemDefaultCb); 2839 mCm.unregisterNetworkCallback(defaultTrackingCb); 2840 2841 // Restore setting. 2842 ConnectivitySettingsManager.setMobileDataPreferredUids( 2843 mContext, mobileDataPreferredUids); 2844 } 2845 } 2846 2847 /** Wait for assigned time. */ 2848 private void waitForMs(long ms) { 2849 try { 2850 Thread.sleep(ms); 2851 } catch (InterruptedException e) { 2852 fail("Thread was interrupted"); 2853 } 2854 } 2855 2856 private void assertBindSocketToNetworkSuccess(final Network network) throws Exception { 2857 final CompletableFuture<Boolean> future = new CompletableFuture<>(); 2858 final ExecutorService executor = Executors.newSingleThreadExecutor(); 2859 try { 2860 executor.execute(() -> { 2861 for (int i = 0; i < 30; i++) { 2862 waitForMs(100); 2863 2864 try (Socket socket = new Socket()) { 2865 network.bindSocket(socket); 2866 future.complete(true); 2867 return; 2868 } catch (IOException e) { } 2869 } 2870 }); 2871 assertTrue(future.get(APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS, 2872 TimeUnit.MILLISECONDS)); 2873 } finally { 2874 executor.shutdown(); 2875 } 2876 } 2877 2878 @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") 2879 @Test 2880 public void testUidsAllowedOnRestrictedNetworks() throws Exception { 2881 assumeTrue(TestUtils.shouldTestSApis()); 2882 2883 // TODO (b/175199465): figure out a reasonable permission check for 2884 // setUidsAllowedOnRestrictedNetworks that allows tests but not system-external callers. 2885 assumeTrue(Build.isDebuggable()); 2886 2887 final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */); 2888 final Set<Integer> originalUidsAllowedOnRestrictedNetworks = 2889 ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext); 2890 // CtsNetTestCases uid should not list in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting 2891 // because it has been just installed to device. In case the uid is existed in setting 2892 // mistakenly, try to remove the uid and set correct uids to setting. 2893 originalUidsAllowedOnRestrictedNetworks.remove(uid); 2894 runWithShellPermissionIdentity(() -> 2895 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks( 2896 mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS); 2897 2898 final Handler h = new Handler(Looper.getMainLooper()); 2899 final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback(); 2900 mCm.registerBestMatchingNetworkCallback(new NetworkRequest.Builder().clearCapabilities() 2901 .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), testNetworkCb, h); 2902 2903 // Create test network agent with restricted network. 2904 final NetworkCapabilities nc = new NetworkCapabilities.Builder() 2905 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 2906 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 2907 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 2908 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) 2909 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 2910 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 2911 .build(); 2912 final NetworkScore score = new NetworkScore.Builder() 2913 .setExiting(false) 2914 .setTransportPrimary(false) 2915 .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER) 2916 .build(); 2917 final NetworkAgent agent = new NetworkAgent(mContext, Looper.getMainLooper(), 2918 TAG, nc, new LinkProperties(), score, new NetworkAgentConfig.Builder().build(), 2919 new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {}; 2920 runWithShellPermissionIdentity(() -> agent.register(), 2921 android.Manifest.permission.MANAGE_TEST_NETWORKS); 2922 agent.markConnected(); 2923 2924 final Network network = agent.getNetwork(); 2925 2926 try (Socket socket = new Socket()) { 2927 testNetworkCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2928 entry -> network.equals(entry.getNetwork())); 2929 // Verify that the network is restricted. 2930 final NetworkCapabilities testNetworkNc = mCm.getNetworkCapabilities(network); 2931 assertNotNull(testNetworkNc); 2932 assertFalse(testNetworkNc.hasCapability( 2933 NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); 2934 // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it 2935 // does not allow to bind socket to restricted network. 2936 assertThrows(IOException.class, () -> network.bindSocket(socket)); 2937 2938 // Add CtsNetTestCases uid to UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting, then it can 2939 // bind socket to restricted network normally. 2940 final Set<Integer> newUidsAllowedOnRestrictedNetworks = 2941 new ArraySet<>(originalUidsAllowedOnRestrictedNetworks); 2942 newUidsAllowedOnRestrictedNetworks.add(uid); 2943 runWithShellPermissionIdentity(() -> 2944 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks( 2945 mContext, newUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS); 2946 // Wait a while for sending allowed uids on the restricted network to netd. 2947 // TODD: Have a significant signal to know the uids has been send to netd. 2948 assertBindSocketToNetworkSuccess(network); 2949 } finally { 2950 mCm.unregisterNetworkCallback(testNetworkCb); 2951 agent.unregister(); 2952 2953 // Restore setting. 2954 runWithShellPermissionIdentity(() -> 2955 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks( 2956 mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS); 2957 } 2958 } 2959 } 2960