diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java index 05b1dcf9e6..dfaec751ae 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java @@ -289,6 +289,6 @@ public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback { return new MdnsServiceTypeClient( serviceType, socketClient, executorProvider.newServiceTypeClientSchedulerExecutor(), socketKey, - sharedLog.forSubComponent(tag)); + sharedLog.forSubComponent(tag), handler.getLooper()); } } \ No newline at end of file diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java index 8d5949cefb..9c49b8f767 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java @@ -16,10 +16,14 @@ package com.android.server.connectivity.mdns; +import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; + import static java.util.concurrent.TimeUnit.MILLISECONDS; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -60,6 +64,7 @@ public class MdnsServiceTypeClient { private final ScheduledExecutorService executor; @NonNull private final SocketKey socketKey; @NonNull private final SharedLog sharedLog; + @NonNull private final Handler handler; private final Object lock = new Object(); private final ArrayMap listeners = new ArrayMap<>(); @@ -99,9 +104,10 @@ public class MdnsServiceTypeClient { @NonNull MdnsSocketClientBase socketClient, @NonNull ScheduledExecutorService executor, @NonNull SocketKey socketKey, - @NonNull SharedLog sharedLog) { + @NonNull SharedLog sharedLog, + @NonNull Looper looper) { this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), socketKey, - sharedLog); + sharedLog, looper); } @VisibleForTesting @@ -111,7 +117,8 @@ public class MdnsServiceTypeClient { @NonNull ScheduledExecutorService executor, @NonNull MdnsResponseDecoder.Clock clock, @NonNull SocketKey socketKey, - @NonNull SharedLog sharedLog) { + @NonNull SharedLog sharedLog, + @NonNull Looper looper) { this.serviceType = serviceType; this.socketClient = socketClient; this.executor = executor; @@ -120,6 +127,7 @@ public class MdnsServiceTypeClient { this.clock = clock; this.socketKey = socketKey; this.sharedLog = sharedLog; + this.handler = new Handler(looper); } private static MdnsServiceInfo buildMdnsServiceInfoFromResponse( @@ -182,6 +190,7 @@ public class MdnsServiceTypeClient { public void startSendAndReceive( @NonNull MdnsServiceBrowserListener listener, @NonNull MdnsSearchOptions searchOptions) { + ensureRunningOnHandlerThread(handler); synchronized (lock) { this.searchOptions = searchOptions; boolean hadReply = false; @@ -271,6 +280,7 @@ public class MdnsServiceTypeClient { * listener}. Otherwise returns {@code false}. */ public boolean stopSendAndReceive(@NonNull MdnsServiceBrowserListener listener) { + ensureRunningOnHandlerThread(handler); synchronized (lock) { if (listeners.remove(listener) == null) { return listeners.isEmpty(); @@ -282,15 +292,12 @@ public class MdnsServiceTypeClient { } } - public String[] getServiceTypeLabels() { - return serviceTypeLabels; - } - /** * Process an incoming response packet. */ public synchronized void processResponse(@NonNull MdnsPacket packet, @NonNull SocketKey socketKey) { + ensureRunningOnHandlerThread(handler); synchronized (lock) { // Augment the list of current known responses, and generated responses for resolve // requests if there is no known response @@ -340,6 +347,7 @@ public class MdnsServiceTypeClient { } public synchronized void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { + ensureRunningOnHandlerThread(handler); for (int i = 0; i < listeners.size(); i++) { listeners.keyAt(i).onFailedToParseMdnsResponse(receivedPacketNumber, errorCode); } @@ -347,6 +355,7 @@ public class MdnsServiceTypeClient { /** Notify all services are removed because the socket is destroyed. */ public void notifySocketDestroyed() { + ensureRunningOnHandlerThread(handler); synchronized (lock) { for (MdnsResponse response : instanceNameToResponse.values()) { final String name = response.getServiceInstanceName(); diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java index 0a299bf161..cf6275fd38 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java @@ -41,6 +41,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.InetAddresses; import android.net.Network; +import android.os.Handler; +import android.os.HandlerThread; import android.text.TextUtils; import com.android.net.module.util.CollectionUtils; @@ -49,7 +51,9 @@ import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry; import com.android.server.connectivity.mdns.MdnsServiceTypeClient.QueryTaskConfig; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.HandlerUtils; +import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -82,6 +86,7 @@ import java.util.stream.Stream; @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) public class MdnsServiceTypeClientTests { private static final int INTERFACE_INDEX = 999; + private static final long DEFAULT_TIMEOUT = 2000L; private static final String SERVICE_TYPE = "_googlecast._tcp.local"; private static final String[] SERVICE_TYPE_LABELS = TextUtils.split(SERVICE_TYPE, "\\."); private static final InetSocketAddress IPV4_ADDRESS = new InetSocketAddress( @@ -119,6 +124,8 @@ public class MdnsServiceTypeClientTests { private MdnsServiceTypeClient client; private SocketKey socketKey; + private HandlerThread thread; + private Handler handler; @Before @SuppressWarnings("DoNotMock") @@ -174,9 +181,12 @@ public class MdnsServiceTypeClientTests { .thenReturn(expectedIPv6Packets[14]) .thenReturn(expectedIPv6Packets[15]); + thread = new HandlerThread("MdnsServiceTypeClientTests"); + thread.start(); + handler = new Handler(thread.getLooper()); client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, - mockDecoderClock, socketKey, mockSharedLog) { + mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; @@ -184,11 +194,40 @@ public class MdnsServiceTypeClientTests { }; } + @After + public void tearDown() { + if (thread != null) { + thread.quitSafely(); + } + } + + private void runOnHandler(Runnable r) { + handler.post(r); + HandlerUtils.waitForIdle(handler, DEFAULT_TIMEOUT); + } + + private void startSendAndReceive(MdnsServiceBrowserListener listener, + MdnsSearchOptions searchOptions) { + runOnHandler(() -> client.startSendAndReceive(listener, searchOptions)); + } + + private void processResponse(MdnsPacket packet, SocketKey socketKey) { + runOnHandler(() -> client.processResponse(packet, socketKey)); + } + + private void stopSendAndReceive(MdnsServiceBrowserListener listener) { + runOnHandler(() -> client.stopSendAndReceive(listener)); + } + + private void notifySocketDestroyed() { + runOnHandler(() -> client.notifySocketDestroyed()); + } + @Test public void sendQueries_activeScanMode() { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // First burst, 3 queries. verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true); @@ -228,7 +267,7 @@ public class MdnsServiceTypeClientTests { 14, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false); // Stop sending packets. - client.stopSendAndReceive(mockListenerOne); + stopSendAndReceive(mockListenerOne); verify(expectedSendFutures[15]).cancel(true); } @@ -236,7 +275,7 @@ public class MdnsServiceTypeClientTests { public void sendQueries_reentry_activeScanMode() { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // First burst, first query is sent. verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true); @@ -248,7 +287,7 @@ public class MdnsServiceTypeClientTests { .addSubtype("abcde") .setIsPassiveMode(false) .build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // The previous scheduled task should be canceled. verify(expectedSendFutures[1]).cancel(true); @@ -260,7 +299,7 @@ public class MdnsServiceTypeClientTests { 3, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false); // Stop sending packets. - client.stopSendAndReceive(mockListenerOne); + stopSendAndReceive(mockListenerOne); verify(expectedSendFutures[5]).cancel(true); } @@ -268,7 +307,7 @@ public class MdnsServiceTypeClientTests { public void sendQueries_passiveScanMode() { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // First burst, 3 query. verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true); @@ -284,7 +323,7 @@ public class MdnsServiceTypeClientTests { false); // Stop sending packets. - client.stopSendAndReceive(mockListenerOne); + stopSendAndReceive(mockListenerOne); verify(expectedSendFutures[5]).cancel(true); } @@ -293,7 +332,7 @@ public class MdnsServiceTypeClientTests { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode( false).setNumOfQueriesBeforeBackoff(11).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // First burst, 3 queries. verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true); @@ -328,7 +367,7 @@ public class MdnsServiceTypeClientTests { // 0.8 * smallestRemainingTtl is larger than time to next run. long currentTime = TEST_TTL / 2 + TEST_ELAPSED_REALTIME; doReturn(currentTime).when(mockDecoderClock).elapsedRealtime(); - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.0.2.123", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); @@ -345,7 +384,7 @@ public class MdnsServiceTypeClientTests { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode( true).setNumOfQueriesBeforeBackoff(3).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true); verifyAndSendQuery( 1, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false); @@ -358,7 +397,7 @@ public class MdnsServiceTypeClientTests { // In backoff mode, the current scheduled task will be canceled and reschedule if the // 0.8 * smallestRemainingTtl is larger than time to next run. doReturn(TEST_ELAPSED_REALTIME + 20000).when(mockDecoderClock).elapsedRealtime(); - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.0.2.123", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); @@ -372,7 +411,7 @@ public class MdnsServiceTypeClientTests { // If the records is not refreshed, the current scheduled task will not be canceled. doReturn(TEST_ELAPSED_REALTIME + 20001).when(mockDecoderClock).elapsedRealtime(); - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.0.2.123", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL, @@ -382,13 +421,13 @@ public class MdnsServiceTypeClientTests { // In backoff mode, the current scheduled task will not be canceled if the // 0.8 * smallestRemainingTtl is smaller than time to next run. doReturn(TEST_ELAPSED_REALTIME).when(mockDecoderClock).elapsedRealtime(); - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.0.2.123", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); verify(expectedSendFutures[7], never()).cancel(true); - client.stopSendAndReceive(mockListenerOne); + stopSendAndReceive(mockListenerOne); verify(expectedSendFutures[7]).cancel(true); } @@ -396,7 +435,7 @@ public class MdnsServiceTypeClientTests { public void sendQueries_reentry_passiveScanMode() { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // First burst, first query is sent. verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true); @@ -408,7 +447,7 @@ public class MdnsServiceTypeClientTests { .addSubtype("abcde") .setIsPassiveMode(true) .build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // The previous scheduled task should be canceled. verify(expectedSendFutures[1]).cancel(true); @@ -420,7 +459,7 @@ public class MdnsServiceTypeClientTests { 3, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false); // Stop sending packets. - client.stopSendAndReceive(mockListenerOne); + stopSendAndReceive(mockListenerOne); verify(expectedSendFutures[5]).cancel(true); } @@ -492,7 +531,7 @@ public class MdnsServiceTypeClientTests { public void testIfPreviousTaskIsCanceledWhenNewSessionStarts() { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Change the sutypes and start a new session. @@ -502,7 +541,7 @@ public class MdnsServiceTypeClientTests { .addSubtype("abcde") .setIsPassiveMode(true) .build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // Clear the scheduled runnable. currentThreadExecutor.getAndClearLastScheduledRunnable(); @@ -521,9 +560,9 @@ public class MdnsServiceTypeClientTests { //MdnsConfigsFlagsImpl.shouldCancelScanTaskWhenFutureIsNull.override(true); MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); // Change the sutypes and start a new session. - client.stopSendAndReceive(mockListenerOne); + stopSendAndReceive(mockListenerOne); // Clear the scheduled runnable. currentThreadExecutor.getAndClearLastScheduledRunnable(); @@ -538,10 +577,10 @@ public class MdnsServiceTypeClientTests { @Test public void testQueryScheduledWhenAnsweredFromCache() { final MdnsSearchOptions searchOptions = MdnsSearchOptions.getDefaultOptions(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); assertNotNull(currentThreadExecutor.getAndClearSubmittedRunnable()); - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.0.2.123", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); @@ -550,7 +589,7 @@ public class MdnsServiceTypeClientTests { verify(mockListenerOne).onServiceFound(any()); // File another identical query - client.startSendAndReceive(mockListenerTwo, searchOptions); + startSendAndReceive(mockListenerTwo, searchOptions); verify(mockListenerTwo).onServiceNameDiscovered(any()); verify(mockListenerTwo).onServiceFound(any()); @@ -582,9 +621,9 @@ public class MdnsServiceTypeClientTests { @Test public void processResponse_incompleteResponse() { - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", null /* host */, 0 /* port */, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); @@ -606,16 +645,16 @@ public class MdnsServiceTypeClientTests { @Test public void processIPv4Response_completeResponseForNewServiceInstance() throws Exception { final String ipV4Address = "192.168.1.1"; - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", ipV4Address, 5353, /* subtype= */ "ABCDE", Collections.emptyMap(), TEST_TTL), socketKey); // Process a second response with a different port and updated text attributes. - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", ipV4Address, 5354, /* subtype= */ "ABCDE", Collections.singletonMap("key", "value"), TEST_TTL), @@ -660,16 +699,16 @@ public class MdnsServiceTypeClientTests { @Test public void processIPv6Response_getCorrectServiceInfo() throws Exception { final String ipV6Address = "2000:3333::da6c:63ff:fe7c:7483"; - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", ipV6Address, 5353, /* subtype= */ "ABCDE", Collections.emptyMap(), TEST_TTL), socketKey); // Process a second response with a different port and updated text attributes. - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", ipV6Address, 5354, /* subtype= */ "ABCDE", Collections.singletonMap("key", "value"), TEST_TTL), @@ -732,18 +771,18 @@ public class MdnsServiceTypeClientTests { @Test public void processResponse_goodBye() throws Exception { - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); - client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); final String serviceName = "service-instance-1"; final String ipV6Address = "2000:3333::da6c:63ff:fe7c:7483"; // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( serviceName, ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); - client.processResponse(createResponse( + processResponse(createResponse( "goodbye-service", ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), /* ptrTtlMillis= */ 0L), socketKey); @@ -753,7 +792,7 @@ public class MdnsServiceTypeClientTests { verifyServiceRemovedNoCallback(mockListenerTwo); // Verify removed callback would be called. - client.processResponse(createResponse( + processResponse(createResponse( serviceName, ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), 0L), socketKey); @@ -766,12 +805,12 @@ public class MdnsServiceTypeClientTests { @Test public void reportExistingServiceToNewlyRegisteredListeners() throws Exception { // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.168.1.1", 5353, /* subtype= */ "ABCDE", Collections.emptyMap(), TEST_TTL), socketKey); - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); // Verify onServiceNameDiscovered was called once for the existing response. verify(mockListenerOne).onServiceNameDiscovered(serviceInfoCaptor.capture()); @@ -795,12 +834,12 @@ public class MdnsServiceTypeClientTests { assertNull(existingServiceInfo.getAttributeByKey("key")); // Process a goodbye message for the existing response. - client.processResponse(createResponse( + processResponse(createResponse( "service-instance-1", "192.168.1.1", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), /* ptrTtlMillis= */ 0L), socketKey); - client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); // Verify onServiceFound was not called on the newly registered listener after the existing // response is gone. @@ -814,7 +853,7 @@ public class MdnsServiceTypeClientTests { final String serviceInstanceName = "service-instance-1"; client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, - mockDecoderClock, socketKey, mockSharedLog) { + mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; @@ -824,11 +863,11 @@ public class MdnsServiceTypeClientTests { .setRemoveExpiredService(true) .setNumOfQueriesBeforeBackoff(Integer.MAX_VALUE) .build(); - client.startSendAndReceive(mockListenerOne, searchOptions); + startSendAndReceive(mockListenerOne, searchOptions); Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", Collections.emptyMap(), TEST_TTL), socketKey); @@ -857,17 +896,17 @@ public class MdnsServiceTypeClientTests { final String serviceInstanceName = "service-instance-1"; client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, - mockDecoderClock, socketKey, mockSharedLog) { + mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; } }; - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", Collections.emptyMap(), TEST_TTL), socketKey); @@ -890,17 +929,17 @@ public class MdnsServiceTypeClientTests { final String serviceInstanceName = "service-instance-1"; client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, - mockDecoderClock, socketKey, mockSharedLog) { + mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) { @Override MdnsPacketWriter createMdnsPacketWriter() { return mockPacketWriter; } }; - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); Runnable firstMdnsTask = currentThreadExecutor.getAndClearSubmittedRunnable(); // Process the initial response. - client.processResponse(createResponse( + processResponse(createResponse( serviceInstanceName, "192.168.1.1", 5353, /* subtype= */ "ABCDE", Collections.emptyMap(), TEST_TTL), socketKey); @@ -921,27 +960,27 @@ public class MdnsServiceTypeClientTests { final String serviceName = "service-instance"; final String ipV4Address = "192.0.2.0"; final String ipV6Address = "2001:db8::"; - client.startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, MdnsSearchOptions.getDefaultOptions()); InOrder inOrder = inOrder(mockListenerOne); // Process the initial response which is incomplete. final String subtype = "ABCDE"; - client.processResponse(createResponse( + processResponse(createResponse( serviceName, null, 5353, subtype, Collections.emptyMap(), TEST_TTL), socketKey); // Process a second response which has ip address to make response become complete. - client.processResponse(createResponse( + processResponse(createResponse( serviceName, ipV4Address, 5353, subtype, Collections.emptyMap(), TEST_TTL), socketKey); // Process a third response with a different ip address, port and updated text attributes. - client.processResponse(createResponse( + processResponse(createResponse( serviceName, ipV6Address, 5354, subtype, Collections.singletonMap("key", "value"), TEST_TTL), socketKey); // Process the last response which is goodbye message (with the main type, not subtype). - client.processResponse(createResponse( + processResponse(createResponse( serviceName, ipV6Address, 5354, SERVICE_TYPE_LABELS, Collections.singletonMap("key", "value"), /* ptrTtlMillis= */ 0L), socketKey); @@ -1009,8 +1048,8 @@ public class MdnsServiceTypeClientTests { @Test public void testProcessResponse_Resolve() throws Exception { - client = new MdnsServiceTypeClient( - SERVICE_TYPE, mockSocketClient, currentThreadExecutor, socketKey, mockSharedLog); + client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + socketKey, mockSharedLog, thread.getLooper()); final String instanceName = "service-instance"; final String[] hostname = new String[] { "testhost "}; @@ -1020,7 +1059,7 @@ public class MdnsServiceTypeClientTests { final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() .setResolveInstanceName(instanceName).build(); - client.startSendAndReceive(mockListenerOne, resolveOptions); + startSendAndReceive(mockListenerOne, resolveOptions); InOrder inOrder = inOrder(mockListenerOne, mockSocketClient); // Verify a query for SRV/TXT was sent, but no PTR query @@ -1053,7 +1092,7 @@ public class MdnsServiceTypeClientTests { Collections.emptyList() /* authorityRecords */, Collections.emptyList() /* additionalRecords */); - client.processResponse(srvTxtResponse, socketKey); + processResponse(srvTxtResponse, socketKey); // Expect a query for A/AAAA final ArgumentCaptor addressQueryCaptor = @@ -1083,7 +1122,7 @@ public class MdnsServiceTypeClientTests { Collections.emptyList() /* additionalRecords */); inOrder.verify(mockListenerOne, never()).onServiceNameDiscovered(any()); - client.processResponse(addressResponse, socketKey); + processResponse(addressResponse, socketKey); inOrder.verify(mockListenerOne).onServiceFound(serviceInfoCaptor.capture()); verifyServiceInfo(serviceInfoCaptor.getValue(), @@ -1100,7 +1139,7 @@ public class MdnsServiceTypeClientTests { @Test public void testRenewTxtSrvInResolve() throws Exception { client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, - mockDecoderClock, socketKey, mockSharedLog); + mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()); final String instanceName = "service-instance"; final String[] hostname = new String[] { "testhost "}; @@ -1110,7 +1149,7 @@ public class MdnsServiceTypeClientTests { final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() .setResolveInstanceName(instanceName).build(); - client.startSendAndReceive(mockListenerOne, resolveOptions); + startSendAndReceive(mockListenerOne, resolveOptions); InOrder inOrder = inOrder(mockListenerOne, mockSocketClient); // Get the query for SRV/TXT @@ -1147,7 +1186,7 @@ public class MdnsServiceTypeClientTests { InetAddresses.parseNumericAddress(ipV6Address))), Collections.emptyList() /* authorityRecords */, Collections.emptyList() /* additionalRecords */); - client.processResponse(srvTxtResponse, socketKey); + processResponse(srvTxtResponse, socketKey); inOrder.verify(mockListenerOne).onServiceNameDiscovered(any()); inOrder.verify(mockListenerOne).onServiceFound(any()); @@ -1192,7 +1231,7 @@ public class MdnsServiceTypeClientTests { InetAddresses.parseNumericAddress(ipV6Address))), Collections.emptyList() /* authorityRecords */, Collections.emptyList() /* additionalRecords */); - client.processResponse(refreshedSrvTxtResponse, socketKey); + processResponse(refreshedSrvTxtResponse, socketKey); // Advance time to updatedReceiptTime + 1, expected no refresh query because the cache // should contain the record that have update last receipt time. @@ -1203,8 +1242,8 @@ public class MdnsServiceTypeClientTests { @Test public void testProcessResponse_ResolveExcludesOtherServices() { - client = new MdnsServiceTypeClient( - SERVICE_TYPE, mockSocketClient, currentThreadExecutor, socketKey, mockSharedLog); + client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + socketKey, mockSharedLog, thread.getLooper()); final String requestedInstance = "instance1"; final String otherInstance = "instance2"; @@ -1216,28 +1255,28 @@ public class MdnsServiceTypeClientTests { // Use different case in the options .setResolveInstanceName(capitalizedRequestInstance).build(); - client.startSendAndReceive(mockListenerOne, resolveOptions); - client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, resolveOptions); + startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); // Complete response from instanceName - client.processResponse(createResponse( + processResponse(createResponse( requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap() /* textAttributes */, TEST_TTL), socketKey); // Complete response from otherInstanceName - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap() /* textAttributes */, TEST_TTL), socketKey); // Address update from otherInstanceName - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); // Goodbye from otherInstanceName - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), 0L /* ttl */), socketKey); @@ -1267,8 +1306,8 @@ public class MdnsServiceTypeClientTests { @Test public void testProcessResponse_SubtypeDiscoveryLimitedToSubtype() { - client = new MdnsServiceTypeClient( - SERVICE_TYPE, mockSocketClient, currentThreadExecutor, socketKey, mockSharedLog); + client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + socketKey, mockSharedLog, thread.getLooper()); final String matchingInstance = "instance1"; final String subtype = "_subtype"; @@ -1280,8 +1319,8 @@ public class MdnsServiceTypeClientTests { // Search with different case. Note MdnsSearchOptions subtype doesn't start with "_" .addSubtype("Subtype").build(); - client.startSendAndReceive(mockListenerOne, options); - client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); + startSendAndReceive(mockListenerOne, options); + startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); // Complete response from instanceName final MdnsPacket packetWithoutSubtype = createResponse( @@ -1304,21 +1343,21 @@ public class MdnsServiceTypeClientTests { newAnswers, packetWithoutSubtype.authorityRecords, packetWithoutSubtype.additionalRecords); - client.processResponse(packetWithSubtype, socketKey); + processResponse(packetWithSubtype, socketKey); // Complete response from otherInstanceName, without subtype - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap() /* textAttributes */, TEST_TTL), socketKey); // Address update from otherInstanceName - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); // Goodbye from otherInstanceName - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), 0L /* ttl */), socketKey); @@ -1348,8 +1387,8 @@ public class MdnsServiceTypeClientTests { @Test public void testNotifySocketDestroyed() throws Exception { - client = new MdnsServiceTypeClient( - SERVICE_TYPE, mockSocketClient, currentThreadExecutor, socketKey, mockSharedLog); + client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor, + socketKey, mockSharedLog, thread.getLooper()); final String requestedInstance = "instance1"; final String otherInstance = "instance2"; @@ -1359,11 +1398,11 @@ public class MdnsServiceTypeClientTests { .setNumOfQueriesBeforeBackoff(Integer.MAX_VALUE) .setResolveInstanceName("instance1").build(); - client.startSendAndReceive(mockListenerOne, resolveOptions); + startSendAndReceive(mockListenerOne, resolveOptions); // Ensure the first task is executed so it schedules a future task currentThreadExecutor.getAndClearSubmittedFuture().get( TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); - client.startSendAndReceive(mockListenerTwo, + startSendAndReceive(mockListenerTwo, MdnsSearchOptions.newBuilder().setNumOfQueriesBeforeBackoff( Integer.MAX_VALUE).build()); @@ -1375,19 +1414,19 @@ public class MdnsServiceTypeClientTests { TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); // Complete response from instanceName - client.processResponse(createResponse( + processResponse(createResponse( requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap() /* textAttributes */, TEST_TTL), socketKey); // Complete response from otherInstanceName - client.processResponse(createResponse( + processResponse(createResponse( otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS, Collections.emptyMap() /* textAttributes */, TEST_TTL), socketKey); verify(expectedSendFutures[1], never()).cancel(true); - client.notifySocketDestroyed(); + notifySocketDestroyed(); verify(expectedSendFutures[1]).cancel(true); // mockListenerOne gets notified for the requested instance