Merge changes from topic "new-ipsec-api"
* changes:
Expose new algorithms as public API
Add new mandatory IPsec algorithms
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index e21cb44..5877f1f 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -22,9 +22,10 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.net.util.IpUtils;
import android.util.Log;
+import com.android.net.module.util.IpUtils;
+
import java.net.InetAddress;
/**
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index 22288b6..c4f8fc2 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -22,11 +22,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.net.util.IpUtils;
import android.os.Parcel;
import android.os.Parcelable;
import android.system.OsConstants;
+import com.android.net.module.util.IpUtils;
+
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index 75086cf..d31218d 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -30,7 +30,7 @@
/**
* Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
- * to networks and makes them available to to the core network stack by creating
+ * to networks and makes them available to the core network stack by creating
* {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
* with via networking APIs such as {@link ConnectivityManager}.
*
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8a1baf2..d07a22d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -140,6 +140,7 @@
import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
+import android.os.BasicShellCommandHandler;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -156,11 +157,8 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.os.ShellCallback;
-import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -238,7 +236,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
@@ -1126,7 +1123,6 @@
// Listen to package add and removal events for all users.
intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
@@ -6195,20 +6191,12 @@
return; // no updating necessary
}
- final NetworkAgentInfo defaultNai = getDefaultNetwork();
- final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId);
-
if (DBG) {
final Collection<InetAddress> dnses = newLp.getDnsServers();
log("Setting DNS servers for network " + netId + " to " + dnses);
}
try {
mDnsManager.noteDnsServersForNetwork(netId, newLp);
- // TODO: netd should listen on [::1]:53 and proxy queries to the current
- // default network, and we should just set net.dns1 to ::1, not least
- // because applications attempting to use net.dns resolvers will bypass
- // the privacy protections of things like DNS-over-TLS.
- if (isDefaultNetwork) mDnsManager.setDefaultDnsSystemProperties(newLp.getDnsServers());
mDnsManager.flushVmDnsCache();
} catch (Exception e) {
loge("Exception in setDnsConfigurationForNetwork: " + e);
@@ -6723,8 +6711,6 @@
? newNetwork.linkProperties.getHttpProxy() : null);
updateTcpBufferSizes(null != newNetwork
? newNetwork.linkProperties.getTcpBufferSizes() : null);
- mDnsManager.setDefaultDnsSystemProperties(null != newNetwork
- ? newNetwork.linkProperties.getDnsServers() : Collections.EMPTY_LIST);
notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
updateAllVpnsCapabilities();
@@ -7659,14 +7645,14 @@
}
@Override
- public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
- FileDescriptor err, @NonNull String[] args, ShellCallback callback,
- @NonNull ResultReceiver resultReceiver) {
- (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
+ err.getFileDescriptor(), args);
}
- private class ShellCmd extends ShellCommand {
-
+ private class ShellCmd extends BasicShellCommandHandler {
@Override
public int onCommand(String cmd) {
if (cmd == null) {
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index cf6a7f6..271ec4e 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -50,7 +50,6 @@
import java.net.InetAddress;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -245,7 +244,6 @@
private final Map<Integer, LinkProperties> mLinkPropertiesMap;
private final Map<Integer, int[]> mTransportsMap;
- private int mNumDnsEntries;
private int mSampleValidity;
private int mSuccessThreshold;
private int mMinSamples;
@@ -409,18 +407,6 @@
}
}
- public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
- int last = 0;
- for (InetAddress dns : dnses) {
- ++last;
- setNetDnsProperty(last, dns.getHostAddress());
- }
- for (int i = last + 1; i <= mNumDnsEntries; ++i) {
- setNetDnsProperty(i, "");
- }
- mNumDnsEntries = last;
- }
-
/**
* Flush DNS caches and events work before boot has completed.
*/
@@ -476,16 +462,6 @@
return Settings.Global.getInt(mContentResolver, which, dflt);
}
- private void setNetDnsProperty(int which, String value) {
- final String key = "net.dns" + which;
- // Log and forget errors setting unsupported properties.
- try {
- mSystemProperties.set(key, value);
- } catch (Exception e) {
- Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
- }
- }
-
private static String getPrivateDnsMode(ContentResolver cr) {
String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 1f0066a..8625a6f 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -47,7 +47,6 @@
import android.net.NetworkUtils;
import android.net.SocketKeepalive.InvalidSocketException;
import android.net.TcpKeepalivePacketData;
-import android.net.util.IpUtils;
import android.net.util.KeepaliveUtils;
import android.os.Binder;
import android.os.Handler;
@@ -63,6 +62,7 @@
import com.android.internal.R;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.IpUtils;
import java.io.FileDescriptor;
import java.net.InetAddress;
@@ -367,6 +367,13 @@
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
}
}
+ // Ignore the case when the network disconnects immediately after stop() has been
+ // called and the keepalive code is waiting for the response from the modem. This
+ // might happen when the caller listens for a lower-layer network disconnect
+ // callback and stop the keepalive at that time. But the stop() races with the
+ // stop() generated in ConnectivityService network disconnection code path.
+ if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return;
+
// Store the reason of stopping, and report it after the keepalive is fully stopped.
if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
@@ -380,9 +387,6 @@
// e.g. invalid parameter.
cleanupStoppedKeepalive(mNai, mSlot);
break;
- case STOPPING:
- // Keepalive is already in stopping state, ignore.
- return;
default:
mStartedState = STOPPING;
switch (mType) {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 124b660..0fe84ab 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -63,6 +63,7 @@
"services.net",
],
libs: [
+ "android.net.ipsec.ike.stubs.module_lib",
"android.test.runner",
"android.test.base",
"android.test.mock",
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
index 005cbe9..89fc6ea 100644
--- a/tests/net/TEST_MAPPING
+++ b/tests/net/TEST_MAPPING
@@ -8,5 +8,10 @@
{
"name": "FrameworksNetDeflakeTest"
}
+ ],
+ "imports": [
+ {
+ "path": "cts/tests/tests/net"
+ }
]
}
\ No newline at end of file
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 9f0b41f..85704d0 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -67,6 +67,9 @@
private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
+ // Controls how test network agent is going to wait before responding to keepalive
+ // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
+ private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
@@ -134,12 +137,17 @@
if (mWrapper.mExpectedKeepaliveSlot != null) {
assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
}
- onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
+ mWrapper.mHandlerThread.getThreadHandler().postDelayed(
+ () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError),
+ mWrapper.mKeepaliveResponseDelay);
}
@Override
public void stopSocketKeepalive(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
+ final int slot = msg.arg1;
+ mWrapper.mHandlerThread.getThreadHandler().postDelayed(
+ () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError),
+ mWrapper.mKeepaliveResponseDelay);
}
@Override
@@ -205,7 +213,7 @@
public void connect() {
assertNotEquals("MockNetworkAgents can only be connected once",
- getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
+ mNetworkInfo.getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
@@ -248,6 +256,10 @@
mStopKeepaliveError = reason;
}
+ public void setKeepaliveResponseDelay(long delay) {
+ mKeepaliveResponseDelay = delay;
+ }
+
public void setExpectedKeepaliveSlot(Integer slot) {
mExpectedKeepaliveSlot = slot;
}
@@ -256,10 +268,6 @@
return mNetworkAgent;
}
- public NetworkInfo getNetworkInfo() {
- return mNetworkInfo;
- }
-
public NetworkCapabilities getNetworkCapabilities() {
return mNetworkCapabilities;
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 57c356d..862e552 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4292,6 +4292,32 @@
myNet = connectKeepaliveNetwork(lp);
mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+ // Check that a stop followed by network disconnects does not result in crash.
+ try (SocketKeepalive ka = mCm.createSocketKeepalive(
+ myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
+ ka.start(validKaInterval);
+ callback.expectStarted();
+ // Delay the response of keepalive events in networkAgent long enough to make sure
+ // the follow-up network disconnection will be processed first.
+ mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS);
+ ka.stop();
+
+ // Make sure the stop has been processed. Wait for executor idle is needed to prevent
+ // flaky since the actual stop call to the service is delegated to executor thread.
+ waitForIdleSerialExecutor(executor, TIMEOUT_MS);
+ waitForIdle();
+
+ mWiFiNetworkAgent.disconnect();
+ mWiFiNetworkAgent.expectDisconnected();
+ callback.expectStopped();
+ callback.assertNoCallback();
+ }
+
+ // Reconnect.
+ waitForIdle();
+ myNet = connectKeepaliveNetwork(lp);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+
// Check that keepalive slots start from 1 and increment. The first one gets slot 1.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
int srcPort2 = 0;
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 753dbf8..32bfa70 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -159,7 +159,6 @@
// Send a validation event that is tracked on the alternate netId
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp);
@@ -196,7 +195,6 @@
}));
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
fixedLp = new LinkProperties(lp);
mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
@@ -232,7 +230,6 @@
lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updatePrivateDnsValidation(
new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
@@ -246,7 +243,6 @@
mDnsManager.getPrivateDnsConfig());
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updatePrivateDnsValidation(
new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
@@ -295,7 +291,6 @@
mDnsManager.getPrivateDnsConfig());
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updatePrivateDnsValidation(
new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
@@ -341,7 +336,6 @@
lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor =
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index e8c4ee9..daa2627 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -20,6 +20,7 @@
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
+import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
@@ -45,7 +46,9 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -66,6 +69,7 @@
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
+import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.Network;
@@ -75,6 +79,8 @@
import android.net.UidRange;
import android.net.VpnManager;
import android.net.VpnService;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.ConditionVariable;
@@ -101,6 +107,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -150,6 +157,11 @@
private static final String TEST_VPN_IDENTITY = "identity";
private static final byte[] TEST_VPN_PSK = "psk".getBytes();
+ private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
+ private static final String TEST_IFACE_NAME = "TEST_IFACE";
+ private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
+ private static final long TEST_TIMEOUT_MS = 500L;
+
/**
* Names and UIDs for some fake packages. Important points:
* - UID is ordered increasing.
@@ -227,6 +239,13 @@
// Deny all appops by default.
when(mAppOps.noteOpNoThrow(anyInt(), anyInt(), anyString()))
.thenReturn(AppOpsManager.MODE_IGNORED);
+
+ // Setup IpSecService
+ final IpSecTunnelInterfaceResponse tunnelResp =
+ new IpSecTunnelInterfaceResponse(
+ IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
+ when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
+ .thenReturn(tunnelResp);
}
@Test
@@ -988,6 +1007,52 @@
eq(AppOpsManager.MODE_IGNORED));
}
+ private NetworkCallback triggerOnAvailableAndGetCallback() {
+ final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
+ .requestNetwork(any(), networkCallbackCaptor.capture());
+
+ final NetworkCallback cb = networkCallbackCaptor.getValue();
+ cb.onAvailable(TEST_NETWORK);
+ return cb;
+ }
+
+ @Test
+ public void testStartPlatformVpnAuthenticationFailed() throws Exception {
+ final ArgumentCaptor<IkeSessionCallback> captor =
+ ArgumentCaptor.forClass(IkeSessionCallback.class);
+ final IkeProtocolException exception = mock(IkeProtocolException.class);
+ when(exception.getErrorType())
+ .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
+
+ final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final NetworkCallback cb = triggerOnAvailableAndGetCallback();
+
+ // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
+ // state
+ verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
+ .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
+ final IkeSessionCallback ikeCb = captor.getValue();
+ ikeCb.onClosedExceptionally(exception);
+
+ verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
+ assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ }
+
+ @Test
+ public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
+ when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
+ .thenThrow(new IllegalArgumentException());
+ final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final NetworkCallback cb = triggerOnAvailableAndGetCallback();
+
+ // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
+ // state
+ verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
+ assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ }
+
private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null, mKeyStore));
@@ -1090,7 +1155,7 @@
new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
"name", profile.username, "password", profile.password,
"linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
- "idle", "1800", "mtu", "1400", "mru", "1400" },
+ "idle", "1800", "mtu", "1270", "mru", "1270" },
deps.mtpdArgs.get(10, TimeUnit.SECONDS));
// Now wait for the runner to be ready before testing for the route.
legacyRunnerReady.block(10_000);
@@ -1198,7 +1263,7 @@
}
@Override
- public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ public boolean isInterfacePresent(final Vpn vpn, final String iface) {
return true;
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 8f09377..6d2c7dc 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -150,7 +151,7 @@
}
private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
- assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
+ assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId));
final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
// Verify callback with the subscriberId and the RAT type should be as expected.
// It will fail if get a callback with an unexpected RAT type.
@@ -302,26 +303,84 @@
reset(mDelegate);
// Set IMSI to null again to simulate somehow IMSI is not available, such as
- // modem crash. Verify service should not unregister listener.
+ // modem crash. Verify service should unregister listener.
updateSubscriberIdForTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, never()).listen(any(), anyInt());
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
reset(mDelegate);
+ clearInvocations(mTelephonyManager);
- // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
- // is not available. The monitor keeps the listener even if the IMSI disappears because
- // the IMSI can never change for any given subId, therefore even if the IMSI is updated
- // to null, the monitor should continue accepting updates of the RAT type. However,
- // telephony is never actually supposed to do this, if the IMSI disappears there should
- // not be updates, but it's still the right thing to do theoretically.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ // Simulate somehow IMSI is back. Verify service will register with
+ // another listener and fire callback accordingly.
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ reset(mDelegate);
+ clearInvocations(mTelephonyManager);
+
+ // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works.
+ setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
TelephonyManager.NETWORK_TYPE_LTE);
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
reset(mDelegate);
mMonitor.stop();
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+
+ /**
+ * Verify that when IMSI suddenly changed for a given subId, the service will register a new
+ * listener and unregister the old one, and report changes on updated IMSI. This is for modem
+ * feature that may be enabled for certain carrier, which changes to use a different IMSI while
+ * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same.
+ */
+ @Test
+ public void testSubscriberIdChanged() {
+ mMonitor.start();
+ // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+ // before changing RAT type.
+ addTestSub(TEST_SUBID1, TEST_IMSI1);
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+
+ // Set RAT type of sim1 to UMTS.
+ // Verify RAT type of sim1 changes accordingly.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+ clearInvocations(mTelephonyManager);
+
+ // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with
+ // another listener and remove the old one. The RAT type of new IMSI stays at
+ // NETWORK_TYPE_UNKNOWN until received initial callback from telephony.
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
eq(PhoneStateListener.LISTEN_NONE));
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ reset(mDelegate);
+
+ // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received
+ // from telephony after registration. Verify RAT type of sim1 changes with IMSI2
+ // accordingly.
+ setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
}
}