summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSal Savage <salsavage@google.com>2019-01-09 15:46:08 -0800
committerSal Savage <salsavage@google.com>2019-01-15 11:56:50 -0800
commit79929d71005b8af04e7489b32728ad4a5c231eb7 (patch)
treed456c93de4bc0f84b52cd7b318a75848a29723f2
parent8af1c3493fa8a855813a538135e274c97aa0a99b (diff)
downloadethernet-79929d71005b8af04e7489b32728ad4a5c231eb7.tar.gz
Allow network transport type override
Bug: b/112588045 Test: atest EthernetServiceTests --verbose Test: kitchensink with RPi devices connected by USB -> Ethernet adapters. Edit config.xml to try different tranport overrides manually. Use dumpsys ethernet to show final final network scores. Change-Id: I482e78a76d06c9c090aa6816db14bb346eb6528b
-rw-r--r--java/com/android/server/ethernet/EthernetNetworkFactory.java119
-rw-r--r--java/com/android/server/ethernet/EthernetTracker.java76
-rw-r--r--tests/java/com/android/server/ethernet/EthernetTrackerTest.java216
3 files changed, 377 insertions, 34 deletions
diff --git a/java/com/android/server/ethernet/EthernetNetworkFactory.java b/java/com/android/server/ethernet/EthernetNetworkFactory.java
index 54bcdc3..1f4f7fa 100644
--- a/java/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/java/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -16,9 +16,11 @@
package com.android.server.ethernet;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
@@ -37,10 +39,12 @@ import android.net.util.InterfaceParams;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
+import java.lang.Math;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -239,6 +243,52 @@ public class EthernetNetworkFactory extends NetworkFactory {
private NetworkAgent mNetworkAgent;
private IpConfiguration mIpConfig;
+ /**
+ * An object to contain all transport type information, including base network score and
+ * the legacy transport type it maps to (if any)
+ */
+ private static class TransportInfo {
+ final int mLegacyType;
+ final int mScore;
+
+ private TransportInfo(int legacyType, int score) {
+ mLegacyType = legacyType;
+ mScore = score;
+ }
+ }
+
+ /**
+ * A map of TRANSPORT_* types to TransportInfo, making scoring and legacy type information
+ * available for each type an ethernet interface could propagate.
+ *
+ * Unfortunately, base scores for the various transports are not yet centrally located.
+ * They've been lifted from the corresponding NetworkFactory files in the meantime.
+ *
+ * Additionally, there are no legacy type equivalents to LOWPAN or WIFI_AWARE. These types
+ * are set to TYPE_NONE to match the behavior of their own network factories.
+ */
+ private static final SparseArray<TransportInfo> sTransports = new SparseArray();
+ static {
+ // LowpanInterfaceTracker.NETWORK_SCORE
+ sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN,
+ new TransportInfo(ConnectivityManager.TYPE_NONE, 30));
+ // WifiAwareDataPathStateManager.NETWORK_FACTORY_SCORE_AVAIL
+ sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE,
+ new TransportInfo(ConnectivityManager.TYPE_NONE, 1));
+ // EthernetNetworkFactory.NETWORK_SCORE
+ sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET,
+ new TransportInfo(ConnectivityManager.TYPE_ETHERNET, 70));
+ // BluetoothTetheringNetworkFactory.NETWORK_SCORE
+ sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH,
+ new TransportInfo(ConnectivityManager.TYPE_BLUETOOTH, 69));
+ // WifiNetworkFactory.SCORE_FILTER / NetworkAgent.WIFI_BASE_SCORE
+ sTransports.put(NetworkCapabilities.TRANSPORT_WIFI,
+ new TransportInfo(ConnectivityManager.TYPE_WIFI, 60));
+ // TelephonyNetworkFactory.TELEPHONY_NETWORK_SCORE
+ sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR,
+ new TransportInfo(ConnectivityManager.TYPE_MOBILE, 50));
+ }
+
long refCount = 0;
private final IpClient.Callback mIpClientCallback = new IpClient.Callback() {
@@ -259,14 +309,23 @@ public class EthernetNetworkFactory extends NetworkFactory {
};
NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context,
- NetworkCapabilities capabilities) {
+ @NonNull NetworkCapabilities capabilities) {
name = ifaceName;
- mCapabilities = capabilities;
+ mCapabilities = checkNotNull(capabilities);
mHandler = handler;
mContext = context;
+ int legacyType = ConnectivityManager.TYPE_NONE;
+ int[] transportTypes = mCapabilities.getTransportTypes();
+ if (transportTypes.length > 0) {
+ legacyType = getLegacyType(transportTypes[0]);
+ } else {
+ // Should never happen as transport is always one of ETHERNET or a valid override
+ Log.w(TAG, "There is no transport type associated with network interface '"
+ + mLinkProperties.getInterfaceName() + "' -- Legacy type set to TYPE_NONE");
+ }
mHwAddress = hwAddress;
- mNetworkInfo = new NetworkInfo(TYPE_ETHERNET, 0, NETWORK_TYPE, "");
+ mNetworkInfo = new NetworkInfo(legacyType, 0, NETWORK_TYPE, "");
mNetworkInfo.setExtraInfo(mHwAddress);
mNetworkInfo.setIsAvailable(true);
}
@@ -283,6 +342,47 @@ public class EthernetNetworkFactory extends NetworkFactory {
return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
+ /**
+ * Determines the legacy transport type from a NetworkCapabilities transport type. Defaults
+ * to legacy TYPE_NONE if there is no known conversion
+ */
+ private static int getLegacyType(int transport) {
+ TransportInfo transportInfo = sTransports.get(transport, /* if dne */ null);
+ if (transportInfo != null) {
+ return transportInfo.mLegacyType;
+ }
+ return ConnectivityManager.TYPE_NONE;
+ }
+
+ /**
+ * Determines the network score based on the transport associated with the interface.
+ * Ethernet interfaces could propagate a transport types forward. Since we can't
+ * get more information about the statuses of the interfaces on the other end of the local
+ * interface, we'll best-effort assign the score as the base score of the assigned transport
+ * when the link is up. When the link is down, the score is set to zero.
+ *
+ * This function is called with the purpose of assigning and updating the network score of
+ * the member NetworkAgent.
+ */
+ private int getNetworkScore() {
+ // never set the network score below 0.
+ if (!mLinkUp) {
+ return 0;
+ }
+
+ int[] transportTypes = mCapabilities.getTransportTypes();
+ if (transportTypes.length < 1) {
+ Log.w(TAG, "There is no transport type associated with network interface '"
+ + mLinkProperties.getInterfaceName() + "' -- Score set to zero");
+ return 0;
+ }
+ TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null);
+ if (transportInfo != null) {
+ return transportInfo.mScore;
+ }
+ return 0;
+ }
+
private void start() {
if (mIpClient != null) {
if (DBG) Log.d(TAG, "IpClient already started");
@@ -317,7 +417,7 @@ public class EthernetNetworkFactory extends NetworkFactory {
// Create our NetworkAgent.
mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,
NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties,
- NETWORK_SCORE) {
+ getNetworkScore()) {
public void unwanted() {
if (this == mNetworkAgent) {
stop();
@@ -390,8 +490,11 @@ public class EthernetNetworkFactory extends NetworkFactory {
mNetworkAgent.sendNetworkCapabilities(mCapabilities);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent.sendLinkProperties(mLinkProperties);
- // never set the network score below 0.
- mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
+
+ // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now
+ // since the agent isn't update frequently. Consider caching the score in the future if
+ // agent updating is required more often
+ mNetworkAgent.sendNetworkScore(getNetworkScore());
}
private void clear() {
@@ -433,7 +536,9 @@ public class EthernetNetworkFactory extends NetworkFactory {
+ "up: " + mLinkUp + ", "
+ "hwAddress: " + mHwAddress + ", "
+ "networkInfo: " + mNetworkInfo + ", "
+ + "networkCapabilities: " + mCapabilities + ", "
+ "networkAgent: " + mNetworkAgent + ", "
+ + "score: " + getNetworkScore() + ", "
+ "ipClient: " + mIpClient + ","
+ "linkProperties: " + mLinkProperties
+ "}";
diff --git a/java/com/android/server/ethernet/EthernetTracker.java b/java/com/android/server/ethernet/EthernetTracker.java
index 00eedd5..099e054 100644
--- a/java/com/android/server/ethernet/EthernetTracker.java
+++ b/java/com/android/server/ethernet/EthernetTracker.java
@@ -294,12 +294,20 @@ final class EthernetTracker {
}
}
+ /**
+ * Parses an Ethernet interface configuration
+ *
+ * @param configString represents an Ethernet configuration in the following format: {@code
+ * <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]}
+ */
private void parseEthernetConfig(String configString) {
- String[] tokens = configString.split(";");
+ String[] tokens = configString.split(";", /* limit of tokens */ 4);
String name = tokens[0];
String capabilities = tokens.length > 1 ? tokens[1] : null;
+ String transport = tokens.length > 3 ? tokens[3] : null;
NetworkCapabilities nc = createNetworkCapabilities(
- !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities);
+ !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities,
+ transport);
mNetworkCapabilities.put(name, nc);
if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) {
@@ -320,24 +328,76 @@ final class EthernetTracker {
}
private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) {
- return createNetworkCapabilities(clearDefaultCapabilities, null);
+ return createNetworkCapabilities(clearDefaultCapabilities, null, null);
}
- private static NetworkCapabilities createNetworkCapabilities(
- boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities) {
+ /**
+ * Parses a static list of network capabilities
+ *
+ * @param clearDefaultCapabilities Indicates whether or not to clear any default capabilities
+ * @param commaSeparatedCapabilities A comma separated string list of integer encoded
+ * NetworkCapability.NET_CAPABILITY_* values
+ * @param overrideTransport A string representing a single override transport type, must be one
+ * of the NetworkCapability.TRANSPORT_* values. TRANSPORT_VPN is
+ * not supported. Errors with input will cause the override to
+ * be ignored.
+ */
+ @VisibleForTesting
+ static NetworkCapabilities createNetworkCapabilities(
+ boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities,
+ @Nullable String overrideTransport) {
NetworkCapabilities nc = new NetworkCapabilities();
if (clearDefaultCapabilities) {
- nc.clearAll(); // Remove default capabilities.
+ nc.clearAll(); // Remove default capabilities and transports
+ }
+
+ // Determine the transport type. If someone has tried to define an override transport then
+ // attempt to add it. Since we can only have one override, all errors with it will
+ // gracefully default back to TRANSPORT_ETHERNET and warn the user. VPN is not allowed as an
+ // override type. Wifi Aware and LoWPAN are currently unsupported as well.
+ int transport = NetworkCapabilities.TRANSPORT_ETHERNET;
+ if (!TextUtils.isEmpty(overrideTransport)) {
+ try {
+ int parsedTransport = Integer.valueOf(overrideTransport);
+ if (parsedTransport == NetworkCapabilities.TRANSPORT_VPN
+ || parsedTransport == NetworkCapabilities.TRANSPORT_WIFI_AWARE
+ || parsedTransport == NetworkCapabilities.TRANSPORT_LOWPAN) {
+ Log.e(TAG, "Override transport '" + parsedTransport + "' is not supported -- "
+ + "Defaulting to TRANSPORT_ETHERNET");
+ } else {
+ transport = parsedTransport;
+ }
+ } catch (NumberFormatException nfe) {
+ Log.e(TAG, "Override transport type '" + overrideTransport + "' could not be parsed"
+ + "-- Defaulting to TRANSPORT_ETHERNET");
+ }
+ }
+
+ // Apply the transport. If the user supplied a valid number that is not a valid transport
+ // then adding will throw an exception. Default back to TRANSPORT_ETHERNET if that happens
+ try {
+ nc.addTransportType(transport);
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value"
+ + " -- Defaulting to TRANSPORT_ETHERNET");
+ nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
}
- nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
+
nc.setLinkUpstreamBandwidthKbps(100 * 1000);
nc.setLinkDownstreamBandwidthKbps(100 * 1000);
if (!TextUtils.isEmpty(commaSeparatedCapabilities)) {
for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) {
if (!TextUtils.isEmpty(strNetworkCapability)) {
- nc.addCapability(Integer.valueOf(strNetworkCapability));
+ try {
+ nc.addCapability(Integer.valueOf(strNetworkCapability));
+ } catch (NumberFormatException nfe) {
+ Log.e(TAG, "Capability '" + strNetworkCapability + "' could not be parsed");
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, strNetworkCapability + " is not a valid "
+ + "NetworkCapability.NET_CAPABILITY_* value");
+ }
}
}
}
diff --git a/tests/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/java/com/android/server/ethernet/EthernetTrackerTest.java
index 70d316d..a56c9fe 100644
--- a/tests/java/com/android/server/ethernet/EthernetTrackerTest.java
+++ b/tests/java/com/android/server/ethernet/EthernetTrackerTest.java
@@ -23,6 +23,7 @@ import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
+import android.net.NetworkCapabilities;
import android.net.StaticIpConfiguration;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -35,47 +36,55 @@ import java.net.InetAddress;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class EthernetTrackerTest {
-
+ /**
+ * Test: Creation of various valid static IP configurations
+ */
@Test
public void createStaticIpConfiguration() {
- assertStaticConfiguration("", new StaticIpConfiguration());
+ // Empty gives default StaticIPConfiguration object
+ assertStaticConfiguration(new StaticIpConfiguration(), "");
+ // Setting only the IP address properly cascades and assumes defaults
assertStaticConfiguration(
- "ip=192.0.2.10/24",
- new StaticIpConfigBuilder().setIp("192.0.2.10/24").build());
+ new StaticIpConfigBuilder().setIp("192.0.2.10/24").build(),
+ "ip=192.0.2.10/24");
+ // Setting other fields properly cascades them
assertStaticConfiguration(
- "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android",
new StaticIpConfigBuilder()
.setIp("192.0.2.10/24")
.setDns(new String[] {"4.4.4.4", "8.8.8.8"})
.setGateway("192.0.2.1")
.setDomains("android")
- .build());
+ .build(),
+ "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android");
// Verify order doesn't matter
assertStaticConfiguration(
- "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ",
new StaticIpConfigBuilder()
.setIp("192.0.2.10/24")
.setDns(new String[] {"4.4.4.4", "8.8.8.8"})
.setGateway("192.0.2.1")
.setDomains("android")
- .build());
+ .build(),
+ "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ");
}
+ /**
+ * Test: Attempt creation of various bad static IP configurations
+ */
@Test
public void createStaticIpConfiguration_Bad() {
- assertFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key
- assertFails("ip=192.0.2.1"); // mask is missing
- assertFails("ip=a.b.c"); // not a valid ip address
- assertFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns
- assertFails("="); // Key and value is empty
- assertFails("ip="); // Value is empty
- assertFails("ip=192.0.2.1/24 gateway="); // Gateway is empty
+ assertStaticConfigurationFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key
+ assertStaticConfigurationFails("ip=192.0.2.1"); // mask is missing
+ assertStaticConfigurationFails("ip=a.b.c"); // not a valid ip address
+ assertStaticConfigurationFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns
+ assertStaticConfigurationFails("="); // Key and value is empty
+ assertStaticConfigurationFails("ip="); // Value is empty
+ assertStaticConfigurationFails("ip=192.0.2.1/24 gateway="); // Gateway is empty
}
- private void assertFails(String config) {
+ private void assertStaticConfigurationFails(String config) {
try {
EthernetTracker.parseStaticIpConfiguration(config);
fail("Expected to fail: " + config);
@@ -84,8 +93,8 @@ public class EthernetTrackerTest {
}
}
- private void assertStaticConfiguration(String configAsString,
- StaticIpConfiguration expectedStaticIpConfig) {
+ private void assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig,
+ String configAsString) {
IpConfiguration expectedIpConfiguration = new IpConfiguration(IpAssignment.STATIC,
ProxySettings.NONE, expectedStaticIpConfig, null);
@@ -118,9 +127,178 @@ public class EthernetTrackerTest {
return this;
}
-
StaticIpConfiguration build() {
return new StaticIpConfiguration(config);
}
}
+
+ /**
+ * Test: Attempt to create a capabilties with various valid sets of capabilities/transports
+ */
+ @Test
+ public void createNetworkCapabilities() {
+
+ // Particularly common expected results
+ NetworkCapabilities defaultEthernetCleared = new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .build();
+
+ NetworkCapabilities ethernetClearedWithCommonCaps = new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addCapability(12)
+ .addCapability(13)
+ .addCapability(14)
+ .addCapability(15)
+ .build();
+
+ // Empty capabilities and transports lists with a "please clear defaults" should
+ // yield an empty capabilities set with TRANPORT_ETHERNET
+ assertNetworkCapabilities(defaultEthernetCleared, true, "", "");
+
+ // Empty capabilities and transports without the clear defaults flag should return the
+ // default capabilities set with TRANSPORT_ETHERNET
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .build(),
+ false, "", "");
+
+ // A list of capabilities without the clear defaults flag should return the default
+ // capabilities, mixed with the desired capabilities, and TRANSPORT_ETHERNET
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addCapability(11)
+ .addCapability(12)
+ .build(),
+ false, "11,12", "");
+
+ // Adding a list of capabilities with a clear defaults will leave exactly those capabilities
+ // with a default TRANSPORT_ETHERNET since no overrides are specified
+ assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15", "");
+
+ // Adding any invalid capabilities to the list will cause them to be ignored
+ assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,65,73", "");
+ assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,abcdefg", "");
+
+ // Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport
+ // and apply only the override to the capabiltities object
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(0)
+ .build(),
+ true, "", "0");
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(1)
+ .build(),
+ true, "", "1");
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(2)
+ .build(),
+ true, "", "2");
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransport(3)
+ .build(),
+ true, "", "3");
+
+ // "4" is TRANSPORT_VPN, which is unsupported. Should default back to TRANPORT_ETHERNET
+ assertNetworkCapabilities(defaultEthernetCleared, true, "", "4");
+
+ // "5" is TRANSPORT_WIFI_AWARE, which is currently supported due to no legacy TYPE_NONE
+ // conversion. When that becomes available, this test must be updated
+ assertNetworkCapabilities(defaultEthernetCleared, true, "", "5");
+
+ // "6" is TRANSPORT_LOWPAN, which is currently supported due to no legacy TYPE_NONE
+ // conversion. When that becomes available, this test must be updated
+ assertNetworkCapabilities(defaultEthernetCleared, true, "", "6");
+
+ // Adding an invalid override transport will leave the transport as TRANSPORT_ETHERNET
+ assertNetworkCapabilities(defaultEthernetCleared,true, "", "100");
+ assertNetworkCapabilities(defaultEthernetCleared, true, "", "abcdefg");
+
+ // Ensure the adding of both capabilities and transports work
+ assertNetworkCapabilities(
+ new NetworkCapabilitiesBuilder()
+ .clearAll()
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addCapability(12)
+ .addCapability(13)
+ .addCapability(14)
+ .addCapability(15)
+ .addTransport(3)
+ .build(),
+ true, "12,13,14,15", "3");
+
+ // Ensure order does not matter for capability list
+ assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "13,12,15,14", "");
+ }
+
+ private void assertNetworkCapabilities(NetworkCapabilities expectedNetworkCapabilities,
+ boolean clearCapabilties, String configCapabiltiies,String configTransports) {
+ assertEquals(expectedNetworkCapabilities,
+ EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies,
+ configTransports));
+ }
+
+ private static class NetworkCapabilitiesBuilder {
+ private final NetworkCapabilities nc = new NetworkCapabilities();
+
+ NetworkCapabilitiesBuilder clearAll(){
+ // This is THE ONLY one that doesn't return a reference to the object so I wrapped
+ // everything in a builder to keep things consistent and clean above. Fix if this
+ // ever changes
+ nc.clearAll();
+ return this;
+ }
+
+ NetworkCapabilitiesBuilder addCapability(int capability) {
+ nc.addCapability(capability);
+ return this;
+ }
+
+ NetworkCapabilitiesBuilder addTransport(int transport) {
+ nc.addTransportType(transport);
+ return this;
+ }
+
+ NetworkCapabilitiesBuilder setLinkUpstreamBandwidthKbps(int upKbps) {
+ nc.setLinkUpstreamBandwidthKbps(upKbps);
+ return this;
+ }
+
+ NetworkCapabilitiesBuilder setLinkDownstreamBandwidthKbps(int downKbps) {
+ nc.setLinkDownstreamBandwidthKbps(downKbps);
+ return this;
+ }
+
+ NetworkCapabilities build() {
+ return new NetworkCapabilities(nc);
+ }
+ }
}