Merge "Fix data stall false alarm caused by TCP signal"
diff --git a/Android.bp b/Android.bp
index 0aba37c..b849ea5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -67,6 +67,7 @@
     min_sdk_version: "29",
     sdk_version: "module_current",
     libs: [
+        "framework-configinfrastructure",
         "framework-connectivity",
         "framework-connectivity-t",
         "framework-statsd",
@@ -297,7 +298,6 @@
         "net-utils-device-common-ip",
         "net-utils-device-common-netlink",
     ],
-    plugins: ["java_api_finder"],
 }
 
 // The versions of the android library containing network stack code compiled for each SDK variant.
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c1bc9cf..3869fc9 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -20,8 +20,16 @@
     {
       "name": "NetworkStackTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
     },
+    // This is used to verify NetworkStackRootTests with all latest modules listed below on
+    // preivous OS platforms.
     {
-      "name": "NetworkStackIntegrationTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
+      "name": "NetworkStackRootTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
+    },
+    // This is used to verify NetworkStackRootTests with latest CaptivePortalLoginGoogle.apk
+    // but with other modules on different version(e.g. an older tethering module to verify
+    // backwards compatibility of APIs).
+    {
+      "name": "NetworkStackRootTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk]"
     }
   ],
   "imports": [
diff --git a/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java b/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java
index 473db91..fceb19a 100644
--- a/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java
+++ b/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java
@@ -23,6 +23,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
 import com.android.networkstack.apishim.common.TelephonyManagerShim;
@@ -72,6 +73,12 @@
                 int[] pkgUids = toIntArray(privilegedUids);
                 listener.onCarrierPrivilegesChanged(pkgNames, pkgUids);
             }
+
+            @Override
+            public void onCarrierServiceChanged(@Nullable final String carrierServicePackageName,
+                    final int carrierServiceUid) {
+                listener.onCarrierServiceChanged(carrierServicePackageName, carrierServiceUid);
+            }
         };
         mTm.registerCarrierPrivilegesCallback(logicalSlotIndex, executor,
                 carrierPrivilegesCallback);
@@ -86,6 +93,7 @@
         mListenerMap.remove(listener);
     }
 
+    // TODO : remove this method when all changes are in
     /** See android.telephony.TelephonyManager#getCarrierServicePackageNameForLogicalSlot */
     public String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
         return mTm.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex);
diff --git a/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java b/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java
index 492624a..6fec190 100644
--- a/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java
+++ b/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java
@@ -16,6 +16,8 @@
 
 package com.android.networkstack.apishim.common;
 
