Merge "Fix HostsideVpnTest#testExcludedRoutes"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 302c0b3..b1e6a9f 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -32,6 +32,9 @@
},
{
"name": "libnetworkstats_test"
+ },
+ {
+ "name": "FrameworksNetIntegrationTests"
}
],
"postsubmit": [
@@ -55,6 +58,9 @@
},
{
"name": "libnetworkstats_test"
+ },
+ {
+ "name": "FrameworksNetDeflakeTest"
}
],
"mainline-presubmit": [
@@ -88,6 +94,38 @@
"name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
"keywords": ["sim"]
},
+ // TODO: move to mainline-presubmit when known green.
+ // Test with APK modules only, in cases where APEX is not supported, or the other modules were simply not updated
+ {
+ "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk]",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.ConnectivityModuleTest"
+ }
+ ]
+ },
+ // TODO: move to mainline-presubmit when known green.
+ // Test with connectivity/tethering module only, to catch integration issues with older versions of other modules.
+ // "new tethering + old NetworkStack" is not a configuration that should really exist in the field, but
+ // there is no strong guarantee, and it is required by MTS testing for module qualification, where modules
+ // are tested independently.
+ {
+ "name": "CtsNetTestCasesLatestSdk[com.google.android.tethering.apex]",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
{
"name": "TetheringCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
},
@@ -96,6 +134,23 @@
"name": "bpf_existence_test[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
}
],
+ "auto-postsubmit": [
+ // Test tag for automotive targets. These are only running in postsubmit so as to harden the
+ // automotive targets to avoid introducing additional test flake and build time. The plan for
+ // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
+ // Additionally, this tag is used in targeted test suites to limit resource usage on the test
+ // infra during the hardening phase.
+ // TODO: this tag to be removed once the above is no longer an issue.
+ {
+ "name": "FrameworksNetTests"
+ },
+ {
+ "name": "FrameworksNetIntegrationTests"
+ },
+ {
+ "name": "FrameworksNetDeflakeTest"
+ }
+ ],
"imports": [
{
"path": "frameworks/base/core/java/android/net"
@@ -108,12 +163,6 @@
},
{
"path": "packages/modules/CaptivePortalLogin"
- },
- {
- "path": "packages/modules/Connectivity"
- },
- {
- "path": "packages/modules/Connectivity/Tethering"
}
]
}
diff --git a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
index 26040a2..22d2c5d 100644
--- a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
@@ -27,14 +27,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.TetherStatsValue;
-import java.util.function.BiConsumer;
-
/**
* Bpf coordinator class for API shims.
*/
@@ -164,7 +163,7 @@
@Override
public void tetherOffloadRuleForEach(boolean downstream,
- @NonNull BiConsumer<Tether4Key, Tether4Value> action) {
+ @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action) {
/* no op */
}
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index e3b1539..5afb862 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import com.android.net.module.util.BpfMap;
+import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
@@ -47,7 +48,6 @@
import java.io.FileDescriptor;
import java.io.IOException;
-import java.util.function.BiConsumer;
/**
* Bpf coordinator class for API shims.
@@ -410,7 +410,7 @@
@Override
public void tetherOffloadRuleForEach(boolean downstream,
- @NonNull BiConsumer<Tether4Key, Tether4Value> action) {
+ @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action) {
if (!isInitialized()) return;
try {
diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
index d663968..915e210 100644
--- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
+++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
@@ -22,14 +22,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.TetherStatsValue;
-import java.util.function.BiConsumer;
-
/**
* Bpf coordinator class for API shims.
*/
@@ -163,7 +162,7 @@
*/
@Nullable
public abstract void tetherOffloadRuleForEach(boolean downstream,
- @NonNull BiConsumer<Tether4Key, Tether4Value> action);
+ @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action);
/**
* Whether there is currently any IPv4 rule on the specified upstream.
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index d2188d1..6eaf68b 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -30,6 +30,7 @@
"androidx.test.rules",
"mockito-target-extended-minus-junit4",
"net-tests-utils",
+ "net-utils-device-common-bpf",
"testables",
],
libs: [
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 8bf1a2b..705d187 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.TETHER_PRIVILEGED;
@@ -53,11 +54,15 @@
import android.net.TetheringManager.TetheringEventCallback;
import android.net.TetheringManager.TetheringRequest;
import android.net.TetheringTester.TetheredDevice;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Base64;
import android.util.Log;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -67,17 +72,24 @@
import com.android.net.module.util.PacketBuilder;
import com.android.net.module.util.Struct;
+import com.android.net.module.util.bpf.Tether4Key;
+import com.android.net.module.util.bpf.Tether4Value;
import com.android.net.module.util.structs.EthernetHeader;
import com.android.net.module.util.structs.Icmpv6Header;
import com.android.net.module.util.structs.Ipv4Header;
import com.android.net.module.util.structs.Ipv6Header;
import com.android.net.module.util.structs.UdpHeader;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DumpTestUtils;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TapPacketReader;
import com.android.testutils.TestNetworkTracker;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -88,9 +100,12 @@
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -101,10 +116,17 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
public class EthernetTetheringTest {
+ @Rule
+ public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
private static final String TAG = EthernetTetheringTest.class.getSimpleName();
private static final int TIMEOUT_MS = 5000;
private static final int TETHER_REACHABILITY_ATTEMPTS = 20;
+ private static final int DUMP_POLLING_MAX_RETRY = 100;
+ private static final int DUMP_POLLING_INTERVAL_MS = 50;
+ // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
+ // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
+ private static final int UDP_STREAM_TS_MS = 2000;
private static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/8");
private static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64");
private static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8");
@@ -112,6 +134,10 @@
private static final ByteBuffer TEST_REACHABILITY_PAYLOAD =
ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa });
+ private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
+ private static final String BASE64_DELIMITER = ",";
+ private static final String LINE_DELIMITER = "\\n";
+
private final Context mContext = InstrumentationRegistry.getContext();
private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class);
private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class);
@@ -136,10 +162,11 @@
// Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
// tethered client callbacks. The restricted networks permission is needed to ensure that
// EthernetManager#isAvailable will correctly return true on devices where Ethernet is
- // marked restricted, like cuttlefish.
+ // marked restricted, like cuttlefish. The dump permission is needed to verify bpf related
+ // functions via dumpsys output.
mUiAutomation.adoptShellPermissionIdentity(
MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP);
mRunTests = mTm.isTetheringSupported() && mEm != null;
assumeTrue(mRunTests);
@@ -747,12 +774,15 @@
private static final byte TYPE_OF_SERVICE = 0;
private static final short ID = 27149;
private static final short ID2 = 27150;
+ private static final short ID3 = 27151;
private static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0
private static final byte TIME_TO_LIVE = (byte) 0x40;
private static final ByteBuffer PAYLOAD =
ByteBuffer.wrap(new byte[] { (byte) 0x12, (byte) 0x34 });
private static final ByteBuffer PAYLOAD2 =
ByteBuffer.wrap(new byte[] { (byte) 0x56, (byte) 0x78 });
+ private static final ByteBuffer PAYLOAD3 =
+ ByteBuffer.wrap(new byte[] { (byte) 0x9a, (byte) 0xbc });
private boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEther,
@NonNull final ByteBuffer payload) {
@@ -830,7 +860,8 @@
return false;
}
- private void runUdp4Test(TetheringTester tester, RemoteResponder remote) throws Exception {
+ private void runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf)
+ throws Exception {
final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
"1:2:3:4:5:6"));
@@ -861,10 +892,51 @@
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, true/* hasEther */, PAYLOAD2);
});
+
+ if (usingBpf) {
+ // Send second UDP packet in original direction.
+ // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
+ // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
+ // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
+ // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
+ // and apply ASSURED flag.
+ // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
+ // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
+ Thread.sleep(UDP_STREAM_TS_MS);
+ final ByteBuffer originalPacket2 = buildUdpv4Packet(tethered.macAddr,
+ tethered.routerMacAddr, ID, tethered.ipv4Addr /* srcIp */,
+ REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */,
+ REMOTE_PORT /*dstPort */, PAYLOAD3 /* payload */);
+ tester.verifyUpload(remote, originalPacket2, p -> {
+ Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
+ return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD3);
+ });
+
+ final HashMap<Tether4Key, Tether4Value> upstreamMap = pollIpv4UpstreamMapFromDump();
+ assertNotNull(upstreamMap);
+ assertEquals(1, upstreamMap.size());
+
+ final Map.Entry<Tether4Key, Tether4Value> rule =
+ upstreamMap.entrySet().iterator().next();
+
+ final Tether4Key key = rule.getKey();
+ assertEquals(IPPROTO_UDP, key.l4proto);
+ assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), key.src4));
+ assertEquals(LOCAL_PORT, key.srcPort);
+ assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), key.dst4));
+ assertEquals(REMOTE_PORT, key.dstPort);
+
+ final Tether4Value value = rule.getValue();
+ assertTrue(Arrays.equals(publicIp4Addr.getAddress(),
+ InetAddress.getByAddress(value.src46).getAddress()));
+ assertEquals(LOCAL_PORT, value.srcPort);
+ assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
+ InetAddress.getByAddress(value.dst46).getAddress()));
+ assertEquals(REMOTE_PORT, value.dstPort);
+ }
}
- @Test
- public void testUdpV4() throws Exception {
+ void initializeTethering() throws Exception {
assumeFalse(mEm.isAvailable());
// MyTetheringEventCallback currently only support await first available upstream. Tethering
@@ -885,8 +957,75 @@
mDownstreamReader = makePacketReader(mDownstreamIface);
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
+ }
- runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader));
+ @Test
+ @IgnoreAfter(Build.VERSION_CODES.Q)
+ public void testTetherUdpV4WithoutBpf() throws Exception {
+ initializeTethering();
+ runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
+ false /* usingBpf */);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testTetherUdpV4WithBpf() throws Exception {
+ initializeTethering();
+ runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
+ true /* usingBpf */);
+ }
+
+ @Nullable
+ private Pair<Tether4Key, Tether4Value> parseTether4KeyValue(@NonNull String dumpStr) {
+ Log.w(TAG, "Parsing string: " + dumpStr);
+
+ String[] keyValueStrs = dumpStr.split(BASE64_DELIMITER);
+ if (keyValueStrs.length != 2 /* key + value */) {
+ fail("The length is " + keyValueStrs.length + " but expect 2. "
+ + "Split string(s): " + TextUtils.join(",", keyValueStrs));
+ }
+
+ final byte[] keyBytes = Base64.decode(keyValueStrs[0], Base64.DEFAULT);
+ Log.d(TAG, "keyBytes: " + dumpHexString(keyBytes));
+ final ByteBuffer keyByteBuffer = ByteBuffer.wrap(keyBytes);
+ keyByteBuffer.order(ByteOrder.nativeOrder());
+ final Tether4Key tether4Key = Struct.parse(Tether4Key.class, keyByteBuffer);
+ Log.w(TAG, "tether4Key: " + tether4Key);
+
+ final byte[] valueBytes = Base64.decode(keyValueStrs[1], Base64.DEFAULT);
+ Log.d(TAG, "valueBytes: " + dumpHexString(valueBytes));
+ final ByteBuffer valueByteBuffer = ByteBuffer.wrap(valueBytes);
+ valueByteBuffer.order(ByteOrder.nativeOrder());
+ final Tether4Value tether4Value = Struct.parse(Tether4Value.class, valueByteBuffer);
+ Log.w(TAG, "tether4Value: " + tether4Value);
+
+ return new Pair<>(tether4Key, tether4Value);
+ }
+
+ @NonNull
+ private HashMap<Tether4Key, Tether4Value> dumpIpv4UpstreamMap() throws Exception {
+ final String rawMapStr = DumpTestUtils.dumpService(Context.TETHERING_SERVICE,
+ DUMPSYS_TETHERING_RAWMAP_ARG);
+ final HashMap<Tether4Key, Tether4Value> map = new HashMap<>();
+
+ for (final String line : rawMapStr.split(LINE_DELIMITER)) {
+ final Pair<Tether4Key, Tether4Value> rule = parseTether4KeyValue(line.trim());
+ map.put(rule.first, rule.second);
+ }
+ return map;
+ }
+
+ @Nullable
+ private HashMap<Tether4Key, Tether4Value> pollIpv4UpstreamMapFromDump() throws Exception {
+ for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
+ final HashMap<Tether4Key, Tether4Value> map = dumpIpv4UpstreamMap();
+ if (!map.isEmpty()) return map;
+
+ Thread.sleep(DUMP_POLLING_INTERVAL_MS);
+ }
+
+ fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
+ return null;
}
private <T> List<T> toList(T... array) {
diff --git a/Tethering/tests/privileged/src/com/android/net/module/util/BpfBitmapTest.java b/Tethering/tests/privileged/src/com/android/net/module/util/BpfBitmapTest.java
new file mode 100644
index 0000000..2112396
--- /dev/null
+++ b/Tethering/tests/privileged/src/com/android/net/module/util/BpfBitmapTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.networkstack.tethering;
+
+import static com.android.networkstack.tethering.util.TetheringUtils.getTetheringJniLibraryName;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.net.module.util.BpfBitmap;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner.class)
+public final class BpfBitmapTest {
+ private static final String TEST_BITMAP_PATH =
+ "/sys/fs/bpf/tethering/map_test_bitmap";
+
+ private static final int mTestData[] = {0,1,2,6,63,64,72};
+ private BpfBitmap mTestBitmap;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestBitmap = new BpfBitmap(TEST_BITMAP_PATH);
+ mTestBitmap.clear();
+ assertTrue(mTestBitmap.isEmpty());
+ }
+
+ @Test
+ public void testSet() throws Exception {
+ for (int i : mTestData) {
+ mTestBitmap.set(i);
+ assertFalse(mTestBitmap.isEmpty());
+ assertTrue(mTestBitmap.get(i));
+ // Check that the next item in the bitmap is unset since test data is in
+ // ascending order.
+ assertFalse(mTestBitmap.get(i + 1));
+ }
+ }
+
+ @Test
+ public void testSetThenUnset() throws Exception {
+ for (int i : mTestData) {
+ mTestBitmap.set(i);
+ assertFalse(mTestBitmap.isEmpty());
+ assertTrue(mTestBitmap.get(i));
+ // Since test unsets all test data during each iteration, ensure all other
+ // bit are unset.
+ for (int j = 0; j < 128; ++j) if (j != i) assertFalse(mTestBitmap.get(j));
+ mTestBitmap.unset(i);
+ }
+ }
+
+ @Test
+ public void testSetAllThenUnsetAll() throws Exception {
+ for (int i : mTestData) {
+ mTestBitmap.set(i);
+ }
+
+ for (int i : mTestData) {
+ mTestBitmap.unset(i);
+ if (i < mTestData.length)
+ assertFalse(mTestBitmap.isEmpty());
+ assertFalse(mTestBitmap.get(i));
+ }
+ assertTrue(mTestBitmap.isEmpty());
+ }
+
+ @Test
+ public void testClear() throws Exception {
+ for (int i = 0; i < 128; ++i) {
+ mTestBitmap.set(i);
+ }
+ assertFalse(mTestBitmap.isEmpty());
+ mTestBitmap.clear();
+ assertTrue(mTestBitmap.isEmpty());
+ }
+}
diff --git a/bpf_progs/test.c b/bpf_progs/test.c
index a76e346..c9c73f1 100644
--- a/bpf_progs/test.c
+++ b/bpf_progs/test.c
@@ -28,6 +28,9 @@
// Used only by TetheringPrivilegedTests, not by production code.
DEFINE_BPF_MAP_GRW(tether_downstream6_map, HASH, TetherDownstream6Key, Tether6Value, 16,
AID_NETWORK_STACK)
+// Used only by BpfBitmapTest, not by production code.
+DEFINE_BPF_MAP_GRW(bitmap, ARRAY, int, uint64_t, 2,
+ AID_NETWORK_STACK)
DEFINE_BPF_PROG_KVER("xdp/drop_ipv4_udp_ether", AID_ROOT, AID_NETWORK_STACK,
xdp_test, KVER(5, 9, 0))
diff --git a/framework/src/android/net/KeepalivePacketData.java b/framework/src/android/net/KeepalivePacketData.java
index 5877f1f..f47cc5c 100644
--- a/framework/src/android/net/KeepalivePacketData.java
+++ b/framework/src/android/net/KeepalivePacketData.java
@@ -116,4 +116,13 @@
return mPacket.clone();
}
+ @Override
+ public String toString() {
+ return "KeepalivePacketData[srcAddress=" + mSrcAddress
+ + ", dstAddress=" + mDstAddress
+ + ", srcPort=" + mSrcPort
+ + ", dstPort=" + mDstPort
+ + ", packet.length=" + mPacket.length
+ + ']';
+ }
}
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index c29eb2b..f13c68d 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -24,6 +24,7 @@
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedPrimitiveArray.h>
+#include <netjniutils/netjniutils.h>
#include <net/if.h>
#include <vector>
@@ -108,6 +109,7 @@
}
size_t size = uids.size();
+ static_assert(sizeof(*(uids.get())) == sizeof(int32_t));
std::vector<int32_t> data ((int32_t *)&uids[0], (int32_t*)&uids[size]);
int res = mTc.replaceUidOwnerMap(chainName, isAllowlist, data);
if (res) {
@@ -116,27 +118,11 @@
return (jint)res;
}
-static FirewallType getFirewallType(ChildChain chain) {
- switch (chain) {
- case DOZABLE:
- return ALLOWLIST;
- case STANDBY:
- return DENYLIST;
- case POWERSAVE:
- return ALLOWLIST;
- case RESTRICTED:
- return ALLOWLIST;
- case NONE:
- default:
- return DENYLIST;
- }
-}
-
static jint native_setUidRule(JNIEnv* env, jobject clazz, jint childChain, jint uid,
jint firewallRule) {
auto chain = static_cast<ChildChain>(childChain);
auto rule = static_cast<FirewallRule>(firewallRule);
- FirewallType fType = getFirewallType(chain);
+ FirewallType fType = mTc.getFirewallType(chain);
int res = mTc.changeUidOwnerRule(chain, uid, rule, fType);
if (res) {
@@ -160,6 +146,7 @@
}
size_t size = uids.size();
+ static_assert(sizeof(*(uids.get())) == sizeof(int32_t));
std::vector<int32_t> data ((int32_t *)&uids[0], (int32_t*)&uids[size]);
Status status = mTc.addUidInterfaceRules(ifIndex, data);
if (!isOk(status)) {
@@ -175,6 +162,7 @@
}
size_t size = uids.size();
+ static_assert(sizeof(*(uids.get())) == sizeof(int32_t));
std::vector<int32_t> data ((int32_t *)&uids[0], (int32_t*)&uids[size]);
Status status = mTc.removeUidInterfaceRules(data);
if (!isOk(status)) {
@@ -202,6 +190,15 @@
mTc.setPermissionForUids(permission, data);
}
+static void native_dump(JNIEnv* env, jobject clazz, jobject javaFd, jboolean verbose) {
+ int fd = netjniutils::GetNativeFileDescriptor(env, javaFd);
+ if (fd < 0) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
+ return;
+ }
+ mTc.dump(fd, verbose);
+}
+
/*
* JNI registration.
*/
@@ -232,6 +229,8 @@
(void*)native_swapActiveStatsMap},
{"native_setPermissionForUids", "(I[I)V",
(void*)native_setPermissionForUids},
+ {"native_dump", "(Ljava/io/FileDescriptor;Z)V",
+ (void*)native_dump},
};
// clang-format on
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 1cbfd94..393ee0a 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -601,8 +601,10 @@
}
}
-void TrafficController::dump(DumpWriter& dw, bool verbose) {
+void TrafficController::dump(int fd, bool verbose) {
std::lock_guard guard(mMutex);
+ DumpWriter dw(fd);
+
ScopedIndent indentTop(dw);
dw.println("TrafficController");
diff --git a/service/native/include/TrafficController.h b/service/native/include/TrafficController.h
index 6fe117f..79e75ac 100644
--- a/service/native/include/TrafficController.h
+++ b/service/native/include/TrafficController.h
@@ -62,7 +62,7 @@
netdutils::Status updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
FirewallType type) EXCLUDES(mMutex);
- void dump(netdutils::DumpWriter& dw, bool verbose) EXCLUDES(mMutex);
+ void dump(int fd, bool verbose) EXCLUDES(mMutex);
netdutils::Status replaceRulesInMap(UidOwnerMatchType match, const std::vector<int32_t>& uids)
EXCLUDES(mMutex);
diff --git a/service/native/libs/libclat/bpfhelper.cpp b/service/native/libs/libclat/bpfhelper.cpp
index 6e230d0..00785ad 100644
--- a/service/native/libs/libclat/bpfhelper.cpp
+++ b/service/native/libs/libclat/bpfhelper.cpp
@@ -28,16 +28,6 @@
#define DEVICEPREFIX "v4-"
using android::base::unique_fd;
-using android::net::RAWIP;
-using android::net::getClatEgress4MapFd;
-using android::net::getClatIngress6MapFd;
-using android::net::getClatEgress4ProgFd;
-using android::net::getClatIngress6ProgFd;
-using android::net::tcQdiscAddDevClsact;
-using android::net::tcFilterAddDevEgressClatIpv4;
-using android::net::tcFilterAddDevIngressClatIpv6;
-using android::net::tcFilterDelDevEgressClatIpv4;
-using android::net::tcFilterDelDevIngressClatIpv6;
using android::bpf::BpfMap;
BpfMap<ClatEgress4Key, ClatEgress4Value> mClatEgress4Map;
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index ddee275..f2ca18b 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.system.OsConstants.EOPNOTSUPP;
+
import android.net.INetd;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -24,6 +26,9 @@
import com.android.modules.utils.build.SdkLevel;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
/**
* BpfNetMaps is responsible for providing traffic controller relevant functionality.
*
@@ -273,6 +278,23 @@
native_setPermissionForUids(permissions, uids);
}
+ /**
+ * Dump BPF maps
+ *
+ * @param fd file descriptor to output
+ * @throws IOException when file descriptor is invalid.
+ * @throws ServiceSpecificException when the method is called on an unsupported device.
+ */
+ public void dump(final FileDescriptor fd, boolean verbose)
+ throws IOException, ServiceSpecificException {
+ if (USE_NETD) {
+ throw new ServiceSpecificException(
+ EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T"
+ + " devices, use dumpsys netd trafficcontroller instead.");
+ }
+ native_dump(fd, verbose);
+ }
+
private static native void native_init();
private native int native_addNaughtyApp(int uid);
private native int native_removeNaughtyApp(int uid);
@@ -285,4 +307,5 @@
private native int native_removeUidInterfaceRules(int[] uids);
private native int native_swapActiveStatsMap();
private native void native_setPermissionForUids(int permissions, int[] uids);
+ private native void native_dump(FileDescriptor fd, boolean verbose);
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 6024a2a..1b57c27 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -313,6 +313,7 @@
public static final String SHORT_ARG = "--short";
private static final String NETWORK_ARG = "networks";
private static final String REQUEST_ARG = "requests";
+ private static final String TRAFFICCONTROLLER_ARG = "trafficcontroller";
private static final boolean DBG = true;
private static final boolean DDBG = Log.isLoggable(TAG, Log.DEBUG);
@@ -645,8 +646,9 @@
* Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
* Both of the arguments are bitmasks, and the value of bits come from
* INetworkMonitor.NETWORK_VALIDATION_PROBE_*.
- * arg1 = A bitmask to describe which probes are completed.
- * arg2 = A bitmask to describe which probes are successful.
+ * arg1 = unused
+ * arg2 = netId
+ * obj = A Pair of integers: the bitmasks of, respectively, completed and successful probes.
*/
public static final int EVENT_PROBE_STATUS_CHANGED = 45;
@@ -1409,6 +1411,8 @@
// converting rateInBytesPerSecond from long to int is safe here because the
// setting's range is limited to INT_MAX.
// TODO: add long/uint64 support to tcFilterAddDevIngressPolice.
+ Log.i(TAG,
+ "enableIngressRateLimit on " + iface + ": " + rateInBytesPerSecond + "B/s");
TcUtils.tcFilterAddDevIngressPolice(params.index, TC_PRIO_POLICE, (short) ETH_P_ALL,
(int) rateInBytesPerSecond, TC_POLICE_BPF_PROG_PATH);
} catch (IOException e) {
@@ -1430,6 +1434,8 @@
return;
}
try {
+ Log.i(TAG,
+ "disableIngressRateLimit on " + iface);
TcUtils.tcFilterDelDev(params.index, true, TC_PRIO_POLICE, (short) ETH_P_ALL);
} catch (IOException e) {
loge("TcUtils.tcFilterDelDev(ifaceIndex=" + params.index
@@ -1752,7 +1758,7 @@
// Watch for ingress rate limit changes.
mSettingsObserver.observe(
- Settings.Secure.getUriFor(
+ Settings.Global.getUriFor(
ConnectivitySettingsManager.INGRESS_RATE_LIMIT_BYTES_PER_SECOND),
EVENT_INGRESS_RATE_LIMIT_CHANGED);
}
@@ -3212,6 +3218,10 @@
} else if (CollectionUtils.contains(args, REQUEST_ARG)) {
dumpNetworkRequests(pw);
return;
+ } else if (CollectionUtils.contains(args, TRAFFICCONTROLLER_ARG)) {
+ boolean verbose = !CollectionUtils.contains(args, SHORT_ARG);
+ dumpTrafficController(pw, fd, verbose);
+ return;
}
pw.print("NetworkProviders for:");
@@ -3429,6 +3439,17 @@
}
}
+ private void dumpTrafficController(IndentingPrintWriter pw, final FileDescriptor fd,
+ boolean verbose) {
+ try {
+ mBpfNetMaps.dump(fd, verbose);
+ } catch (ServiceSpecificException e) {
+ pw.println(e.getMessage());
+ } catch (IOException e) {
+ loge("Dump BPF maps failed, " + e);
+ }
+ }
+
private void dumpAllRequestInfoLogsToLogcat() {
try (PrintWriter logPw = new PrintWriter(new Writer() {
@Override
@@ -3602,19 +3623,21 @@
}
private boolean maybeHandleNetworkMonitorMessage(Message msg) {
+ final int netId = msg.arg2;
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
switch (msg.what) {
default:
return false;
case EVENT_PROBE_STATUS_CHANGED: {
- final Integer netId = (Integer) msg.obj;
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
if (nai == null) {
break;
}
+ final int probesCompleted = ((Pair<Integer, Integer>) msg.obj).first;
+ final int probesSucceeded = ((Pair<Integer, Integer>) msg.obj).second;
final boolean probePrivateDnsCompleted =
- ((msg.arg1 & NETWORK_VALIDATION_PROBE_PRIVDNS) != 0);
+ ((probesCompleted & NETWORK_VALIDATION_PROBE_PRIVDNS) != 0);
final boolean privateDnsBroken =
- ((msg.arg2 & NETWORK_VALIDATION_PROBE_PRIVDNS) == 0);
+ ((probesSucceeded & NETWORK_VALIDATION_PROBE_PRIVDNS) == 0);
if (probePrivateDnsCompleted) {
if (nai.networkCapabilities.isPrivateDnsBroken() != privateDnsBroken) {
nai.networkCapabilities.setPrivateDnsBroken(privateDnsBroken);
@@ -3641,7 +3664,6 @@
case EVENT_NETWORK_TESTED: {
final NetworkTestedResults results = (NetworkTestedResults) msg.obj;
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(results.mNetId);
if (nai == null) break;
handleNetworkTested(nai, results.mTestResult,
@@ -3649,9 +3671,7 @@
break;
}
case EVENT_PROVISIONING_NOTIFICATION: {
- final int netId = msg.arg2;
final boolean visible = toBool(msg.arg1);
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
// If captive portal status has changed, update capabilities or disconnect.
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
nai.lastCaptivePortalDetected = visible;
@@ -3685,14 +3705,12 @@
break;
}
case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
break;
}
case EVENT_CAPPORT_DATA_CHANGED: {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
handleCapportApiDataUpdate(nai, (CaptivePortalData) msg.obj);
break;
@@ -3832,6 +3850,7 @@
// the same looper so messages will be processed in sequence.
final Message msg = mTrackerHandler.obtainMessage(
EVENT_NETWORK_TESTED,
+ 0, mNetId,
new NetworkTestedResults(
mNetId, p.result, p.timestampMillis, p.redirectUrl));
mTrackerHandler.sendMessage(msg);
@@ -3869,7 +3888,7 @@
public void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) {
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
EVENT_PROBE_STATUS_CHANGED,
- probesCompleted, probesSucceeded, new Integer(mNetId)));
+ 0, mNetId, new Pair<>(probesCompleted, probesSucceeded)));
}
@Override
@@ -10684,8 +10703,11 @@
}
private boolean canNetworkBeRateLimited(@NonNull final NetworkAgentInfo networkAgent) {
- if (!networkAgent.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) {
- // rate limits only apply to networks that provide internet connectivity.
+ final NetworkCapabilities agentCaps = networkAgent.networkCapabilities;
+ // Only test networks (they cannot hold NET_CAPABILITY_INTERNET) and networks that provide
+ // internet connectivity can be rate limited.
+ if (!agentCaps.hasCapability(NET_CAPABILITY_INTERNET) && !agentCaps.hasTransport(
+ TRANSPORT_TEST)) {
return false;
}
diff --git a/tests/TEST_MAPPING b/tests/TEST_MAPPING
deleted file mode 100644
index 502f885..0000000
--- a/tests/TEST_MAPPING
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksNetIntegrationTests"
- }
- ],
- "postsubmit": [
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
- "auto-postsubmit": [
- // Test tag for automotive targets. These are only running in postsubmit so as to harden the
- // automotive targets to avoid introducing additional test flake and build time. The plan for
- // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
- // Additionally, this tag is used in targeted test suites to limit resource usage on the test
- // infra during the hardening phase.
- // TODO: this tag to be removed once the above is no longer an issue.
- {
- "name": "FrameworksNetTests"
- },
- {
- "name": "FrameworksNetIntegrationTests"
- },
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
- "imports": [
- {
- "path": "packages/modules/Connectivity"
- }
- ]
-}
\ No newline at end of file
diff --git a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
index 8d8958d..d14d127 100644
--- a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
+++ b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
@@ -67,6 +67,7 @@
import androidx.test.InstrumentationRegistry
import androidx.test.filters.SmallTest
import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString
+import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import junit.framework.Assert.assertEquals
@@ -295,6 +296,7 @@
testIntValues = intArrayOf(0))
}
+ @ConnectivityModuleTest // get/setIngressRateLimitInBytesPerSecond was added via module update
@Test
fun testInternetNetworkRateLimitInBytesPerSecond() {
val defaultRate = getIngressRateLimitInBytesPerSecond(context)
diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml
index d761c27..d605799 100644
--- a/tests/cts/net/AndroidTestTemplate.xml
+++ b/tests/cts/net/AndroidTestTemplate.xml
@@ -21,6 +21,8 @@
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.tethering.apex" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index ea64252..ac520d1 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -3259,6 +3259,19 @@
assertTrue(dumpOutput, dumpOutput.contains("Active default network"));
}
+ @Test @IgnoreUpTo(SC_V2)
+ public void testDumpBpfNetMaps() throws Exception {
+ final String[] args = new String[] {"--short", "trafficcontroller"};
+ String dumpOutput = DumpTestUtils.dumpServiceWithShellPermission(
+ Context.CONNECTIVITY_SERVICE, args);
+ assertTrue(dumpOutput, dumpOutput.contains("TrafficController"));
+ assertFalse(dumpOutput, dumpOutput.contains("BPF map content"));
+
+ dumpOutput = DumpTestUtils.dumpServiceWithShellPermission(
+ Context.CONNECTIVITY_SERVICE, args[1]);
+ assertTrue(dumpOutput, dumpOutput.contains("BPF map content"));
+ }
+
private void unregisterRegisteredCallbacks() {
for (NetworkCallback callback: mRegisteredCallbacks) {
mCm.unregisterNetworkCallback(callback);
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 886b078..ea98289 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -75,6 +75,7 @@
import com.android.testutils.TestableNetworkCallback
import org.junit.After
import org.junit.AfterClass
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Rule
@@ -88,6 +89,7 @@
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.UUID
+import java.util.regex.Pattern
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@@ -125,8 +127,25 @@
private lateinit var tunNetworkCallback: TestNetworkCallback
private lateinit var reader: TapPacketReader
+ private fun getKernelVersion(): IntArray {
+ // Example:
+ // 4.9.29-g958411d --> 4.9
+ val release = Os.uname().release
+ val m = Pattern.compile("^(\\d+)\\.(\\d+)").matcher(release)
+ assertTrue(m.find(), "No pattern in release string: " + release)
+ return intArrayOf(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)))
+ }
+
+ private fun kernelIsAtLeast(major: Int, minor: Int): Boolean {
+ val version = getKernelVersion()
+ return (version.get(0) > major || (version.get(0) == major && version.get(1) >= minor))
+ }
+
@Before
fun setUp() {
+ // For BPF support kernel needs to be at least 5.4.
+ assumeTrue(kernelIsAtLeast(5, 4))
+
runAsShell(MANAGE_TEST_NETWORKS) {
val tnm = realContext.getSystemService(TestNetworkManager::class.java)
diff --git a/tests/cts/net/src/android/net/cts/EthernetNetworkSpecifierTest.java b/tests/cts/net/src/android/net/cts/EthernetNetworkSpecifierTest.java
new file mode 100644
index 0000000..5bde8c8
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/EthernetNetworkSpecifierTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.net.EthernetNetworkSpecifier;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
+@RunWith(DevSdkIgnoreRunner.class)
+public class EthernetNetworkSpecifierTest {
+
+ @Test
+ public void testConstructor() {
+ final String iface = "testIface";
+ final EthernetNetworkSpecifier ns = new EthernetNetworkSpecifier(iface);
+ assertEquals(iface, ns.getInterfaceName());
+ }
+
+ @Test
+ public void testConstructorWithNullValue() {
+ assertThrows("Should not be able to call constructor with null value.",
+ IllegalArgumentException.class,
+ () -> new EthernetNetworkSpecifier(null));
+ }
+
+ @Test
+ public void testConstructorWithEmptyValue() {
+ assertThrows("Should not be able to call constructor with empty value.",
+ IllegalArgumentException.class,
+ () -> new EthernetNetworkSpecifier(""));
+ }
+
+ @Test
+ public void testEquals() {
+ final String iface = "testIface";
+ final EthernetNetworkSpecifier nsOne = new EthernetNetworkSpecifier(iface);
+ final EthernetNetworkSpecifier nsTwo = new EthernetNetworkSpecifier(iface);
+ assertEquals(nsOne, nsTwo);
+ }
+
+ @Test
+ public void testNotEquals() {
+ final String iface = "testIface";
+ final String ifaceTwo = "testIfaceTwo";
+ final EthernetNetworkSpecifier nsOne = new EthernetNetworkSpecifier(iface);
+ final EthernetNetworkSpecifier nsTwo = new EthernetNetworkSpecifier(ifaceTwo);
+ assertNotEquals(nsOne, nsTwo);
+ }
+}
diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
index d221694..1d19d26 100644
--- a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
+++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
@@ -29,6 +29,7 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
import libcore.net.InetAddressUtils;
@@ -106,6 +107,10 @@
assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
}
+ @ConnectivityModuleTest // The builder was added in an S+ module update.
+ // This whole class is not skipped (marked @ConnectivityModuleTest) in MTS for non-connectivity
+ // modules like NetworkStack, as NetworkStack uses IpConfiguration a lot on Q+, so tests that
+ // cover older APIs are still useful to provide used API coverage for NetworkStack.
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testBuilder() {
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 344482b..810d1c6 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -77,6 +77,7 @@
import com.android.modules.utils.build.SdkLevel
import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.CompatUtil
+import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.RecorderCallback.CallbackEntry.Available
@@ -153,6 +154,10 @@
// NetworkAgent is not updatable in R-, so this test does not need to be compatible with older
// versions. NetworkAgent was also based on AsyncChannel before S so cannot be tested the same way.
@IgnoreUpTo(Build.VERSION_CODES.R)
+// NetworkAgent is updated as part of the connectivity module, and running NetworkAgent tests in MTS
+// for modules other than Connectivity does not provide much value. Only run them in connectivity
+// module MTS, so the tests only need to cover the case of an updated NetworkAgent.
+@ConnectivityModuleTest
class NetworkAgentTest {
private val LOCAL_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1")
private val REMOTE_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.2")
diff --git a/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java b/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java
index 9b2756c..e2d3346 100644
--- a/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java
+++ b/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java
@@ -35,6 +35,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
import org.junit.Rule;
@@ -256,7 +257,7 @@
assertEquals(DNS1, s.getDnsServers().get(0));
}
- @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+ @ConnectivityModuleTest @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testIllegalBuilders() {
assertThrows("Can't set IP Address to IPv6!", IllegalArgumentException.class, () -> {
diff --git a/tests/mts/Android.bp b/tests/mts/Android.bp
index 2c44010..74fee3d 100644
--- a/tests/mts/Android.bp
+++ b/tests/mts/Android.bp
@@ -27,6 +27,9 @@
"connectivity-mainline-presubmit-cc-defaults",
],
require_root: true,
+ header_libs: [
+ "bpf_headers",
+ ],
static_libs: [
"libbase",
"libmodules-utils-build",
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index 142e013..2bba282 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -23,6 +23,7 @@
#include <android/api-level.h>
#include <android-base/properties.h>
#include <android-modules-utils/sdk_level.h>
+#include <bpf/BpfUtils.h>
#include <gtest/gtest.h>
@@ -151,6 +152,8 @@
}
TEST_F(BpfExistenceTest, TestPrograms) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
// Pre-flight check to ensure test has been updated.
uint64_t buildVersionSdk = android_get_device_api_level();
ASSERT_NE(0, buildVersionSdk) << "Unable to determine device SDK version";
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 76c0c38..34bcf3f 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -198,7 +198,10 @@
@Mock
private LocationPermissionChecker mLocationPermissionChecker;
private @Mock IBpfMap<U32, U8> mUidCounterSetMap;
- private @Mock NetworkStatsService.TagStatsDeleter mTagStatsDeleter;
+ private @Mock IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap;
+ private @Mock IBpfMap<StatsMapKey, StatsMapValue> mStatsMapA;
+ private @Mock IBpfMap<StatsMapKey, StatsMapValue> mStatsMapB;
+ private @Mock IBpfMap<UidStatsMapKey, StatsMapValue> mAppUidStatsMap;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
@@ -361,8 +364,23 @@
}
@Override
- public NetworkStatsService.TagStatsDeleter getTagStatsDeleter() {
- return mTagStatsDeleter;
+ public IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() {
+ return mCookieTagMap;
+ }
+
+ @Override
+ public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapA() {
+ return mStatsMapA;
+ }
+
+ @Override
+ public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapB() {
+ return mStatsMapB;
+ }
+
+ @Override
+ public IBpfMap<UidStatsMapKey, StatsMapValue> getAppUidStatsMap() {
+ return mAppUidStatsMap;
}
};
}
@@ -702,10 +720,8 @@
final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_BLUE);
mServiceContext.sendBroadcast(intent);
- verify(mTagStatsDeleter).deleteTagData(UID_BLUE);
intent.putExtra(EXTRA_UID, UID_RED);
mServiceContext.sendBroadcast(intent);
- verify(mTagStatsDeleter).deleteTagData(UID_RED);
// existing uid and total should remain unchanged; but removed UID
// should be gone completely.