diff options
author | Steven Moreland <smoreland@google.com> | 2019-02-11 10:57:59 -0800 |
---|---|---|
committer | Steven Moreland <smoreland@google.com> | 2019-02-11 11:00:44 -0800 |
commit | 567b4cf7b54062947b5eabe6ecef7b70fbb7301b (patch) | |
tree | e7ffe81f03f43359763c39a8c5cf307ba7e96ba7 /tests/net/java/com/android/server/ConnectivityServiceTest.java | |
parent | 4f7ea9f121ef0b81ab9688636cb8ef570f15559c (diff) | |
parent | 0932a16cdf085a16b2b6bf46d457745e317eb4ad (diff) |
Merge QP1A.190205.002
Change-Id: I8e29d3d840642579119f10af2f90dd536304070f
Diffstat (limited to 'tests/net/java/com/android/server/ConnectivityServiceTest.java')
-rw-r--r-- | tests/net/java/com/android/server/ConnectivityServiceTest.java | 483 |
1 files changed, 419 insertions, 64 deletions
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 882babff4aee..e2d59d648563 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -57,6 +57,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import static android.net.shared.NetworkParcelableUtil.fromStableParcelable; import static com.android.internal.util.TestUtils.waitForIdleHandler; import static com.android.internal.util.TestUtils.waitForIdleLooper; @@ -107,6 +108,8 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.net.IpPrefix; +import android.net.IpSecManager; +import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MatchAllNetworkSpecifier; @@ -117,11 +120,14 @@ import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; +import android.net.NetworkParcelable; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkUtils; +import android.net.ProxyInfo; import android.net.RouteInfo; +import android.net.SocketKeepalive; import android.net.UidRange; import android.net.metrics.IpConnectivityLog; import android.net.shared.NetworkMonitorUtils; @@ -158,6 +164,7 @@ import com.android.server.connectivity.DefaultNetworkMetrics; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.NetworkPinner; @@ -186,6 +193,9 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -402,8 +412,8 @@ public class ConnectivityServiceTest { private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); private int mScore; private NetworkAgent mNetworkAgent; - private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED; - private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE; + private int mStartKeepaliveError = SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED; + private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; private Integer mExpectedKeepaliveSlot = null; // Contains the redirectUrl from networkStatus(). Before reading, wait for // mNetworkStatusReceived. @@ -475,8 +485,8 @@ public class ConnectivityServiceTest { fail(e.getMessage()); } - final ArgumentCaptor<Network> nmNetworkCaptor = - ArgumentCaptor.forClass(Network.class); + final ArgumentCaptor<NetworkParcelable> nmNetworkCaptor = + ArgumentCaptor.forClass(NetworkParcelable.class); final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor = ArgumentCaptor.forClass(INetworkMonitorCallbacks.class); doNothing().when(mNetworkStack).makeNetworkMonitor( @@ -486,22 +496,22 @@ public class ConnectivityServiceTest { mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext, "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities, - linkProperties, mScore, new NetworkMisc()) { + linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) { @Override public void unwanted() { mDisconnected.open(); } @Override - public void startPacketKeepalive(Message msg) { + public void startSocketKeepalive(Message msg) { int slot = msg.arg1; if (mExpectedKeepaliveSlot != null) { assertEquals((int) mExpectedKeepaliveSlot, slot); } - onPacketKeepaliveEvent(slot, mStartKeepaliveError); + onSocketKeepaliveEvent(slot, mStartKeepaliveError); } @Override - public void stopPacketKeepalive(Message msg) { - onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError); + public void stopSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError); } @Override @@ -516,7 +526,8 @@ public class ConnectivityServiceTest { } }; - assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId); + assertEquals( + mNetworkAgent.netId, fromStableParcelable(nmNetworkCaptor.getValue()).netId); mNmCallbacks = nmCbCaptor.getValue(); try { @@ -715,7 +726,7 @@ public class ConnectivityServiceTest { /** * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove * operations have been processed. Before ConnectivityService can add or remove any requests, - * the factory must be told to expect those operations by calling expectAddRequests or + * the factory must be told to expect those operations by calling expectAddRequestsWithScores or * expectRemoveRequests. */ private static class MockNetworkFactory extends NetworkFactory { @@ -724,19 +735,22 @@ public class ConnectivityServiceTest { private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false); // Used to expect that requests be removed or added on a separate thread, without sleeping. - // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then - // cause some other thread to add or remove requests, then call waitForRequests(). We can - // either expect requests to be added or removed, but not both, because CountDownLatch can - // only count in one direction. - private CountDownLatch mExpectations; + // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly + // once, then cause some other thread to add or remove requests, then call + // waitForRequests(). + // It is not possible to wait for both add and remove requests. When adding, the queue + // contains the expected score. When removing, the value is unused, all matters is the + // number of objects in the queue. + private final LinkedBlockingQueue<Integer> mExpectations; // Whether we are currently expecting requests to be added or removed. Valid only if - // mExpectations is non-null. + // mExpectations is non-empty. private boolean mExpectingAdditions; public MockNetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter) { super(looper, context, logTag, filter); + mExpectations = new LinkedBlockingQueue<>(); } public int getMyRequestCount() { @@ -768,69 +782,82 @@ public class ConnectivityServiceTest { } @Override - protected void handleAddRequest(NetworkRequest request, int score) { - // If we're expecting anything, we must be expecting additions. - if (mExpectations != null && !mExpectingAdditions) { - fail("Can't add requests while expecting requests to be removed"); - } - - // Add the request. - super.handleAddRequest(request, score); + protected void handleAddRequest(NetworkRequest request, int score, + int factorySerialNumber) { + synchronized (mExpectations) { + final Integer expectedScore = mExpectations.poll(); // null if the queue is empty + + assertNotNull("Added more requests than expected (" + request + " score : " + + score + ")", expectedScore); + // If we're expecting anything, we must be expecting additions. + if (!mExpectingAdditions) { + fail("Can't add requests while expecting requests to be removed"); + } + if (expectedScore != score) { + fail("Expected score was " + expectedScore + " but actual was " + score + + " in added request"); + } - // Reduce the number of request additions we're waiting for. - if (mExpectingAdditions) { - assertTrue("Added more requests than expected", mExpectations.getCount() > 0); - mExpectations.countDown(); + // Add the request. + super.handleAddRequest(request, score, factorySerialNumber); + mExpectations.notify(); } } @Override protected void handleRemoveRequest(NetworkRequest request) { - // If we're expecting anything, we must be expecting removals. - if (mExpectations != null && mExpectingAdditions) { - fail("Can't remove requests while expecting requests to be added"); - } + synchronized (mExpectations) { + final Integer expectedScore = mExpectations.poll(); // null if the queue is empty - // Remove the request. - super.handleRemoveRequest(request); + assertTrue("Removed more requests than expected", expectedScore != null); + // If we're expecting anything, we must be expecting removals. + if (mExpectingAdditions) { + fail("Can't remove requests while expecting requests to be added"); + } - // Reduce the number of request removals we're waiting for. - if (!mExpectingAdditions) { - assertTrue("Removed more requests than expected", mExpectations.getCount() > 0); - mExpectations.countDown(); + // Remove the request. + super.handleRemoveRequest(request); + mExpectations.notify(); } } private void assertNoExpectations() { - if (mExpectations != null) { - fail("Can't add expectation, " + mExpectations.getCount() + " already pending"); + if (mExpectations.size() != 0) { + fail("Can't add expectation, " + mExpectations.size() + " already pending"); } } - // Expects that count requests will be added. - public void expectAddRequests(final int count) { + // Expects that requests with the specified scores will be added. + public void expectAddRequestsWithScores(final int... scores) { assertNoExpectations(); mExpectingAdditions = true; - mExpectations = new CountDownLatch(count); + for (int score : scores) { + mExpectations.add(score); + } } // Expects that count requests will be removed. public void expectRemoveRequests(final int count) { assertNoExpectations(); mExpectingAdditions = false; - mExpectations = new CountDownLatch(count); + for (int i = 0; i < count; ++i) { + mExpectations.add(0); // For removals the score is ignored so any value will do. + } } // Waits for the expected request additions or removals to happen within a timeout. public void waitForRequests() throws InterruptedException { - assertNotNull("Nothing to wait for", mExpectations); - mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); - final long count = mExpectations.getCount(); + final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS; + synchronized (mExpectations) { + while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) { + mExpectations.wait(deadline - SystemClock.elapsedRealtime()); + } + } + final long count = mExpectations.size(); final String msg = count + " requests still not " + (mExpectingAdditions ? "added" : "removed") + " after " + TIMEOUT_MS + " ms"; assertEquals(msg, 0, count); - mExpectations = null; } public void waitForNetworkRequests(final int count) throws InterruptedException { @@ -896,6 +923,7 @@ public class ConnectivityServiceTest { mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mConnected = true; mConfig = new VpnConfig(); + mConfig.isMetered = false; } @Override @@ -1002,6 +1030,11 @@ public class ConnectivityServiceTest { } @Override + protected ProxyTracker makeProxyTracker() { + return mock(ProxyTracker.class); + } + + @Override protected int reserveNetId() { while (true) { final int netId = super.reserveNetId(); @@ -1023,6 +1056,11 @@ public class ConnectivityServiceTest { } } + @Override + protected boolean queryUserAccess(int uid, int netId) { + return true; + } + public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) { return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd; } @@ -1508,6 +1546,12 @@ public class ConnectivityServiceTest { verifyActiveNetwork(TRANSPORT_WIFI); } + @Test + public void testRequiresValidation() { + assertTrue(NetworkMonitorUtils.isValidationRequired( + mCm.getDefaultRequest().networkCapabilities)); + } + enum CallbackState { NONE, AVAILABLE, @@ -2245,6 +2289,12 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent); } + private int[] makeIntArray(final int size, final int value) { + final int[] array = new int[size]; + Arrays.fill(array, value); + return array; + } + private void tryNetworkFactoryRequests(int capability) throws Exception { // Verify NOT_RESTRICTED is set appropriately final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability) @@ -2266,7 +2316,7 @@ public class ConnectivityServiceTest { mServiceContext, "testFactory", filter); testFactory.setScoreFilter(40); ConditionVariable cv = testFactory.getNetworkStartedCV(); - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); testFactory.register(); testFactory.waitForNetworkRequests(1); int expectedRequestCount = 1; @@ -2277,7 +2327,7 @@ public class ConnectivityServiceTest { assertFalse(testFactory.getMyStartRequested()); NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build(); networkCallback = new NetworkCallback(); - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); // New request mCm.requestNetwork(request, networkCallback); expectedRequestCount++; testFactory.waitForNetworkRequests(expectedRequestCount); @@ -2297,7 +2347,7 @@ public class ConnectivityServiceTest { // When testAgent connects, ConnectivityService will re-send us all current requests with // the new score. There are expectedRequestCount such requests, and we must wait for all of // them. - testFactory.expectAddRequests(expectedRequestCount); + testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50)); testAgent.connect(false); testAgent.addCapability(capability); waitFor(cv); @@ -2305,7 +2355,7 @@ public class ConnectivityServiceTest { assertFalse(testFactory.getMyStartRequested()); // Bring in a bunch of requests. - testFactory.expectAddRequests(10); + testFactory.expectAddRequestsWithScores(makeIntArray(10, 50)); assertEquals(expectedRequestCount, testFactory.getMyRequestCount()); ConnectivityManager.NetworkCallback[] networkCallbacks = new ConnectivityManager.NetworkCallback[10]; @@ -2328,8 +2378,11 @@ public class ConnectivityServiceTest { // Drop the higher scored network. cv = testFactory.getNetworkStartedCV(); + // With the default network disconnecting, the requests are sent with score 0 to factories. + testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0)); testAgent.disconnect(); waitFor(cv); + testFactory.waitForNetworkRequests(expectedRequestCount); assertEquals(expectedRequestCount, testFactory.getMyRequestCount()); assertTrue(testFactory.getMyStartRequested()); @@ -3151,22 +3204,23 @@ public class ConnectivityServiceTest { testFactory.setScoreFilter(40); // Register the factory and expect it to start looking for a network. - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet. testFactory.register(); testFactory.waitForNetworkRequests(1); assertTrue(testFactory.getMyStartRequested()); // Bring up wifi. The factory stops looking for a network. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - testFactory.expectAddRequests(2); // Because the default request changes score twice. + // Score 60 - 40 penalty for not validated yet, then 60 when it validates + testFactory.expectAddRequestsWithScores(20, 60); mWiFiNetworkAgent.connect(true); - testFactory.waitForNetworkRequests(1); + testFactory.waitForRequests(); assertFalse(testFactory.getMyStartRequested()); ContentResolver cr = mServiceContext.getContentResolver(); // Turn on mobile data always on. The factory starts looking again. - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0 setAlwaysOnNetworks(true); testFactory.waitForNetworkRequests(2); assertTrue(testFactory.getMyStartRequested()); @@ -3174,7 +3228,7 @@ public class ConnectivityServiceTest { // Bring up cell data and check that the factory stops looking. assertLength(1, mCm.getAllNetworks()); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - testFactory.expectAddRequests(2); // Because the cell request changes score twice. + testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); testFactory.waitForNetworkRequests(2); @@ -3542,6 +3596,80 @@ public class ConnectivityServiceTest { } } + private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback { + + public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; + + private class CallbackValue { + public CallbackType callbackType; + public int error; + + CallbackValue(CallbackType type) { + this.callbackType = type; + this.error = SocketKeepalive.SUCCESS; + assertTrue("onError callback must have error", type != CallbackType.ON_ERROR); + } + + CallbackValue(CallbackType type, int error) { + this.callbackType = type; + this.error = error; + assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR); + } + + @Override + public boolean equals(Object o) { + return o instanceof CallbackValue + && this.callbackType == ((CallbackValue) o).callbackType + && this.error == ((CallbackValue) o).error; + } + + @Override + public String toString() { + return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, + error); + } + } + + private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>(); + + @Override + public void onStarted() { + mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED)); + } + + @Override + public void onStopped() { + mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED)); + } + + @Override + public void onError(int error) { + mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error)); + } + + private void expectCallback(CallbackValue callbackValue) { + try { + assertEquals( + callbackValue, + mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms"); + } + } + + public void expectStarted() { + expectCallback(new CallbackValue(CallbackType.ON_STARTED)); + } + + public void expectStopped() { + expectCallback(new CallbackValue(CallbackType.ON_STOPPED)); + } + + public void expectError(int error) { + expectCallback(new CallbackValue(CallbackType.ON_ERROR, error)); + } + } + private Network connectKeepaliveNetwork(LinkProperties lp) { // Ensure the network is disconnected before we do anything. if (mWiFiNetworkAgent != null) { @@ -3689,6 +3817,155 @@ public class ConnectivityServiceTest { } @Test + public void testNattSocketKeepalives() throws Exception { + final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor(); + doTestNattSocketKeepalivesWithExecutor(executorSingleThread); + executorSingleThread.shutdown(); + + final Executor executorInline = (Runnable r) -> r.run(); + doTestNattSocketKeepalivesWithExecutor(executorInline); + } + + private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception { + // TODO: 1. Move this outside of ConnectivityServiceTest. + // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService. + final int srcPort = 12345; + final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129"); + final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35"); + final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1"); + final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8"); + final InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888"); + + final int validKaInterval = 15; + final int invalidKaInterval = 9; + + final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); + final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort); + + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("wlan12"); + lp.addLinkAddress(new LinkAddress(myIPv6, 64)); + lp.addLinkAddress(new LinkAddress(myIPv4, 25)); + lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234"))); + lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); + + Network notMyNet = new Network(61234); + Network myNet = connectKeepaliveNetwork(lp); + + TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + SocketKeepalive ka; + + // Attempt to start keepalives with invalid parameters and check for errors. + // Invalid network. + ka = mCm.createSocketKeepalive(notMyNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK); + + // Invalid interval. + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(invalidKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_INTERVAL); + + // Invalid destination. + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv6, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); + + // Invalid source; + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv6, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); + + // NAT-T is only supported for IPv4. + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv6, dstIPv6, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); + + // Sanity check before testing started keepalive. + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectError(SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED); + + // Check that a started keepalive can be stopped. + mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS); + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectStarted(); + mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS); + ka.stop(); + callback.expectStopped(); + + // Check that deleting the IP address stops the keepalive. + LinkProperties bogusLp = new LinkProperties(lp); + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectStarted(); + bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25)); + bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25)); + mWiFiNetworkAgent.sendLinkProperties(bogusLp); + callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); + mWiFiNetworkAgent.sendLinkProperties(lp); + + // Check that a started keepalive is stopped correctly when the network disconnects. + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectStarted(); + mWiFiNetworkAgent.disconnect(); + waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK); + + // ... and that stopping it after that has no adverse effects. + waitForIdle(); + final Network myNetAlias = myNet; + assertNull(mCm.getNetworkCapabilities(myNetAlias)); + ka.stop(); + + // Reconnect. + myNet = connectKeepaliveNetwork(lp); + mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS); + + // Check things work as expected when the keepalive is stopped and the network disconnects. + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectStarted(); + ka.stop(); + mWiFiNetworkAgent.disconnect(); + waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + waitForIdle(); + callback.expectStopped(); + + // Reconnect. + myNet = connectKeepaliveNetwork(lp); + mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS); + + // Check that keepalive slots start from 1 and increment. The first one gets slot 1. + mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); + ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback); + ka.start(validKaInterval); + callback.expectStarted(); + + // The second one gets slot 2. + mWiFiNetworkAgent.setExpectedKeepaliveSlot(2); + final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789); + TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(); + SocketKeepalive ka2 = + mCm.createSocketKeepalive(myNet, testSocket2, myIPv4, dstIPv4, executor, callback2); + ka2.start(validKaInterval); + callback2.expectStarted(); + + ka.stop(); + callback.expectStopped(); + + ka2.stop(); + callback2.expectStopped(); + + testSocket.close(); + testSocket2.close(); + + mWiFiNetworkAgent.disconnect(); + } + + @Test public void testGetCaptivePortalServerUrl() throws Exception { String url = mCm.getCaptivePortalServerUrl(); assertEquals("http://connectivitycheck.gstatic.com/generate_204", url); @@ -4404,8 +4681,7 @@ public class ConnectivityServiceTest { mMockVpn.setUids(ranges); // VPN networks do not satisfy the default request and are automatically validated // by NetworkMonitor - assertFalse(NetworkMonitorUtils.isValidationRequired( - mCm.getDefaultRequest().networkCapabilities, vpnNetworkAgent.mNetworkCapabilities)); + assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities)); vpnNetworkAgent.setNetworkValid(); vpnNetworkAgent.connect(false); @@ -4775,7 +5051,7 @@ public class ConnectivityServiceTest { // Clat iface up, expect stack link updated. clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true); - waitForIdle(); + networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork()) .getStackedLinks(); assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0)); @@ -4783,7 +5059,6 @@ public class ConnectivityServiceTest { // Change trivial linkproperties and see if stacked link is preserved. cellLp.addDnsServer(InetAddress.getByName("8.8.8.8")); mCellNetworkAgent.sendLinkProperties(cellLp); - waitForIdle(); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); List<LinkProperties> stackedLpsAfterChange = @@ -4795,19 +5070,19 @@ public class ConnectivityServiceTest { cellLp.addLinkAddress(myIpv4); cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME)); mCellNetworkAgent.sendLinkProperties(cellLp); - waitForIdle(); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME); // Clat iface removed, expect linkproperties revert to original one clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME); - waitForIdle(); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork()); assertEquals(cellLp, actualLpAfterIpv4); // Clean up mCellNetworkAgent.disconnect(); + networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); + networkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(networkCallback); } @@ -4910,4 +5185,84 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(lp); verifyTcpBufferSizeChange(TEST_TCP_BUFFER_SIZES); } + + @Test + public void testGetGlobalProxyForNetwork() { + final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + final Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); + when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo); + assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork)); + } + + @Test + public void testGetProxyForActiveNetwork() { + final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + assertNull(mService.getProxyForNetwork(null)); + + final LinkProperties testLinkProperties = new LinkProperties(); + testLinkProperties.setHttpProxy(testProxyInfo); + + mWiFiNetworkAgent.sendLinkProperties(testLinkProperties); + waitForIdle(); + + assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); + } + + @Test + public void testGetProxyForVPN() { + final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); + + // Set up a WiFi network with no proxy + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + assertNull(mService.getProxyForNetwork(null)); + + // Set up a VPN network with a proxy + final int uid = Process.myUid(); + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setUids(ranges); + LinkProperties testLinkProperties = new LinkProperties(); + testLinkProperties.setHttpProxy(testProxyInfo); + vpnNetworkAgent.sendLinkProperties(testLinkProperties); + waitForIdle(); + + // Connect to VPN with proxy + mMockVpn.setNetworkAgent(vpnNetworkAgent); + vpnNetworkAgent.connect(true); + mMockVpn.connect(); + waitForIdle(); + + // Test that the VPN network returns a proxy, and the WiFi does not. + assertEquals(testProxyInfo, mService.getProxyForNetwork(vpnNetworkAgent.getNetwork())); + assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); + assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork())); + + // Test that the VPN network returns no proxy when it is set to null. + testLinkProperties.setHttpProxy(null); + vpnNetworkAgent.sendLinkProperties(testLinkProperties); + waitForIdle(); + assertNull(mService.getProxyForNetwork(vpnNetworkAgent.getNetwork())); + assertNull(mService.getProxyForNetwork(null)); + + // Set WiFi proxy and check that the vpn proxy is still null. + testLinkProperties.setHttpProxy(testProxyInfo); + mWiFiNetworkAgent.sendLinkProperties(testLinkProperties); + waitForIdle(); + assertNull(mService.getProxyForNetwork(null)); + + // Disconnect from VPN and check that the active network, which is now the WiFi, has the + // correct proxy setting. + vpnNetworkAgent.disconnect(); + waitForIdle(); + assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork())); + assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); + } } |