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 waitForValidation, final boolean useSystemDefault)1105 private Network waitForActiveNetworkMetered(final int targetTransportType, 1106 final boolean requestedMeteredness, final boolean waitForValidation, 1107 final boolean useSystemDefault) 1108 throws Exception { 1109 final CompletableFuture<Network> networkFuture = new CompletableFuture<>(); 1110 final NetworkCallback networkCallback = new NetworkCallback() { 1111 @Override 1112 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { 1113 if (!nc.hasTransport(targetTransportType)) return; 1114 1115 final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); 1116 final boolean validated = nc.hasCapability(NET_CAPABILITY_VALIDATED); 1117 if (metered == requestedMeteredness && (!waitForValidation || validated)) { 1118 networkFuture.complete(network); 1119 } 1120 } 1121 }; 1122 1123 try { 1124 // Registering a callback here guarantees onCapabilitiesChanged is called immediately 1125 // with the current setting. Therefore, if the setting has already been changed, 1126 // this method will return right away, and if not, it'll wait for the setting to change. 1127 if (useSystemDefault) { 1128 runWithShellPermissionIdentity(() -> 1129 mCmShim.registerSystemDefaultNetworkCallback(networkCallback, 1130 new Handler(Looper.getMainLooper())), 1131 NETWORK_SETTINGS); 1132 } else { 1133 mCm.registerDefaultNetworkCallback(networkCallback); 1134 } 1135 1136 // Changing meteredness on wifi involves reconnecting, which can take several seconds 1137 // (involves re-associating, DHCP...). 1138 return networkFuture.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1139 } catch (TimeoutException e) { 1140 throw new AssertionError("Timed out waiting for active network metered status to " 1141 + "change to " + requestedMeteredness + " ; network = " 1142 + mCm.getActiveNetwork(), e); 1143 } finally { 1144 mCm.unregisterNetworkCallback(networkCallback); 1145 } 1146 } 1147 setWifiMeteredStatusAndWait(String ssid, boolean isMetered, boolean waitForValidation)1148 private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered, 1149 boolean waitForValidation) throws Exception { 1150 setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */); 1151 mCtsNetUtils.ensureWifiConnected(); 1152 return waitForActiveNetworkMetered(TRANSPORT_WIFI, 1153 isMetered /* requestedMeteredness */, 1154 waitForValidation, 1155 true /* useSystemDefault */); 1156 } 1157 assertMultipathPreferenceIsEventually(Network network, int oldValue, int expectedValue)1158 private void assertMultipathPreferenceIsEventually(Network network, int oldValue, 1159 int expectedValue) { 1160 // Quick check : if oldValue == expectedValue, there is no way to guarantee the test 1161 // is not flaky. 1162 assertNotSame(oldValue, expectedValue); 1163 1164 for (int i = 0; i < NUM_TRIES_MULTIPATH_PREF_CHECK; ++i) { 1165 final int actualValue = mCm.getMultipathPreference(network); 1166 if (actualValue == expectedValue) { 1167 return; 1168 } 1169 if (actualValue != oldValue) { 1170 fail("Multipath preference is neither previous (" + oldValue 1171 + ") nor expected (" + expectedValue + ")"); 1172 } 1173 SystemClock.sleep(INTERVAL_MULTIPATH_PREF_CHECK_MS); 1174 } 1175 fail("Timed out waiting for multipath preference to change. expected = " 1176 + expectedValue + " ; actual = " + mCm.getMultipathPreference(network)); 1177 } 1178 getCurrentMeteredMultipathPreference(ContentResolver resolver)1179 private int getCurrentMeteredMultipathPreference(ContentResolver resolver) { 1180 final String rawMeteredPref = Settings.Global.getString(resolver, 1181 NETWORK_METERED_MULTIPATH_PREFERENCE); 1182 return TextUtils.isEmpty(rawMeteredPref) 1183 ? getIntResourceForName(NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME) 1184 : Integer.parseInt(rawMeteredPref); 1185 } 1186 findNextPrefValue(ContentResolver resolver)1187 private int findNextPrefValue(ContentResolver resolver) { 1188 // A bit of a nuclear hammer, but race conditions in CTS are bad. To be able to 1189 // detect a correct setting value without race conditions, the next pref must 1190 // be a valid value (range 0..3) that is different from the old setting of the 1191 // metered preference and from the unmetered preference. 1192 final int meteredPref = getCurrentMeteredMultipathPreference(resolver); 1193 final int unmeteredPref = ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED; 1194 if (0 != meteredPref && 0 != unmeteredPref) return 0; 1195 if (1 != meteredPref && 1 != unmeteredPref) return 1; 1196 return 2; 1197 } 1198 1199 /** 1200 * Verify that getMultipathPreference does return appropriate values 1201 * for metered and unmetered networks. 1202 */ 1203 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1204 @Test testGetMultipathPreference()1205 public void testGetMultipathPreference() throws Exception { 1206 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1207 final ContentResolver resolver = mContext.getContentResolver(); 1208 mCtsNetUtils.ensureWifiConnected(); 1209 final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); 1210 final String oldMeteredSetting = getWifiMeteredStatus(ssid); 1211 final String oldMeteredMultipathPreference = Settings.Global.getString( 1212 resolver, NETWORK_METERED_MULTIPATH_PREFERENCE); 1213 try { 1214 final int initialMeteredPreference = getCurrentMeteredMultipathPreference(resolver); 1215 int newMeteredPreference = findNextPrefValue(resolver); 1216 Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, 1217 Integer.toString(newMeteredPreference)); 1218 // Wifi meteredness changes from unmetered to metered will disconnect and reconnect 1219 // since R. 1220 final Network network = setWifiMeteredStatusAndWait(ssid, true /* isMetered */, 1221 false /* waitForValidation */); 1222 assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID())); 1223 assertEquals(mCm.getNetworkCapabilities(network).hasCapability( 1224 NET_CAPABILITY_NOT_METERED), false); 1225 assertMultipathPreferenceIsEventually(network, initialMeteredPreference, 1226 newMeteredPreference); 1227 1228 final int oldMeteredPreference = newMeteredPreference; 1229 newMeteredPreference = findNextPrefValue(resolver); 1230 Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, 1231 Integer.toString(newMeteredPreference)); 1232 assertEquals(mCm.getNetworkCapabilities(network).hasCapability( 1233 NET_CAPABILITY_NOT_METERED), false); 1234 assertMultipathPreferenceIsEventually(network, 1235 oldMeteredPreference, newMeteredPreference); 1236 1237 // No disconnect from unmetered to metered. 1238 setWifiMeteredStatusAndWait(ssid, false /* isMetered */, false /* waitForValidation */); 1239 assertEquals(mCm.getNetworkCapabilities(network).hasCapability( 1240 NET_CAPABILITY_NOT_METERED), true); 1241 assertMultipathPreferenceIsEventually(network, newMeteredPreference, 1242 ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED); 1243 } finally { 1244 Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, 1245 oldMeteredMultipathPreference); 1246 setWifiMeteredStatus(ssid, oldMeteredSetting); 1247 } 1248 } 1249 1250 // TODO: move the following socket keep alive test to dedicated test class. 1251 /** 1252 * Callback used in tcp keepalive offload that allows caller to wait callback fires. 1253 */ 1254 private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback { 1255 public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; 1256 1257 public static class CallbackValue { 1258 public final CallbackType callbackType; 1259 public final int error; 1260 CallbackValue(final CallbackType type, final int error)1261 private CallbackValue(final CallbackType type, final int error) { 1262 this.callbackType = type; 1263 this.error = error; 1264 } 1265 1266 public static class OnStartedCallback extends CallbackValue { OnStartedCallback()1267 OnStartedCallback() { super(CallbackType.ON_STARTED, 0); } 1268 } 1269 1270 public static class OnStoppedCallback extends CallbackValue { OnStoppedCallback()1271 OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); } 1272 } 1273 1274 public static class OnErrorCallback extends CallbackValue { OnErrorCallback(final int error)1275 OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); } 1276 } 1277 1278 @Override equals(Object o)1279 public boolean equals(Object o) { 1280 return o.getClass() == this.getClass() 1281 && this.callbackType == ((CallbackValue) o).callbackType 1282 && this.error == ((CallbackValue) o).error; 1283 } 1284 1285 @Override toString()1286 public String toString() { 1287 return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error); 1288 } 1289 } 1290 1291 private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>(); 1292 1293 @Override onStarted()1294 public void onStarted() { 1295 mCallbacks.add(new CallbackValue.OnStartedCallback()); 1296 } 1297 1298 @Override onStopped()1299 public void onStopped() { 1300 mCallbacks.add(new CallbackValue.OnStoppedCallback()); 1301 } 1302 1303 @Override onError(final int error)1304 public void onError(final int error) { 1305 mCallbacks.add(new CallbackValue.OnErrorCallback(error)); 1306 } 1307 pollCallback()1308 public CallbackValue pollCallback() { 1309 try { 1310 return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS, 1311 TimeUnit.MILLISECONDS); 1312 } catch (InterruptedException e) { 1313 fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms"); 1314 } 1315 return null; 1316 } expectCallback(CallbackValue expectedCallback)1317 private void expectCallback(CallbackValue expectedCallback) { 1318 final CallbackValue actualCallback = pollCallback(); 1319 assertEquals(expectedCallback, actualCallback); 1320 } 1321 expectStarted()1322 public void expectStarted() { 1323 expectCallback(new CallbackValue.OnStartedCallback()); 1324 } 1325 expectStopped()1326 public void expectStopped() { 1327 expectCallback(new CallbackValue.OnStoppedCallback()); 1328 } 1329 expectError(int error)1330 public void expectError(int error) { 1331 expectCallback(new CallbackValue.OnErrorCallback(error)); 1332 } 1333 } 1334 getAddrByName(final String hostname, final int family)1335 private InetAddress getAddrByName(final String hostname, final int family) throws Exception { 1336 final InetAddress[] allAddrs = InetAddress.getAllByName(hostname); 1337 for (InetAddress addr : allAddrs) { 1338 if (family == AF_INET && addr instanceof Inet4Address) return addr; 1339 1340 if (family == AF_INET6 && addr instanceof Inet6Address) return addr; 1341 1342 if (family == AF_UNSPEC) return addr; 1343 } 1344 return null; 1345 } 1346 getConnectedSocket(final Network network, final String host, final int port, final int family)1347 private Socket getConnectedSocket(final Network network, final String host, final int port, 1348 final int family) throws Exception { 1349 final Socket s = network.getSocketFactory().createSocket(); 1350 try { 1351 final InetAddress addr = getAddrByName(host, family); 1352 if (addr == null) fail("Fail to get destination address for " + family); 1353 1354 final InetSocketAddress sockAddr = new InetSocketAddress(addr, port); 1355 s.connect(sockAddr); 1356 } catch (Exception e) { 1357 s.close(); 1358 throw e; 1359 } 1360 return s; 1361 } 1362 getSupportedKeepalivesForNet(@onNull Network network)1363 private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception { 1364 final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); 1365 1366 // Get number of supported concurrent keepalives for testing network. 1367 final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); 1368 return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( 1369 keepalivesPerTransport, nc); 1370 } 1371 isTcpKeepaliveSupportedByKernel()1372 private static boolean isTcpKeepaliveSupportedByKernel() { 1373 final String kVersionString = VintfRuntimeInfo.getKernelVersion(); 1374 return compareMajorMinorVersion(kVersionString, "4.8") >= 0; 1375 } 1376 getVersionFromString(String version)1377 private static Pair<Integer, Integer> getVersionFromString(String version) { 1378 // Only gets major and minor number of the version string. 1379 final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); 1380 final Matcher m = versionPattern.matcher(version); 1381 if (m.matches()) { 1382 final int major = Integer.parseInt(m.group(1)); 1383 final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); 1384 return new Pair<>(major, minor); 1385 } else { 1386 return new Pair<>(0, 0); 1387 } 1388 } 1389 1390 // TODO: Move to util class. compareMajorMinorVersion(final String s1, final String s2)1391 private static int compareMajorMinorVersion(final String s1, final String s2) { 1392 final Pair<Integer, Integer> v1 = getVersionFromString(s1); 1393 final Pair<Integer, Integer> v2 = getVersionFromString(s2); 1394 1395 if (v1.first == v2.first) { 1396 return Integer.compare(v1.second, v2.second); 1397 } else { 1398 return Integer.compare(v1.first, v2.first); 1399 } 1400 } 1401 1402 /** 1403 * Verifies that version string compare logic returns expected result for various cases. 1404 * Note that only major and minor number are compared. 1405 */ 1406 @Test testMajorMinorVersionCompare()1407 public void testMajorMinorVersionCompare() { 1408 assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); 1409 assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); 1410 assertEquals(1, compareMajorMinorVersion("5.0", "4.8")); 1411 assertEquals(1, compareMajorMinorVersion("5", "4.8")); 1412 assertEquals(0, compareMajorMinorVersion("5", "5.0")); 1413 assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8")); 1414 assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8")); 1415 assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8")); 1416 assertEquals(0, compareMajorMinorVersion("4.8", "4.8")); 1417 assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0")); 1418 assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8")); 1419 } 1420 1421 /** 1422 * Verifies that the keepalive API cannot create any keepalive when the maximum number of 1423 * keepalives is set to 0. 1424 */ 1425 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1426 @Test testKeepaliveWifiUnsupported()1427 public void testKeepaliveWifiUnsupported() throws Exception { 1428 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1429 1430 final Network network = mCtsNetUtils.ensureWifiConnected(); 1431 if (getSupportedKeepalivesForNet(network) != 0) return; 1432 final InetAddress srcAddr = getFirstV4Address(network); 1433 assumeTrue("This test requires native IPv4", srcAddr != null); 1434 1435 runWithShellPermissionIdentity(() -> { 1436 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0)); 1437 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); 1438 }); 1439 } 1440 1441 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1442 @Test 1443 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") testCreateTcpKeepalive()1444 public void testCreateTcpKeepalive() throws Exception { 1445 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1446 1447 final Network network = mCtsNetUtils.ensureWifiConnected(); 1448 if (getSupportedKeepalivesForNet(network) == 0) return; 1449 final InetAddress srcAddr = getFirstV4Address(network); 1450 assumeTrue("This test requires native IPv4", srcAddr != null); 1451 1452 // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support 1453 // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive 1454 // needs to be supported except if the kernel doesn't support it. 1455 if (!isTcpKeepaliveSupportedByKernel()) { 1456 // Verify that the callback result is expected. 1457 runWithShellPermissionIdentity(() -> { 1458 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); 1459 }); 1460 Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " 1461 + VintfRuntimeInfo.getKernelVersion()); 1462 return; 1463 } 1464 1465 final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); 1466 // So far only ipv4 tcp keepalive offload is supported. 1467 // TODO: add test case for ipv6 tcp keepalive offload when it is supported. 1468 try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, AF_INET)) { 1469 1470 // Should able to start keep alive offload when socket is idle. 1471 final Executor executor = mContext.getMainExecutor(); 1472 final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); 1473 1474 mUiAutomation.adoptShellPermissionIdentity(); 1475 try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { 1476 sk.start(MIN_KEEPALIVE_INTERVAL); 1477 callback.expectStarted(); 1478 1479 // App should not able to write during keepalive offload. 1480 final OutputStream out = s.getOutputStream(); 1481 try { 1482 out.write(requestBytes); 1483 fail("Should not able to write"); 1484 } catch (IOException e) { } 1485 // App should not able to read during keepalive offload. 1486 final InputStream in = s.getInputStream(); 1487 byte[] responseBytes = new byte[4096]; 1488 try { 1489 in.read(responseBytes); 1490 fail("Should not able to read"); 1491 } catch (IOException e) { } 1492 1493 // Stop. 1494 sk.stop(); 1495 callback.expectStopped(); 1496 } finally { 1497 mUiAutomation.dropShellPermissionIdentity(); 1498 } 1499 1500 // Ensure socket is still connected. 1501 assertTrue(s.isConnected()); 1502 assertFalse(s.isClosed()); 1503 1504 // Let socket be not idle. 1505 try { 1506 final OutputStream out = s.getOutputStream(); 1507 out.write(requestBytes); 1508 } catch (IOException e) { 1509 fail("Failed to write data " + e); 1510 } 1511 // Make sure response data arrives. 1512 final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue(); 1513 final FileDescriptor fd = s.getFileDescriptor$(); 1514 final CountDownLatch mOnReceiveLatch = new CountDownLatch(1); 1515 fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> { 1516 mOnReceiveLatch.countDown(); 1517 return 0; // Unregister listener. 1518 }); 1519 if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) { 1520 fdHandlerQueue.removeOnFileDescriptorEventListener(fd); 1521 fail("Timeout: no response data"); 1522 } 1523 1524 // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue 1525 // that has not been read. 1526 mUiAutomation.adoptShellPermissionIdentity(); 1527 try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { 1528 sk.start(MIN_KEEPALIVE_INTERVAL); 1529 callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); 1530 } finally { 1531 mUiAutomation.dropShellPermissionIdentity(); 1532 } 1533 } 1534 } 1535 createConcurrentKeepalivesOfType( int requestCount, @NonNull TestSocketKeepaliveCallback callback, Supplier<SocketKeepalive> kaFactory)1536 private ArrayList<SocketKeepalive> createConcurrentKeepalivesOfType( 1537 int requestCount, @NonNull TestSocketKeepaliveCallback callback, 1538 Supplier<SocketKeepalive> kaFactory) { 1539 final ArrayList<SocketKeepalive> kalist = new ArrayList<>(); 1540 1541 int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT; 1542 1543 // Test concurrent keepalives with the given supplier. 1544 while (kalist.size() < requestCount) { 1545 final SocketKeepalive ka = kaFactory.get(); 1546 ka.start(MIN_KEEPALIVE_INTERVAL); 1547 TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); 1548 assertNotNull(cv); 1549 if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { 1550 if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { 1551 // Unsupported. 1552 break; 1553 } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { 1554 // Limit reached or temporary unavailable due to stopped slot is not yet 1555 // released. 1556 if (remainingRetries > 0) { 1557 SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS); 1558 remainingRetries--; 1559 continue; 1560 } 1561 break; 1562 } 1563 } 1564 if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { 1565 kalist.add(ka); 1566 } else { 1567 fail("Unexpected error when creating " + (kalist.size() + 1) + " " 1568 + ka.getClass().getSimpleName() + ": " + cv); 1569 } 1570 } 1571 1572 return kalist; 1573 } 1574 createConcurrentNattSocketKeepalives( @onNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1575 private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives( 1576 @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount, 1577 @NonNull TestSocketKeepaliveCallback callback) throws Exception { 1578 1579 final Executor executor = mContext.getMainExecutor(); 1580 1581 // Initialize a real NaT-T socket. 1582 final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); 1583 final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); 1584 final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); 1585 assertNotNull(srcAddr); 1586 assertNotNull(dstAddr); 1587 1588 // Test concurrent Nat-T keepalives. 1589 final ArrayList<SocketKeepalive> result = createConcurrentKeepalivesOfType(requestCount, 1590 callback, () -> mCm.createSocketKeepalive(network, nattSocket, 1591 srcAddr, dstAddr, executor, callback)); 1592 1593 nattSocket.close(); 1594 return result; 1595 } 1596 createConcurrentTcpSocketKeepalives( @onNull Network network, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1597 private @NonNull ArrayList<SocketKeepalive> createConcurrentTcpSocketKeepalives( 1598 @NonNull Network network, int requestCount, 1599 @NonNull TestSocketKeepaliveCallback callback) { 1600 final Executor executor = mContext.getMainExecutor(); 1601 1602 // Create concurrent TCP keepalives. 1603 return createConcurrentKeepalivesOfType(requestCount, callback, () -> { 1604 // Assert that TCP connections can be established. The file descriptor of tcp 1605 // sockets will be duplicated and kept valid in service side if the keepalives are 1606 // successfully started. 1607 try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, 1608 AF_INET)) { 1609 return mCm.createSocketKeepalive(network, tcpSocket, executor, callback); 1610 } catch (Exception e) { 1611 fail("Unexpected error when creating TCP socket: " + e); 1612 } 1613 return null; 1614 }); 1615 } 1616 1617 /** 1618 * Creates concurrent keepalives until the specified counts of each type of keepalives are 1619 * reached or the expected error callbacks are received for each type of keepalives. 1620 * 1621 * @return the total number of keepalives created. 1622 */ 1623 private int createConcurrentSocketKeepalives( 1624 @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount) 1625 throws Exception { 1626 final ArrayList<SocketKeepalive> kalist = new ArrayList<>(); 1627 final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); 1628 1629 kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback)); 1630 kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); 1631 1632 final int ret = kalist.size(); 1633 1634 // Clean up. 1635 for (final SocketKeepalive ka : kalist) { 1636 ka.stop(); 1637 callback.expectStopped(); 1638 } 1639 kalist.clear(); 1640 1641 return ret; 1642 } 1643 1644 /** 1645 * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't 1646 * get leaked after iterations. 1647 */ 1648 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1649 @Test 1650 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") 1651 public void testSocketKeepaliveLimitWifi() throws Exception { 1652 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1653 1654 final Network network = mCtsNetUtils.ensureWifiConnected(); 1655 final int supported = getSupportedKeepalivesForNet(network); 1656 if (supported == 0) { 1657 return; 1658 } 1659 final InetAddress srcAddr = getFirstV4Address(network); 1660 assumeTrue("This test requires native IPv4", srcAddr != null); 1661 1662 runWithShellPermissionIdentity(() -> { 1663 // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. 1664 assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); 1665 1666 // Verifies that Nat-T keepalives can be established. 1667 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1668 supported + 1, 0)); 1669 // Verifies that keepalives don't get leaked in second round. 1670 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, 1671 0)); 1672 }); 1673 1674 // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support 1675 // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. 1676 if (!isTcpKeepaliveSupportedByKernel()) return; 1677 1678 runWithShellPermissionIdentity(() -> { 1679 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, 1680 supported + 1)); 1681 1682 // Verifies that different types can be established at the same time. 1683 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1684 supported / 2, supported - supported / 2)); 1685 1686 // Verifies that keepalives don't get leaked in second round. 1687 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, 1688 supported)); 1689 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1690 supported / 2, supported - supported / 2)); 1691 }); 1692 } 1693 1694 /** 1695 * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and 1696 * don't get leaked after iterations. 1697 */ 1698 @AppModeFull(reason = "Cannot request network in instant app mode") 1699 @Test 1700 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") 1701 public void testSocketKeepaliveLimitTelephony() throws Exception { 1702 if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { 1703 Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" 1704 + " supports telephony"); 1705 return; 1706 } 1707 1708 final int firstSdk = SdkLevel.isAtLeastS() 1709 ? Build.VERSION.DEVICE_INITIAL_SDK_INT 1710 // FIRST_SDK_INT was a @TestApi field renamed to DEVICE_INITIAL_SDK_INT in S 1711 : Build.VERSION.class.getField("FIRST_SDK_INT").getInt(null); 1712 if (firstSdk < Build.VERSION_CODES.Q) { 1713 Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching" 1714 + " before Q: " + firstSdk); 1715 return; 1716 } 1717 1718 final Network network = mCtsNetUtils.connectToCell(); 1719 final int supported = getSupportedKeepalivesForNet(network); 1720 final InetAddress srcAddr = getFirstV4Address(network); 1721 assumeTrue("This test requires native IPv4", srcAddr != null); 1722 1723 runWithShellPermissionIdentity(() -> { 1724 // Verifies that the supported keepalive slots meet minimum requirement. 1725 assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); 1726 // Verifies that Nat-T keepalives can be established. 1727 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 1728 supported + 1, 0)); 1729 // Verifies that keepalives don't get leaked in second round. 1730 assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, 1731 0)); 1732 }); 1733 } 1734 1735 private int getIntResourceForName(@NonNull String resName) { 1736 final Resources r = mContext.getResources(); 1737 final int resId = r.getIdentifier(resName, "integer", "android"); 1738 return r.getInteger(resId); 1739 } 1740 1741 /** 1742 * Verifies that the keepalive slots are limited as customized for unprivileged requests. 1743 */ 1744 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1745 @Test 1746 @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware") 1747 public void testSocketKeepaliveUnprivileged() throws Exception { 1748 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1749 1750 final Network network = mCtsNetUtils.ensureWifiConnected(); 1751 final int supported = getSupportedKeepalivesForNet(network); 1752 if (supported == 0) { 1753 return; 1754 } 1755 final InetAddress srcAddr = getFirstV4Address(network); 1756 assumeTrue("This test requires native IPv4", srcAddr != null); 1757 1758 // Resource ID might be shifted on devices that compiled with different symbols. 1759 // Thus, resolve ID at runtime is needed. 1760 final int allowedUnprivilegedPerUid = 1761 getIntResourceForName(KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME); 1762 final int reservedPrivilegedSlots = 1763 getIntResourceForName(KEEPALIVE_RESERVED_PER_SLOT_RES_NAME); 1764 // Verifies that unprivileged request per uid cannot exceed the limit customized in the 1765 // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test 1766 // does not apply to TCP. 1767 assertGreaterOrEqual(supported, reservedPrivilegedSlots); 1768 assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); 1769 final int expectedUnprivileged = 1770 Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); 1771 assertEquals(expectedUnprivileged, 1772 createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0)); 1773 } 1774 1775 private static void assertGreaterOrEqual(long greater, long lesser) { 1776 assertTrue("" + greater + " expected to be greater than or equal to " + lesser, 1777 greater >= lesser); 1778 } 1779 1780 /** 1781 * Verifies that apps are not allowed to access restricted networks even if they declare the 1782 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests. 1783 * See. b/144679405. 1784 */ 1785 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1786 @Test 1787 public void testRestrictedNetworkPermission() throws Exception { 1788 // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. 1789 final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(), 1790 GET_PERMISSIONS); 1791 final int index = ArrayUtils.indexOf( 1792 app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS); 1793 assertTrue(index >= 0); 1794 assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED); 1795 1796 // Ensure that NetworkUtils.queryUserAccess always returns false since this package should 1797 // not have netd system permission to call this function. 1798 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 1799 assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId)); 1800 1801 // Ensure that this package cannot bind to any restricted network that's currently 1802 // connected. 1803 Network[] networks = mCm.getAllNetworks(); 1804 for (Network network : networks) { 1805 NetworkCapabilities nc = mCm.getNetworkCapabilities(network); 1806 if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { 1807 try { 1808 network.bindSocket(new Socket()); 1809 fail("Bind to restricted network " + network + " unexpectedly succeeded"); 1810 } catch (IOException expected) {} 1811 } 1812 } 1813 } 1814 1815 /** 1816 * Verifies that apps are allowed to call setAirplaneMode if they declare 1817 * NETWORK_AIRPLANE_MODE permission in their manifests. 1818 * See b/145164696. 1819 */ 1820 @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps") 1821 @Test 1822 public void testSetAirplaneMode() throws Exception{ 1823 final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI); 1824 final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 1825 // store the current state of airplane mode 1826 final boolean isAirplaneModeEnabled = isAirplaneModeEnabled(); 1827 final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); 1828 final TestableNetworkCallback telephonyCb = new TestableNetworkCallback(); 1829 // disable airplane mode to reach a known state 1830 runShellCommand("cmd connectivity airplane-mode disable"); 1831 // Verify that networks are available as expected if wifi or cell is supported. Continue the 1832 // test if none of them are supported since test should still able to verify the permission 1833 // mechanism. 1834 if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb); 1835 if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb); 1836 1837 try { 1838 // Verify we cannot set Airplane Mode without correct permission: 1839 try { 1840 setAndVerifyAirplaneMode(true); 1841 fail("SecurityException should have been thrown when setAirplaneMode was called" 1842 + "without holding permission NETWORK_AIRPLANE_MODE."); 1843 } catch (SecurityException expected) {} 1844 1845 // disable airplane mode again to reach a known state 1846 runShellCommand("cmd connectivity airplane-mode disable"); 1847 1848 // adopt shell permission which holds NETWORK_AIRPLANE_MODE 1849 mUiAutomation.adoptShellPermissionIdentity(); 1850 1851 // Verify we can enable Airplane Mode with correct permission: 1852 try { 1853 setAndVerifyAirplaneMode(true); 1854 } catch (SecurityException e) { 1855 fail("SecurityException should not have been thrown when setAirplaneMode(true) was" 1856 + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); 1857 } 1858 // Verify that the enabling airplane mode takes effect as expected to prevent flakiness 1859 // caused by fast airplane mode switches. Ensure network lost before turning off 1860 // airplane mode. 1861 if (supportWifi) waitForLost(wifiCb); 1862 if (supportTelephony) waitForLost(telephonyCb); 1863 1864 // Verify we can disable Airplane Mode with correct permission: 1865 try { 1866 setAndVerifyAirplaneMode(false); 1867 } catch (SecurityException e) { 1868 fail("SecurityException should not have been thrown when setAirplaneMode(false) was" 1869 + "called whilst holding the NETWORK_AIRPLANE_MODE permission."); 1870 } 1871 // Verify that turning airplane mode off takes effect as expected. 1872 if (supportWifi) waitForAvailable(wifiCb); 1873 if (supportTelephony) waitForAvailable(telephonyCb); 1874 } finally { 1875 if (supportWifi) mCm.unregisterNetworkCallback(wifiCb); 1876 if (supportTelephony) mCm.unregisterNetworkCallback(telephonyCb); 1877 // Restore the previous state of airplane mode and permissions: 1878 runShellCommand("cmd connectivity airplane-mode " 1879 + (isAirplaneModeEnabled ? "enable" : "disable")); 1880 mUiAutomation.dropShellPermissionIdentity(); 1881 } 1882 } 1883 1884 private void requestAndWaitForAvailable(@NonNull final NetworkRequest request, 1885 @NonNull final TestableNetworkCallback cb) { 1886 mCm.registerNetworkCallback(request, cb); 1887 waitForAvailable(cb); 1888 } 1889 1890 private void waitForAvailable(@NonNull final TestableNetworkCallback cb) { 1891 cb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 1892 c -> c instanceof CallbackEntry.Available); 1893 } 1894 1895 private void waitForAvailable( 1896 @NonNull final TestableNetworkCallback cb, final int expectedTransport) { 1897 cb.eventuallyExpect( 1898 CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 1899 entry -> { 1900 final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork()); 1901 return nc.hasTransport(expectedTransport); 1902 } 1903 ); 1904 } 1905 1906 private void waitForAvailable( 1907 @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) { 1908 cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */, 1909 true /* validated */, 1910 false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS); 1911 } 1912 1913 private void waitForLost(@NonNull final TestableNetworkCallback cb) { 1914 cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS, 1915 c -> c instanceof CallbackEntry.Lost); 1916 } 1917 1918 private void setAndVerifyAirplaneMode(Boolean expectedResult) 1919 throws Exception { 1920 final CompletableFuture<Boolean> actualResult = new CompletableFuture(); 1921 BroadcastReceiver receiver = new BroadcastReceiver() { 1922 @Override 1923 public void onReceive(Context context, Intent intent) { 1924 // The defaultValue of getExtraBoolean should be the opposite of what is 1925 // expected, thus ensuring a test failure if the extra is absent. 1926 actualResult.complete(intent.getBooleanExtra("state", !expectedResult)); 1927 } 1928 }; 1929 try { 1930 mContext.registerReceiver(receiver, 1931 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 1932 mCm.setAirplaneMode(expectedResult); 1933 final String msg = "Setting Airplane Mode failed,"; 1934 assertEquals(msg, expectedResult, actualResult.get(AIRPLANE_MODE_CHANGE_TIMEOUT_MS, 1935 TimeUnit.MILLISECONDS)); 1936 } finally { 1937 mContext.unregisterReceiver(receiver); 1938 } 1939 } 1940 1941 private static boolean isAirplaneModeEnabled() { 1942 return runShellCommand("cmd connectivity airplane-mode") 1943 .trim().equals("enabled"); 1944 } 1945 1946 @Test 1947 public void testGetCaptivePortalServerUrl() { 1948 final String permission = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q 1949 ? CONNECTIVITY_INTERNAL 1950 : NETWORK_SETTINGS; 1951 final String url = runAsShell(permission, mCm::getCaptivePortalServerUrl); 1952 assertNotNull("getCaptivePortalServerUrl must not be null", url); 1953 try { 1954 final URL parsedUrl = new URL(url); 1955 // As per the javadoc, the URL must be HTTP 1956 assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol()); 1957 } catch (MalformedURLException e) { 1958 throw new AssertionFailedError("Captive portal server URL is invalid: " + e); 1959 } 1960 } 1961 1962 /** 1963 * Verifies that apps are forbidden from getting ssid information from 1964 * {@Code NetworkCapabilities} if they do not hold NETWORK_SETTINGS permission. 1965 * See b/161370134. 1966 */ 1967 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 1968 @Test 1969 public void testSsidInNetworkCapabilities() throws Exception { 1970 assumeTrue("testSsidInNetworkCapabilities cannot execute unless device supports WiFi", 1971 mPackageManager.hasSystemFeature(FEATURE_WIFI)); 1972 1973 final Network network = mCtsNetUtils.ensureWifiConnected(); 1974 final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID()); 1975 assertNotNull("Ssid getting from WifiManager is null", ssid); 1976 // This package should have no NETWORK_SETTINGS permission. Verify that no ssid is contained 1977 // in the NetworkCapabilities. 1978 verifySsidFromQueriedNetworkCapabilities(network, ssid, false /* hasSsid */); 1979 verifySsidFromCallbackNetworkCapabilities(ssid, false /* hasSsid */); 1980 // Adopt shell permission to allow to get ssid information. 1981 runWithShellPermissionIdentity(() -> { 1982 verifySsidFromQueriedNetworkCapabilities(network, ssid, true /* hasSsid */); 1983 verifySsidFromCallbackNetworkCapabilities(ssid, true /* hasSsid */); 1984 }); 1985 } 1986 1987 private void verifySsidFromQueriedNetworkCapabilities(@NonNull Network network, 1988 @NonNull String ssid, boolean hasSsid) throws Exception { 1989 // Verify if ssid is contained in NetworkCapabilities queried from ConnectivityManager. 1990 final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); 1991 assertNotNull("NetworkCapabilities of the network is null", nc); 1992 assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find()); 1993 } 1994 1995 private void verifySsidFromCallbackNetworkCapabilities(@NonNull String ssid, boolean hasSsid) 1996 throws Exception { 1997 final CompletableFuture<NetworkCapabilities> foundNc = new CompletableFuture(); 1998 final NetworkCallback callback = new NetworkCallback() { 1999 @Override 2000 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { 2001 foundNc.complete(nc); 2002 } 2003 }; 2004 try { 2005 mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); 2006 // Registering a callback here guarantees onCapabilitiesChanged is called immediately 2007 // because WiFi network should be connected. 2008 final NetworkCapabilities nc = 2009 foundNc.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 2010 // Verify if ssid is contained in the NetworkCapabilities received from callback. 2011 assertNotNull("NetworkCapabilities of the network is null", nc); 2012 assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find()); 2013 } finally { 2014 mCm.unregisterNetworkCallback(callback); 2015 } 2016 } 2017 2018 /** 2019 * Verify background request can only be requested when acquiring 2020 * {@link android.Manifest.permission.NETWORK_SETTINGS}. 2021 */ 2022 @AppModeFull(reason = "Instant apps cannot create test networks") 2023 @Test 2024 public void testRequestBackgroundNetwork() { 2025 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2026 // shims, and @IgnoreUpTo does not check that. 2027 assumeTrue(TestUtils.shouldTestSApis()); 2028 2029 // Create a tun interface. Use the returned interface name as the specifier to create 2030 // a test network request. 2031 final TestNetworkManager tnm = runWithShellPermissionIdentity(() -> 2032 mContext.getSystemService(TestNetworkManager.class), 2033 android.Manifest.permission.MANAGE_TEST_NETWORKS); 2034 final TestNetworkInterface testNetworkInterface = runWithShellPermissionIdentity(() -> 2035 tnm.createTunInterface(new LinkAddress[]{TEST_LINKADDR}), 2036 android.Manifest.permission.MANAGE_TEST_NETWORKS, 2037 android.Manifest.permission.NETWORK_SETTINGS); 2038 assertNotNull(testNetworkInterface); 2039 2040 final NetworkRequest testRequest = new NetworkRequest.Builder() 2041 .addTransportType(TRANSPORT_TEST) 2042 // Test networks do not have NOT_VPN or TRUSTED capabilities by default 2043 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) 2044 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 2045 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier( 2046 testNetworkInterface.getInterfaceName())) 2047 .build(); 2048 2049 // Verify background network cannot be requested without NETWORK_SETTINGS permission. 2050 final TestableNetworkCallback callback = new TestableNetworkCallback(); 2051 final Handler handler = new Handler(Looper.getMainLooper()); 2052 assertThrows(SecurityException.class, 2053 () -> mCmShim.requestBackgroundNetwork(testRequest, callback, handler)); 2054 2055 Network testNetwork = null; 2056 try { 2057 // Request background test network via Shell identity which has NETWORK_SETTINGS 2058 // permission granted. 2059 runWithShellPermissionIdentity( 2060 () -> mCmShim.requestBackgroundNetwork(testRequest, callback, handler), 2061 new String[] { android.Manifest.permission.NETWORK_SETTINGS }); 2062 2063 // Register the test network agent which has no foreground request associated to it. 2064 // And verify it can satisfy the background network request just fired. 2065 final Binder binder = new Binder(); 2066 runWithShellPermissionIdentity(() -> 2067 tnm.setupTestNetwork(testNetworkInterface.getInterfaceName(), binder), 2068 new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS, 2069 android.Manifest.permission.NETWORK_SETTINGS }); 2070 waitForAvailable(callback); 2071 testNetwork = callback.getLastAvailableNetwork(); 2072 assertNotNull(testNetwork); 2073 2074 // The test network that has just connected is a foreground network, 2075 // non-listen requests will get available callback before it can be put into 2076 // background if no foreground request can be satisfied. Thus, wait for a short 2077 // period is needed to let foreground capability go away. 2078 callback.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, 2079 NETWORK_CALLBACK_TIMEOUT_MS, 2080 c -> c instanceof CallbackEntry.CapabilitiesChanged 2081 && !((CallbackEntry.CapabilitiesChanged) c).getCaps() 2082 .hasCapability(NET_CAPABILITY_FOREGROUND)); 2083 final NetworkCapabilities nc = mCm.getNetworkCapabilities(testNetwork); 2084 assertFalse("expected background network, but got " + nc, 2085 nc.hasCapability(NET_CAPABILITY_FOREGROUND)); 2086 } finally { 2087 final Network n = testNetwork; 2088 runWithShellPermissionIdentity(() -> { 2089 if (null != n) { 2090 tnm.teardownTestNetwork(n); 2091 callback.eventuallyExpect(CallbackEntry.LOST, 2092 NETWORK_CALLBACK_TIMEOUT_MS, 2093 lost -> n.equals(lost.getNetwork())); 2094 } 2095 testNetworkInterface.getFileDescriptor().close(); 2096 }, new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS }); 2097 mCm.unregisterNetworkCallback(callback); 2098 } 2099 } 2100 2101 private class DetailedBlockedStatusCallback extends TestableNetworkCallback { 2102 public void expectAvailableCallbacks(Network network) { 2103 super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */, 2104 BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS); 2105 } 2106 public void expectBlockedStatusCallback(Network network, int blockedStatus) { 2107 super.expectBlockedStatusCallback(blockedStatus, network, NETWORK_CALLBACK_TIMEOUT_MS); 2108 } 2109 public void onBlockedStatusChanged(Network network, int blockedReasons) { 2110 getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons)); 2111 } 2112 } 2113 2114 private void setRequireVpnForUids(boolean requireVpn, Collection<Range<Integer>> ranges) 2115 throws Exception { 2116 mCmShim.setRequireVpnForUids(requireVpn, ranges); 2117 for (Range<Integer> range : ranges) { 2118 if (requireVpn) { 2119 mVpnRequiredUidRanges.add(range); 2120 } else { 2121 assertTrue(mVpnRequiredUidRanges.remove(range)); 2122 } 2123 } 2124 } 2125 2126 private void doTestBlockedStatusCallback() throws Exception { 2127 final DetailedBlockedStatusCallback myUidCallback = new DetailedBlockedStatusCallback(); 2128 final DetailedBlockedStatusCallback otherUidCallback = new DetailedBlockedStatusCallback(); 2129 2130 final int myUid = Process.myUid(); 2131 final int otherUid = UserHandle.getUid(5, Process.FIRST_APPLICATION_UID); 2132 final Handler handler = new Handler(Looper.getMainLooper()); 2133 mCm.registerDefaultNetworkCallback(myUidCallback, handler); 2134 mCmShim.registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, handler); 2135 2136 final Network defaultNetwork = mCm.getActiveNetwork(); 2137 final List<DetailedBlockedStatusCallback> allCallbacks = 2138 List.of(myUidCallback, otherUidCallback); 2139 for (DetailedBlockedStatusCallback callback : allCallbacks) { 2140 callback.expectAvailableCallbacks(defaultNetwork); 2141 } 2142 2143 final Range<Integer> myUidRange = new Range<>(myUid, myUid); 2144 final Range<Integer> otherUidRange = new Range<>(otherUid, otherUid); 2145 2146 setRequireVpnForUids(true, List.of(myUidRange)); 2147 myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN); 2148 otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2149 2150 setRequireVpnForUids(true, List.of(myUidRange, otherUidRange)); 2151 myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2152 otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN); 2153 2154 // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not 2155 // unblock myUid because it was added to the blocked ranges twice. 2156 setRequireVpnForUids(false, List.of(myUidRange)); 2157 myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2158 otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2159 2160 setRequireVpnForUids(false, List.of(myUidRange, otherUidRange)); 2161 myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); 2162 otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE); 2163 2164 myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2165 otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS); 2166 } 2167 2168 @Test 2169 public void testBlockedStatusCallback() { 2170 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2171 // shims, and @IgnoreUpTo does not check that. 2172 assumeTrue(TestUtils.shouldTestSApis()); 2173 runWithShellPermissionIdentity(() -> doTestBlockedStatusCallback(), NETWORK_SETTINGS); 2174 } 2175 2176 private void doTestLegacyLockdownEnabled() throws Exception { 2177 NetworkInfo info = mCm.getActiveNetworkInfo(); 2178 assertNotNull(info); 2179 assertEquals(DetailedState.CONNECTED, info.getDetailedState()); 2180 2181 try { 2182 mCmShim.setLegacyLockdownVpnEnabled(true); 2183 2184 // setLegacyLockdownVpnEnabled is asynchronous and only takes effect when the 2185 // ConnectivityService handler thread processes it. Ensure it has taken effect by doing 2186 // something that blocks until the handler thread is idle. 2187 final TestableNetworkCallback callback = new TestableNetworkCallback(); 2188 mCm.registerDefaultNetworkCallback(callback); 2189 waitForAvailable(callback); 2190 mCm.unregisterNetworkCallback(callback); 2191 2192 // Test one of the effects of setLegacyLockdownVpnEnabled: the fact that any NetworkInfo 2193 // in state CONNECTED is degraded to CONNECTING if the legacy VPN is not connected. 2194 info = mCm.getActiveNetworkInfo(); 2195 assertNotNull(info); 2196 assertEquals(DetailedState.CONNECTING, info.getDetailedState()); 2197 } finally { 2198 mCmShim.setLegacyLockdownVpnEnabled(false); 2199 } 2200 } 2201 2202 @Test 2203 public void testLegacyLockdownEnabled() { 2204 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2205 // shims, and @IgnoreUpTo does not check that. 2206 assumeTrue(TestUtils.shouldTestSApis()); 2207 runWithShellPermissionIdentity(() -> doTestLegacyLockdownEnabled(), NETWORK_SETTINGS); 2208 } 2209 2210 @Test 2211 public void testGetCapabilityCarrierName() { 2212 assumeTrue(TestUtils.shouldTestSApis()); 2213 assertEquals("ENTERPRISE", NetworkInformationShimImpl.newInstance() 2214 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_ENTERPRISE)); 2215 assertNull(NetworkInformationShimImpl.newInstance() 2216 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_NOT_VCN_MANAGED)); 2217 } 2218 2219 @Test 2220 public void testSetGlobalProxy() { 2221 assumeTrue(TestUtils.shouldTestSApis()); 2222 // Behavior is verified in gts. Verify exception thrown w/o permission. 2223 assertThrows(SecurityException.class, () -> mCm.setGlobalProxy( 2224 ProxyInfo.buildDirectProxy("example.com" /* host */, 8080 /* port */))); 2225 } 2226 2227 @Test 2228 public void testFactoryResetWithoutPermission() { 2229 assumeTrue(TestUtils.shouldTestSApis()); 2230 assertThrows(SecurityException.class, () -> mCm.factoryReset()); 2231 } 2232 2233 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 2234 @Test 2235 public void testFactoryReset() throws Exception { 2236 assumeTrue(TestUtils.shouldTestSApis()); 2237 2238 // Store current settings. 2239 final int curAvoidBadWifi = 2240 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext); 2241 final int curPrivateDnsMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext); 2242 2243 TestTetheringEventCallback tetherEventCallback = null; 2244 final CtsTetheringUtils tetherUtils = new CtsTetheringUtils(mContext); 2245 try { 2246 tetherEventCallback = tetherUtils.registerTetheringEventCallback(); 2247 // Adopt for NETWORK_SETTINGS permission. 2248 mUiAutomation.adoptShellPermissionIdentity(); 2249 // start tethering 2250 tetherEventCallback.assumeWifiTetheringSupported(mContext); 2251 tetherUtils.startWifiTethering(tetherEventCallback); 2252 // Update setting to verify the behavior. 2253 mCm.setAirplaneMode(true); 2254 ConnectivitySettingsManager.setPrivateDnsMode(mContext, 2255 ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF); 2256 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, 2257 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE); 2258 assertEquals(AIRPLANE_MODE_ON, Settings.Global.getInt( 2259 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON)); 2260 // Verify factoryReset 2261 mCm.factoryReset(); 2262 verifySettings(AIRPLANE_MODE_OFF, 2263 ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, 2264 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT); 2265 2266 tetherEventCallback.expectNoTetheringActive(); 2267 } finally { 2268 // Restore settings. 2269 mCm.setAirplaneMode(false); 2270 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, curAvoidBadWifi); 2271 ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode); 2272 if (tetherEventCallback != null) { 2273 tetherUtils.unregisterTetheringEventCallback(tetherEventCallback); 2274 } 2275 tetherUtils.stopAllTethering(); 2276 mUiAutomation.dropShellPermissionIdentity(); 2277 } 2278 } 2279 2280 /** 2281 * Verify that {@link ConnectivityManager#setProfileNetworkPreference} cannot be called 2282 * without required NETWORK_STACK permissions. 2283 */ 2284 @Test 2285 public void testSetProfileNetworkPreference_NoPermission() { 2286 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2287 // shims, and @IgnoreUpTo does not check that. 2288 assumeTrue(TestUtils.shouldTestSApis()); 2289 assertThrows(SecurityException.class, () -> mCm.setProfileNetworkPreference( 2290 UserHandle.of(0), PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null /* executor */, 2291 null /* listener */)); 2292 } 2293 2294 @Test 2295 public void testSystemReady() { 2296 assumeTrue(TestUtils.shouldTestSApis()); 2297 assertThrows(SecurityException.class, () -> mCm.systemReady()); 2298 } 2299 2300 @Test 2301 public void testGetIpSecNetIdRange() { 2302 assumeTrue(TestUtils.shouldTestSApis()); 2303 // The lower refers to ConnectivityManager.TUN_INTF_NETID_START. 2304 final long lower = 64512; 2305 // The upper refers to ConnectivityManager.TUN_INTF_NETID_START 2306 // + ConnectivityManager.TUN_INTF_NETID_RANGE - 1 2307 final long upper = 65535; 2308 assertEquals(lower, (long) ConnectivityManager.getIpSecNetIdRange().getLower()); 2309 assertEquals(upper, (long) ConnectivityManager.getIpSecNetIdRange().getUpper()); 2310 } 2311 2312 private void verifySettings(int expectedAirplaneMode, int expectedPrivateDnsMode, 2313 int expectedAvoidBadWifi) throws Exception { 2314 assertEquals(expectedAirplaneMode, Settings.Global.getInt( 2315 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON)); 2316 assertEquals(expectedPrivateDnsMode, 2317 ConnectivitySettingsManager.getPrivateDnsMode(mContext)); 2318 assertEquals(expectedAvoidBadWifi, 2319 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext)); 2320 } 2321 2322 /** 2323 * Verify that per-app OEM network preference functions as expected for network preference TEST. 2324 * For specified apps, validate networks are prioritized in order: unmetered, TEST transport, 2325 * default network. 2326 */ 2327 @AppModeFull(reason = "Instant apps cannot create test networks") 2328 @Test 2329 public void testSetOemNetworkPreferenceForTestPref() throws Exception { 2330 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2331 // shims, and @IgnoreUpTo does not check that. 2332 assumeTrue(TestUtils.shouldTestSApis()); 2333 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); 2334 2335 final TestNetworkTracker tnt = callWithShellPermissionIdentity( 2336 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS)); 2337 final TestableNetworkCallback defaultCallback = new TestableNetworkCallback(); 2338 final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback(); 2339 2340 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2341 final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity( 2342 () -> mCm.getNetworkCapabilities(wifiNetwork)); 2343 final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid()); 2344 final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered(); 2345 2346 try { 2347 // This network will be used for unmetered. Wait for it to be validated because 2348 // OEM_NETWORK_PREFERENCE_TEST only prefers NOT_METERED&VALIDATED to a network with 2349 // TRANSPORT_TEST, like OEM_NETWORK_PREFERENCE_OEM_PAID. 2350 setWifiMeteredStatusAndWait(ssid, false /* isMetered */, true /* waitForValidation */); 2351 2352 setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST); 2353 registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2354 2355 // Validate that an unmetered network is used over other networks. 2356 waitForAvailable(defaultCallback, wifiNetwork); 2357 waitForAvailable(systemDefaultCallback, wifiNetwork); 2358 2359 // Validate that when setting unmetered to metered, unmetered is lost and replaced by 2360 // the network with the TEST transport. Also wait for validation here, in case there 2361 // is a bug that's only visible when the network is validated. 2362 setWifiMeteredStatusAndWait(ssid, true /* isMetered */, true /* waitForValidation */); 2363 defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork, 2364 NETWORK_CALLBACK_TIMEOUT_MS); 2365 waitForAvailable(defaultCallback, tnt.getNetwork()); 2366 // Depending on if this device has cellular connectivity or not, multiple available 2367 // callbacks may be received. Eventually, metered Wi-Fi should be the final available 2368 // callback in any case therefore confirm its receipt before continuing to assure the 2369 // system is in the expected state. 2370 waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI); 2371 } finally { 2372 // Validate that removing the test network will fallback to the default network. 2373 runWithShellPermissionIdentity(tnt::teardown); 2374 defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork(), 2375 NETWORK_CALLBACK_TIMEOUT_MS); 2376 waitForAvailable(defaultCallback); 2377 2378 setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */); 2379 2380 // Cleanup any prior test state from setOemNetworkPreference 2381 clearOemNetworkPreference(); 2382 unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2383 } 2384 } 2385 2386 /** 2387 * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY. 2388 * For specified apps, validate that only TEST transport type networks are used. 2389 */ 2390 @AppModeFull(reason = "Instant apps cannot create test networks") 2391 @Test 2392 public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception { 2393 // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31 2394 // shims, and @IgnoreUpTo does not check that. 2395 assumeTrue(TestUtils.shouldTestSApis()); 2396 2397 final TestNetworkTracker tnt = callWithShellPermissionIdentity( 2398 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS)); 2399 final TestableNetworkCallback defaultCallback = new TestableNetworkCallback(); 2400 final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback(); 2401 2402 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2403 2404 try { 2405 setOemNetworkPreferenceForMyPackage( 2406 OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY); 2407 registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2408 waitForAvailable(defaultCallback, tnt.getNetwork()); 2409 waitForAvailable(systemDefaultCallback, wifiNetwork); 2410 } finally { 2411 runWithShellPermissionIdentity(tnt::teardown); 2412 defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork(), 2413 NETWORK_CALLBACK_TIMEOUT_MS); 2414 2415 // This network preference should only ever use the test network therefore available 2416 // should not trigger when the test network goes down (e.g. switch to cellular). 2417 defaultCallback.assertNoCallback(); 2418 // The system default should still be connected to Wi-fi 2419 assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork()); 2420 2421 // Cleanup any prior test state from setOemNetworkPreference 2422 clearOemNetworkPreference(); 2423 2424 // The default (non-test) network should be available as the network pref was cleared. 2425 waitForAvailable(defaultCallback); 2426 unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback); 2427 } 2428 } 2429 2430 private void unregisterTestOemNetworkPreferenceCallbacks( 2431 @NonNull final TestableNetworkCallback defaultCallback, 2432 @NonNull final TestableNetworkCallback systemDefaultCallback) { 2433 mCm.unregisterNetworkCallback(defaultCallback); 2434 mCm.unregisterNetworkCallback(systemDefaultCallback); 2435 } 2436 2437 private void registerTestOemNetworkPreferenceCallbacks( 2438 @NonNull final TestableNetworkCallback defaultCallback, 2439 @NonNull final TestableNetworkCallback systemDefaultCallback) { 2440 mCm.registerDefaultNetworkCallback(defaultCallback); 2441 runWithShellPermissionIdentity(() -> 2442 mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, 2443 new Handler(Looper.getMainLooper())), NETWORK_SETTINGS); 2444 } 2445 2446 private static final class OnCompleteListenerCallback { 2447 final CompletableFuture<Object> mDone = new CompletableFuture<>(); 2448 2449 public void onComplete() { 2450 mDone.complete(new Object()); 2451 } 2452 2453 void expectOnComplete() throws Exception { 2454 try { 2455 mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 2456 } catch (TimeoutException e) { 2457 fail("Expected onComplete() not received after " 2458 + NETWORK_CALLBACK_TIMEOUT_MS + " ms"); 2459 } 2460 } 2461 } 2462 2463 private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception { 2464 final OemNetworkPreferences pref = new OemNetworkPreferences.Builder() 2465 .addNetworkPreference(mContext.getPackageName(), networkPref) 2466 .build(); 2467 final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback(); 2468 mUiAutomation.adoptShellPermissionIdentity(); 2469 try { 2470 mCm.setOemNetworkPreference( 2471 pref, mContext.getMainExecutor(), oemPrefListener::onComplete); 2472 } finally { 2473 mUiAutomation.dropShellPermissionIdentity(); 2474 } 2475 oemPrefListener.expectOnComplete(); 2476 } 2477 2478 /** 2479 * This will clear the OEM network preference on the device. As there is currently no way of 2480 * getting the existing preference, if this is executed while an existing preference is in 2481 * place, that preference will need to be reapplied after executing this test. 2482 * @throws Exception 2483 */ 2484 private void clearOemNetworkPreference() throws Exception { 2485 final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build(); 2486 final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback(); 2487 mUiAutomation.adoptShellPermissionIdentity(); 2488 try { 2489 mCm.setOemNetworkPreference( 2490 clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete); 2491 } finally { 2492 mUiAutomation.dropShellPermissionIdentity(); 2493 } 2494 oemPrefListener.expectOnComplete(); 2495 } 2496 2497 @Test 2498 public void testSetAcceptPartialConnectivity_NoPermission_GetException() { 2499 assumeTrue(TestUtils.shouldTestSApis()); 2500 assertThrows(SecurityException.class, () -> mCm.setAcceptPartialConnectivity( 2501 mCm.getActiveNetwork(), false /* accept */ , false /* always */)); 2502 } 2503 2504 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2505 @Test 2506 public void testAcceptPartialConnectivity_validatedNetwork() throws Exception { 2507 assumeTrue(TestUtils.shouldTestSApis()); 2508 assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" 2509 + " unless device supports WiFi", 2510 mPackageManager.hasSystemFeature(FEATURE_WIFI)); 2511 2512 try { 2513 // Wait for partial connectivity to be detected on the network 2514 final Network network = preparePartialConnectivity(); 2515 2516 runAsShell(NETWORK_SETTINGS, () -> { 2517 // The always bit is verified in NetworkAgentTest 2518 mCm.setAcceptPartialConnectivity(network, true /* accept */, false /* always */); 2519 }); 2520 2521 // Accept partial connectivity network should result in a validated network 2522 expectNetworkHasCapability(network, NET_CAPABILITY_VALIDATED, WIFI_CONNECT_TIMEOUT_MS); 2523 } finally { 2524 resetValidationConfig(); 2525 // Reconnect wifi to reset the wifi status 2526 reconnectWifi(); 2527 } 2528 } 2529 2530 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2531 @Test 2532 public void testRejectPartialConnectivity_TearDownNetwork() throws Exception { 2533 assumeTrue(TestUtils.shouldTestSApis()); 2534 assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" 2535 + " unless device supports WiFi", 2536 mPackageManager.hasSystemFeature(FEATURE_WIFI)); 2537 2538 final TestNetworkCallback cb = new TestNetworkCallback(); 2539 try { 2540 // Wait for partial connectivity to be detected on the network 2541 final Network network = preparePartialConnectivity(); 2542 2543 mCm.requestNetwork(makeWifiNetworkRequest(), cb); 2544 runAsShell(NETWORK_SETTINGS, () -> { 2545 // The always bit is verified in NetworkAgentTest 2546 mCm.setAcceptPartialConnectivity(network, false /* accept */, false /* always */); 2547 }); 2548 // Reject partial connectivity network should cause the network being torn down 2549 assertEquals(network, cb.waitForLost()); 2550 } finally { 2551 mCm.unregisterNetworkCallback(cb); 2552 resetValidationConfig(); 2553 // Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot 2554 // apply here. Thus, turn off wifi first and restart to restore. 2555 runShellCommand("svc wifi disable"); 2556 mCtsNetUtils.ensureWifiConnected(); 2557 } 2558 } 2559 2560 @Test 2561 public void testSetAcceptUnvalidated_NoPermission_GetException() { 2562 assumeTrue(TestUtils.shouldTestSApis()); 2563 assertThrows(SecurityException.class, () -> mCm.setAcceptUnvalidated( 2564 mCm.getActiveNetwork(), false /* accept */ , false /* always */)); 2565 } 2566 2567 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2568 @Test 2569 public void testRejectUnvalidated_TearDownNetwork() throws Exception { 2570 assumeTrue(TestUtils.shouldTestSApis()); 2571 final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) 2572 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 2573 assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" 2574 + " unless device supports WiFi and telephony", canRunTest); 2575 2576 final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); 2577 try { 2578 // Ensure at least one default network candidate connected. 2579 mCtsNetUtils.connectToCell(); 2580 2581 final Network wifiNetwork = prepareUnvalidatedNetwork(); 2582 // Default network should not be wifi ,but checking that wifi is not the default doesn't 2583 // guarantee that it won't become the default in the future. 2584 assertNotEquals(wifiNetwork, mCm.getActiveNetwork()); 2585 2586 mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); 2587 runAsShell(NETWORK_SETTINGS, () -> { 2588 mCm.setAcceptUnvalidated(wifiNetwork, false /* accept */, false /* always */); 2589 }); 2590 waitForLost(wifiCb); 2591 } finally { 2592 mCm.unregisterNetworkCallback(wifiCb); 2593 resetValidationConfig(); 2594 /// Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot 2595 // apply here. Thus, turn off wifi first and restart to restore. 2596 runShellCommand("svc wifi disable"); 2597 mCtsNetUtils.ensureWifiConnected(); 2598 } 2599 } 2600 2601 @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") 2602 @Test 2603 public void testSetAvoidUnvalidated() throws Exception { 2604 assumeTrue(TestUtils.shouldTestSApis()); 2605 // TODO: Allow in debuggable ROM only. To be replaced by FabricatedOverlay 2606 assumeTrue(Build.isDebuggable()); 2607 final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) 2608 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 2609 assumeTrue("testSetAvoidUnvalidated cannot execute" 2610 + " unless device supports WiFi and telephony", canRunTest); 2611 2612 final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); 2613 final TestableNetworkCallback defaultCb = new TestableNetworkCallback(); 2614 final int previousAvoidBadWifi = 2615 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext); 2616 2617 allowBadWifi(); 2618 2619 final Network cellNetwork = mCtsNetUtils.connectToCell(); 2620 final Network wifiNetwork = prepareValidatedNetwork(); 2621 2622 mCm.registerDefaultNetworkCallback(defaultCb); 2623 mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); 2624 2625 try { 2626 // Verify wifi is the default network. 2627 defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2628 entry -> wifiNetwork.equals(entry.getNetwork())); 2629 wifiCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2630 entry -> wifiNetwork.equals(entry.getNetwork())); 2631 assertTrue(mCm.getNetworkCapabilities(wifiNetwork).hasCapability( 2632 NET_CAPABILITY_VALIDATED)); 2633 2634 // Configure response code for unvalidated network 2635 configTestServer(Status.INTERNAL_ERROR, Status.INTERNAL_ERROR); 2636 mCm.reportNetworkConnectivity(wifiNetwork, false); 2637 // Default network should stay on unvalidated wifi because avoid bad wifi is disabled. 2638 defaultCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, 2639 NETWORK_CALLBACK_TIMEOUT_MS, 2640 entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps() 2641 .hasCapability(NET_CAPABILITY_VALIDATED)); 2642 wifiCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, 2643 NETWORK_CALLBACK_TIMEOUT_MS, 2644 entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps() 2645 .hasCapability(NET_CAPABILITY_VALIDATED)); 2646 2647 runAsShell(NETWORK_SETTINGS, () -> { 2648 mCm.setAvoidUnvalidated(wifiNetwork); 2649 }); 2650 // Default network should be updated to validated cellular network. 2651 defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2652 entry -> cellNetwork.equals(entry.getNetwork())); 2653 // No update on wifi callback. 2654 wifiCb.assertNoCallback(); 2655 } finally { 2656 mCm.unregisterNetworkCallback(wifiCb); 2657 mCm.unregisterNetworkCallback(defaultCb); 2658 resetAvoidBadWifi(previousAvoidBadWifi); 2659 resetValidationConfig(); 2660 // Reconnect wifi to reset the wifi status 2661 reconnectWifi(); 2662 } 2663 } 2664 2665 private void resetAvoidBadWifi(int settingValue) { 2666 setTestAllowBadWifiResource(0 /* timeMs */); 2667 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, settingValue); 2668 } 2669 2670 private void allowBadWifi() { 2671 setTestAllowBadWifiResource( 2672 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS /* timeMs */); 2673 ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, 2674 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE); 2675 } 2676 2677 private void setTestAllowBadWifiResource(long timeMs) { 2678 runAsShell(NETWORK_SETTINGS, () -> { 2679 mCm.setTestAllowBadWifiUntil(timeMs); 2680 }); 2681 } 2682 2683 private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout) 2684 throws Exception { 2685 final CompletableFuture<Network> future = new CompletableFuture(); 2686 final NetworkCallback cb = new NetworkCallback() { 2687 @Override 2688 public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) { 2689 if (n.equals(network) && nc.hasCapability(expectedNetCap)) { 2690 future.complete(network); 2691 } 2692 } 2693 }; 2694 2695 try { 2696 mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), cb); 2697 return future.get(timeout, TimeUnit.MILLISECONDS); 2698 } finally { 2699 mCm.unregisterNetworkCallback(cb); 2700 } 2701 } 2702 2703 private void resetValidationConfig() { 2704 NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); 2705 mHttpServer.stop(); 2706 } 2707 2708 private void prepareHttpServer() throws Exception { 2709 runAsShell(READ_DEVICE_CONFIG, () -> { 2710 // Verify that the test URLs are not normally set on the device, but do not fail if the 2711 // test URLs are set to what this test uses (URLs on localhost), in case the test was 2712 // interrupted manually and rerun. 2713 assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL); 2714 assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL); 2715 }); 2716 2717 NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); 2718 2719 mHttpServer.start(); 2720 } 2721 2722 private Network reconnectWifi() { 2723 mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); 2724 return mCtsNetUtils.ensureWifiConnected(); 2725 } 2726 2727 private Network prepareValidatedNetwork() throws Exception { 2728 prepareHttpServer(); 2729 configTestServer(Status.NO_CONTENT, Status.NO_CONTENT); 2730 // Disconnect wifi first then start wifi network with configuration. 2731 final Network wifiNetwork = reconnectWifi(); 2732 2733 return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_VALIDATED, 2734 WIFI_CONNECT_TIMEOUT_MS); 2735 } 2736 2737 private Network preparePartialConnectivity() throws Exception { 2738 prepareHttpServer(); 2739 // Configure response code for partial connectivity 2740 configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, 2741 Status.NO_CONTENT /* httpStatusCode */); 2742 // Disconnect wifi first then start wifi network with configuration. 2743 mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); 2744 final Network network = mCtsNetUtils.ensureWifiConnected(); 2745 2746 return expectNetworkHasCapability(network, NET_CAPABILITY_PARTIAL_CONNECTIVITY, 2747 WIFI_CONNECT_TIMEOUT_MS); 2748 } 2749 2750 private Network prepareUnvalidatedNetwork() throws Exception { 2751 prepareHttpServer(); 2752 // Configure response code for unvalidated network 2753 configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, 2754 Status.INTERNAL_ERROR /* httpStatusCode */); 2755 2756 // Disconnect wifi first then start wifi network with configuration. 2757 mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); 2758 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2759 return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_INTERNET, 2760 WIFI_CONNECT_TIMEOUT_MS); 2761 } 2762 2763 private String makeUrl(String path) { 2764 return "http://localhost:" + mHttpServer.getListeningPort() + path; 2765 } 2766 2767 private void assertEmptyOrLocalhostUrl(String urlKey) { 2768 final String url = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, urlKey); 2769 assertTrue(urlKey + " must not be set in production scenarios, current value= " + url, 2770 TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME.equals(Uri.parse(url).getHost())); 2771 } 2772 2773 private void configTestServer(IStatus httpsStatusCode, IStatus httpStatusCode) { 2774 mHttpServer.addResponse(new TestHttpServer.Request( 2775 TEST_HTTPS_URL_PATH, Method.GET, "" /* queryParameters */), 2776 httpsStatusCode, null /* locationHeader */, "" /* content */); 2777 mHttpServer.addResponse(new TestHttpServer.Request( 2778 TEST_HTTP_URL_PATH, Method.GET, "" /* queryParameters */), 2779 httpStatusCode, null /* locationHeader */, "" /* content */); 2780 NetworkValidationTestUtil.setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)); 2781 NetworkValidationTestUtil.setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)); 2782 NetworkValidationTestUtil.setUrlExpirationDeviceConfig( 2783 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS); 2784 } 2785 2786 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 2787 @Test 2788 public void testMobileDataPreferredUids() throws Exception { 2789 assumeTrue(TestUtils.shouldTestSApis()); 2790 final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) 2791 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); 2792 assumeTrue("testMobileDataPreferredUidsWithCallback cannot execute" 2793 + " unless device supports both WiFi and telephony", canRunTest); 2794 2795 final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */); 2796 final Set<Integer> mobileDataPreferredUids = 2797 ConnectivitySettingsManager.getMobileDataPreferredUids(mContext); 2798 // CtsNetTestCases uid should not list in MOBILE_DATA_PREFERRED_UIDS setting because it just 2799 // installs to device. In case the uid is existed in setting mistakenly, try to remove the 2800 // uid and set correct uids to setting. 2801 mobileDataPreferredUids.remove(uid); 2802 ConnectivitySettingsManager.setMobileDataPreferredUids(mContext, mobileDataPreferredUids); 2803 2804 // For testing mobile data preferred uids feature, it needs both wifi and cell network. 2805 final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); 2806 final Network cellNetwork = mCtsNetUtils.connectToCell(); 2807 final TestableNetworkCallback defaultTrackingCb = new TestableNetworkCallback(); 2808 final TestableNetworkCallback systemDefaultCb = new TestableNetworkCallback(); 2809 final Handler h = new Handler(Looper.getMainLooper()); 2810 runWithShellPermissionIdentity(() -> mCm.registerSystemDefaultNetworkCallback( 2811 systemDefaultCb, h), NETWORK_SETTINGS); 2812 mCm.registerDefaultNetworkCallback(defaultTrackingCb); 2813 2814 try { 2815 // CtsNetTestCases uid is not listed in MOBILE_DATA_PREFERRED_UIDS setting, so the 2816 // per-app default network should be same as system default network. 2817 waitForAvailable(systemDefaultCb, wifiNetwork); 2818 defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2819 entry -> wifiNetwork.equals(entry.getNetwork())); 2820 // Active network for CtsNetTestCases uid should be wifi now. 2821 assertEquals(wifiNetwork, mCm.getActiveNetwork()); 2822 2823 // Add CtsNetTestCases uid to MOBILE_DATA_PREFERRED_UIDS setting, then available per-app 2824 // default network callback should be received with cell network. 2825 final Set<Integer> newMobileDataPreferredUids = new ArraySet<>(mobileDataPreferredUids); 2826 newMobileDataPreferredUids.add(uid); 2827 ConnectivitySettingsManager.setMobileDataPreferredUids( 2828 mContext, newMobileDataPreferredUids); 2829 defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2830 entry -> cellNetwork.equals(entry.getNetwork())); 2831 // System default network doesn't change. 2832 systemDefaultCb.assertNoCallback(); 2833 // Active network for CtsNetTestCases uid should change to cell, too. 2834 assertEquals(cellNetwork, mCm.getActiveNetwork()); 2835 2836 // Remove CtsNetTestCases uid from MOBILE_DATA_PREFERRED_UIDS setting, then available 2837 // per-app default network callback should be received again with system default network 2838 newMobileDataPreferredUids.remove(uid); 2839 ConnectivitySettingsManager.setMobileDataPreferredUids( 2840 mContext, newMobileDataPreferredUids); 2841 defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2842 entry -> wifiNetwork.equals(entry.getNetwork())); 2843 // System default network still doesn't change. 2844 systemDefaultCb.assertNoCallback(); 2845 // Active network for CtsNetTestCases uid should change back to wifi. 2846 assertEquals(wifiNetwork, mCm.getActiveNetwork()); 2847 } finally { 2848 mCm.unregisterNetworkCallback(systemDefaultCb); 2849 mCm.unregisterNetworkCallback(defaultTrackingCb); 2850 2851 // Restore setting. 2852 ConnectivitySettingsManager.setMobileDataPreferredUids( 2853 mContext, mobileDataPreferredUids); 2854 } 2855 } 2856 2857 /** Wait for assigned time. */ 2858 private void waitForMs(long ms) { 2859 try { 2860 Thread.sleep(ms); 2861 } catch (InterruptedException e) { 2862 fail("Thread was interrupted"); 2863 } 2864 } 2865 2866 private void assertBindSocketToNetworkSuccess(final Network network) throws Exception { 2867 final CompletableFuture<Boolean> future = new CompletableFuture<>(); 2868 final ExecutorService executor = Executors.newSingleThreadExecutor(); 2869 try { 2870 executor.execute(() -> { 2871 for (int i = 0; i < 30; i++) { 2872 waitForMs(100); 2873 2874 try (Socket socket = new Socket()) { 2875 network.bindSocket(socket); 2876 future.complete(true); 2877 return; 2878 } catch (IOException e) { } 2879 } 2880 }); 2881 assertTrue(future.get(APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS, 2882 TimeUnit.MILLISECONDS)); 2883 } finally { 2884 executor.shutdown(); 2885 } 2886 } 2887 2888 @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") 2889 @Test 2890 public void testUidsAllowedOnRestrictedNetworks() throws Exception { 2891 assumeTrue(TestUtils.shouldTestSApis()); 2892 2893 // TODO (b/175199465): figure out a reasonable permission check for 2894 // setUidsAllowedOnRestrictedNetworks that allows tests but not system-external callers. 2895 assumeTrue(Build.isDebuggable()); 2896 2897 final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */); 2898 final Set<Integer> originalUidsAllowedOnRestrictedNetworks = 2899 ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext); 2900 // CtsNetTestCases uid should not list in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting 2901 // because it has been just installed to device. In case the uid is existed in setting 2902 // mistakenly, try to remove the uid and set correct uids to setting. 2903 originalUidsAllowedOnRestrictedNetworks.remove(uid); 2904 runWithShellPermissionIdentity(() -> 2905 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks( 2906 mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS); 2907 2908 final Handler h = new Handler(Looper.getMainLooper()); 2909 final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback(); 2910 mCm.registerBestMatchingNetworkCallback(new NetworkRequest.Builder().clearCapabilities() 2911 .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), testNetworkCb, h); 2912 2913 // Create test network agent with restricted network. 2914 final NetworkCapabilities nc = new NetworkCapabilities.Builder() 2915 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 2916 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 2917 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 2918 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) 2919 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 2920 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 2921 .build(); 2922 final NetworkScore score = new NetworkScore.Builder() 2923 .setExiting(false) 2924 .setTransportPrimary(false) 2925 .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER) 2926 .build(); 2927 final NetworkAgent agent = new NetworkAgent(mContext, Looper.getMainLooper(), 2928 TAG, nc, new LinkProperties(), score, new NetworkAgentConfig.Builder().build(), 2929 new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {}; 2930 runWithShellPermissionIdentity(() -> agent.register(), 2931 android.Manifest.permission.MANAGE_TEST_NETWORKS); 2932 agent.markConnected(); 2933 2934 final Network network = agent.getNetwork(); 2935 2936 try (Socket socket = new Socket()) { 2937 testNetworkCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, 2938 entry -> network.equals(entry.getNetwork())); 2939 // Verify that the network is restricted. 2940 final NetworkCapabilities testNetworkNc = mCm.getNetworkCapabilities(network); 2941 assertNotNull(testNetworkNc); 2942 assertFalse(testNetworkNc.hasCapability( 2943 NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); 2944 // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it 2945 // does not allow to bind socket to restricted network. 2946 assertThrows(IOException.class, () -> network.bindSocket(socket)); 2947 2948 // Add CtsNetTestCases uid to UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting, then it can 2949 // bind socket to restricted network normally. 2950 final Set<Integer> newUidsAllowedOnRestrictedNetworks = 2951 new ArraySet<>(originalUidsAllowedOnRestrictedNetworks); 2952 newUidsAllowedOnRestrictedNetworks.add(uid); 2953 runWithShellPermissionIdentity(() -> 2954 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks( 2955 mContext, newUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS); 2956 // Wait a while for sending allowed uids on the restricted network to netd. 2957 // TODD: Have a significant signal to know the uids has been send to netd. 2958 assertBindSocketToNetworkSuccess(network); 2959 } finally { 2960 mCm.unregisterNetworkCallback(testNetworkCb); 2961 agent.unregister(); 2962 2963 // Restore setting. 2964 runWithShellPermissionIdentity(() -> 2965 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks( 2966 mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS); 2967 } 2968 } 2969 } 2970