+import androidx.annotation.Nullable;
+
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -30,12 +32,17 @@
  */
 public interface TelephonyManagerShim {
     /** See android.telephony.TelephonyManager.CarrierPrivilegesListener */
-    public interface CarrierPrivilegesListenerShim {
+    interface CarrierPrivilegesListenerShim {
         /** See android.telephony.TelephonyManager
-         * .CarrierPrivilegesListener#onCarrierPrivilegesChanged */
-        void onCarrierPrivilegesChanged(
+         * .CarrierPrivilegesCallback#onCarrierPrivilegesChanged */
+        default void onCarrierPrivilegesChanged(
                 List<String> privilegedPackageNames,
-                int[] privilegedUids);
+                int[] privilegedUids) {}
+        // TODO : remove the default implementation of this method once all changes are in
+        /** See CarrierPrivilegesCallback#onCarrierServiceChanged */
+        default void onCarrierServiceChanged(
+                @Nullable String carrierServicePackageName,
+                int carrierServiceUid) {}
     }
 
     /** See android.telephony.TelephonyManager#addCarrierPrivilegesListener */
@@ -54,6 +61,7 @@
         throw new UnsupportedApiLevelException("Only supported starting from API 33");
     }
 
+    // TODO : remove this method when all changes are in
     /** See android.telephony.TelephonyManager#getCarrierServicePackageNameForLogicalSlot */
     default String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex)
             throws UnsupportedApiLevelException {
diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java
index 4135f68..654d390 100644
--- a/src/android/net/ip/IpClientLinkObserver.java
+++ b/src/android/net/ip/IpClientLinkObserver.java
@@ -45,6 +45,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.HexDump;
 import com.android.net.module.util.InterfaceParams;
 import com.android.net.module.util.SharedLog;
 import com.android.net.module.util.ip.NetlinkMonitor;
@@ -205,7 +206,8 @@
     private void maybeLog(String operation, String iface, LinkAddress address) {
         if (DBG) {
             Log.d(mTag, operation + ": " + address + " on " + iface
-                    + " flags " + address.getFlags() + " scope " + address.getScope());
+                    + " flags " + "0x" + HexDump.toHexString(address.getFlags())
+                    + " scope " + address.getScope());
         }
     }
 
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java
index 670a320..e152558 100755
--- a/src/com/android/networkstack/util/NetworkStackUtils.java
+++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -194,14 +194,6 @@
             "dhcp_slow_retransmission_version";
 
     /**
-     * Minimum module version at which to enable dismissal CaptivePortalLogin app in validated
-     * network feature. CaptivePortalLogin app will also use validation facilities in
-     * {@link NetworkMonitor} to perform portal validation if feature is enabled.
-     */
-    public static final String DISMISS_PORTAL_IN_VALIDATED_NETWORK =
-            "dismiss_portal_in_validated_network";
-
-    /**
      * Experiment flag to enable considering DNS probes returning private IP addresses as failed
      * when attempting to detect captive portals.
      *
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index d34437f..8e0130e 100755
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -86,7 +86,6 @@
 import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
 import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTPS_URLS;
 import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTP_URLS;
-import static com.android.networkstack.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK;
 import static com.android.networkstack.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION;
 
 import android.app.PendingIntent;
@@ -1325,10 +1324,7 @@
         private boolean useRedirectUrlForPortal() {
             // It must match the conditions in CaptivePortalLogin in which the redirect URL is not
             // used to validate that the portal is gone.
-            final boolean aboveQ =
-                    ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q);
-            return aboveQ && mDependencies.isFeatureEnabled(mContext, NAMESPACE_CONNECTIVITY,
-                    DISMISS_PORTAL_IN_VALIDATED_NETWORK, aboveQ /* defaultEnabled */);
+            return ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q);
         }
 
         @Override
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp
index fca588d..5926fec 100644
--- a/tests/integration/Android.bp
+++ b/tests/integration/Android.bp
@@ -82,6 +82,7 @@
     platform_apis: true,
     test_suites: ["device-tests"],
     jarjar_rules: ":NetworkStackJarJarRules",
+    host_required: ["net-tests-utils-host-common"],
     test_config_template: "AndroidTestTemplate_Integration.xml",
 }
 
@@ -104,6 +105,7 @@
     platform_apis: true,
     test_suites: ["device-tests"],
     jarjar_rules: ":NetworkStackJarJarRules",
+    host_required: ["net-tests-utils-host-common"],
     test_config_template: "AndroidTestTemplate_Integration.xml",
 }
 
@@ -123,8 +125,11 @@
     ],
     platform_apis: true,
     test_suites: ["general-tests", "mts-networking"],
+    compile_multilib: "both",
     manifest: "AndroidManifest_root.xml",
     jarjar_rules: ":NetworkStackJarJarRules",
+    host_required: ["net-tests-utils-host-common"],
+    test_config_template: "AndroidTestTemplate_Integration.xml",
 }
 
 // Special version of the network stack tests that includes all tests necessary for code coverage
diff --git a/tests/integration/AndroidTestTemplate_Integration.xml b/tests/integration/AndroidTestTemplate_Integration.xml
index 7ea8ad6..6107ccc 100644
--- a/tests/integration/AndroidTestTemplate_Integration.xml
+++ b/tests/integration/AndroidTestTemplate_Integration.xml
@@ -23,8 +23,12 @@
          that the shell can write to and that the networkstack can read from. -->
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
+    <target_preparer class="com.android.testutils.DisableConfigSyncTargetPreparer" />
+
+    <option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex" />
+    <option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.server.networkstack.integrationtests" />
+        <option name="package" value="{PACKAGE}" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <!-- By default, include and exclude filters go into /data/local/tmp/ajur/, which these
              tests cannot access because they run in the network_stack selinux context. Move
diff --git a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
index 2aeecfa..becb968 100644
--- a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
+++ b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
@@ -265,6 +265,7 @@
     private static final int IFA_F_STABLE_PRIVACY = 0x800;
 
     protected static final long TEST_TIMEOUT_MS = 2_000L;
+    private static final long TEST_WAIT_ENOBUFS_TIMEOUT_MS = 30_000L;
 
     @Rule
     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
@@ -1806,9 +1807,10 @@
                 mPacketReader.popPacket(PACKET_TIMEOUT_MS, this::isRouterSolicitation));
     }
 
-    private void sendRouterAdvertisement(boolean waitForRs, short lifetime) throws Exception {
+    private void sendRouterAdvertisement(boolean waitForRs, short lifetime, int valid,
+            int preferred) throws Exception {
         final String dnsServer = "2001:4860:4860::64";
-        final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64");
+        final ByteBuffer pio = buildPioOption(valid, preferred, "2001:db8:1::/64");
         final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer);
         sendRouterAdvertisement(waitForRs, lifetime, pio, rdnss);
     }
