From 00c17ed78dce2f3dc71fcb8c762a188fdf6bafbf Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 21 Mar 2025 12:33:11 -0700 Subject: [PATCH 1/2] Move NetworkCapabilities parsing to EthernetConfigParser entirely Previously, this code path was hard to follow. EthernetConfigParser parsed the capabilities specified in the xml, while createDefaultNetworkCapabilities and / or createNetworkCapabilities added additional capabilities to those specified in the xml. This change moves the creation of the final NetworkCapabilities for configured interfaces inside EthernetConfigParser to make it easier to follow. Test: TH Change-Id: I367f53774eeee5aeca0fa7071db0403a6ce8bac5 --- .../server/ethernet/EthernetTracker.java | 137 ++++++------- .../server/ethernet/EthernetTrackerTest.java | 181 +++++------------- 2 files changed, 98 insertions(+), 220 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 1c453cb4e8..e41f1d692a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -69,7 +69,6 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; -import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; @@ -104,6 +103,22 @@ public class EthernetTracker { // TODO: consider using SharedLog consistently across ethernet service. private static final SharedLog sLog = new SharedLog(TAG); + @VisibleForTesting + public static final NetworkCapabilities DEFAULT_CAPABILITIES = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_ETHERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + // TODO: do not hardcode link bandwidth. + .setLinkUpstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) + .setLinkDownstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) + .build(); + + /** * Interface names we track. This is a product-dependent regular expression. * Use isValidEthernetInterface to check if a interface name is a valid ethernet interface (this @@ -648,7 +663,7 @@ public class EthernetTracker { nc = mNetworkCapabilities.get(hwAddress); if (nc == null) { final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); - nc = createDefaultNetworkCapabilities(isTestIface, TRANSPORT_ETHERNET); + nc = createDefaultNetworkCapabilities(isTestIface); } } @@ -762,24 +777,9 @@ public class EthernetTracker { * ;[Network Capabilities];[IP config];[Override Transport]} */ private void parseEthernetConfig(String configString) { - final EthernetConfigParser config = new EthernetConfigParser(configString); - NetworkCapabilities nc; - // Starting with Android B (API level 36), we provide default NetworkCapabilities - // for Ethernet interfaces when no explicit capabilities are specified in the - // configuration string. This change is made to ensure consistent and expected - // network behavior for Ethernet devices. - // - // It's possible that OEMs or device manufacturers may have relied on the previous - // behavior (where interfaces without specified capabilities would have minimal - // capabilities) to prevent certain Ethernet interfaces from becoming - // the default network. To avoid breaking existing device configurations, this - // change is gated by the SDK level. - if (mDeps.isAtLeastB() && config.mCaps.isEmpty()) { - nc = createDefaultNetworkCapabilities(false /* isTestIface */, config.mTransport); - } else { - nc = createNetworkCapabilities(config.mCaps, config.mTransport).build(); - } - mNetworkCapabilities.put(config.mIface, nc); + final EthernetConfigParser config = + new EthernetConfigParser(configString, mDeps.isAtLeastB()); + mNetworkCapabilities.put(config.mIface, config.mCaps); if (null != config.mIpConfig) { IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig); @@ -787,65 +787,18 @@ public class EthernetTracker { } } - private static NetworkCapabilities createDefaultNetworkCapabilities( - boolean isTestIface, int transportType) { - NetworkCapabilities.Builder builder = - createNetworkCapabilities(Collections.emptyList(), transportType) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - + private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { + final NetworkCapabilities.Builder builder = + new NetworkCapabilities.Builder(DEFAULT_CAPABILITIES); if (isTestIface) { builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); - } else { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + // TODO: do not remove INTERNET capability for test networks. + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } return builder.build(); } - /** - * Parses a static list of network capabilities - * - * @param capabilities A List of NetworkCapabilities. - * @param overrideTransport A string representing a single integer encoded 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.Builder createNetworkCapabilities(List capabilities, - int transportType) { - - final NetworkCapabilities.Builder builder = - capabilities.isEmpty() - ? new NetworkCapabilities.Builder() - : NetworkCapabilities.Builder.withoutDefaultCapabilities(); - - // 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. - builder.addTransportType(transportType); - - builder.setLinkUpstreamBandwidthKbps(100 * 1000); - builder.setLinkDownstreamBandwidthKbps(100 * 1000); - - for (int capability : capabilities) { - builder.addCapability(capability); - } - // Ethernet networks have no way to update the following capabilities, so they always - // have them. - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - - return builder; - } - /** * Parses static IP configuration. * @@ -1017,30 +970,43 @@ public class EthernetTracker { @VisibleForTesting static class EthernetConfigParser { final String mIface; - final List mCaps; + final NetworkCapabilities mCaps; final String mIpConfig; - final int mTransport; - private static List parseCapabilities(@Nullable String capabilitiesString) { + private static NetworkCapabilities parseCapabilities(@Nullable String capabilitiesString, + boolean isAtLeastB) { + final NetworkCapabilities.Builder builder = + NetworkCapabilities.Builder.withoutDefaultCapabilities(); + builder.setLinkUpstreamBandwidthKbps(100 * 1000 /* 100 Mbps */); + builder.setLinkDownstreamBandwidthKbps(100 * 1000 /* 100 Mbps */); + // Ethernet networks have no way to update the following capabilities, so they always + // have them. + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + if (TextUtils.isEmpty(capabilitiesString)) { - return Collections.emptyList(); + if (!isAtLeastB) { + return builder.build(); + } + // On Android B+, a null or empty string defaults to the same set of default + // capabilities assigned to unconfigured interfaces. + return new NetworkCapabilities(DEFAULT_CAPABILITIES); } - final ArrayList capabilities = new ArrayList<>(); for (String strNetworkCapability : capabilitiesString.split(",")) { if (TextUtils.isEmpty(strNetworkCapability)) { continue; } final Integer capability; try { - capability = Integer.valueOf(strNetworkCapability); + builder.addCapability(Integer.valueOf(strNetworkCapability)); } catch (NumberFormatException e) { Log.e(TAG, "Failed to parse capability: " + strNetworkCapability, e); continue; } - capabilities.add(capability); } - return Collections.unmodifiableList(capabilities); + return builder.build(); } private static int parseTransportType(@Nullable String transportString) { @@ -1071,13 +1037,18 @@ public class EthernetTracker { } } - EthernetConfigParser(String configString) { + EthernetConfigParser(String configString, boolean isAtLeastB) { Objects.requireNonNull(configString, "EthernetConfigParser requires non-null config"); final String[] tokens = configString.split(";", /* limit of tokens */ 4); mIface = tokens[0]; - mCaps = parseCapabilities(tokens.length > 1 ? tokens[1] : null); + + final NetworkCapabilities nc = + parseCapabilities(tokens.length > 1 ? tokens[1] : null, isAtLeastB); + final int transportType = parseTransportType(tokens.length > 3 ? tokens[3] : null); + nc.addTransportType(transportType); + mCaps = nc; + mIpConfig = tokens.length > 2 && !TextUtils.isEmpty(tokens[2]) ? tokens[2] : null; - mTransport = parseTransportType(tokens.length > 3 ? tokens[3] : null); } } } diff --git a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java index 03fb505c10..dc469a168c 100644 --- a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -180,163 +180,70 @@ public class EthernetTrackerTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); } - /** - * Test: Attempt to create a capabilities with various valid sets of capabilities/transports - */ + @Test - public void createNetworkCapabilities() { - // Particularly common expected results - NetworkCapabilities defaultCapabilities = - makeEthernetCapabilitiesBuilder(false /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) - .build(); + public void testNetworkCapabilityParsing() { + final NetworkCapabilities baseNc = NetworkCapabilities.Builder.withoutDefaultCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .setLinkUpstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) + .setLinkDownstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .build(); - NetworkCapabilities ethernetClearedWithCommonCaps = - makeEthernetCapabilitiesBuilder(true /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) - .addCapability(12) - .addCapability(13) - .addCapability(14) - .addCapability(15) - .build(); + EthernetConfigParser parser = new EthernetConfigParser("eth0;", false /*isAtLeastB*/); + assertThat(parser.mCaps).isEqualTo(baseNc); - // Empty capabilities and transports should return the default capabilities set - // with TRANSPORT_ETHERNET - assertParsedNetworkCapabilities(defaultCapabilities, "", ""); + // On Android B+, empty capabilities default to using DEFAULT_CAPABILITIES. + parser = new EthernetConfigParser("eth0;;;;;;;", true /*isAtLeastB*/); + assertThat(parser.mCaps).isEqualTo(EthernetTracker.DEFAULT_CAPABILITIES); - // Adding a list of capabilities will leave exactly those capabilities with a default - // TRANSPORT_ETHERNET since no overrides are specified - assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, "12,13,14,15", ""); + parser = new EthernetConfigParser("eth0;12,13,14,15;", false /*isAtLeastB*/); + assertThat(parser.mCaps.getCapabilities()).asList().containsAtLeast(12, 13, 14, 15); - // Adding any invalid capabilities to the list will cause them to be ignored - assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, "12,13,14,15,65,73", ""); - assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, "12,13,14,15,abcdefg", ""); + parser = new EthernetConfigParser("eth0;12,13,500,abc", false /*isAtLeastB*/); + // 18, 20, 21 are added by EthernetConfigParser. + assertThat(parser.mCaps.getCapabilities()).asList().containsExactly(12, 13, 18, 20, 21); - // Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport - // and apply only the override to the capabilities object - assertParsedNetworkCapabilities( - makeEthernetCapabilitiesBuilder(false /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransportType(0) - .build(), - "", - "0"); - assertParsedNetworkCapabilities( - makeEthernetCapabilitiesBuilder(false /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransportType(1) - .build(), - "", - "1"); - assertParsedNetworkCapabilities( - makeEthernetCapabilitiesBuilder(false /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransportType(2) - .build(), - "", - "2"); - assertParsedNetworkCapabilities( - makeEthernetCapabilitiesBuilder(false /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransportType(3) - .build(), - "", - "3"); + parser = new EthernetConfigParser("eth0;1,2,3;;0", false /*isAtLeastB*/); + assertThat(parser.mCaps.getCapabilities()).asList().containsAtLeast(1, 2, 3); + assertThat(parser.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue(); - // "4" is TRANSPORT_VPN, which is unsupported. Should default back to TRANSPORT_ETHERNET - assertParsedNetworkCapabilities(defaultCapabilities, "", "4"); + // TRANSPORT_VPN (4) is not allowed. + parser = new EthernetConfigParser("eth0;;;4", false /*isAtLeastB*/); + assertThat(parser.mCaps.hasSingleTransport(NetworkCapabilities.TRANSPORT_ETHERNET)).isTrue(); - // "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 - assertParsedNetworkCapabilities(defaultCapabilities, "", "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 - assertParsedNetworkCapabilities(defaultCapabilities, "", "6"); - - // Adding an invalid override transport will leave the transport as TRANSPORT_ETHERNET - assertParsedNetworkCapabilities(defaultCapabilities, "", "100"); - assertParsedNetworkCapabilities(defaultCapabilities, "", "abcdefg"); - - // Ensure the adding of both capabilities and transports work - assertParsedNetworkCapabilities( - makeEthernetCapabilitiesBuilder(true /* clearDefaults */) - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addCapability(12) - .addCapability(13) - .addCapability(14) - .addCapability(15) - .addTransportType(3) - .build(), - "12,13,14,15", - "3"); - - // Ensure order does not matter for capability list - assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, "13,12,15,14", ""); - } - - private void assertParsedNetworkCapabilities( - NetworkCapabilities expectedNetworkCapabilities, - String configCapabilities, - String configTransports) { - final String ipConfig = ""; - final String configString = - String.join(";", TEST_IFACE, configCapabilities, ipConfig, configTransports); - final EthernetConfigParser config = new EthernetConfigParser(configString); - assertEquals( - expectedNetworkCapabilities, - EthernetTracker.createNetworkCapabilities(config.mCaps, config.mTransport).build()); + // invalid capability and transport type + parser = new EthernetConfigParser("eth0;-1,a,1000,,;;-1", false /*isAtLeastB*/); + assertThat(parser.mCaps).isEqualTo(baseNc); } @Test - public void testCreateEthernetConfigParserReturnsCorrectValue() { - final String capabilities = "2,4,6,8"; - final String ipConfig = "3"; - final String transport = "1"; - final String configString = String.join(";", TEST_IFACE, capabilities, ipConfig, transport); + public void testInterfaceNameParsing() { + EthernetConfigParser parser = new EthernetConfigParser("eth12", false /*isAtLeastB*/); + assertThat(parser.mIface).isEqualTo("eth12"); - final EthernetConfigParser config = new EthernetConfigParser(configString); + parser = new EthernetConfigParser("", true /*isAtLeastB*/); + assertThat(parser.mIface).isEqualTo(""); - assertEquals(TEST_IFACE, config.mIface); - assertThat(config.mCaps).containsExactly(2, 4, 6, 8); - assertEquals(ipConfig, config.mIpConfig); - assertEquals(NetworkCapabilities.TRANSPORT_WIFI, config.mTransport); + parser = new EthernetConfigParser("eth0;12;", true /*isAtLeastB*/); + assertThat(parser.mIface).isEqualTo("eth0"); } @Test - public void testCreateEthernetConfigParser_withInvalidTransport() { - final String capabilities = "2"; - final String ipConfig = "3"; - final String transport = "100"; // Invalid transport type - final String configString = String.join(";", TEST_IFACE, capabilities, ipConfig, transport); - - final EthernetConfigParser config = new EthernetConfigParser(configString); - assertEquals(NetworkCapabilities.TRANSPORT_ETHERNET, config.mTransport); - } - - @Test - public void testCreateEthernetConfigParser_withDisallowedTransport() { - final String capabilities = "2"; - final String ipConfig = "3"; - final String transport = "4"; // TRANSPORT_VPN is not allowed - final String configString = String.join(";", TEST_IFACE, capabilities, ipConfig, transport); - - final EthernetConfigParser config = new EthernetConfigParser(configString); - assertEquals(NetworkCapabilities.TRANSPORT_ETHERNET, config.mTransport); + public void testIpConfigParsing() { + // Note that EthernetConfigParser doesn't actually parse the IpConfig (yet). + final EthernetConfigParser parser = new EthernetConfigParser( + "eth0;1,2,3;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8;1", + false /*isAtLeastB*/); + assertThat(parser.mIpConfig) + .isEqualTo("ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8"); } @Test public void testCreateEthernetConfigParserThrowsNpeWithNullInput() { - assertThrows(NullPointerException.class, () -> new EthernetConfigParser(null)); + assertThrows(NullPointerException.class, () -> new EthernetConfigParser(null, false)); } @Test From bcb2869df13a6db0894a0361afa0c5a6948dd902 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 21 Mar 2025 12:49:45 -0700 Subject: [PATCH 2/2] Use "*" to indicate default capabilities in config Instead of using an empty string, make the use of default capabilities explicit by requiring "*" to be specified. This behavior is more consistent and allows OEMs to explicitly configure an interface without any capabilities (apart from those which are hard-coded). (Technically, they could do so by specifying one of the hardcoded capabilities in the config). Test: TH Change-Id: I1d25e5c4b302b0dbde5e1bb91fc1ed5a7b08be9d --- .../com/android/server/ethernet/EthernetTracker.java | 11 ++++++----- .../res/values/config.xml | 2 ++ .../android/server/ethernet/EthernetTrackerTest.java | 11 +++++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index e41f1d692a..7a192cefff 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -985,11 +985,12 @@ public class EthernetTracker { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - if (TextUtils.isEmpty(capabilitiesString)) { - if (!isAtLeastB) { - return builder.build(); - } - // On Android B+, a null or empty string defaults to the same set of default + if (capabilitiesString == null) { + return builder.build(); + } + + if (isAtLeastB && capabilitiesString.equals("*")) { + // On Android B+, a "*" string defaults to the same set of default // capabilities assigned to unconfigured interfaces. return new NetworkCapabilities(DEFAULT_CAPABILITIES); } diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml index 1b0f29dcd6..514563b891 100644 --- a/service/ServiceConnectivityResources/res/values/config.xml +++ b/service/ServiceConnectivityResources/res/values/config.xml @@ -193,6 +193,8 @@ The NOT_ROAMING, NOT_CONGESTED and NOT_SUSPENDED capabilities are always added automatically because this configuration provides no way to update them dynamically. + On Android B+, a "*" string configures the same default capabilities as is + used for interfaces without any explicit configuration. [IP config] Optional. If empty or not specified - DHCP will be used, otherwise use the following format to specify static IP configuration: ip= gateway= dns= diff --git a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java index dc469a168c..c1291b0563 100644 --- a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -192,13 +192,20 @@ public class EthernetTrackerTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .build(); + // Empty capabilities always default to the baseNc above. EthernetConfigParser parser = new EthernetConfigParser("eth0;", false /*isAtLeastB*/); assertThat(parser.mCaps).isEqualTo(baseNc); + parser = new EthernetConfigParser("eth0;", true /*isAtLeastB*/); + assertThat(parser.mCaps).isEqualTo(baseNc); - // On Android B+, empty capabilities default to using DEFAULT_CAPABILITIES. - parser = new EthernetConfigParser("eth0;;;;;;;", true /*isAtLeastB*/); + // On Android B+, "*" defaults to using DEFAULT_CAPABILITIES. + parser = new EthernetConfigParser("eth0;*;;;;;;", true /*isAtLeastB*/); assertThat(parser.mCaps).isEqualTo(EthernetTracker.DEFAULT_CAPABILITIES); + // But not so before B. + parser = new EthernetConfigParser("eth0;*", false /*isAtLeastB*/); + assertThat(parser.mCaps).isEqualTo(baseNc); + parser = new EthernetConfigParser("eth0;12,13,14,15;", false /*isAtLeastB*/); assertThat(parser.mCaps.getCapabilities()).asList().containsAtLeast(12, 13, 14, 15);