Merge "Migrate IPsec CTS out of tests/tests/net"
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index 741c961..47b114b 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -24,7 +24,6 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
-        "vts10",
         "general-tests",
     ],
 }
diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp
index e129be7..9903756 100644
--- a/tests/cts/hostside/app/Android.bp
+++ b/tests/cts/hostside/app/Android.bp
@@ -35,7 +35,6 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
-        "vts10",
         "general-tests",
     ],
 }
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index bb492a1..f9e30b6 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -78,6 +78,17 @@
         stopForegroundService();
         assertAppIdle(true);
         assertBackgroundNetworkAccess(false);
+
+        // Set Idle after foreground service start.
+        launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
+        setAppIdle(true);
+        addPowerSaveModeWhitelist(TEST_PKG);
+        removePowerSaveModeWhitelist(TEST_PKG);
+        assertForegroundServiceNetworkAccess();
+        stopForegroundService();
+        assertAppIdle(true);
+        assertBackgroundNetworkAccess(false);
+
     }
 
     @Test
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index a451ea8..81a431c 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -17,13 +17,26 @@
 package com.android.cts.net.hostside;
 
 import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.*;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.ECONNABORTED;
+import static android.system.OsConstants.IPPROTO_ICMP;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
 
 import android.annotation.Nullable;
+import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.LinkProperties;
@@ -32,12 +45,13 @@
 import android.net.NetworkRequest;
 import android.net.Proxy;
 import android.net.ProxyInfo;
+import android.net.Uri;
 import android.net.VpnService;
 import android.net.wifi.WifiManager;
-import android.provider.Settings;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
@@ -64,12 +78,12 @@
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
-import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.Random;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -1009,6 +1023,9 @@
     }
 
     public void testB141603906() throws Exception {
+        if (!supportedHardware()) {
+            return;
+        }
         final InetSocketAddress src = new InetSocketAddress(0);
         final InetSocketAddress dst = new InetSocketAddress(0);
         final int NUM_THREADS = 8;
@@ -1087,4 +1104,62 @@
             received = true;
         }
     }
+
+    /**
+     * Verifies that DownloadManager has CONNECTIVITY_USE_RESTRICTED_NETWORKS permission that can
+     * bind socket to VPN when it is in VPN disallowed list but requested downloading app is in VPN
+     * allowed list.
+     * See b/165774987.
+     */
+    public void testDownloadWithDownloadManagerDisallowed() throws Exception {
+        if (!supportedHardware()) return;
+
+        // Start a VPN with DownloadManager package in disallowed list.
+        startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
+                new String[] {"192.0.2.0/24", "2001:db8::/32"},
+                "" /* allowedApps */, "com.android.providers.downloads", null /* proxyInfo */,
+                null /* underlyingNetworks */, false /* isAlwaysMetered */);
+
+        final Context context = VpnTest.this.getInstrumentation().getContext();
+        final DownloadManager dm = context.getSystemService(DownloadManager.class);
+        final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            context.registerReceiver(receiver,
+                    new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+
+            // Enqueue a request and check only one download.
+            final long id = dm.enqueue(new Request(Uri.parse("https://www.google.com")));
+            assertEquals(1, getTotalNumberDownloads(dm, new Query()));
+            assertEquals(1, getTotalNumberDownloads(dm, new Query().setFilterById(id)));
+
+            // Wait for download complete and check status.
+            assertEquals(id, receiver.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertEquals(1, getTotalNumberDownloads(dm,
+                    new Query().setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL)));
+
+            // Remove download.
+            assertEquals(1, dm.remove(id));
+            assertEquals(0, getTotalNumberDownloads(dm, new Query()));
+        } finally {
+            context.unregisterReceiver(receiver);
+        }
+    }
+
+    private static int getTotalNumberDownloads(final DownloadManager dm, final Query query) {
+        try (Cursor cursor = dm.query(query)) { return cursor.getCount(); }
+    }
+
+    private static class DownloadCompleteReceiver extends BroadcastReceiver {
+        private final CompletableFuture<Long> future = new CompletableFuture<>();
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            future.complete(intent.getLongExtra(
+                    DownloadManager.EXTRA_DOWNLOAD_ID, -1 /* defaultValue */));
+        }
+
+        public long get(long timeout, TimeUnit unit) throws Exception {
+            return future.get(timeout, unit);
+        }
+    }
 }
diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp
index a6e9b11..8e27931 100644
--- a/tests/cts/hostside/app2/Android.bp
+++ b/tests/cts/hostside/app2/Android.bp
@@ -23,7 +23,6 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
-        "vts10",
         "general-tests",
     ],
     certificate: ":cts-net-app",
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
index 62925ad..49b5f9d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
@@ -95,4 +95,9 @@
     public void testB141603906() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testB141603906");
     }
