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