Merge changes from topics "vpnmove-getconnectionowneruid", "vpnmove-systemdefaultcallback", "vpnmove-vpntransportinfo"

* changes:
  Accept both pre-S and post-S errors in getConnectionOwnerUid.
  Add CTS coverage for VpnTransportInfo.
  Add test coverage for registerSystemDefaultNetworkCallback.
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 81a431c..4668ba3 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
@@ -16,6 +16,8 @@
 
 package com.android.cts.net.hostside;
 
+import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
@@ -25,6 +27,9 @@
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.POLLIN;
 import static android.system.OsConstants.SOCK_DGRAM;
+import static android.test.MoreAsserts.assertNotEqual;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import android.annotation.Nullable;
 import android.app.DownloadManager;
@@ -45,9 +50,14 @@
 import android.net.NetworkRequest;
 import android.net.Proxy;
 import android.net.ProxyInfo;
+import android.net.TransportInfo;
 import android.net.Uri;
+import android.net.VpnManager;
 import android.net.VpnService;
+import android.net.VpnTransportInfo;
 import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
@@ -687,6 +697,20 @@
         setAndVerifyPrivateDns(initialMode);
     }
 
+    private class NeverChangeNetworkCallback extends NetworkCallback {
+        private volatile Network mLastNetwork;
+
+        public void onAvailable(Network n) {
+            assertNull("Callback got onAvailable more than once: " + mLastNetwork + ", " + n,
+                    mLastNetwork);
+            mLastNetwork = n;
+        }
+
+        public Network getLastNetwork() {
+            return mLastNetwork;
+        }
+    }
+
     public void testDefault() throws Exception {
         if (!supportedHardware()) return;
         // If adb TCP port opened, this test may running by adb over network.
@@ -702,6 +726,14 @@
                 getInstrumentation().getTargetContext(), MyVpnService.ACTION_ESTABLISHED);
         receiver.register();
 
+
+        // Expect the system default network not to change.
+        final NeverChangeNetworkCallback neverChangeCallback = new NeverChangeNetworkCallback();
+        final Network defaultNetwork = mCM.getActiveNetwork();
+        runWithShellPermissionIdentity(() ->
+                mCM.registerSystemDefaultNetworkCallback(neverChangeCallback,
+                        new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
+
         FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS);
 
         startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
@@ -719,6 +751,19 @@
 
         checkTrafficOnVpn();
 
+        expectVpnTransportInfo(mCM.getActiveNetwork());
+
+        // Check that system default network callback has not seen any network changes, but the app
+        // default network callback has. This needs to be done before testing private DNS because
+        // checkStrictModePrivateDns will set the private DNS server to a nonexistent name, which
+        // will cause validation to fail could cause the default network to switch (e.g., from wifi
+        // to cellular).
+        assertEquals(defaultNetwork, neverChangeCallback.getLastNetwork());
+        assertNotEqual(defaultNetwork, mCM.getActiveNetwork());
+        runWithShellPermissionIdentity(
+                () ->  mCM.unregisterNetworkCallback(neverChangeCallback),
+                NETWORK_SETTINGS);
+
         checkStrictModePrivateDns();
 
         receiver.unregisterQuietly();
@@ -739,6 +784,8 @@
 
         checkTrafficOnVpn();
 
+        expectVpnTransportInfo(mCM.getActiveNetwork());
+
         checkStrictModePrivateDns();
     }
 
@@ -764,6 +811,10 @@
         assertSocketStillOpen(remoteFd, TEST_HOST);
 
         checkNoTrafficOnVpn();
+
+        final Network network = mCM.getActiveNetwork();
+        final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
+        assertFalse(nc.hasTransport(TRANSPORT_VPN));
     }
 
     public void testGetConnectionOwnerUidSecurity() throws Exception {
@@ -778,8 +829,11 @@
         InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort());
         try {
             int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem);
-            fail("Only an active VPN app may call this API.");
-        } catch (SecurityException expected) {
+            assertEquals("Only an active VPN app should see connection information",
+                    INVALID_UID, uid);
+        } catch (SecurityException acceptable) {
+            // R and below throw SecurityException if a non-active VPN calls this method.
+            // As long as we can't actually get socket information, either behaviour is fine.
             return;
         }
     }
@@ -918,6 +972,8 @@
         // VPN with no underlying networks should be metered by default.
         assertTrue(isNetworkMetered(mNetwork));
         assertTrue(mCM.isActiveNetworkMetered());
