Merge changes Icd842479,I2206a846

* changes:
  Add MdnsInterfaceSocket and MdnsSocketProvider
  Put the Network info in MdnsServiceInfo
This commit is contained in:
Paul Hu
2022-12-12 08:16:23 +00:00
committed by Gerrit Code Review
21 changed files with 1237 additions and 99 deletions

View File

@@ -21,6 +21,7 @@ import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -111,7 +112,7 @@ public class ConnectivityMonitorWithConnectivityManagerTests {
any(NetworkRequest.class), callbackCaptor.capture());
final NetworkCallback callback = callbackCaptor.getValue();
final Network testNetwork = new Network(1 /* netId */);
final Network testNetwork = mock(Network.class);
// Simulate network available.
callback.onAvailable(testNetwork);

View File

@@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.net.InetAddresses;
import android.net.Network;
import com.android.net.module.util.HexDump;
import com.android.testutils.DevSdkIgnoreRule;
@@ -165,7 +166,8 @@ public class MdnsResponseDecoderTests {
packet.setSocketAddress(
new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT));
responses.clear();
int errorCode = decoder.decode(packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED);
int errorCode = decoder.decode(
packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class));
assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
assertEquals(1, responses.size());
}
@@ -178,7 +180,8 @@ public class MdnsResponseDecoderTests {
packet.setSocketAddress(
new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT));
responses.clear();
int errorCode = decoder.decode(packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED);
int errorCode = decoder.decode(
packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class));
assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
assertEquals(2, responses.size());
}
@@ -237,7 +240,8 @@ public class MdnsResponseDecoderTests {
new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
responses.clear();
int errorCode = decoder.decode(packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED);
int errorCode = decoder.decode(
packet, responses, MdnsSocket.INTERFACE_INDEX_UNSPECIFIED, mock(Network.class));
assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
MdnsResponse response = responses.get(0);
@@ -287,10 +291,13 @@ public class MdnsResponseDecoderTests {
new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
responses.clear();
int errorCode = decoder.decode(packet, responses, /* interfaceIndex= */ 10);
final Network network = mock(Network.class);
int errorCode = decoder.decode(
packet, responses, /* interfaceIndex= */ 10, network);
assertEquals(errorCode, MdnsResponseDecoder.SUCCESS);
assertEquals(responses.size(), 1);
assertEquals(responses.get(0).getInterfaceIndex(), 10);
assertEquals(network, responses.get(0).getNetwork());
}
@Test
@@ -306,7 +313,8 @@ public class MdnsResponseDecoderTests {
new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
responses.clear();
int errorCode = decoder.decode(packet, responses, /* interfaceIndex= */ 0);
int errorCode = decoder.decode(
packet, responses, /* interfaceIndex= */ 0, mock(Network.class));
assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
// This should emit two records:
@@ -340,7 +348,8 @@ public class MdnsResponseDecoderTests {
new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT));
responses.clear();
int errorCode = decoder.decode(packet, responses, /* interfaceIndex= */ 0);
int errorCode = decoder.decode(
packet, responses, /* interfaceIndex= */ 0, mock(Network.class));
assertEquals(MdnsResponseDecoder.SUCCESS, errorCode);
// This should emit only two records:

View File

@@ -21,8 +21,12 @@ import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
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 static org.mockito.Mockito.mock;
import android.net.Network;
import com.android.net.module.util.HexDump;
import com.android.testutils.DevSdkIgnoreRule;
@@ -92,6 +96,9 @@ public class MdnsResponseTests {
+ "3839300878797A3D"
+ "21402324");
private static final int INTERFACE_INDEX = 999;
private final Network mNetwork = mock(Network.class);
// The following helper classes act as wrappers so that IPv4 and IPv6 address records can
// be explicitly created by type using same constructor signature as all other records.
static class MdnsInet4AddressRecord extends MdnsInetAddressRecord {
@@ -127,7 +134,7 @@ public class MdnsResponseTests {
// Construct an MdnsResponse with the specified data packets applied.
private MdnsResponse makeMdnsResponse(long time, List<PacketAndRecordClass> responseList)
throws IOException {
MdnsResponse response = new MdnsResponse(time);
MdnsResponse response = new MdnsResponse(time, INTERFACE_INDEX, mNetwork);
for (PacketAndRecordClass responseData : responseList) {
DatagramPacket packet =
new DatagramPacket(responseData.packetData, responseData.packetData.length);
@@ -159,7 +166,7 @@ public class MdnsResponseTests {
String[] name = reader.readLabels();
reader.skip(2); // skip record type indication.
MdnsInetAddressRecord record = new MdnsInetAddressRecord(name, MdnsRecord.TYPE_A, reader);
MdnsResponse response = new MdnsResponse(0);
MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasInet4AddressRecord());
assertTrue(response.setInet4AddressRecord(record));
assertEquals(response.getInet4AddressRecord(), record);
@@ -173,7 +180,7 @@ public class MdnsResponseTests {
reader.skip(2); // skip record type indication.
MdnsInetAddressRecord record =
new MdnsInetAddressRecord(name, MdnsRecord.TYPE_AAAA, reader);
MdnsResponse response = new MdnsResponse(0);
MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasInet6AddressRecord());
assertTrue(response.setInet6AddressRecord(record));
assertEquals(response.getInet6AddressRecord(), record);
@@ -186,7 +193,7 @@ public class MdnsResponseTests {
String[] name = reader.readLabels();
reader.skip(2); // skip record type indication.
MdnsPointerRecord record = new MdnsPointerRecord(name, reader);
MdnsResponse response = new MdnsResponse(0);
MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasPointerRecords());
assertTrue(response.addPointerRecord(record));
List<MdnsPointerRecord> recordList = response.getPointerRecords();
@@ -202,7 +209,7 @@ public class MdnsResponseTests {
String[] name = reader.readLabels();
reader.skip(2); // skip record type indication.
MdnsServiceRecord record = new MdnsServiceRecord(name, reader);
MdnsResponse response = new MdnsResponse(0);
MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasServiceRecord());
assertTrue(response.setServiceRecord(record));
assertEquals(response.getServiceRecord(), record);
@@ -215,23 +222,31 @@ public class MdnsResponseTests {
String[] name = reader.readLabels();
reader.skip(2); // skip record type indication.
MdnsTextRecord record = new MdnsTextRecord(name, reader);
MdnsResponse response = new MdnsResponse(0);
MdnsResponse response = new MdnsResponse(0, INTERFACE_INDEX, mNetwork);
assertFalse(response.hasTextRecord());
assertTrue(response.setTextRecord(record));
assertEquals(response.getTextRecord(), record);
}
@Test
public void getInterfaceIndex_returnsDefaultValue() {
MdnsResponse response = new MdnsResponse(/* now= */ 0);
assertEquals(response.getInterfaceIndex(), -1);
public void getInterfaceIndex() {
final MdnsResponse response1 = new MdnsResponse(/* now= */ 0, INTERFACE_INDEX, mNetwork);
assertEquals(INTERFACE_INDEX, response1.getInterfaceIndex());
final MdnsResponse response2 =
new MdnsResponse(/* now= */ 0, 1234 /* interfaceIndex */, mNetwork);
assertEquals(1234, response2.getInterfaceIndex());
}
@Test
public void getInterfaceIndex_afterSet_returnsValue() {
MdnsResponse response = new MdnsResponse(/* now= */ 0);
response.setInterfaceIndex(5);
assertEquals(response.getInterfaceIndex(), 5);
public void testGetNetwork() {
final MdnsResponse response1 =
new MdnsResponse(/* now= */ 0, INTERFACE_INDEX, null /* network */);
assertNull(response1.getNetwork());
final MdnsResponse response2 =
new MdnsResponse(/* now= */ 0, 1234 /* interfaceIndex */, mNetwork);
assertEquals(mNetwork, response2.getNetwork());
}
@Test

View File

@@ -16,13 +16,16 @@
package com.android.server.connectivity.mdns;
import static com.android.server.connectivity.mdns.MdnsSocket.INTERFACE_INDEX_UNSPECIFIED;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.net.Network;
import android.os.Parcel;
import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
@@ -128,7 +131,7 @@ public class MdnsServiceInfoTest {
"2001::1",
List.of());
assertEquals(info.getInterfaceIndex(), -1);
assertEquals(info.getInterfaceIndex(), INTERFACE_INDEX_UNSPECIFIED);
}
@Test
@@ -149,6 +152,41 @@ public class MdnsServiceInfoTest {
assertEquals(info.getInterfaceIndex(), 20);
}
@Test
public void testGetNetwork() {
final MdnsServiceInfo info1 =
new MdnsServiceInfo(
"my-mdns-service",
new String[] {"_googlecast", "_tcp"},
List.of(),
new String[] {"my-host", "local"},
12345,
"192.168.1.1",
"2001::1",
List.of(),
/* textEntries= */ null,
/* interfaceIndex= */ 20);
assertNull(info1.getNetwork());
final Network network = mock(Network.class);
final MdnsServiceInfo info2 =
new MdnsServiceInfo(
"my-mdns-service",
new String[] {"_googlecast", "_tcp"},
List.of(),
new String[] {"my-host", "local"},
12345,
"192.168.1.1",
"2001::1",
List.of(),
/* textEntries= */ null,
/* interfaceIndex= */ 20,
network);
assertEquals(network, info2.getNetwork());
}
@Test
public void parcelable_canBeParceledAndUnparceled() {
Parcel parcel = Parcel.obtain();
@@ -165,7 +203,9 @@ public class MdnsServiceInfoTest {
List.of(
MdnsServiceInfo.TextEntry.fromString("vn=Google Inc."),
MdnsServiceInfo.TextEntry.fromString("mn=Google Nest Hub Max"),
MdnsServiceInfo.TextEntry.fromString("test=")));
MdnsServiceInfo.TextEntry.fromString("test=")),
20 /* interfaceIndex */,
new Network(123));
beforeParcel.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
@@ -179,6 +219,8 @@ public class MdnsServiceInfoTest {
assertEquals(beforeParcel.getIpv4Address(), afterParcel.getIpv4Address());
assertEquals(beforeParcel.getIpv6Address(), afterParcel.getIpv6Address());
assertEquals(beforeParcel.getAttributes(), afterParcel.getAttributes());
assertEquals(beforeParcel.getInterfaceIndex(), afterParcel.getInterfaceIndex());
assertEquals(beforeParcel.getNetwork(), afterParcel.getNetwork());
}
@Test

View File

@@ -39,6 +39,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.InetAddresses;
import android.net.Network;
import android.text.TextUtils;
import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
@@ -79,6 +80,7 @@ public class MdnsServiceTypeClientTests {
private static final int INTERFACE_INDEX = 999;
private static final String SERVICE_TYPE = "_googlecast._tcp.local";
private static final String[] SERVICE_TYPE_LABELS = TextUtils.split(SERVICE_TYPE, "\\.");
private static final Network NETWORK = mock(Network.class);
@Mock
private MdnsServiceBrowserListener mockListenerOne;
@@ -385,7 +387,8 @@ public class MdnsServiceTypeClientTests {
private static void verifyServiceInfo(MdnsServiceInfo serviceInfo, String serviceName,
String[] serviceType, String ipv4Address, String ipv6Address, int port,
List<String> subTypes, Map<String, String> attributes, int interfaceIndex) {
List<String> subTypes, Map<String, String> attributes, int interfaceIndex,
Network network) {
assertEquals(serviceName, serviceInfo.getServiceInstanceName());
assertArrayEquals(serviceType, serviceInfo.getServiceType());
assertEquals(ipv4Address, serviceInfo.getIpv4Address());
@@ -396,6 +399,7 @@ public class MdnsServiceTypeClientTests {
assertEquals(attributes.get(key), serviceInfo.getAttributeByKey(key));
}
assertEquals(interfaceIndex, serviceInfo.getInterfaceIndex());
assertEquals(network, serviceInfo.getNetwork());
}
@Test
@@ -405,6 +409,7 @@ public class MdnsServiceTypeClientTests {
MdnsResponse response = mock(MdnsResponse.class);
when(response.getServiceInstanceName()).thenReturn("service-instance-1");
doReturn(INTERFACE_INDEX).when(response).getInterfaceIndex();
doReturn(NETWORK).when(response).getNetwork();
when(response.isComplete()).thenReturn(false);
client.processResponse(response);
@@ -417,7 +422,8 @@ public class MdnsServiceTypeClientTests {
0 /* port */,
List.of() /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
verify(mockListenerOne, never()).onServiceFound(any(MdnsServiceInfo.class));
verify(mockListenerOne, never()).onServiceUpdated(any(MdnsServiceInfo.class));
@@ -436,7 +442,8 @@ public class MdnsServiceTypeClientTests {
5353,
/* subtype= */ "ABCDE",
Collections.emptyMap(),
/* interfaceIndex= */ 20);
/* interfaceIndex= */ 20,
NETWORK);
client.processResponse(initialResponse);
// Process a second response with a different port and updated text attributes.
@@ -447,7 +454,8 @@ public class MdnsServiceTypeClientTests {
5354,
/* subtype= */ "ABCDE",
Collections.singletonMap("key", "value"),
/* interfaceIndex= */ 20);
/* interfaceIndex= */ 20,
NETWORK);
client.processResponse(secondResponse);
// Verify onServiceNameDiscovered was called once for the initial response.
@@ -460,7 +468,8 @@ public class MdnsServiceTypeClientTests {
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
20 /* interfaceIndex */);
20 /* interfaceIndex */,
NETWORK);
// Verify onServiceFound was called once for the initial response.
verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture());
@@ -471,6 +480,7 @@ public class MdnsServiceTypeClientTests {
assertEquals(initialServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
assertNull(initialServiceInfo.getAttributeByKey("key"));
assertEquals(initialServiceInfo.getInterfaceIndex(), 20);
assertEquals(NETWORK, initialServiceInfo.getNetwork());
// Verify onServiceUpdated was called once for the second response.
verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture());
@@ -482,6 +492,7 @@ public class MdnsServiceTypeClientTests {
assertEquals(updatedServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
assertEquals(updatedServiceInfo.getAttributeByKey("key"), "value");
assertEquals(updatedServiceInfo.getInterfaceIndex(), 20);
assertEquals(NETWORK, updatedServiceInfo.getNetwork());
}
@Test
@@ -497,7 +508,8 @@ public class MdnsServiceTypeClientTests {
5353,
/* subtype= */ "ABCDE",
Collections.emptyMap(),
/* interfaceIndex= */ 20);
/* interfaceIndex= */ 20,
NETWORK);
client.processResponse(initialResponse);
// Process a second response with a different port and updated text attributes.
@@ -508,7 +520,8 @@ public class MdnsServiceTypeClientTests {
5354,
/* subtype= */ "ABCDE",
Collections.singletonMap("key", "value"),
/* interfaceIndex= */ 20);
/* interfaceIndex= */ 20,
NETWORK);
client.processResponse(secondResponse);
System.out.println("secondResponses ip"
@@ -524,7 +537,8 @@ public class MdnsServiceTypeClientTests {
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
20 /* interfaceIndex */);
20 /* interfaceIndex */,
NETWORK);
// Verify onServiceFound was called once for the initial response.
verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture());
@@ -535,6 +549,7 @@ public class MdnsServiceTypeClientTests {
assertEquals(initialServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
assertNull(initialServiceInfo.getAttributeByKey("key"));
assertEquals(initialServiceInfo.getInterfaceIndex(), 20);
assertEquals(NETWORK, initialServiceInfo.getNetwork());
// Verify onServiceUpdated was called once for the second response.
verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture());
@@ -546,6 +561,7 @@ public class MdnsServiceTypeClientTests {
assertEquals(updatedServiceInfo.getSubtypes(), Collections.singletonList("ABCDE"));
assertEquals(updatedServiceInfo.getAttributeByKey("key"), "value");
assertEquals(updatedServiceInfo.getInterfaceIndex(), 20);
assertEquals(NETWORK, updatedServiceInfo.getNetwork());
}
private void verifyServiceRemovedNoCallback(MdnsServiceBrowserListener listener) {
@@ -554,15 +570,17 @@ public class MdnsServiceTypeClientTests {
}
private void verifyServiceRemovedCallback(MdnsServiceBrowserListener listener,
String serviceName, String[] serviceType, int interfaceIndex) {
String serviceName, String[] serviceType, int interfaceIndex, Network network) {
verify(listener).onServiceRemoved(argThat(
info -> serviceName.equals(info.getServiceInstanceName())
&& Arrays.equals(serviceType, info.getServiceType())
&& info.getInterfaceIndex() == interfaceIndex));
&& info.getInterfaceIndex() == interfaceIndex
&& network.equals(info.getNetwork())));
verify(listener).onServiceNameRemoved(argThat(
info -> serviceName.equals(info.getServiceInstanceName())
&& Arrays.equals(serviceType, info.getServiceType())
&& info.getInterfaceIndex() == interfaceIndex));
&& info.getInterfaceIndex() == interfaceIndex
&& network.equals(info.getNetwork())));
}
@Test
@@ -580,11 +598,13 @@ public class MdnsServiceTypeClientTests {
5353 /* port */,
/* subtype= */ "ABCDE",
Collections.emptyMap(),
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
client.processResponse(initialResponse);
MdnsResponse response = mock(MdnsResponse.class);
doReturn("goodbye-service").when(response).getServiceInstanceName();
doReturn(INTERFACE_INDEX).when(response).getInterfaceIndex();
doReturn(NETWORK).when(response).getNetwork();
doReturn(true).when(response).isGoodbye();
client.processResponse(response);
// Verify removed callback won't be called if the service is not existed.
@@ -595,9 +615,9 @@ public class MdnsServiceTypeClientTests {
doReturn(serviceName).when(response).getServiceInstanceName();
client.processResponse(response);
verifyServiceRemovedCallback(
mockListenerOne, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX);
mockListenerOne, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX, NETWORK);
verifyServiceRemovedCallback(
mockListenerTwo, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX);
mockListenerTwo, serviceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX, NETWORK);
}
@Test
@@ -610,7 +630,8 @@ public class MdnsServiceTypeClientTests {
5353,
/* subtype= */ "ABCDE",
Collections.emptyMap(),
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
client.processResponse(initialResponse);
client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions());
@@ -625,7 +646,8 @@ public class MdnsServiceTypeClientTests {
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
// Verify onServiceFound was called once for the existing response.
verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture());
@@ -662,7 +684,7 @@ public class MdnsServiceTypeClientTests {
MdnsResponse initialResponse =
createMockResponse(
serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"),
Map.of(), INTERFACE_INDEX);
Map.of(), INTERFACE_INDEX, NETWORK);
client.processResponse(initialResponse);
// Clear the scheduled runnable.
@@ -696,7 +718,7 @@ public class MdnsServiceTypeClientTests {
MdnsResponse initialResponse =
createMockResponse(
serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"),
Map.of(), INTERFACE_INDEX);
Map.of(), INTERFACE_INDEX, NETWORK);
client.processResponse(initialResponse);
// Clear the scheduled runnable.
@@ -714,8 +736,8 @@ public class MdnsServiceTypeClientTests {
firstMdnsTask.run();
// Verify removed callback was called.
verifyServiceRemovedCallback(
mockListenerOne, serviceInstanceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX);
verifyServiceRemovedCallback(mockListenerOne, serviceInstanceName, SERVICE_TYPE_LABELS,
INTERFACE_INDEX, NETWORK);
}
@Test
@@ -736,7 +758,7 @@ public class MdnsServiceTypeClientTests {
MdnsResponse initialResponse =
createMockResponse(
serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"),
Map.of(), INTERFACE_INDEX);
Map.of(), INTERFACE_INDEX, NETWORK);
client.processResponse(initialResponse);
// Clear the scheduled runnable.
@@ -770,7 +792,7 @@ public class MdnsServiceTypeClientTests {
MdnsResponse initialResponse =
createMockResponse(
serviceInstanceName, "192.168.1.1", 5353, List.of("ABCDE"),
Map.of(), INTERFACE_INDEX);
Map.of(), INTERFACE_INDEX, NETWORK);
client.processResponse(initialResponse);
// Clear the scheduled runnable.
@@ -781,8 +803,8 @@ public class MdnsServiceTypeClientTests {
firstMdnsTask.run();
// Verify removed callback was called.
verifyServiceRemovedCallback(
mockListenerOne, serviceInstanceName, SERVICE_TYPE_LABELS, INTERFACE_INDEX);
verifyServiceRemovedCallback(mockListenerOne, serviceInstanceName, SERVICE_TYPE_LABELS,
INTERFACE_INDEX, NETWORK);
}
@Test
@@ -801,7 +823,8 @@ public class MdnsServiceTypeClientTests {
5353,
"ABCDE" /* subtype */,
Collections.emptyMap(),
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
client.processResponse(initialResponse);
// Process a second response which has ip address to make response become complete.
@@ -812,7 +835,8 @@ public class MdnsServiceTypeClientTests {
5353,
"ABCDE" /* subtype */,
Collections.emptyMap(),
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
client.processResponse(secondResponse);
// Process a third response with a different ip address, port and updated text attributes.
@@ -823,7 +847,8 @@ public class MdnsServiceTypeClientTests {
5354,
"ABCDE" /* subtype */,
Collections.singletonMap("key", "value"),
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
client.processResponse(thirdResponse);
// Process the last response which is goodbye message.
@@ -842,7 +867,8 @@ public class MdnsServiceTypeClientTests {
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
// Verify onServiceFound was second called for the second response.
inOrder.verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture());
@@ -854,7 +880,8 @@ public class MdnsServiceTypeClientTests {
5353 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", null) /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
// Verify onServiceUpdated was third called for the third response.
inOrder.verify(mockListenerOne).onServiceUpdated(serviceInfoCaptor.capture());
@@ -866,7 +893,8 @@ public class MdnsServiceTypeClientTests {
5354 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", "value") /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
// Verify onServiceRemoved was called for the last response.
inOrder.verify(mockListenerOne).onServiceRemoved(serviceInfoCaptor.capture());
@@ -878,7 +906,8 @@ public class MdnsServiceTypeClientTests {
5354 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", "value") /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
// Verify onServiceNameRemoved was called for the last response.
inOrder.verify(mockListenerOne).onServiceNameRemoved(serviceInfoCaptor.capture());
@@ -890,7 +919,8 @@ public class MdnsServiceTypeClientTests {
5354 /* port */,
Collections.singletonList("ABCDE") /* subTypes */,
Collections.singletonMap("key", "value") /* attributes */,
INTERFACE_INDEX);
INTERFACE_INDEX,
NETWORK);
}
// verifies that the right query was enqueued with the right delay, and send query by executing
@@ -962,26 +992,25 @@ public class MdnsServiceTypeClientTests {
int port,
@NonNull List<String> subtypes,
@NonNull Map<String, String> textAttributes,
int interfaceIndex)
int interfaceIndex,
Network network)
throws Exception {
String[] hostName = new String[]{"hostname"};
MdnsServiceRecord serviceRecord = mock(MdnsServiceRecord.class);
when(serviceRecord.getServiceHost()).thenReturn(hostName);
when(serviceRecord.getServicePort()).thenReturn(port);
MdnsResponse response = spy(new MdnsResponse(0));
MdnsResponse response = spy(new MdnsResponse(0, interfaceIndex, network));
MdnsInetAddressRecord inetAddressRecord = mock(MdnsInetAddressRecord.class);
if (host.contains(":")) {
when(inetAddressRecord.getInet6Address())
.thenReturn((Inet6Address) Inet6Address.getByName(host));
response.setInet6AddressRecord(inetAddressRecord);
response.setInterfaceIndex(interfaceIndex);
} else {
when(inetAddressRecord.getInet4Address())
.thenReturn((Inet4Address) Inet4Address.getByName(host));
response.setInet4AddressRecord(inetAddressRecord);
response.setInterfaceIndex(interfaceIndex);
}
MdnsTextRecord textRecord = mock(MdnsTextRecord.class);
@@ -1011,10 +1040,10 @@ public class MdnsServiceTypeClientTests {
int port,
@NonNull String subtype,
@NonNull Map<String, String> textAttributes,
int interfaceIndex)
int interfaceIndex,
Network network)
throws Exception {
MdnsResponse response = new MdnsResponse(0);
response.setInterfaceIndex(interfaceIndex);
MdnsResponse response = new MdnsResponse(0, interfaceIndex, network);
// Set PTR record
final MdnsPointerRecord pointerRecord = new MdnsPointerRecord(

View File

@@ -501,8 +501,7 @@ public class MdnsSocketClientTests {
//MdnsConfigsFlagsImpl.allowNetworkInterfaceIndexPropagation.override(true);
when(mockMulticastSocket.getInterfaceIndex()).thenReturn(21);
mdnsClient =
new MdnsSocketClient(mContext, mockMulticastLock) {
mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock) {
@Override
MdnsSocket createMdnsSocket(int port) {
if (port == MdnsConstants.MDNS_PORT) {
@@ -525,8 +524,7 @@ public class MdnsSocketClientTests {
//MdnsConfigsFlagsImpl.allowNetworkInterfaceIndexPropagation.override(false);
when(mockMulticastSocket.getInterfaceIndex()).thenReturn(21);
mdnsClient =
new MdnsSocketClient(mContext, mockMulticastLock) {
mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock) {
@Override
MdnsSocket createMdnsSocket(int port) {
if (port == MdnsConstants.MDNS_PORT) {

View File

@@ -0,0 +1,289 @@
/*
* 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.server.connectivity.mdns;
import static com.android.testutils.ContextUtils.mockService;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.INetd;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.TetheringManager;
import android.net.TetheringManager.TetheringEventCallback;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.mdns.MdnsSocketProvider.Dependencies;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
@RunWith(DevSdkIgnoreRunner.class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
public class MdnsSocketProviderTest {
private static final String TEST_IFACE_NAME = "test";
private static final String LOCAL_ONLY_IFACE_NAME = "local_only";
private static final String TETHERED_IFACE_NAME = "tethered";
private static final long DEFAULT_TIMEOUT = 2000L;
private static final long NO_CALLBACK_TIMEOUT = 200L;
private static final LinkAddress LINKADDRV4 = new LinkAddress("192.0.2.0/24");
private static final LinkAddress LINKADDRV6 =
new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64");
private static final Network TEST_NETWORK = new Network(123);
private static final Network LOCAL_NETWORK = new Network(INetd.LOCAL_NET_ID);
@Mock private Context mContext;
@Mock private Dependencies mDeps;
@Mock private ConnectivityManager mCm;
@Mock private TetheringManager mTm;
@Mock private NetworkInterfaceWrapper mTestNetworkIfaceWrapper;
@Mock private NetworkInterfaceWrapper mLocalOnlyIfaceWrapper;
@Mock private NetworkInterfaceWrapper mTetheredIfaceWrapper;
private Handler mHandler;
private MdnsSocketProvider mSocketProvider;
private NetworkCallback mNetworkCallback;
private TetheringEventCallback mTetheringEventCallback;
@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
mockService(mContext, ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mCm);
mockService(mContext, TetheringManager.class, Context.TETHERING_SERVICE, mTm);
doReturn(true).when(mDeps).canScanOnInterface(any());
doReturn(mTestNetworkIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TEST_IFACE_NAME);
doReturn(mLocalOnlyIfaceWrapper).when(mDeps)
.getNetworkInterfaceByName(LOCAL_ONLY_IFACE_NAME);
doReturn(mTetheredIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TETHERED_IFACE_NAME);
doReturn(mock(MdnsInterfaceSocket.class))
.when(mDeps).createMdnsInterfaceSocket(any(), anyInt());
final HandlerThread thread = new HandlerThread("MdnsSocketProviderTest");
thread.start();
mHandler = new Handler(thread.getLooper());
final ArgumentCaptor<NetworkCallback> nwCallbackCaptor =
ArgumentCaptor.forClass(NetworkCallback.class);
final ArgumentCaptor<TetheringEventCallback> teCallbackCaptor =
ArgumentCaptor.forClass(TetheringEventCallback.class);
mSocketProvider = new MdnsSocketProvider(mContext, thread.getLooper(), mDeps);
mHandler.post(mSocketProvider::startMonitoringSockets);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mCm).registerNetworkCallback(any(), nwCallbackCaptor.capture(), any());
verify(mTm).registerTetheringEventCallback(any(), teCallbackCaptor.capture());
mNetworkCallback = nwCallbackCaptor.getValue();
mTetheringEventCallback = teCallbackCaptor.getValue();
}
private class TestSocketCallback implements MdnsSocketProvider.SocketCallback {
private class SocketEvent {
public final Network mNetwork;
public final List<LinkAddress> mAddresses;
SocketEvent(Network network, List<LinkAddress> addresses) {
mNetwork = network;
mAddresses = Collections.unmodifiableList(addresses);
}
}
private class SocketCreatedEvent extends SocketEvent {
SocketCreatedEvent(Network nw, List<LinkAddress> addresses) {
super(nw, addresses);
}
}
private class InterfaceDestroyedEvent extends SocketEvent {
InterfaceDestroyedEvent(Network nw, List<LinkAddress> addresses) {
super(nw, addresses);
}
}
private class AddressesChangedEvent extends SocketEvent {
AddressesChangedEvent(Network nw, List<LinkAddress> addresses) {
super(nw, addresses);
}
}
private final ArrayTrackRecord<SocketEvent>.ReadHead mHistory =
new ArrayTrackRecord<SocketEvent>().newReadHead();
@Override
public void onSocketCreated(Network network, MdnsInterfaceSocket socket,
List<LinkAddress> addresses) {
mHistory.add(new SocketCreatedEvent(network, addresses));
}
@Override
public void onInterfaceDestroyed(Network network, MdnsInterfaceSocket socket) {
mHistory.add(new InterfaceDestroyedEvent(network, List.of()));
}
@Override
public void onAddressesChanged(Network network, List<LinkAddress> addresses) {
mHistory.add(new AddressesChangedEvent(network, addresses));
}
public void expectedSocketCreatedForNetwork(Network network, List<LinkAddress> addresses) {
final SocketEvent event = mHistory.poll(DEFAULT_TIMEOUT, c -> true);
assertNotNull(event);
assertTrue(event instanceof SocketCreatedEvent);
assertEquals(network, event.mNetwork);
assertEquals(addresses, event.mAddresses);
}
public void expectedInterfaceDestroyedForNetwork(Network network) {
final SocketEvent event = mHistory.poll(DEFAULT_TIMEOUT, c -> true);
assertNotNull(event);
assertTrue(event instanceof InterfaceDestroyedEvent);
assertEquals(network, event.mNetwork);
}
public void expectedAddressesChangedForNetwork(Network network,
List<LinkAddress> addresses) {
final SocketEvent event = mHistory.poll(DEFAULT_TIMEOUT, c -> true);
assertNotNull(event);
assertTrue(event instanceof AddressesChangedEvent);
assertEquals(network, event.mNetwork);
assertEquals(event.mAddresses, addresses);
}
public void expectedNoCallback() {
final SocketEvent event = mHistory.poll(NO_CALLBACK_TIMEOUT, c -> true);
assertNull(event);
}
}
@Test
public void testSocketRequestAndUnrequestSocket() {
final TestSocketCallback testCallback1 = new TestSocketCallback();
mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback1));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
final LinkProperties testLp = new LinkProperties();
testLp.setInterfaceName(TEST_IFACE_NAME);
testLp.setLinkAddresses(List.of(LINKADDRV4));
mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mTestNetworkIfaceWrapper).getNetworkInterface();
testCallback1.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
final TestSocketCallback testCallback2 = new TestSocketCallback();
mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback2));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
final TestSocketCallback testCallback3 = new TestSocketCallback();
mHandler.post(() -> mSocketProvider.requestSocket(null /* network */, testCallback3));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
testCallback3.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
mHandler.post(() -> mTetheringEventCallback.onLocalOnlyInterfacesChanged(
List.of(LOCAL_ONLY_IFACE_NAME)));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mLocalOnlyIfaceWrapper).getNetworkInterface();
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
testCallback3.expectedSocketCreatedForNetwork(LOCAL_NETWORK, List.of());
mHandler.post(() -> mTetheringEventCallback.onTetheredInterfacesChanged(
List.of(TETHERED_IFACE_NAME)));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mTetheredIfaceWrapper).getNetworkInterface();
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
testCallback3.expectedSocketCreatedForNetwork(LOCAL_NETWORK, List.of());
mHandler.post(() -> mSocketProvider.unrequestSocket(testCallback1));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
testCallback3.expectedNoCallback();
mHandler.post(() -> mNetworkCallback.onLost(TEST_NETWORK));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedInterfaceDestroyedForNetwork(TEST_NETWORK);
testCallback3.expectedInterfaceDestroyedForNetwork(TEST_NETWORK);
mHandler.post(() -> mTetheringEventCallback.onLocalOnlyInterfacesChanged(List.of()));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
testCallback3.expectedInterfaceDestroyedForNetwork(LOCAL_NETWORK);
mHandler.post(() -> mSocketProvider.unrequestSocket(testCallback3));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
testCallback3.expectedNoCallback();
}
@Test
public void testAddressesChanged() throws Exception {
final TestSocketCallback testCallback = new TestSocketCallback();
mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback.expectedNoCallback();
final LinkProperties testLp = new LinkProperties();
testLp.setInterfaceName(TEST_IFACE_NAME);
testLp.setLinkAddresses(List.of(LINKADDRV4));
mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mTestNetworkIfaceWrapper, times(1)).getNetworkInterface();
testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
final LinkProperties newTestLp = new LinkProperties();
newTestLp.setInterfaceName(TEST_IFACE_NAME);
newTestLp.setLinkAddresses(List.of(LINKADDRV4, LINKADDRV6));
mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, newTestLp));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mTestNetworkIfaceWrapper, times(1)).getNetworkInterface();
testCallback.expectedAddressesChangedForNetwork(
TEST_NETWORK, List.of(LINKADDRV4, LINKADDRV6));
}
}