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