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 81a431cfda..4668ba3670 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_ICMPV6; 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.NetworkCapabilities; 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 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { checkTrafficOnVpn(); + expectVpnTransportInfo(mCM.getActiveNetwork()); + checkStrictModePrivateDns(); } @@ -764,6 +811,10 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { // 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 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { 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 @@ public class VpnTest extends InstrumentationTestCase { // 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 @@ public class VpnTest extends InstrumentationTestCase { // 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 @@ public class VpnTest extends InstrumentationTestCase { } } + 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 ce006524c4..3145d7eaba 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.util.KeepaliveUtils; 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 @@ public class ConnectivityManagerTest { 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 @@ public class ConnectivityManagerTest { } 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 4dbde1b0be..41537a94c3 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.RouteInfo 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 @@ class NetworkAgentTest { @Test @IgnoreUpTo(Build.VERSION_CODES.R) - fun testSetUnderlyingNetworks() { + fun testSetUnderlyingNetworksAndVpnSpecifier() { val request = NetworkRequest.Builder() .addTransportType(TRANSPORT_TEST) .addTransportType(TRANSPORT_VPN) @@ -560,6 +562,7 @@ class NetworkAgentTest { 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 @@ class NetworkAgentTest { // 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))