@@ -1823,11 +1825,13 @@
     }
 
     private void sendBasicRouterAdvertisement(boolean waitForRs) throws Exception {
-        sendRouterAdvertisement(waitForRs, (short) 1800);
+        sendRouterAdvertisement(waitForRs, (short) 1800 /* lifetime */, 3600 /* valid */,
+                1800 /* preferred */);
     }
 
-    private void sendRouterAdvertisementWithZeroLifetime() throws Exception {
-        sendRouterAdvertisement(false /* waitForRs */, (short) 0);
+    private void sendRouterAdvertisementWithZeroRouterLifetime() throws Exception {
+        sendRouterAdvertisement(false /* waitForRs */, (short) 0 /* lifetime */, 3600 /* valid */,
+                1800 /* preferred */);
     }
 
     // TODO: move this and the following method to a common location and use them in ApfTest.
@@ -2868,7 +2872,7 @@
 
         // Send RA with 0-lifetime and wait until all IPv6-related default route and DNS servers
         // have been removed, then verify if there is IPv4-only info left in the LinkProperties.
-        sendRouterAdvertisementWithZeroLifetime();
+        sendRouterAdvertisementWithZeroRouterLifetime();
         verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
                 argThat(x -> {
                     final boolean isOnlyIPv4Provisioned = (x.getLinkAddresses().size() == 1
@@ -2907,7 +2911,7 @@
         // Send RA with 0-lifetime and wait until all global IPv6 addresses, IPv6-related default
         // route and DNS servers have been removed, then verify if there is IPv4-only, IPv6 link
         // local address and route to fe80::/64 info left in the LinkProperties.
-        sendRouterAdvertisementWithZeroLifetime();
+        sendRouterAdvertisementWithZeroRouterLifetime();
         verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange(
                 argThat(x -> {
                     // Only IPv4 provisioned and IPv6 link-local address
@@ -4008,7 +4012,7 @@
 
         // Unblock the IpClient handler and ENOBUFS should happen then.
         latch.countDown();
-        HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS);
+        HandlerUtils.waitForIdle(handler, TEST_WAIT_ENOBUFS_TIMEOUT_MS);
 
         reset(mCb);
 
@@ -4016,7 +4020,7 @@
         // Due to ignoring the ENOBUFS and wait until handler gets idle, IpClient should be still
         // able to see the RA with 0 router lifetime and the IPv6 default route will be removed.
         // LinkProperties should not include any route to the new prefix 2001:db8:dead:beef::/64.
-        sendRouterAdvertisementWithZeroLifetime();
+        sendRouterAdvertisementWithZeroRouterLifetime();
         final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
         verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
         final LinkProperties lp = captor.getValue();
@@ -4051,4 +4055,34 @@
         }
         assertEquals(2, nsList.size()); // from privacy address and stable privacy address
     }
+
+    @Test
+    public void testDeprecatedGlobalUnicastAddress() throws Exception {
+        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+                .withoutIPv4()
+                .build();
+        startIpClientProvisioning(config);
+        doIpv6OnlyProvisioning();
+
+        // Send RA with PIO(0 preferred but valid lifetime) to deprecate the global IPv6 addresses.
+        // Check all of global IPv6 addresses will become deprecated, but still valid.
+        // NetworkStackUtils#isIPv6GUA() will return false for deprecated addresses, however, when
+        // checking if the DNS is still reachable, deprecated addresses are not acceptable, that
+        // results in the on-link DNS server gets lost from LinkProperties, and provisioning failure
+        // happened.
+        // TODO: update the logic of checking reachable on-link DNS server to accept the deprecated
+        // addresses, then onProvisioningFailure callback should never happen.
+        sendRouterAdvertisement(false /* waitForRs*/, (short) 1800 /* router lifetime */,
+                3600 /* valid */, 0 /* preferred */);
+        final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
+        verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
+        final LinkProperties lp = captor.getValue();
+        assertNotNull(lp);
+        assertFalse(lp.hasGlobalIpv6Address());
+        assertEquals(3, lp.getLinkAddresses().size()); // IPv6 privacy, stable privacy, link-local
+        for (LinkAddress la : lp.getLinkAddresses()) {
+            final Inet6Address address = (Inet6Address) la.getAddress();
+            assertFalse(NetworkStackUtils.isIPv6GUA(la));
+        }
+    }
 }
diff --git a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
index 9c40eff..481bfdc 100644
--- a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
+++ b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
@@ -23,6 +23,7 @@
 import android.content.pm.PackageManager.MATCH_SYSTEM_ONLY
 import android.net.INetworkStackConnector
 import android.os.IBinder
+import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry
 import kotlin.test.fail
 
@@ -31,6 +32,7 @@
  */
 class TestNetworkStackServiceClient private constructor() : NetworkStackClientBase() {
     companion object {
+        private val TAG = "TestNetworkStackServiceClient"
         private val testNetworkStackServiceAction = "android.net.INetworkStackConnector.Test"
         private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
         private val networkStackVersion by lazy {
@@ -49,6 +51,7 @@
 
         @JvmStatic
         fun isSupported(): Boolean {
+            Log.d(TAG, "Running network stack module version is " + networkStackVersion)
             // TestNetworkStackService was introduced in NetworkStack version 301100000.
             // It is also available at HEAD in development branches, where the version code is
             // 300000000.
diff --git a/tests/integration/signature/android/net/util/NetworkStackUtilsIntegrationTest.kt b/tests/integration/signature/android/net/util/NetworkStackUtilsIntegrationTest.kt
index 17153de..3436cb6 100644
--- a/tests/integration/signature/android/net/util/NetworkStackUtilsIntegrationTest.kt
+++ b/tests/integration/signature/android/net/util/NetworkStackUtilsIntegrationTest.kt
@@ -59,8 +59,10 @@
 import java.net.Inet4Address
 import java.net.Inet6Address
 import java.nio.ByteBuffer
+import java.util.Arrays
 import kotlin.reflect.KClass
 import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
 import kotlin.test.fail
 
@@ -75,6 +77,10 @@
     private val TEST_TARGET_MAC = MacAddress.fromString("01:23:45:67:89:0A")
     private val TEST_INET6ADDR_1 = parseNumericAddress("2001:db8::1") as Inet6Address
     private val TEST_INET6ADDR_2 = parseNumericAddress("2001:db8::2") as Inet6Address
+    private val TEST_INET6ADDR_3 = parseNumericAddress("fd01:db8::3") as Inet6Address
+
+    // RFC4291 section 2.7.1
+    private val SOLICITED_NODE_MULTICAST_PREFIX = "FF02:0:0:0:0:1:FF00::/104"
 
     private val readerHandler = HandlerThread(
             NetworkStackUtilsIntegrationTest::class.java.simpleName)
@@ -185,6 +191,31 @@
         assertArrayEquals("Received packet != expected $descr",
                 expected, buffer.copyOfRange(0, readPacket))
     }
+
+    private fun assertSolicitedNodeMulticastAddress(
+        expected: Inet6Address?,
+        unicast: Inet6Address
+    ) {
+        assertNotNull(expected)
+        val prefix = IpPrefix(SOLICITED_NODE_MULTICAST_PREFIX)
+        assertTrue(prefix.contains(expected))
+        assertTrue(expected.isMulticastAddress())
+        // check the last 3 bytes of address
+        assertArrayEquals(Arrays.copyOfRange(expected.getAddress(), 13, 15),
+                Arrays.copyOfRange(unicast.getAddress(), 13, 15))
+    }
+
+    @Test
+    fun testConvertIpv6AddressToSolicitedNodeMulticast() {
+        val addr1 = NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast(TEST_INET6ADDR_1)
+        assertSolicitedNodeMulticastAddress(addr1, TEST_INET6ADDR_1)
+
+        val addr2 = NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast(TEST_INET6ADDR_2)
+        assertSolicitedNodeMulticastAddress(addr2, TEST_INET6ADDR_2)
+
+        val addr3 = NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast(TEST_INET6ADDR_3)
+        assertSolicitedNodeMulticastAddress(addr3, TEST_INET6ADDR_3)
+    }
 }
 
 private fun ByteBuffer.readAsArray(): ByteArray {
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index ae9eea4..122ec6e 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -58,7 +58,6 @@
 import static com.android.networkstack.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
 import static com.android.networkstack.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
 import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT;
-import static com.android.networkstack.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK;
 import static com.android.networkstack.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION;
 import static com.android.server.connectivity.NetworkMonitor.INITIAL_REEVALUATE_DELAY_MS;
 import static com.android.server.connectivity.NetworkMonitor.extractCharset;
@@ -74,7 +73,6 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.after;
@@ -582,7 +580,6 @@
         setConsecutiveDnsTimeoutThreshold(5);
         mCreatedNetworkMonitors = new HashSet<>();
         mRegisteredReceivers = new HashSet<>();
-        setDismissPortalInValidatedNetwork(false);
     }
 
     @After
@@ -2055,7 +2052,8 @@
                 null /* redirectUrl */);
     }
 
-    public void setupAndLaunchCaptivePortalApp(final NetworkMonitor nm) throws Exception {
+    public void setupAndLaunchCaptivePortalApp(final NetworkMonitor nm, String expectedUrl)
+            throws Exception {
         setSslException(mHttpsConnection);
         setPortal302(mHttpConnection);
         doReturn(TEST_LOGIN_URL).when(mHttpConnection).getHeaderField(eq("location"));
@@ -2083,15 +2081,27 @@
         assertEquals(TEST_NETID, networkCaptor.getValue().netId);
         // Portal URL should be detection URL.
         final String redirectUrl = bundle.getString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
-        assertEquals(TEST_HTTP_URL, redirectUrl);
+        assertEquals(expectedUrl, redirectUrl);
 
         resetCallbacks();
     }
 
+
     @Test
-    public void testCaptivePortalLogin() throws Exception {
+    public void testCaptivePortalLogin_beforeR() throws Exception {
+        assumeFalse(ShimUtils.isAtLeastR());
+        testCaptivePortalLogin(TEST_HTTP_URL);
+    }
+
+    @Test
+    public void testCaptivePortalLogin_AfterR() throws Exception {
+        assumeTrue(ShimUtils.isAtLeastR());
+        testCaptivePortalLogin(TEST_LOGIN_URL);
+    }
+
+    private void testCaptivePortalLogin(String expectedUrl) throws Exception {
         final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES);
-        setupAndLaunchCaptivePortalApp(nm);
+        setupAndLaunchCaptivePortalApp(nm, expectedUrl);
 
         // Have the app report that the captive portal is dismissed, and check that we revalidate.
         setStatus(mHttpsConnection, 204);
@@ -2106,9 +2116,20 @@
     }
 
     @Test
-    public void testCaptivePortalUseAsIs() throws Exception {
+    public void testCaptivePortalUseAsIs_beforeR() throws Exception {
+        assumeFalse(ShimUtils.isAtLeastR());
+        testCaptivePortalUseAsIs(TEST_HTTP_URL);
+    }
+
+    @Test
+    public void testCaptivePortalUseAsIs_AfterR() throws Exception {
+        assumeTrue(ShimUtils.isAtLeastR());
+        testCaptivePortalUseAsIs(TEST_LOGIN_URL);
+    }
+
+    private void testCaptivePortalUseAsIs(String expectedUrl) throws Exception {
         final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES);
-        setupAndLaunchCaptivePortalApp(nm);
+        setupAndLaunchCaptivePortalApp(nm, expectedUrl);
 
         // The user decides this network is wanted as is, either by encountering an SSL error or
         // encountering an unknown scheme and then deciding to continue through the browser, or by
@@ -2676,7 +2697,6 @@
 
     private void testDismissPortalInValidatedNetworkEnabled(String expectedUrl, String locationUrl)
             throws Exception {
-        setDismissPortalInValidatedNetwork(true);
         setSslException(mHttpsConnection);
         setPortal302(mHttpConnection);
         doReturn(locationUrl).when(mHttpConnection).getHeaderField(eq("location"));
@@ -2880,9 +2900,6 @@
     public void testIsCaptivePortal_FromExternalSource() throws Exception {
         assumeTrue(CaptivePortalDataShimImpl.isSupported());
         assumeTrue(ShimUtils.isAtLeastS());
-        doReturn(true).when(mDependencies)
-                .isFeatureEnabled(any(), eq(NAMESPACE_CONNECTIVITY),
-                        eq(DISMISS_PORTAL_IN_VALIDATED_NETWORK), anyBoolean());
         final NetworkMonitor monitor = makeMonitor(WIFI_NOT_METERED_CAPABILITIES);
 
         NetworkInformationShim networkShim = NetworkInformationShimImpl.newInstance();
@@ -3058,11 +3075,6 @@
                 eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt());
     }
 
-    private void setDismissPortalInValidatedNetwork(boolean enabled) {
-        doReturn(enabled).when(mDependencies).isFeatureEnabled(any(), any(),
-                eq(DISMISS_PORTAL_IN_VALIDATED_NETWORK), anyBoolean());
-    }
-
     private void setDeviceConfig(String key, String value) {
         doReturn(value).when(mDependencies).getDeviceConfigProperty(eq(NAMESPACE_CONNECTIVITY),
                 eq(key), any() /* defaultValue */);