Merge changes from topic "ka05" am: 908eb08326 am: 9a4614f4b0
am: ee5162e5b5
Change-Id: Ie56c431a6d934c752d1de30fc4bf98a7e557e5b2
This commit is contained in:
@@ -107,6 +107,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;
|
||||
@@ -122,6 +124,7 @@ import android.net.NetworkSpecifier;
|
||||
import android.net.NetworkStack;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.SocketKeepalive;
|
||||
import android.net.UidRange;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
import android.net.shared.NetworkMonitorUtils;
|
||||
@@ -186,6 +189,8 @@ 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.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -402,8 +407,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.
|
||||
@@ -3548,6 +3553,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) {
|
||||
@@ -3694,6 +3773,145 @@ public class ConnectivityServiceTest {
|
||||
callback3.expectStopped();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNattSocketKeepalives() throws Exception {
|
||||
// TODO: 1. Move this outside of ConnectivityServiceTest.
|
||||
// 2. Add helper function to test against newSingleThreadExecutor as well as inline
|
||||
// executor.
|
||||
// 3. 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);
|
||||
|
||||
final Executor executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCaptivePortalServerUrl() throws Exception {
|
||||
String url = mCm.getCaptivePortalServerUrl();
|
||||
|
||||
Reference in New Issue
Block a user