UpstreamNetworkMonitor: add NOTIFY_TEST_NETWORK_AVAILABLE
Used for test interface upstream can replace existing non-test
upstream interface, like ethernet on cuttlefish.
This helps to fix the flaky test when we are using test interface on
cuttlefish. Because the ethernet and test interface upstream update
event order can't be guaranteed.
Bug: 237369591
Bug: 242067530
Test: atest ConnectivityCoverageTests
Change-Id: I9da71ee116bf1ebc9831f61f25acf42e328a8370
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 75f63c8..5191bb7 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -1975,6 +1975,10 @@
return;
}
+ if (arg1 == UpstreamNetworkMonitor.NOTIFY_TEST_NETWORK_AVAILABLE) {
+ chooseUpstreamType(false);
+ }
+
if (ns == null || !pertainsToCurrentUpstream(ns)) {
// TODO: In future, this is where upstream evaluation and selection
// could be handled for notifications which include sufficient data.
diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 16c031b..15df0c6 100644
--- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -85,11 +85,12 @@
private static final boolean DBG = false;
private static final boolean VDBG = false;
- public static final int EVENT_ON_CAPABILITIES = 1;
- public static final int EVENT_ON_LINKPROPERTIES = 2;
- public static final int EVENT_ON_LOST = 3;
- public static final int EVENT_DEFAULT_SWITCHED = 4;
- public static final int NOTIFY_LOCAL_PREFIXES = 10;
+ public static final int EVENT_ON_CAPABILITIES = 1;
+ public static final int EVENT_ON_LINKPROPERTIES = 2;
+ public static final int EVENT_ON_LOST = 3;
+ public static final int EVENT_DEFAULT_SWITCHED = 4;
+ public static final int NOTIFY_LOCAL_PREFIXES = 10;
+ public static final int NOTIFY_TEST_NETWORK_AVAILABLE = 11;
// This value is used by deprecated preferredUpstreamIfaceTypes selection which is default
// disabled.
@VisibleForTesting
@@ -467,6 +468,17 @@
notifyTarget(EVENT_DEFAULT_SWITCHED, ns);
}
+ private void maybeHandleTestNetwork(@NonNull Network network) {
+ if (!mPreferTestNetworks) return;
+
+ final UpstreamNetworkState ns = mNetworkMap.get(network);
+ if (network.equals(mTetheringUpstreamNetwork) || !isTestNetwork(ns)) return;
+
+ // Test network is available. Notify tethering.
+ Log.d(TAG, "Handle test network: " + network);
+ notifyTarget(NOTIFY_TEST_NETWORK_AVAILABLE, ns);
+ }
+
private void recomputeLocalPrefixes() {
final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
if (!mLocalPrefixes.equals(localPrefixes)) {
@@ -549,6 +561,12 @@
// So it's not useful to do this work for non-LISTEN_ALL callbacks.
if (mCallbackType == CALLBACK_LISTEN_ALL) {
recomputeLocalPrefixes();
+
+ // When the LISTEN_ALL network callback calls onLinkPropertiesChanged, it means that
+ // all the network information for the network is known (because
+ // onLinkPropertiesChanged is called after onAvailable and onCapabilitiesChanged).
+ // Inform tethering that the test network might have changed.
+ maybeHandleTestNetwork(network);
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
index b2cbf75..e0d77ee 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
@@ -19,6 +19,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static com.android.networkstack.apishim.common.ShimUtils.isAtLeastS;
@@ -329,6 +330,28 @@
this.legacyType = toLegacyType(networkCapabilities);
}
+ // Used for test network only because ConnectivityManager.networkCapabilitiesForType
+ // doesn't support "TRANSPORT_TEST -> TYPE_TEST" in #matchesLegacyType. Beware of
+ // satisfiedByNetworkCapabilities doesn't check on new |networkCapabilities| as
+ // #matchesLegacyType.
+ // TODO: refactor when tethering no longer uses CONNECTIVITY_ACTION.
+ private TestNetworkAgent(TestConnectivityManager cm) {
+ this.cm = cm;
+ networkId = new Network(cm.getNetworkId());
+ networkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_TEST)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ linkProperties = new LinkProperties();
+ legacyType = TYPE_TEST;
+ }
+
+ // TODO: refactor when tethering no longer uses CONNECTIVITY_ACTION.
+ public static TestNetworkAgent buildTestNetworkAgentForTestNetwork(
+ TestConnectivityManager cm) {
+ return new TestNetworkAgent(cm);
+ }
+
private static int toLegacyType(NetworkCapabilities nc) {
for (int type = 0; type < ConnectivityManager.TYPE_TEST; type++) {
if (matchesLegacyType(nc, type)) return type;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
index 9b9507b..b0cb7f2 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
@@ -449,6 +449,36 @@
}
@Test
+ public void testGetCurrentPreferredUpstream_TestNetworkPreferred() throws Exception {
+ mUNM.startTrackDefaultNetwork(mEntitleMgr);
+ mUNM.startObserveAllNetworks();
+ mUNM.setUpstreamConfig(true /* autoUpstream */, false /* dunRequired */);
+ mUNM.setTryCell(true);
+ mUNM.setPreferTestNetworks(true);
+
+ // [1] Mobile connects, DUN not required -> mobile selected.
+ final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, CELL_CAPABILITIES);
+ cellAgent.fakeConnect();
+ mCM.makeDefaultNetwork(cellAgent);
+ mLooper.dispatchAll();
+ assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+ assertEquals(0, mCM.mRequested.size());
+
+ // [2] Test network connects -> test network selected.
+ final TestNetworkAgent testAgent =
+ TestNetworkAgent.buildTestNetworkAgentForTestNetwork(mCM);
+ testAgent.fakeConnect();
+ mLooper.dispatchAll();
+ assertEquals(testAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+ assertEquals(0, mCM.mRequested.size());
+
+ // [3] Disable test networks preferred -> mobile selected.
+ mUNM.setPreferTestNetworks(false);
+ assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+ assertEquals(0, mCM.mRequested.size());
+ }
+
+ @Test
public void testLocalPrefixes() throws Exception {
mUNM.startTrackDefaultNetwork(mEntitleMgr);
mUNM.startObserveAllNetworks();