+
+        expectVpnTransportInfo(mCM.getActiveNetwork());
     }
 
     public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception {
@@ -944,6 +1000,8 @@
         assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork));
         // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync.
         assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered());
+
+        expectVpnTransportInfo(mCM.getActiveNetwork());
     }
 
     public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception {
@@ -971,6 +1029,8 @@
         assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork));
         // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync.
         assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered());
+
+        expectVpnTransportInfo(mCM.getActiveNetwork());
     }
 
     public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception {
@@ -995,6 +1055,8 @@
         // VPN's meteredness does not depend on underlying network since it is always metered.
         assertTrue(isNetworkMetered(mNetwork));
         assertTrue(mCM.isActiveNetworkMetered());
+
+        expectVpnTransportInfo(mCM.getActiveNetwork());
     }
 
     public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception {
@@ -1020,6 +1082,8 @@
         // VPN's meteredness does not depend on underlying network since it is always metered.
         assertTrue(isNetworkMetered(mNetwork));
         assertTrue(mCM.isActiveNetworkMetered());
+
+        expectVpnTransportInfo(mCM.getActiveNetwork());
     }
 
     public void testB141603906() throws Exception {
@@ -1069,6 +1133,14 @@
         }
     }
 
+    private void expectVpnTransportInfo(Network network) {
+        final NetworkCapabilities vpnNc = mCM.getNetworkCapabilities(network);
+        assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
+        final TransportInfo ti = vpnNc.getTransportInfo();
+        assertTrue(ti instanceof VpnTransportInfo);
+        assertEquals(VpnManager.TYPE_VPN_SERVICE, ((VpnTransportInfo) ti).type);
+    }
+
     private void assertDefaultProxy(ProxyInfo expected) {
         assertEquals("Incorrect proxy config.", expected, mCM.getDefaultProxy());
         String expectedHost = expected == null ? null : expected.getHost();
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index ce00652..3145d7e 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -93,6 +93,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.SystemClock;
@@ -532,6 +533,13 @@
         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
 
+        final TestNetworkCallback systemDefaultTrackingCallback = new TestNetworkCallback();
+        runWithShellPermissionIdentity(() ->
+                mCm.registerSystemDefaultNetworkCallback(systemDefaultTrackingCallback,
+                        new Handler(Looper.getMainLooper())),
+                NETWORK_SETTINGS);
+
+
         Network wifiNetwork = null;
 
         try {
@@ -551,6 +559,9 @@
         } finally {
             mCm.unregisterNetworkCallback(callback);
             mCm.unregisterNetworkCallback(defaultTrackingCallback);
+            runWithShellPermissionIdentity(
+                    () -> mCm.unregisterNetworkCallback(systemDefaultTrackingCallback),
+                    NETWORK_SETTINGS);
         }
     }
 
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 4dbde1b..41537a9 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -48,6 +48,8 @@
 import android.net.SocketKeepalive
 import android.net.StringNetworkSpecifier
 import android.net.Uri
+import android.net.VpnManager
+import android.net.VpnTransportInfo
 import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter
 import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled
 import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested
@@ -545,7 +547,7 @@
 
     @Test
     @IgnoreUpTo(Build.VERSION_CODES.R)
-    fun testSetUnderlyingNetworks() {
+    fun testSetUnderlyingNetworksAndVpnSpecifier() {
         val request = NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_TEST)
                 .addTransportType(TRANSPORT_VPN)
@@ -560,6 +562,7 @@
             addTransportType(TRANSPORT_VPN)
             removeCapability(NET_CAPABILITY_NOT_VPN)
             addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+            setTransportInfo(VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE))
         }
         val defaultNetwork = mCM.activeNetwork
         assertNotNull(defaultNetwork)
@@ -574,6 +577,8 @@
         // Check that the default network's transport is propagated to the VPN.
         var vpnNc = mCM.getNetworkCapabilities(agent.network)
         assertNotNull(vpnNc)
+        assertEquals(VpnManager.TYPE_VPN_SERVICE,
+                (vpnNc.transportInfo as VpnTransportInfo).type)
 
         val testAndVpn = intArrayOf(TRANSPORT_TEST, TRANSPORT_VPN)
         assertTrue(hasAllTransports(vpnNc, testAndVpn))