+
+    public void testDownloadWithDownloadManagerDisallowed() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest",
+                "testDownloadWithDownloadManagerDisallowed");
+    }
 }
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index 4c00428..913380a 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -66,7 +66,6 @@
     defaults: ["CtsNetTestCasesDefaults"],
     test_suites: [
         "cts",
-        "vts10",
         "general-tests",
     ],
     test_config_template: "AndroidTestTemplate.xml",
diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING
index 3162e22..9167c98 100644
--- a/tests/cts/net/TEST_MAPPING
+++ b/tests/cts/net/TEST_MAPPING
@@ -1,6 +1,6 @@
 {
   // TODO: move to mainline-presubmit once supported
-  "postsubmit": [
+  "presubmit": [
     {
       "name": "CtsNetTestCasesLatestSdk",
       "options": [
diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp
index 0ce9826..e43a5e8 100644
--- a/tests/cts/net/api23Test/Android.bp
+++ b/tests/cts/net/api23Test/Android.bp
@@ -45,7 +45,6 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
-        "vts10",
         "general-tests",
     ],
 
diff --git a/tests/cts/net/appForApi23/Android.bp b/tests/cts/net/appForApi23/Android.bp
index 399c199..cec6d7f 100644
--- a/tests/cts/net/appForApi23/Android.bp
+++ b/tests/cts/net/appForApi23/Android.bp
@@ -26,7 +26,6 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
-        "vts10",
         "general-tests",
     ],
 
diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp
index cd94709..60e31bc 100644
--- a/tests/cts/net/jni/NativeMultinetworkJni.cpp
+++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp
@@ -458,20 +458,16 @@
     setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
 
     // For reference see:
-    //     https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1
+    //     https://datatracker.ietf.org/doc/html/draft-ietf-quic-invariants
     uint8_t quic_packet[1200] = {
-        0x0d,                    // public flags:
-                                 //   - version present (0x01),
-                                 //   - 64bit connection ID (0x0c),
-                                 //   - 1 byte packet number (0x00)
+        0xc0,                    // long header
+        0xaa, 0xda, 0xca, 0xca,  // reserved-space version number
+        0x08,                    // destination connection ID length
         0, 0, 0, 0, 0, 0, 0, 0,  // 64bit connection ID
-        0xaa, 0xda, 0xca, 0xaa,  // reserved-space version number
-        1,                       // 1 byte packet number
-        0x00,                    // private flags
-        0x07,                    // PING frame (cuz why not)
+        0x00,                    // source connection ID length
     };
 
-    arc4random_buf(quic_packet + 1, 8);  // random connection ID
+    arc4random_buf(quic_packet + 6, 8);  // random connection ID
 
     uint8_t response[1500];
     ssize_t sent, rcvd;
@@ -496,7 +492,7 @@
                   i + 1, MAX_RETRIES, rcvd, errnum);
         }
     }
