Merge "Introduce interface name field to SocketKey" into main

This commit is contained in:
Paul Hu 2025-06-16 18:28:55 -07:00 • committed by Android (Google) Code Review
commit fff6a3fdcd
11 changed files with 90 additions and 42 deletions

View file

@ -219,7 +219,7 @@ public class ConnectivityMonitorWithConnectivityManager implements ConnectivityM
if (netIf == null) {
return null;
}
return new SocketKey(match.first, netIf.getIndex());
return new SocketKey(match.first, netIf.getIndex(), netIf.getName());
}
@Nullable
@ -229,7 +229,7 @@ public class ConnectivityMonitorWithConnectivityManager implements ConnectivityM
}
final Pair<Network, LinkProperties> match = findMatchingNetwork(
lp -> iface.getName().equals(lp.getInterfaceName()));
return match == null ? null : new SocketKey(match.first, iface.getIndex());
return match == null ? null : new SocketKey(match.first, iface.getIndex(), iface.getName());
}
private Pair<Network, LinkProperties> findMatchingNetwork(

View file

@ -38,6 +38,7 @@ import java.util.List;
*/
public class MdnsSocket {
static final int INTERFACE_INDEX_UNSPECIFIED = -1;
static final String INTERFACE_NAME_UNKNOWN = "";
public static final InetSocketAddress MULTICAST_IPV4_ADDRESS =
new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT);
public static final InetSocketAddress MULTICAST_IPV6_ADDRESS =
@ -122,18 +123,35 @@ public class MdnsSocket {
/**
* Returns the index of the network interface that this socket is bound to. If the interface
* cannot be determined, returns -1.
* cannot be determined, returns INTERFACE_INDEX_UNSPECIFIED.
*/
public int getInterfaceIndex() {
if (multicastSocket.isClosed()) {
sharedLog.e("Socket is closed");
return -1;
return INTERFACE_INDEX_UNSPECIFIED;
}
try {
return multicastSocket.getNetworkInterface().getIndex();
} catch (SocketException | NullPointerException e) {
sharedLog.e("Failed to retrieve interface index for socket.", e);
return -1;
return INTERFACE_INDEX_UNSPECIFIED;
}
}
/**
* Returns the name of the network interface that this socket is bound to.
*/
@NonNull
public String getInterfaceName() {
if (multicastSocket.isClosed()) {
sharedLog.e("Socket is closed");
return INTERFACE_NAME_UNKNOWN;
}
try {
return multicastSocket.getNetworkInterface().getName();
} catch (SocketException | NullPointerException e) {
sharedLog.e("Failed to retrieve interface name for socket.", e);
return INTERFACE_NAME_UNKNOWN;
}
}

View file

@ -241,7 +241,8 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
throw new IllegalArgumentException("This socket client does not support requesting "
+ "specific networks");
}
socketCreationCallback.onSocketCreated(new SocketKey(multicastSocket.getInterfaceIndex()));
socketCreationCallback.onSocketCreated(new SocketKey(
multicastSocket.getInterfaceIndex(), multicastSocket.getInterfaceName()));
}
@Override
@ -469,22 +470,29 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
? interfaceProvider.guessNetworkOfRemoteHost(packetAddress)
: null;
final int interfaceIndex;
final String interfaceName;
if (socket == null || !propagateInterfaceIndex) {
interfaceIndex = MdnsSocket.INTERFACE_INDEX_UNSPECIFIED;
interfaceName = MdnsSocket.INTERFACE_NAME_UNKNOWN;
} else if (mdnsFeatureFlags.mIsSocketClientNetworkGuessingEnabled) {
interfaceIndex = key == null
? MdnsSocket.INTERFACE_INDEX_UNSPECIFIED
: key.getInterfaceIndex();
interfaceName = key == null
? MdnsSocket.INTERFACE_NAME_UNKNOWN
: key.getInterfaceName();
} else {
// Note this is incorrect: getInterfaceIndex is the last interface that sent
// a packet, not the one that received the packet.
interfaceIndex = socket.getInterfaceIndex();
interfaceName = socket.getInterfaceName();
}
processResponsePacket(
packet,
responseType,
interfaceIndex,
key == null ? null : key.getNetwork());
key == null ? null : key.getNetwork(),
interfaceName);
}
} catch (IOException e) {
if (!shouldStopSocketLoop) {
@ -496,7 +504,7 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
}
private int processResponsePacket(@NonNull DatagramPacket packet, String responseType,
int interfaceIndex, @Nullable Network network) {
int interfaceIndex, @Nullable Network network, @NonNull String interfaceName) {
int packetNumber = ++receivedPacketNumber;
final MdnsPacket response;
@ -508,7 +516,7 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
responseType, packetNumber, e.code));
if (callback != null) {
callback.onFailedToParseMdnsResponse(packetNumber, e.code,
new SocketKey(network, interfaceIndex));
new SocketKey(network, interfaceIndex, interfaceName));
}
return e.code;
}
@ -519,7 +527,7 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
if (callback != null) {
callback.onResponseReceived(
response, new SocketKey(network, interfaceIndex));
response, new SocketKey(network, interfaceIndex, interfaceName));
}
return MdnsResponseErrorCode.SUCCESS;

