Merge "Report discovery metrics data" into main
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 062ecc5..119fbc6 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
@@ -17,7 +17,8 @@
package com.android.networkstack.tethering.apishim.api31;
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
-import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
+import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import android.net.IpPrefix;
import android.net.MacAddress;
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 6affb62..56b5c2e 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -28,11 +28,11 @@
import static android.net.TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
import static android.net.util.NetworkConstants.asByte;
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
+import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import static com.android.networkstack.tethering.UpstreamNetworkState.isVcnInterface;
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
import static com.android.networkstack.tethering.util.TetheringMessageBase.BASE_IPSERVER;
diff --git a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 18c2171..50d6c4b 100644
--- a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -16,7 +16,6 @@
package android.net.ip;
-import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.SOCK_RAW;
@@ -30,6 +29,7 @@
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS;
import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK;
+import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import static com.android.net.module.util.NetworkStackConstants.TAG_SYSTEM_NEIGHBOR;
import static com.android.networkstack.tethering.util.TetheringUtils.getAllNodesForScopeId;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
index b1f875b..4413d26 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -20,6 +20,8 @@
import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.SOCK_STREAM;
+import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY;
+import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_NEW;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1;
@@ -34,6 +36,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -57,7 +60,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
@@ -75,8 +77,9 @@
private OffloadHardwareInterface mOffloadHw;
private OffloadHalCallback mOffloadHalCallback;
- @Mock private IOffloadHal mIOffload;
- @Mock private NativeHandle mNativeHandle;
+ private IOffloadHal mIOffload;
+ private NativeHandle mNativeHandle1;
+ private NativeHandle mNativeHandle2;
// Random values to test Netlink message.
private static final short TEST_TYPE = 184;
@@ -97,7 +100,9 @@
@Override
public NativeHandle createConntrackSocket(final int groups) {
- return mNativeHandle;
+ return groups == (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)
+ ? mNativeHandle1
+ : mNativeHandle2;
}
}
@@ -105,45 +110,89 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mOffloadHalCallback = new OffloadHalCallback();
- when(mIOffload.initOffload(any(NativeHandle.class), any(NativeHandle.class),
- any(OffloadHalCallback.class))).thenReturn(true);
+ mIOffload = mock(IOffloadHal.class);
}
- private void startOffloadHardwareInterface(int offloadHalVersion)
+ private void startOffloadHardwareInterface(int offloadHalVersion, boolean isHalInitSuccess)
throws Exception {
+ startOffloadHardwareInterface(offloadHalVersion, isHalInitSuccess, mock(NativeHandle.class),
+ mock(NativeHandle.class));
+ }
+
+ private void startOffloadHardwareInterface(int offloadHalVersion, boolean isHalInitSuccess,
+ NativeHandle handle1, NativeHandle handle2) throws Exception {
final SharedLog log = new SharedLog("test");
final Handler handler = new Handler(mTestLooper.getLooper());
- final int num = offloadHalVersion != OFFLOAD_HAL_VERSION_NONE ? 1 : 0;
+ final boolean hasNullHandle = handle1 == null || handle2 == null;
+ // If offloadHalVersion is OFFLOAD_HAL_VERSION_NONE or it has null NativeHandle arguments,
+ // mIOffload.initOffload() shouldn't be called.
+ final int initNum = (offloadHalVersion != OFFLOAD_HAL_VERSION_NONE && !hasNullHandle)
+ ? 1
+ : 0;
+ // If it is HIDL or has null NativeHandle argument, NativeHandles should be closed.
+ final int handleCloseNum = (hasNullHandle
+ || offloadHalVersion == OFFLOAD_HAL_VERSION_HIDL_1_0
+ || offloadHalVersion == OFFLOAD_HAL_VERSION_HIDL_1_1) ? 1 : 0;
+ mNativeHandle1 = handle1;
+ mNativeHandle2 = handle2;
+ when(mIOffload.initOffload(any(NativeHandle.class), any(NativeHandle.class),
+ any(OffloadHalCallback.class))).thenReturn(isHalInitSuccess);
mOffloadHw = new OffloadHardwareInterface(handler, log,
new MyDependencies(handler, log, offloadHalVersion));
- assertEquals(offloadHalVersion, mOffloadHw.initOffload(mOffloadHalCallback));
- verify(mIOffload, times(num)).initOffload(any(NativeHandle.class), any(NativeHandle.class),
- eq(mOffloadHalCallback));
+ assertEquals(isHalInitSuccess && !hasNullHandle
+ ? offloadHalVersion
+ : OFFLOAD_HAL_VERSION_NONE,
+ mOffloadHw.initOffload(mOffloadHalCallback));
+ verify(mIOffload, times(initNum)).initOffload(any(NativeHandle.class),
+ any(NativeHandle.class), eq(mOffloadHalCallback));
+ if (mNativeHandle1 != null) verify(mNativeHandle1, times(handleCloseNum)).close();
+ if (mNativeHandle2 != null) verify(mNativeHandle2, times(handleCloseNum)).close();
}
@Test
public void testInitFailureWithNoHal() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_NONE);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_NONE, true);
}
@Test
public void testInitSuccessWithAidl() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_AIDL);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_AIDL, true);
}
@Test
public void testInitSuccessWithHidl_1_0() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
}
@Test
public void testInitSuccessWithHidl_1_1() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1, true);
+ }
+
+ @Test
+ public void testInitFailWithAidl() throws Exception {
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_AIDL, false);
+ }
+
+ @Test
+ public void testInitFailWithHidl_1_0() throws Exception {
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, false);
+ }
+
+ @Test
+ public void testInitFailWithHidl_1_1() throws Exception {
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1, false);
+ }
+
+ @Test
+ public void testInitFailDueToNullHandles() throws Exception {
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_AIDL, true, mock(NativeHandle.class),
+ null);
}
@Test
public void testGetForwardedStats() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
ForwardedStats stats = new ForwardedStats(12345, 56780);
when(mIOffload.getForwardedStats(anyString())).thenReturn(stats);
assertEquals(mOffloadHw.getForwardedStats(RMNET0), stats);
@@ -152,7 +201,7 @@
@Test
public void testSetLocalPrefixes() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
final ArrayList<String> localPrefixes = new ArrayList<>();
localPrefixes.add("127.0.0.0/8");
localPrefixes.add("fe80::/64");
@@ -165,7 +214,7 @@
@Test
public void testSetDataLimit() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
final long limit = 12345;
when(mIOffload.setDataLimit(anyString(), anyLong())).thenReturn(true);
assertTrue(mOffloadHw.setDataLimit(RMNET0, limit));
@@ -177,7 +226,7 @@
@Test
public void testSetDataWarningAndLimitFailureWithHidl_1_0() throws Exception {
// Verify V1.0 control HAL would reject the function call with exception.
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
final long warning = 12345;
final long limit = 67890;
assertThrows(UnsupportedOperationException.class,
@@ -187,7 +236,7 @@
@Test
public void testSetDataWarningAndLimit() throws Exception {
// Verify V1.1 control HAL could receive this function call.
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_1, true);
final long warning = 12345;
final long limit = 67890;
when(mIOffload.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true);
@@ -199,7 +248,7 @@
@Test
public void testSetUpstreamParameters() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
final String v4addr = "192.168.10.1";
final String v4gateway = "192.168.10.255";
final ArrayList<String> v6gws = new ArrayList<>(0);
@@ -220,7 +269,7 @@
@Test
public void testUpdateDownstream() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
final String ifName = "wlan1";
final String prefix = "192.168.43.0/24";
when(mIOffload.addDownstream(anyString(), anyString())).thenReturn(true);
@@ -237,7 +286,7 @@
@Test
public void testSendIpv4NfGenMsg() throws Exception {
- startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0);
+ startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_HIDL_1_0, true);
FileDescriptor writeSocket = new FileDescriptor();
FileDescriptor readSocket = new FileDescriptor();
try {
@@ -246,9 +295,9 @@
fail();
return;
}
- when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
+ when(mNativeHandle1.getFileDescriptor()).thenReturn(writeSocket);
- mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS);
+ mOffloadHw.sendIpv4NfGenMsg(mNativeHandle1, TEST_TYPE, TEST_FLAGS);
ByteBuffer buffer = ByteBuffer.allocate(9823); // Arbitrary value > expectedLen.
buffer.order(ByteOrder.nativeOrder());
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 9c6904d..770507e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -68,6 +68,7 @@
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
+import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
import static com.android.networkstack.tethering.TestConnectivityManager.BROADCAST_FIRST;
@@ -157,7 +158,6 @@
import android.net.ip.DadProxy;
import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon;
-import android.net.util.NetworkConstants;
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiManager;
@@ -559,7 +559,7 @@
prop.addDnsServer(InetAddresses.parseNumericAddress("2001:db8::2"));
prop.addLinkAddress(
new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"),
- NetworkConstants.RFC7421_PREFIX_LENGTH));
+ RFC7421_PREFIX_LENGTH));
prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
InetAddresses.parseNumericAddress("2001:db8::1"),
interfaceName, RTN_UNICAST));
diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h
index be604f9..1326db0 100644
--- a/bpf_progs/netd.h
+++ b/bpf_progs/netd.h
@@ -65,8 +65,6 @@
uint64_t rxPackets;
uint64_t txBytes;
uint64_t txPackets;
- uint64_t tcpRxPackets;
- uint64_t tcpTxPackets;
} Stats;
typedef struct {
diff --git a/framework-t/api/OWNERS b/framework-t/api/OWNERS
index de0f905..af583c3 100644
--- a/framework-t/api/OWNERS
+++ b/framework-t/api/OWNERS
@@ -1 +1,2 @@
file:platform/packages/modules/Connectivity:master:/nearby/OWNERS
+file:platform/packages/modules/Connectivity:master:/remoteauth/OWNERS
diff --git a/service-t/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
index 8d8dc32..ae553f0 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
@@ -47,8 +47,8 @@
RX_PACKETS = 1,
TX_BYTES = 2,
TX_PACKETS = 3,
- TCP_RX_PACKETS = 4,
- TCP_TX_PACKETS = 5
+ TCP_RX_PACKETS = 4, // not supported, always returns UNKNOWN (-1)
+ TCP_TX_PACKETS = 5, // not supported, always returns UNKNOWN (-1)
};
static uint64_t getStatsType(Stats* stats, StatsType type) {
@@ -62,9 +62,7 @@
case TX_PACKETS:
return stats->txPackets;
case TCP_RX_PACKETS:
- return stats->tcpRxPackets;
case TCP_TX_PACKETS:
- return stats->tcpTxPackets;
default:
return UNKNOWN;
}
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
index 2e6e3e5..317c3f9 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
@@ -46,8 +46,6 @@
stats->rxPackets = 0;
stats->txBytes = 0;
stats->txPackets = 0;
- stats->tcpRxPackets = -1;
- stats->tcpTxPackets = -1;
}
int bpfGetUidStatsInternal(uid_t uid, Stats* stats,
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
index 097dbe0..2ef7368 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -34,7 +34,6 @@
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.util.List;
-import java.util.Objects;
/**
* The {@link MdnsMultinetworkSocketClient} manages the multinetwork socket for mDns
@@ -49,10 +48,9 @@
@NonNull private final MdnsSocketProvider mSocketProvider;
@NonNull private final SharedLog mSharedLog;
- private final ArrayMap<MdnsServiceBrowserListener, InterfaceSocketCallback> mRequestedNetworks =
+ private final ArrayMap<MdnsServiceBrowserListener, InterfaceSocketCallback> mSocketRequests =
new ArrayMap<>();
- private final ArrayMap<MdnsInterfaceSocket, ReadPacketHandler> mSocketPacketHandlers =
- new ArrayMap<>();
+ private final ArrayMap<SocketKey, ReadPacketHandler> mSocketPacketHandlers = new ArrayMap<>();
private MdnsSocketClientBase.Callback mCallback = null;
private int mReceivedPacketNumber = 0;
@@ -68,8 +66,7 @@
@NonNull
private final SocketCreationCallback mSocketCreationCallback;
@NonNull
- private final ArrayMap<MdnsInterfaceSocket, SocketKey> mActiveSockets =
- new ArrayMap<>();
+ private final ArrayMap<SocketKey, MdnsInterfaceSocket> mActiveSockets = new ArrayMap<>();
InterfaceSocketCallback(SocketCreationCallback socketCreationCallback) {
mSocketCreationCallback = socketCreationCallback;
@@ -80,27 +77,27 @@
@NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {
// The socket may be already created by other request before, try to get the stored
// ReadPacketHandler.
- ReadPacketHandler handler = mSocketPacketHandlers.get(socket);
+ ReadPacketHandler handler = mSocketPacketHandlers.get(socketKey);
if (handler == null) {
// First request to create this socket. Initial a ReadPacketHandler for this socket.
handler = new ReadPacketHandler(socketKey);
- mSocketPacketHandlers.put(socket, handler);
+ mSocketPacketHandlers.put(socketKey, handler);
}
socket.addPacketHandler(handler);
- mActiveSockets.put(socket, socketKey);
+ mActiveSockets.put(socketKey, socket);
mSocketCreationCallback.onSocketCreated(socketKey);
}
@Override
public void onInterfaceDestroyed(@NonNull SocketKey socketKey,
@NonNull MdnsInterfaceSocket socket) {
- notifySocketDestroyed(socket);
- maybeCleanupPacketHandler(socket);
+ notifySocketDestroyed(socketKey);
+ maybeCleanupPacketHandler(socketKey);
}
- private void notifySocketDestroyed(@NonNull MdnsInterfaceSocket socket) {
- final SocketKey socketKey = mActiveSockets.remove(socket);
- if (!isSocketActive(socket)) {
+ private void notifySocketDestroyed(@NonNull SocketKey socketKey) {
+ mActiveSockets.remove(socketKey);
+ if (!isSocketActive(socketKey)) {
mSocketCreationCallback.onSocketDestroyed(socketKey);
}
}
@@ -108,35 +105,38 @@
void onNetworkUnrequested() {
for (int i = mActiveSockets.size() - 1; i >= 0; i--) {
// Iterate from the end so the socket can be removed
- final MdnsInterfaceSocket socket = mActiveSockets.keyAt(i);
- notifySocketDestroyed(socket);
- maybeCleanupPacketHandler(socket);
+ final SocketKey socketKey = mActiveSockets.keyAt(i);
+ notifySocketDestroyed(socketKey);
+ maybeCleanupPacketHandler(socketKey);
}
}
}
- private boolean isSocketActive(@NonNull MdnsInterfaceSocket socket) {
- for (int i = 0; i < mRequestedNetworks.size(); i++) {
- final InterfaceSocketCallback isc = mRequestedNetworks.valueAt(i);
- if (isc.mActiveSockets.containsKey(socket)) {
+ private boolean isSocketActive(@NonNull SocketKey socketKey) {
+ for (int i = 0; i < mSocketRequests.size(); i++) {
+ final InterfaceSocketCallback ifaceSocketCallback = mSocketRequests.valueAt(i);
+ if (ifaceSocketCallback.mActiveSockets.containsKey(socketKey)) {
return true;
}
}
return false;
}
- private ArrayMap<MdnsInterfaceSocket, SocketKey> getActiveSockets() {
- final ArrayMap<MdnsInterfaceSocket, SocketKey> sockets = new ArrayMap<>();
- for (int i = 0; i < mRequestedNetworks.size(); i++) {
- final InterfaceSocketCallback isc = mRequestedNetworks.valueAt(i);
- sockets.putAll(isc.mActiveSockets);
+ @Nullable
+ private MdnsInterfaceSocket getTargetSocket(@NonNull SocketKey targetSocketKey) {
+ for (int i = 0; i < mSocketRequests.size(); i++) {
+ final InterfaceSocketCallback ifaceSocketCallback = mSocketRequests.valueAt(i);
+ final int index = ifaceSocketCallback.mActiveSockets.indexOfKey(targetSocketKey);
+ if (index >= 0) {
+ return ifaceSocketCallback.mActiveSockets.valueAt(index);
+ }
}
- return sockets;
+ return null;
}
- private void maybeCleanupPacketHandler(@NonNull MdnsInterfaceSocket socket) {
- if (isSocketActive(socket)) return;
- mSocketPacketHandlers.remove(socket);
+ private void maybeCleanupPacketHandler(@NonNull SocketKey socketKey) {
+ if (isSocketActive(socketKey)) return;
+ mSocketPacketHandlers.remove(socketKey);
}
private class ReadPacketHandler implements MulticastPacketReader.PacketHandler {
@@ -171,14 +171,14 @@
public void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
@Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback) {
ensureRunningOnHandlerThread(mHandler);
- InterfaceSocketCallback callback = mRequestedNetworks.get(listener);
+ InterfaceSocketCallback callback = mSocketRequests.get(listener);
if (callback != null) {
throw new IllegalArgumentException("Can not register duplicated listener");
}
if (DBG) mSharedLog.v("notifyNetworkRequested: network=" + network);
callback = new InterfaceSocketCallback(socketCreationCallback);
- mRequestedNetworks.put(listener, callback);
+ mSocketRequests.put(listener, callback);
mSocketProvider.requestSocket(network, callback);
}
@@ -186,14 +186,14 @@
@Override
public void notifyNetworkUnrequested(@NonNull MdnsServiceBrowserListener listener) {
ensureRunningOnHandlerThread(mHandler);
- final InterfaceSocketCallback callback = mRequestedNetworks.get(listener);
+ final InterfaceSocketCallback callback = mSocketRequests.get(listener);
if (callback == null) {
mSharedLog.e("Can not be unrequested with unknown listener=" + listener);
return;
}
callback.onNetworkUnrequested();
- // onNetworkUnrequested does cleanups based on mRequestedNetworks, only remove afterwards
- mRequestedNetworks.remove(listener);
+ // onNetworkUnrequested does cleanups based on mSocketRequests, only remove afterwards
+ mSocketRequests.remove(listener);
mSocketProvider.unrequestSocket(callback);
}
@@ -209,42 +209,28 @@
private void sendMdnsPacket(@NonNull DatagramPacket packet, @NonNull SocketKey targetSocketKey,
boolean onlyUseIpv6OnIpv6OnlyNetworks) {
+ final MdnsInterfaceSocket socket = getTargetSocket(targetSocketKey);
+ if (socket == null) {
+ mSharedLog.e("No socket matches targetSocketKey=" + targetSocketKey);
+ return;
+ }
+
final boolean isIpv6 = ((InetSocketAddress) packet.getSocketAddress()).getAddress()
instanceof Inet6Address;
final boolean isIpv4 = ((InetSocketAddress) packet.getSocketAddress()).getAddress()
instanceof Inet4Address;
- final ArrayMap<MdnsInterfaceSocket, SocketKey> activeSockets = getActiveSockets();
- boolean shouldQueryIpv6 = !onlyUseIpv6OnIpv6OnlyNetworks || isIpv6OnlySockets(
- activeSockets, targetSocketKey);
- for (int i = 0; i < activeSockets.size(); i++) {
- final MdnsInterfaceSocket socket = activeSockets.keyAt(i);
- final SocketKey socketKey = activeSockets.valueAt(i);
- // Check ip capability and network before sending packet
- if (((isIpv6 && socket.hasJoinedIpv6() && shouldQueryIpv6)
- || (isIpv4 && socket.hasJoinedIpv4()))
- && Objects.equals(socketKey, targetSocketKey)) {
- try {
- socket.send(packet);
- } catch (IOException e) {
- mSharedLog.e("Failed to send a mDNS packet.", e);
- }
+ final boolean shouldQueryIpv6 = !onlyUseIpv6OnIpv6OnlyNetworks || !socket.hasJoinedIpv4();
+ // Check ip capability and network before sending packet
+ if ((isIpv6 && socket.hasJoinedIpv6() && shouldQueryIpv6)
+ || (isIpv4 && socket.hasJoinedIpv4())) {
+ try {
+ socket.send(packet);
+ } catch (IOException e) {
+ mSharedLog.e("Failed to send a mDNS packet.", e);
}
}
}
- private boolean isIpv6OnlySockets(
- @NonNull ArrayMap<MdnsInterfaceSocket, SocketKey> activeSockets,
- @NonNull SocketKey targetSocketKey) {
- for (int i = 0; i < activeSockets.size(); i++) {
- final MdnsInterfaceSocket socket = activeSockets.keyAt(i);
- final SocketKey socketKey = activeSockets.valueAt(i);
- if (Objects.equals(socketKey, targetSocketKey) && socket.hasJoinedIpv4()) {
- return false;
- }
- }
- return true;
- }
-
private void processResponsePacket(byte[] recvbuf, int length, @NonNull SocketKey socketKey) {
int packetNumber = ++mReceivedPacketNumber;
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 7aff6a4..f08ffc3 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -1143,7 +1143,7 @@
}
}
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static native void native_init(boolean startSkDestroyListener);
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp
index 2469710..da4fe28 100644
--- a/tests/cts/net/native/dns/Android.bp
+++ b/tests/cts/net/native/dns/Android.bp
@@ -30,6 +30,7 @@
],
// To be compatible with R devices, the min_sdk_version must be 30.
min_sdk_version: "30",
+ host_required: ["net-tests-utils-host-common"],
}
cc_test {
diff --git a/tests/cts/net/native/dns/AndroidTest.xml b/tests/cts/net/native/dns/AndroidTest.xml
index 6d03c23..d49696b 100644
--- a/tests/cts/net/native/dns/AndroidTest.xml
+++ b/tests/cts/net/native/dns/AndroidTest.xml
@@ -24,6 +24,8 @@
<option name="push" value="CtsNativeNetDnsTestCases->/data/local/tmp/CtsNativeNetDnsTestCases" />
<option name="append-bitness" value="true" />
</target_preparer>
+ <target_preparer class="com.android.testutils.ConnectivityTestTargetPreparer">
+ </target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="CtsNativeNetDnsTestCases" />
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index e978664..bce08df 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -2744,7 +2744,6 @@
*/
@AppModeFull(reason = "Instant apps cannot create test networks")
@Test
- @SkipMainlinePresubmit(reason = "Out of SLO flakiness")
public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
// Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
// shims, and @IgnoreUpTo does not check that.
@@ -2757,17 +2756,19 @@
final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ final Network testNetwork = tnt.getNetwork();
testAndCleanup(() -> {
setOemNetworkPreferenceForMyPackage(
OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY);
registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
- waitForAvailable(defaultCallback, tnt.getNetwork());
+ waitForAvailable(defaultCallback, testNetwork);
systemDefaultCallback.eventuallyExpect(CallbackEntry.AVAILABLE,
NETWORK_CALLBACK_TIMEOUT_MS, cb -> wifiNetwork.equals(cb.getNetwork()));
}, /* cleanup */ () -> {
runWithShellPermissionIdentity(tnt::teardown);
- defaultCallback.expect(CallbackEntry.LOST, tnt, NETWORK_CALLBACK_TIMEOUT_MS);
+ defaultCallback.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
+ cb -> testNetwork.equals(cb.getNetwork()));
// This network preference should only ever use the test network therefore available
// should not trigger when the test network goes down (e.g. switch to cellular).
@@ -3205,7 +3206,6 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
- @SkipPresubmit(reason = "Out of SLO flakiness")
public void testMobileDataPreferredUids() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index e4ee8de..7be4f78 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -25,6 +25,7 @@
import android.net.LinkProperties
import android.net.LocalSocket
import android.net.LocalSocketAddress
+import android.net.MacAddress
import android.net.Network
import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities
@@ -73,6 +74,8 @@
import android.system.OsConstants.AF_INET6
import android.system.OsConstants.EADDRNOTAVAIL
import android.system.OsConstants.ENETUNREACH
+import android.system.OsConstants.ETH_P_IPV6
+import android.system.OsConstants.IPPROTO_IPV6
import android.system.OsConstants.IPPROTO_UDP
import android.system.OsConstants.SOCK_DGRAM
import android.util.Log
@@ -82,13 +85,21 @@
import com.android.compatibility.common.util.PropertyUtil
import com.android.modules.utils.build.SdkLevel.isAtLeastU
import com.android.net.module.util.ArrayTrackRecord
+import com.android.net.module.util.DnsPacket
+import com.android.net.module.util.HexDump
+import com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN
+import com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN
+import com.android.net.module.util.NetworkStackConstants.UDP_HEADER_LEN
+import com.android.net.module.util.PacketBuilder
import com.android.net.module.util.TrackRecord
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.IPv6UdpFilter
import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
+import com.android.testutils.TapPacketReader
import com.android.testutils.TestableNetworkAgent
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
import com.android.testutils.TestableNetworkCallback
@@ -103,6 +114,7 @@
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.ServerSocket
+import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
import java.util.Random
import java.util.concurrent.Executor
@@ -133,6 +145,8 @@
private const val REGISTRATION_TIMEOUT_MS = 10_000L
private const val DBG = false
private const val TEST_PORT = 12345
+private const val MDNS_PORT = 5353.toShort()
+private val multicastIpv6Addr = parseNumericAddress("ff02::fb") as Inet6Address
@AppModeFull(reason = "Socket cannot bind in instant app mode")
@RunWith(DevSdkIgnoreRunner::class)
@@ -194,8 +208,8 @@
inline fun <reified V : NsdEvent> expectCallback(timeoutMs: Long = TIMEOUT_MS): V {
val nextEvent = nextEvents.poll(timeoutMs)
- assertNotNull(nextEvent, "No callback received after $timeoutMs ms, expected " +
- "${V::class.java.simpleName}")
+ assertNotNull(nextEvent, "No callback received after $timeoutMs ms, " +
+ "expected ${V::class.java.simpleName}")
assertTrue(nextEvent is V, "Expected ${V::class.java.simpleName} but got " +
nextEvent.javaClass.simpleName)
return nextEvent
@@ -411,7 +425,6 @@
val lp = LinkProperties().apply {
interfaceName = ifaceName
}
-
val agent = TestableNetworkAgent(context, handlerThread.looper,
NetworkCapabilities().apply {
removeCapability(NET_CAPABILITY_TRUSTED)
@@ -1144,6 +1157,176 @@
}
}
+ @Test
+ fun testRegisterWithConflictDuringProbing() {
+ // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
+ assumeTrue(TestUtils.shouldTestTApis())
+
+ val si = NsdServiceInfo()
+ si.serviceType = serviceType
+ si.serviceName = serviceName
+ si.network = testNetwork1.network
+ si.port = 12345 // Test won't try to connect so port does not matter
+
+ val packetReader = TapPacketReader(Handler(handlerThread.looper),
+ testNetwork1.iface.fileDescriptor.fileDescriptor, 1500 /* maxPacketSize */)
+ packetReader.startAsyncForTest()
+ handlerThread.waitForIdle(TIMEOUT_MS)
+
+ // Register service on testNetwork1
+ val registrationRecord = NsdRegistrationRecord()
+ nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, { it.run() },
+ registrationRecord)
+
+ tryTest {
+ assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
+ "Did not find a probe for the service")
+ packetReader.sendResponse(buildConflictingAnnouncement())
+
+ // Registration must use an updated name to avoid the conflict
+ val cb = registrationRecord.expectCallback<ServiceRegistered>(REGISTRATION_TIMEOUT_MS)
+ cb.serviceInfo.serviceName.let {
+ assertTrue("Unexpected registered name: $it",
+ it.startsWith(serviceName) && it != serviceName)
+ }
+ } cleanupStep {
+ nsdManager.unregisterService(registrationRecord)
+ registrationRecord.expectCallback<ServiceUnregistered>()
+ } cleanup {
+ packetReader.handler.post { packetReader.stop() }
+ handlerThread.waitForIdle(TIMEOUT_MS)
+ }
+ }
+
+ @Test
+ fun testRegisterWithConflictAfterProbing() {
+ // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
+ assumeTrue(TestUtils.shouldTestTApis())
+
+ val si = NsdServiceInfo()
+ si.serviceType = serviceType
+ si.serviceName = serviceName
+ si.network = testNetwork1.network
+ si.port = 12345 // Test won't try to connect so port does not matter
+
+ // Register service on testNetwork1
+ val registrationRecord = NsdRegistrationRecord()
+ val discoveryRecord = NsdDiscoveryRecord()
+ val registeredService = registerService(registrationRecord, si)
+ val packetReader = TapPacketReader(Handler(handlerThread.looper),
+ testNetwork1.iface.fileDescriptor.fileDescriptor, 1500 /* maxPacketSize */)
+ packetReader.startAsyncForTest()
+ handlerThread.waitForIdle(TIMEOUT_MS)
+
+ tryTest {
+ assertNotNull(packetReader.pollForAdvertisement(serviceName, serviceType),
+ "No announcements sent after initial probing")
+
+ assertEquals(si.serviceName, registeredService.serviceName)
+
+ nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
+ testNetwork1.network, { it.run() }, discoveryRecord)
+ discoveryRecord.waitForServiceDiscovered(si.serviceName, serviceType)
+
+ // Send a conflicting announcement
+ val conflictingAnnouncement = buildConflictingAnnouncement()
+ packetReader.sendResponse(conflictingAnnouncement)
+
+ // Expect to see probes (RFC6762 9., service is reset to probing state)
+ assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
+ "Probe not received within timeout after conflict")
+
+ // Send the conflicting packet again to reply to the probe
+ packetReader.sendResponse(conflictingAnnouncement)
+
+ // Note the legacy mdnsresponder would send an exit announcement here (a 0-lifetime
+ // advertisement just for the PTR record), but not the new advertiser. This probably
+ // follows RFC 6762 8.4, saying that when a record rdata changed, "In the case of shared
+ // records, a host MUST send a "goodbye" announcement with RR TTL zero [...] for the old
+ // rdata, to cause it to be deleted from peer caches, before announcing the new rdata".
+ //
+ // This should be implemented by the new advertiser, but in the case of conflicts it is
+ // not very valuable since an identical PTR record would be used by the conflicting
+ // service (except for subtypes). In that case the exit announcement may be
+ // counter-productive as it conflicts with announcements done by the conflicting
+ // service.
+
+ // Note that before sending the following ServiceRegistered callback for the renamed
+ // service, the legacy mdnsresponder-based implementation would first send a
+ // Service*Registered* callback for the original service name being *unregistered*; it
+ // should have been a ServiceUnregistered callback instead (bug in NsdService
+ // interpretation of the callback).
+ val newRegistration = registrationRecord.expectCallbackEventually<ServiceRegistered>(
+ REGISTRATION_TIMEOUT_MS) {
+ it.serviceInfo.serviceName.startsWith(serviceName) &&
+ it.serviceInfo.serviceName != serviceName
+ }
+
+ discoveryRecord.expectCallbackEventually<ServiceFound> {
+ it.serviceInfo.serviceName == newRegistration.serviceInfo.serviceName
+ }
+ } cleanupStep {
+ nsdManager.stopServiceDiscovery(discoveryRecord)
+ discoveryRecord.expectCallback<DiscoveryStopped>()
+ } cleanupStep {
+ nsdManager.unregisterService(registrationRecord)
+ registrationRecord.expectCallback<ServiceUnregistered>()
+ } cleanup {
+ packetReader.handler.post { packetReader.stop() }
+ handlerThread.waitForIdle(TIMEOUT_MS)
+ }
+ }
+
+ private fun buildConflictingAnnouncement(): ByteBuffer {
+ /*
+ Generated with:
+ scapy.raw(scapy.DNS(rd=0, qr=1, aa=1, qd = None, an =
+ scapy.DNSRRSRV(rrname='NsdTest123456789._nmt123456789._tcp.local',
+ rclass=0x8001, port=31234, target='conflict.local', ttl=120)
+ )).hex()
+ */
+ val mdnsPayload = HexDump.hexStringToByteArray("000084000000000100000000104e736454657" +
+ "3743132333435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00002" +
+ "18001000000780016000000007a0208636f6e666c696374056c6f63616c00")
+ val packetBuffer = ByteBuffer.wrap(mdnsPayload)
+ // Replace service name and types in the packet with the random ones used in the test.
+ // Test service name and types have consistent length and are always ASCII
+ val testPacketName = "NsdTest123456789".encodeToByteArray()
+ val testPacketTypePrefix = "_nmt123456789".encodeToByteArray()
+ val encodedServiceName = serviceName.encodeToByteArray()
+ val encodedTypePrefix = serviceType.split('.')[0].encodeToByteArray()
+ assertEquals(testPacketName.size, encodedServiceName.size)
+ assertEquals(testPacketTypePrefix.size, encodedTypePrefix.size)
+ packetBuffer.position(mdnsPayload.indexOf(testPacketName))
+ packetBuffer.put(encodedServiceName)
+ packetBuffer.position(mdnsPayload.indexOf(testPacketTypePrefix))
+ packetBuffer.put(encodedTypePrefix)
+
+ return buildMdnsPacket(mdnsPayload)
+ }
+
+ private fun buildMdnsPacket(mdnsPayload: ByteArray): ByteBuffer {
+ val packetBuffer = PacketBuilder.allocate(true /* hasEther */, IPPROTO_IPV6,
+ IPPROTO_UDP, mdnsPayload.size)
+ val packetBuilder = PacketBuilder(packetBuffer)
+ // Multicast ethernet address for IPv6 to ff02::fb
+ val multicastEthAddr = MacAddress.fromBytes(
+ byteArrayOf(0x33, 0x33, 0, 0, 0, 0xfb.toByte()))
+ packetBuilder.writeL2Header(
+ MacAddress.fromBytes(byteArrayOf(1, 2, 3, 4, 5, 6)) /* srcMac */,
+ multicastEthAddr,
+ ETH_P_IPV6.toShort())
+ packetBuilder.writeIpv6Header(
+ 0x60000000, // version=6, traffic class=0x0, flowlabel=0x0
+ IPPROTO_UDP.toByte(),
+ 64 /* hop limit */,
+ parseNumericAddress("2001:db8::123") as Inet6Address /* srcIp */,
+ multicastIpv6Addr /* dstIp */)
+ packetBuilder.writeUdpHeader(MDNS_PORT /* srcPort */, MDNS_PORT /* dstPort */)
+ packetBuffer.put(mdnsPayload)
+ return packetBuilder.finalizePacket()
+ }
+
/**
* Register a service and return its registration record.
*/
@@ -1169,7 +1352,65 @@
}
}
+private fun TapPacketReader.pollForMdnsPacket(
+ timeoutMs: Long = REGISTRATION_TIMEOUT_MS,
+ predicate: (TestDnsPacket) -> Boolean
+): ByteArray? {
+ val mdnsProbeFilter = IPv6UdpFilter(srcPort = MDNS_PORT, dstPort = MDNS_PORT).and {
+ val mdnsPayload = it.copyOfRange(
+ ETHER_HEADER_LEN + IPV6_HEADER_LEN + UDP_HEADER_LEN, it.size)
+ try {
+ predicate(TestDnsPacket(mdnsPayload))
+ } catch (e: DnsPacket.ParseException) {
+ false
+ }
+ }
+ return poll(timeoutMs, mdnsProbeFilter)
+}
+
+private fun TapPacketReader.pollForProbe(
+ serviceName: String,
+ serviceType: String,
+ timeoutMs: Long = REGISTRATION_TIMEOUT_MS
+): ByteArray? = pollForMdnsPacket(timeoutMs) { it.isProbeFor("$serviceName.$serviceType.local") }
+
+private fun TapPacketReader.pollForAdvertisement(
+ serviceName: String,
+ serviceType: String,
+ timeoutMs: Long = REGISTRATION_TIMEOUT_MS
+): ByteArray? = pollForMdnsPacket(timeoutMs) { it.isReplyFor("$serviceName.$serviceType.local") }
+
+private class TestDnsPacket(data: ByteArray) : DnsPacket(data) {
+ fun isProbeFor(name: String): Boolean = mRecords[QDSECTION].any {
+ it.dName == name && it.nsType == 0xff /* ANY */
+ }
+
+ fun isReplyFor(name: String): Boolean = mRecords[ANSECTION].any {
+ it.dName == name && it.nsType == 0x21 /* SRV */
+ }
+}
+
private fun ByteArray?.utf8ToString(): String {
if (this == null) return ""
return String(this, StandardCharsets.UTF_8)
}
+
+private fun ByteArray.indexOf(sub: ByteArray): Int {
+ var subIndex = 0
+ forEachIndexed { i, b ->
+ when (b) {
+ // Still matching: continue comparing with next byte
+ sub[subIndex] -> {
+ subIndex++
+ if (subIndex == sub.size) {
+ return i - sub.size + 1
+ }
+ }
+ // Not matching next byte but matches first byte: continue comparing with 2nd byte
+ sub[0] -> subIndex = 1
+ // No matches: continue comparing from first byte
+ else -> subIndex = 0
+ }
+ }
+ return -1
+}
diff --git a/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java b/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java
index 0eb5644..1b22f42 100644
--- a/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java
+++ b/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java
@@ -95,14 +95,17 @@
testIface.getFileDescriptor().close();
}
- if (tunNetworkCallback != null) {
- sCm.unregisterNetworkCallback(tunNetworkCallback);
- }
final Network testNetwork = tunNetworkCallback.currentNetwork;
if (testNetwork != null) {
tnm.teardownTestNetwork(testNetwork);
}
+ // Ensure test network being torn down.
+ tunNetworkCallback.waitForLost();
+
+ if (tunNetworkCallback != null) {
+ sCm.unregisterNetworkCallback(tunNetworkCallback);
+ }
}
}
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index c294e7b..442d69f 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -33,6 +33,8 @@
using android::modules::sdklevel::IsAtLeastR;
using android::modules::sdklevel::IsAtLeastS;
using android::modules::sdklevel::IsAtLeastT;
+using android::modules::sdklevel::IsAtLeastU;
+using android::modules::sdklevel::IsAtLeastV;
#define PLATFORM "/sys/fs/bpf/"
#define TETHERING "/sys/fs/bpf/tethering/"
@@ -147,10 +149,14 @@
// so we should only test for the removal of stuff that was mainline'd,
// and for the presence of mainline stuff.
+ // Note: Q is no longer supported by mainline
+ ASSERT_TRUE(IsAtLeastR());
+
// R can potentially run on pre-4.9 kernel non-eBPF capable devices.
DO_EXPECT(IsAtLeastR() && !IsAtLeastS() && isAtLeastKernelVersion(4, 9, 0), PLATFORM_ONLY_IN_R);
// S requires Linux Kernel 4.9+ and thus requires eBPF support.
+ if (IsAtLeastS()) ASSERT_TRUE(isAtLeastKernelVersion(4, 9, 0));
DO_EXPECT(IsAtLeastS(), MAINLINE_FOR_S_PLUS);
DO_EXPECT(IsAtLeastS() && isAtLeastKernelVersion(5, 10, 0), MAINLINE_FOR_S_5_10_PLUS);
@@ -163,6 +169,10 @@
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS);
// U requires Linux Kernel 4.14+, but nothing (as yet) added or removed in U.
+ if (IsAtLeastU()) ASSERT_TRUE(isAtLeastKernelVersion(4, 14, 0));
+
+ // V requires Linux Kernel 4.19+, but nothing (as yet) added or removed in V.
+ if (IsAtLeastV()) ASSERT_TRUE(isAtLeastKernelVersion(4, 19, 0));
for (const auto& file : mustExist) {
EXPECT_EQ(0, access(file.c_str(), R_OK)) << file << " does not exist";