-    if (rcvd < 9) {
+    if (rcvd < 15) {
         LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum);
         if (rcvd <= 0) {
             LOGD("Does this network block UDP port %s?", kPort);
@@ -505,7 +501,7 @@
         return -EPROTO;
     }
 
-    int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8);
+    int conn_id_cmp = memcmp(quic_packet + 6, response + 7, 8);
     if (conn_id_cmp != 0) {
         LOGD("sent and received connection IDs do not match");
         close(fd);
diff --git a/tests/cts/net/native/qtaguid/Android.bp b/tests/cts/net/native/qtaguid/Android.bp
index 23a0cf7..7c6e19f 100644
--- a/tests/cts/net/native/qtaguid/Android.bp
+++ b/tests/cts/net/native/qtaguid/Android.bp
@@ -42,7 +42,6 @@
     // Tag this module as a cts test artifact
     test_suites: [
         "cts",
-        "vts10",
     ],
 
     cflags: [
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 12a966f..eb5048f 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -30,11 +30,9 @@
 import android.net.NetworkRequest
 import android.net.Uri
 import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig
-import android.net.cts.NetworkValidationTestUtil.runAsShell
 import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig
 import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig
 import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig
-import com.android.testutils.TestHttpServer.Request
 import android.net.cts.util.CtsNetUtils
 import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL
 import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL
@@ -47,7 +45,9 @@
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import androidx.test.runner.AndroidJUnit4
 import com.android.testutils.TestHttpServer
+import com.android.testutils.TestHttpServer.Request
 import com.android.testutils.isDevSdkInRange
+import com.android.testutils.runAsShell
 import fi.iki.elonen.NanoHTTPD.Response.Status
 import junit.framework.AssertionFailedError
 import org.junit.After
@@ -123,7 +123,7 @@
     fun testCaptivePortalIsNotDefaultNetwork() {
         assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY))
         assumeTrue(pm.hasSystemFeature(FEATURE_WIFI))
-        utils.connectToWifi()
+        utils.ensureWifiConnected()
         utils.connectToCell()
 
         // Have network validation use a local server that serves a HTTPS error / HTTP redirect
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 455da26..db4e3e7 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -17,6 +17,7 @@
 package android.net.cts;
 
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.content.pm.PackageManager.FEATURE_ETHERNET;
 import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
 import static android.content.pm.PackageManager.FEATURE_USB_HOST;
@@ -41,6 +42,7 @@
 
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -103,6 +105,8 @@
 
 import libcore.io.Streams;
 
+import junit.framework.AssertionFailedError;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -118,6 +122,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
 import java.net.Socket;
 import java.net.URL;
 import java.net.UnknownHostException;
@@ -219,6 +224,16 @@
         if (mCtsNetUtils.cellConnectAttempted()) {
             mCtsNetUtils.disconnectFromCell();
         }
+
+        // All tests in this class require a working Internet connection as they start. Make
+        // sure there is still one as they end that's ready to use for the next test to use.
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(callback);
+        try {
+            assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable());
+        } finally {
+            mCm.unregisterNetworkCallback(callback);
+        }
     }
 
     /**
@@ -607,7 +622,7 @@
     public void testRequestNetworkCallback_onUnavailable() {
         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
         if (previousWifiEnabledState) {
-            mCtsNetUtils.disconnectFromWifi(null);
+            mCtsNetUtils.ensureWifiDisconnected(null);
         }
 
         final TestNetworkCallback callback = new TestNetworkCallback();
@@ -1499,4 +1514,17 @@
         return runShellCommand("cmd connectivity airplane-mode")
                 .trim().equals("enabled");
     }
+
+    @Test
+    public void testGetCaptivePortalServerUrl() {
+        final String url = runAsShell(NETWORK_SETTINGS, mCm::getCaptivePortalServerUrl);
+        assertNotNull("getCaptivePortalServerUrl must not be null", url);
+        try {
+            final URL parsedUrl = new URL(url);
+            // As per the javadoc, the URL must be HTTP
+            assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol());
+        } catch (MalformedURLException e) {
+            throw new AssertionFailedError("Captive portal server URL is invalid: " + e);
+        }
+    }
 }
diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
index ec656de..5290f0d 100644
--- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
@@ -31,7 +31,6 @@
 import android.net.TestNetworkInterface
 import android.net.TestNetworkManager
 import android.net.Uri
-import android.net.cts.NetworkValidationTestUtil.runAsShell
 import android.net.dhcp.DhcpDiscoverPacket
 import android.net.dhcp.DhcpPacket
 import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE
@@ -45,8 +44,7 @@
 import androidx.test.runner.AndroidJUnit4
 import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress
 import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address
-import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY
-import com.android.testutils.ArpResponder
+import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DhcpClientPacketFilter
 import com.android.testutils.DhcpOptionFilter
@@ -54,10 +52,10 @@
 import com.android.testutils.TapPacketReader
 import com.android.testutils.TestHttpServer
 import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.runAsShell
 import fi.iki.elonen.NanoHTTPD.Response.Status
 import org.junit.After
 import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -131,7 +129,7 @@
                 handlerThread.threadHandler,
                 iface.fileDescriptor.fileDescriptor,
                 MAX_PACKET_LENGTH)
-        handlerThread.threadHandler.post { reader.start() }
+        reader.startAsyncForTest()
         httpServer.start()
 
         // Pad the listening port to make sure it is always of length 5. This ensures the URL has
@@ -233,7 +231,7 @@
     timeoutMs: Long,
     type: Byte
 ): T {
-    val packetBytes = popPacket(timeoutMs, DhcpClientPacketFilter()
+    val packetBytes = poll(timeoutMs, DhcpClientPacketFilter()
             .and(DhcpOptionFilter(DHCP_MESSAGE_TYPE, type)))
             ?: fail("${packetType.simpleName} not received within timeout")
     val packet = DhcpPacket.decodeFullPacket(packetBytes, packetBytes.size, DhcpPacket.ENCAP_L2)
diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt
index 5ef1854..f6fc75b 100644
--- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt
@@ -19,9 +19,7 @@
 import android.Manifest
 import android.net.util.NetworkStackUtils
 import android.provider.DeviceConfig
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.ThrowingRunnable
-import kotlin.test.fail
+import com.android.testutils.runAsShell
 
 /**
  * Collection of utility methods for configuring network validation.
@@ -67,13 +65,4 @@
                     DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */)
         }
     }
-
-    /**
-     * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax.
-     */
-    fun <T> runAsShell(vararg permissions: String, task: () -> T): T {
-        var ret: T? = null
-        runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions)
-        return ret ?: fail("ThrowingRunnable did not return")
-    }
 }
\ No newline at end of file
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 65a8c7c..92dca39 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -757,7 +757,7 @@
             if (!isWifiTetheringSupported(tetherEventCallback)) return;
 
             if (previousWifiEnabledState) {
-                mCtsNetUtils.disconnectFromWifi(null);
+                mCtsNetUtils.ensureWifiDisconnected(null);
             }
 
             final TestNetworkCallback networkCallback = new TestNetworkCallback();