View file

@ -539,7 +539,8 @@ public class MdnsSocketProvider {
final List<LinkAddress> addresses = lp.getLinkAddresses();
final Network network =
networkKey == LOCAL_NET ? null : ((NetworkAsKey) networkKey).mNetwork;
final SocketKey socketKey = new SocketKey(network, networkInterface.getIndex());
final SocketKey socketKey = new SocketKey(
network, networkInterface.getIndex(), networkInterface.getName());
// TODO: technically transport types are mutable, although generally not in ways that
// would meaningfully impact the logic using it here. Consider updating logic to
// support transports being added/removed.

View file

@ -16,6 +16,7 @@
package com.android.server.connectivity.mdns;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Network;
@ -33,14 +34,21 @@ public class SocketKey {
@Nullable
private final Network mNetwork;
private final int mInterfaceIndex;
/**
* The interface name is only for offload interface comparison and isn't used for equality or
* hashing, which could lead to a behavior change.
*/
@NonNull
private final String mInterfaceName;
SocketKey(int interfaceIndex) {
this(null /* network */, interfaceIndex);
SocketKey(int interfaceIndex, @NonNull String interfaceName) {
this(null /* network */, interfaceIndex, interfaceName);
}
SocketKey(@Nullable Network network, int interfaceIndex) {
SocketKey(@Nullable Network network, int interfaceIndex, @NonNull String interfaceName) {
mNetwork = network;
mInterfaceIndex = interfaceIndex;
mInterfaceName = interfaceName;
}
@Nullable
@ -52,6 +60,11 @@ public class SocketKey {
return mInterfaceIndex;
}
@NonNull
public String getInterfaceName() {
return mInterfaceName;
}
@Override
public int hashCode() {
return Objects.hash(mNetwork, mInterfaceIndex);
@ -68,6 +81,8 @@ public class SocketKey {
@Override
public String toString() {
return "SocketKey{ network=" + mNetwork + " interfaceIndex=" + mInterfaceIndex + " }";
return "SocketKey{ network=" + mNetwork
+ " interfaceIndex=" + mInterfaceIndex
+ " interfaceName=" + mInterfaceName + " }";
}
}

View file

@ -148,11 +148,13 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
final Network testNetwork1 = mock(Network.class);
final Network testNetwork2 = mock(Network.class);
final int ifIndex1 = 1;
final NetworkInterfaceWrapper iface1 = getTestInterface("iface1", ifIndex1);
final NetworkInterfaceWrapper iface2 = getTestInterface("iface2", 2);
final String ifName1 = "iface1";
final String ifName2 = "iface2";
final NetworkInterfaceWrapper iface1 = getTestInterface(ifName1, ifIndex1);
final NetworkInterfaceWrapper iface2 = getTestInterface(ifName2, 2);
final LinkProperties lp1 = new LinkProperties();
lp1.setInterfaceName("iface1");
lp1.setInterfaceName(ifName1);
lp1.addRoute(new RouteInfo(
new IpPrefix("192.0.1.123/24"), null, lp1.getInterfaceName(), RTN_UNICAST));
lp1.addRoute(new RouteInfo(
@ -169,8 +171,9 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
callback.onLinkPropertiesChanged(testNetwork1, lp1);
callback.onLinkPropertiesChanged(testNetwork2, lp2);
assertEquals(new SocketKey(testNetwork1, ifIndex1), monitor.guessNetworkOfRemoteHost(
List.of(iface1, iface2), parseNumericAddress("192.0.1.124")));
assertEquals(new SocketKey(testNetwork1, ifIndex1, ifName1),
monitor.guessNetworkOfRemoteHost(
List.of(iface1, iface2), parseNumericAddress("192.0.1.124")));
}
@Test
@ -179,7 +182,8 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
final Network testNetwork = mock(Network.class);
final int ifIndex = 1;
final NetworkInterfaceWrapper iface = getTestInterface("iface1", ifIndex);
final String ifName = "iface1";
final NetworkInterfaceWrapper iface = getTestInterface(ifName, ifIndex);
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName("iface1");
@ -191,7 +195,7 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
callback.onLinkPropertiesChanged(testNetwork, lp);
assertEquals(new SocketKey(testNetwork, ifIndex), monitor.guessNetworkOfRemoteHost(
assertEquals(new SocketKey(testNetwork, ifIndex, ifName), monitor.guessNetworkOfRemoteHost(
List.of(iface), parseNumericAddress("169.254.1.2")));
}
@ -201,8 +205,9 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
final Network testNetwork1 = mock(Network.class);
final Network testNetwork2 = mock(Network.class);
final String interfaceName = "lo";
final NetworkInterfaceWrapper loIface = new NetworkInterfaceWrapper(
NetworkInterface.getByName("lo"));
NetworkInterface.getByName(interfaceName));
final NetworkInterfaceWrapper wrongIface = getTestInterface(
"wrongiface", loIface.getIndex() + 1);
@ -220,7 +225,7 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
callback.onLinkPropertiesChanged(testNetwork1, lp1);
callback.onLinkPropertiesChanged(testNetwork2, lp2);
assertEquals(new SocketKey(testNetwork2, loIface.getIndex()),
assertEquals(new SocketKey(testNetwork2, loIface.getIndex(), interfaceName),
monitor.guessNetworkOfRemoteHost(List.of(wrongIface, loIface),
parseNumericAddress("fe80::124%lo")));
}

View file

@ -74,8 +74,8 @@ private val TEST_ADDR2 = parseNumericAddress("2001:db8::124")
private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */)
private val TEST_LINKADDR2 = LinkAddress(TEST_ADDR2, 64 /* prefixLength */)
private val TEST_NETWORK_1 = mock(Network::class.java)
private val TEST_SOCKETKEY_1 = SocketKey(1001 /* interfaceIndex */)
private val TEST_SOCKETKEY_2 = SocketKey(1002 /* interfaceIndex */)
private val TEST_SOCKETKEY_1 = SocketKey(1001 /* interfaceIndex */, "testInterface1")
private val TEST_SOCKETKEY_2 = SocketKey(1002 /* interfaceIndex */, "testInterface2")
private val TEST_HOSTNAME = arrayOf("Android_test", "local")
private const val TEST_SUBTYPE = "_subtype"
private const val TEST_SUBTYPE2 = "_subtype2"

View file

@ -69,11 +69,11 @@ public class MdnsDiscoveryManagerTests {
private static final Network NETWORK_2 = Mockito.mock(Network.class);
private static final int INTERFACE_INDEX_NULL_NETWORK = 123;
private static final SocketKey SOCKET_KEY_NULL_NETWORK =
new SocketKey(null /* network */, INTERFACE_INDEX_NULL_NETWORK);
new SocketKey(INTERFACE_INDEX_NULL_NETWORK, "interface");
private static final SocketKey SOCKET_KEY_NETWORK_1 =
new SocketKey(NETWORK_1, 998 /* interfaceIndex */);
new SocketKey(NETWORK_1, 998 /* interfaceIndex */, "interface1");
private static final SocketKey SOCKET_KEY_NETWORK_2 =
new SocketKey(NETWORK_2, 997 /* interfaceIndex */);
new SocketKey(NETWORK_2, 997 /* interfaceIndex */, "interface2");
private static final Pair<String, SocketKey> PER_SOCKET_SERVICE_TYPE_1_NULL_NETWORK =
Pair.create(SERVICE_TYPE_1, SOCKET_KEY_NULL_NETWORK);
private static final Pair<String, SocketKey> PER_SOCKET_SERVICE_TYPE_2_NULL_NETWORK =
@ -404,9 +404,10 @@ public class MdnsDiscoveryManagerTests {
final SocketCreationCallback callback = expectSocketCreationCallback(
SERVICE_TYPE_1, mockListenerOne, searchOptions);
final SocketKey unusedIfaceKey = new SocketKey(null, INTERFACE_INDEX_NULL_NETWORK + 1);
final SocketKey matchingIfaceWithNetworkKey =
new SocketKey(Mockito.mock(Network.class), INTERFACE_INDEX_NULL_NETWORK);
final SocketKey unusedIfaceKey = new SocketKey(
INTERFACE_INDEX_NULL_NETWORK + 1, "interfaceOther");
final SocketKey matchingIfaceWithNetworkKey = new SocketKey(
Mockito.mock(Network.class), INTERFACE_INDEX_NULL_NETWORK, "interface");
runOnHandler(() -> {
callback.onSocketCreated(unusedIfaceKey);
callback.onSocketCreated(matchingIfaceWithNetworkKey);

View file

@ -88,7 +88,7 @@ public class MdnsMultinetworkSocketClientTest {
mHandlerThread = new HandlerThread("MdnsMultinetworkSocketClientTest");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mSocketKey = new SocketKey(1000 /* interfaceIndex */);
mSocketKey = new SocketKey(1000 /* interfaceIndex */, "interface");
mSocketClient = new MdnsMultinetworkSocketClient(mHandlerThread.getLooper(), mProvider,
mSharedLog, MdnsFeatureFlags.newBuilder().build());
mHandler.post(() -> mSocketClient.setCallback(mCallback));
@ -150,8 +150,8 @@ public class MdnsMultinetworkSocketClientTest {
doReturn(createEmptyNetworkInterface()).when(socket).getInterface();
}
final SocketKey tetherSocketKey1 = new SocketKey(1001 /* interfaceIndex */);
final SocketKey tetherSocketKey2 = new SocketKey(1002 /* interfaceIndex */);
final SocketKey tetherSocketKey1 = new SocketKey(1001 /* interfaceIndex */, "interface1");
final SocketKey tetherSocketKey2 = new SocketKey(1002 /* interfaceIndex */, "interface2");
// Notify socket created
callback.onSocketCreated(mSocketKey, mSocket, List.of());
verify(mSocketCreationCallback).onSocketCreated(mSocketKey);
@ -263,8 +263,8 @@ public class MdnsMultinetworkSocketClientTest {
doReturn(createEmptyNetworkInterface()).when(socket2).getInterface();
doReturn(createEmptyNetworkInterface()).when(socket3).getInterface();
final SocketKey socketKey2 = new SocketKey(1001 /* interfaceIndex */);
final SocketKey socketKey3 = new SocketKey(1002 /* interfaceIndex */);
final SocketKey socketKey2 = new SocketKey(1001 /* interfaceIndex */, "interface1");
final SocketKey socketKey3 = new SocketKey(1002 /* interfaceIndex */, "interface2");
callback.onSocketCreated(mSocketKey, mSocket, List.of());
callback.onSocketCreated(socketKey2, socket2, List.of());
callback.onSocketCreated(socketKey3, socket3, List.of());
@ -338,7 +338,7 @@ public class MdnsMultinetworkSocketClientTest {
@Test
public void testNotifyNetworkUnrequested_SocketsOnNullNetwork() {
final MdnsInterfaceSocket otherSocket = mock(MdnsInterfaceSocket.class);
final SocketKey otherSocketKey = new SocketKey(1001 /* interfaceIndex */);
final SocketKey otherSocketKey = new SocketKey(1001 /* interfaceIndex */, "interface1");
final SocketCallback callback = expectSocketCallback(
mListener, null /* requestedNetwork */);
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
@ -364,7 +364,7 @@ public class MdnsMultinetworkSocketClientTest {
@Test
public void testSocketCreatedAndDestroyed_NullNetwork() throws IOException {
final MdnsInterfaceSocket otherSocket = mock(MdnsInterfaceSocket.class);
final SocketKey otherSocketKey = new SocketKey(1001 /* interfaceIndex */);
final SocketKey otherSocketKey = new SocketKey(1001 /* interfaceIndex */, "interface1");
final SocketCallback callback = expectSocketCallback(mListener, null /* network */);
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
doReturn(createEmptyNetworkInterface()).when(otherSocket).getInterface();
@ -386,7 +386,7 @@ public class MdnsMultinetworkSocketClientTest {
@Test
public void testSocketDestroyed_MultipleCallbacks() {
final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class);
final SocketKey socketKey2 = new SocketKey(1001 /* interfaceIndex */);
final SocketKey socketKey2 = new SocketKey(1001 /* interfaceIndex */, "interface1");
final SocketCreationCallback creationCallback1 = mock(SocketCreationCallback.class);
final SocketCreationCallback creationCallback2 = mock(SocketCreationCallback.class);
final SocketCreationCallback creationCallback3 = mock(SocketCreationCallback.class);

View file

@ -57,7 +57,7 @@ private const val DEFAULT_TTL_TIME_MS = 120000L
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
class MdnsServiceCacheTest {
private val socketKey = SocketKey(null /* network */, INTERFACE_INDEX)
private val socketKey = SocketKey(INTERFACE_INDEX, "interface")
private val cacheKey1 = CacheKey(SERVICE_TYPE_1, socketKey)
private val cacheKey2 = CacheKey(SERVICE_TYPE_2, socketKey)
private val thread = HandlerThread(MdnsServiceCacheTest::class.simpleName)

View file

@ -161,7 +161,7 @@ public class MdnsServiceTypeClientTests {
expectedIPv4Packets = new DatagramPacket[24];
expectedIPv6Packets = new DatagramPacket[24];
socketKey = new SocketKey(mockNetwork, INTERFACE_INDEX);
socketKey = new SocketKey(mockNetwork, INTERFACE_INDEX, "interface");
for (int i = 0; i < expectedIPv4Packets.length; ++i) {
expectedIPv4Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */,