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