Merge "ethernet: increase test timeout to account for rs delay / retry"
diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags
index 2905e28..109bbda 100644
--- a/Tethering/proguard.flags
+++ b/Tethering/proguard.flags
@@ -1,7 +1,10 @@
# Keep class's integer static field for MessageUtils to parsing their name.
--keep class com.android.networkstack.tethering.Tethering$TetherMainSM {
- static final int CMD_*;
- static final int EVENT_*;
+-keepclassmembers class com.android.server.**,android.net.**,com.android.networkstack.** {
+ static final % POLICY_*;
+ static final % NOTIFY_TYPE_*;
+ static final % TRANSPORT_*;
+ static final % CMD_*;
+ static final % EVENT_*;
}
-keep class com.android.networkstack.tethering.util.BpfMap {
@@ -21,12 +24,8 @@
*;
}
--keepclassmembers class android.net.ip.IpServer {
- static final int CMD_*;
-}
-
# The lite proto runtime uses reflection to access fields based on the names in
# the schema, keep all the fields.
-keepclassmembers class * extends com.android.networkstack.tethering.protobuf.MessageLite {
<fields>;
-}
\ No newline at end of file
+}
diff --git a/service/proguard.flags b/service/proguard.flags
index 478566c..864a28b 100644
--- a/service/proguard.flags
+++ b/service/proguard.flags
@@ -6,3 +6,12 @@
-keepclassmembers public class * extends **.com.android.net.module.util.Struct {
*;
}
+
+-keepclassmembers class com.android.server.**,android.net.**,com.android.networkstack.** {
+ static final % POLICY_*;
+ static final % NOTIFY_TYPE_*;
+ static final % TRANSPORT_*;
+ static final % CMD_*;
+ static final % EVENT_*;
+}
+
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 10b3dc8..f8b47d2 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -3650,8 +3650,18 @@
break;
}
case NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT: {
- // If nai is not yet created, or is already destroyed, ignore.
- if (!shouldDestroyNativeNetwork(nai)) break;
+ if (!nai.isCreated()) {
+ Log.d(TAG, "unregisterAfterReplacement on uncreated " + nai.toShortString()
+ + ", tearing down instead");
+ teardownUnneededNetwork(nai);
+ break;
+ }
+
+ if (nai.isDestroyed()) {
+ Log.d(TAG, "unregisterAfterReplacement on destroyed " + nai.toShortString()
+ + ", ignoring");
+ break;
+ }
final int timeoutMs = (int) arg.second;
if (timeoutMs < 0 || timeoutMs > NetworkAgent.MAX_TEARDOWN_DELAY_MS) {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 310d7bf..4887a78 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -270,7 +270,10 @@
private static final int MIN_KEEPALIVE_INTERVAL = 10;
private static final int NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
- private static final int LISTEN_ACTIVITY_TIMEOUT_MS = 5_000;
+ // Timeout for waiting network to be validated. Set the timeout to 30s, which is more than
+ // DNS timeout.
+ // TODO(b/252972908): reset the original timer when aosp/2188755 is ramped up.
+ private static final int LISTEN_ACTIVITY_TIMEOUT_MS = 30_000;
private static final int NO_CALLBACK_TIMEOUT_MS = 100;
private static final int SOCKET_TIMEOUT_MS = 100;
private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index d2cd7aa..867d672 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -335,6 +335,28 @@
mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID)))
}
+ fun assertLinkPropertiesEventually(
+ n: Network,
+ description: String,
+ condition: (LinkProperties?) -> Boolean
+ ): LinkProperties? {
+ val deadline = SystemClock.elapsedRealtime() + DEFAULT_TIMEOUT_MS
+ do {
+ val lp = mCM.getLinkProperties(n)
+ if (condition(lp)) return lp
+ SystemClock.sleep(10 /* ms */)
+ } while (SystemClock.elapsedRealtime() < deadline)
+ fail("Network $n LinkProperties did not $description after $DEFAULT_TIMEOUT_MS ms")
+ }
+
+ fun assertLinkPropertiesEventuallyNotNull(n: Network) {
+ assertLinkPropertiesEventually(n, "become non-null") { it != null }
+ }
+
+ fun assertLinkPropertiesEventuallyNull(n: Network) {
+ assertLinkPropertiesEventually(n, "become null") { it == null }
+ }
+
@Test
fun testSetSubtypeNameAndExtraInfoByAgentConfig() {
val subtypeLTE = TelephonyManager.NETWORK_TYPE_LTE
@@ -1269,8 +1291,40 @@
agent5.expectCallback<OnNetworkDestroyed>()
agent5.expectCallback<OnNetworkUnwanted>()
+ // If unregisterAfterReplacement is called before markConnected, the network disconnects.
+ val specifier6 = UUID.randomUUID().toString()
+ val callback = TestableNetworkCallback()
+ requestNetwork(makeTestNetworkRequest(specifier = specifier6), callback)
+ val agent6 = createNetworkAgent(specifier = specifier6)
+ val network6 = agent6.register()
+ // No callbacks are sent, so check the LinkProperties to see if the network has connected.
+ assertLinkPropertiesEventuallyNotNull(agent6.network!!)
+
+ // unregisterAfterReplacement tears down the network immediately.
+ // Approximately check that this is the case by picking an unregister timeout that's longer
+ // than the timeout of the expectCallback<OnNetworkUnwanted> below.
+ // TODO: consider adding configurable timeouts to TestableNetworkAgent expectations.
+ val timeoutMs = agent6.DEFAULT_TIMEOUT_MS.toInt() + 1_000
+ agent6.unregisterAfterReplacement(timeoutMs)
+ agent6.expectCallback<OnNetworkUnwanted>()
+ if (!SdkLevel.isAtLeastT()) {
+ // Before T, onNetworkDestroyed is called even if the network was never created.
+ agent6.expectCallback<OnNetworkDestroyed>()
+ }
+ // Poll for LinkProperties becoming null, because when onNetworkUnwanted is called, the
+ // network has not yet been removed from the CS data structures.
+ assertLinkPropertiesEventuallyNull(agent6.network!!)
+ assertFalse(mCM.getAllNetworks().contains(agent6.network!!))
+
+ // After unregisterAfterReplacement is called, the network is no longer usable and
+ // markConnected has no effect.
+ agent6.markConnected()
+ agent6.assertNoCallback()
+ assertNull(mCM.getLinkProperties(agent6.network!!))
+ matchAllCallback.assertNoCallback(200 /* timeoutMs */)
+
// If wifi is replaced within the timeout, the device does not switch to cellular.
- val (cellAgent, cellNetwork) = connectNetwork(TRANSPORT_CELLULAR)
+ val (_, cellNetwork) = connectNetwork(TRANSPORT_CELLULAR)
testCallback.expectAvailableThenValidatedCallbacks(cellNetwork)
matchAllCallback.expectAvailableThenValidatedCallbacks(cellNetwork)
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index cb68235..437622b 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -101,7 +101,7 @@
],
static_libs: [
"androidx.test.rules",
- "androidx.test.uiautomator",
+ "androidx.test.uiautomator_uiautomator",
"bouncycastle-repackaged-unbundled",
"core-tests-support",
"FrameworksNetCommonTests",
diff --git a/tests/unit/java/android/net/NetworkStatsTest.java b/tests/unit/java/android/net/NetworkStatsTest.java
index 709b722..126ad55 100644
--- a/tests/unit/java/android/net/NetworkStatsTest.java
+++ b/tests/unit/java/android/net/NetworkStatsTest.java
@@ -1067,6 +1067,38 @@
}
}
+ @Test
+ public void testClearInterfaces() {
+ final NetworkStats stats = new NetworkStats(TEST_START, 1);
+ final NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1024L, 50L, 100L, 20L, 0L);
+
+ final NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ "test2", 10101, SET_DEFAULT, 0xF0DD, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 51200, 25L, 101010L, 50L, 0L);
+
+ stats.insertEntry(entry1);
+ stats.insertEntry(entry2);
+
+ // Verify that the interfaces have indeed been recorded.
+ assertEquals(2, stats.size());
+ assertValues(stats, 0, "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 50L, 100L, 20L, 0L);
+ assertValues(stats, 1, "test2", 10101, SET_DEFAULT, 0xF0DD, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 51200, 25L, 101010L, 50L, 0L);
+
+ // Clear interfaces.
+ stats.clearInterfaces();
+
+ // Verify that the interfaces are cleared.
+ assertEquals(2, stats.size());
+ assertValues(stats, 0, null /* iface */, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 50L, 100L, 20L, 0L);
+ assertValues(stats, 1, null /* iface */, 10101, SET_DEFAULT, 0xF0DD, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 51200, 25L, 101010L, 50L, 0L);
+ }
+
private static void assertContains(NetworkStats stats, String iface, int uid, int set,
int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 1c54651..39fd780 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -20,6 +20,8 @@
import static android.Manifest.permission.CONTROL_VPN;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP;
@@ -76,6 +78,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.net.ConnectivityDiagnosticsManager;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.Ikev2VpnProfile;
@@ -115,6 +118,7 @@
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.PowerWhitelistManager;
import android.os.Process;
import android.os.UserHandle;
@@ -245,6 +249,7 @@
@Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
@Mock private Vpn.VpnNetworkAgentWrapper mMockNetworkAgent;
@Mock private ConnectivityManager mConnectivityManager;
+ @Mock private ConnectivityDiagnosticsManager mCdm;
@Mock private IpSecService mIpSecService;
@Mock private VpnProfileStore mVpnProfileStore;
@Mock private ScheduledThreadPoolExecutor mExecutor;
@@ -283,6 +288,8 @@
mockService(NotificationManager.class, Context.NOTIFICATION_SERVICE, mNotificationManager);
mockService(ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mConnectivityManager);
mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
+ mockService(ConnectivityDiagnosticsManager.class, Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
+ mCdm);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -1925,6 +1932,56 @@
verifyHandlingNetworkLoss(vpnSnapShot);
}
+ private ConnectivityDiagnosticsCallback getConnectivityDiagCallback() {
+ final ArgumentCaptor<ConnectivityDiagnosticsCallback> cdcCaptor =
+ ArgumentCaptor.forClass(ConnectivityDiagnosticsCallback.class);
+ verify(mCdm).registerConnectivityDiagnosticsCallback(
+ any(), any(), cdcCaptor.capture());
+ return cdcCaptor.getValue();
+ }
+
+ private DataStallReport createDataStallReport() {
+ return new DataStallReport(TEST_NETWORK, 1234 /* reportTimestamp */,
+ 1 /* detectionMethod */, new LinkProperties(), new NetworkCapabilities(),
+ new PersistableBundle());
+ }
+
+ private void verifyMobikeTriggered(List<Network> expected) {
+ final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class);
+ verify(mIkeSessionWrapper).setNetwork(networkCaptor.capture());
+ assertEquals(expected, Collections.singletonList(networkCaptor.getValue()));
+ }
+
+ @Test
+ public void testDataStallInIkev2VpnMobikeDisabled() throws Exception {
+ verifySetupPlatformVpn(
+ createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
+
+ doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+ final ConnectivityDiagnosticsCallback connectivityDiagCallback =
+ getConnectivityDiagCallback();
+ final DataStallReport report = createDataStallReport();
+ connectivityDiagCallback.onDataStallSuspected(report);
+
+ // Should not trigger MOBIKE if MOBIKE is not enabled
+ verify(mIkeSessionWrapper, never()).setNetwork(any());
+ }
+
+ @Test
+ public void testDataStallInIkev2VpnMobikeEnabled() throws Exception {
+ final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+ createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+ doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+ final ConnectivityDiagnosticsCallback connectivityDiagCallback =
+ getConnectivityDiagCallback();
+ final DataStallReport report = createDataStallReport();
+ connectivityDiagCallback.onDataStallSuspected(report);
+
+ // Verify MOBIKE is triggered
+ verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+ }
+
@Test
public void testStartRacoonNumericAddress() throws Exception {
startRacoon("1.2.3.4", "1.2.3.4");