Do not send socket destroyed on unregistration

When a SocketCallback is unregistered from MdnsSocketProvider, do not
send socket destroyed callbacks. Callers may not expect getting
callbacks after unregistration, and the current callbacks are also
broken when an unrequested socket is still in use by another requester.

MdnsAdvertiser already does not depend on getting this callback, as it
only unregisters the SocketCallback after it is done using the socket.
This change fixes MdnsMultinetworkSocketClient to destroy the socket by
itself when unrequesting.

Bug: 276177548
Test: atest
(cherry picked from https://android-review.googlesource.com/q/commit:5fe9bacc63c1b6a77878f23d5f53a07fc482f354)
Merged-In: If95f833e293f3aab91128aab1c9852ebfd41995d
Change-Id: If95f833e293f3aab91128aab1c9852ebfd41995d
This commit is contained in:
Remi NGUYEN VAN
2023-05-15 11:15:18 +09:00
committed by Cherrypicker Worker
parent 60437e59de
commit 6721aa3570
4 changed files with 141 additions and 17 deletions

View File

@@ -24,7 +24,9 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.net.InetAddresses;
@@ -77,12 +79,17 @@ public class MdnsMultinetworkSocketClientTest {
}
private SocketCallback expectSocketCallback() {
return expectSocketCallback(mListener, mNetwork);
}
private SocketCallback expectSocketCallback(MdnsServiceBrowserListener listener,
Network requestedNetwork) {
final ArgumentCaptor<SocketCallback> callbackCaptor =
ArgumentCaptor.forClass(SocketCallback.class);
mHandler.post(() -> mSocketClient.notifyNetworkRequested(
mListener, mNetwork, mSocketCreationCallback));
listener, requestedNetwork, mSocketCreationCallback));
verify(mProvider, timeout(DEFAULT_TIMEOUT))
.requestSocket(eq(mNetwork), callbackCaptor.capture());
.requestSocket(eq(requestedNetwork), callbackCaptor.capture());
return callbackCaptor.getValue();
}
@@ -169,4 +176,83 @@ public class MdnsMultinetworkSocketClientTest {
new String[] { "Android", "local" } /* serviceHost */)
), response.answers);
}
@Test
public void testSocketRemovedAfterNetworkUnrequested() throws IOException {
// Request a socket
final SocketCallback callback = expectSocketCallback(mListener, mNetwork);
final DatagramPacket ipv4Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length,
InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */);
doReturn(true).when(mSocket).hasJoinedIpv4();
doReturn(true).when(mSocket).hasJoinedIpv6();
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
// Notify socket created
callback.onSocketCreated(mNetwork, mSocket, List.of());
verify(mSocketCreationCallback).onSocketCreated(mNetwork);
// Send IPv4 packet and verify sending has been called.
mSocketClient.sendMulticastPacket(ipv4Packet);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mSocket).send(ipv4Packet);
// Request another socket with null network
final MdnsServiceBrowserListener listener2 = mock(MdnsServiceBrowserListener.class);
final Network network2 = mock(Network.class);
final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class);
final SocketCallback callback2 = expectSocketCallback(listener2, null);
doReturn(true).when(socket2).hasJoinedIpv4();
doReturn(true).when(socket2).hasJoinedIpv6();
doReturn(createEmptyNetworkInterface()).when(socket2).getInterface();
// Notify socket created for two networks.
callback2.onSocketCreated(mNetwork, mSocket, List.of());
callback2.onSocketCreated(network2, socket2, List.of());
verify(mSocketCreationCallback, times(2)).onSocketCreated(mNetwork);
verify(mSocketCreationCallback).onSocketCreated(network2);
// Send IPv4 packet and verify sending to two sockets.
mSocketClient.sendMulticastPacket(ipv4Packet);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mSocket, times(2)).send(ipv4Packet);
verify(socket2).send(ipv4Packet);
// Unrequest another socket
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(listener2));
verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback2);
// Send IPv4 packet again and verify only sending via mSocket
mSocketClient.sendMulticastPacket(ipv4Packet);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mSocket, times(3)).send(ipv4Packet);
verify(socket2).send(ipv4Packet);
// Unrequest remaining socket
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(mListener));
verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback);
// Send IPv4 packet and verify no more sending.
mSocketClient.sendMulticastPacket(ipv4Packet);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mSocket, times(3)).send(ipv4Packet);
verify(socket2).send(ipv4Packet);
}
@Test
public void testNotifyNetworkUnrequested_SocketsOnNullNetwork() {
final MdnsInterfaceSocket otherSocket = mock(MdnsInterfaceSocket.class);
final SocketCallback callback = expectSocketCallback(
mListener, null /* requestedNetwork */);
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
doReturn(createEmptyNetworkInterface()).when(otherSocket).getInterface();
callback.onSocketCreated(null /* network */, mSocket, List.of());
verify(mSocketCreationCallback).onSocketCreated(null);
callback.onSocketCreated(null /* network */, otherSocket, List.of());
verify(mSocketCreationCallback, times(2)).onSocketCreated(null);
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(mListener));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mProvider).unrequestSocket(callback);
verify(mSocketCreationCallback, times(2)).onSocketDestroyed(null /* network */);
}
}

View File

@@ -349,8 +349,8 @@ public class MdnsSocketProviderTest {
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
// Expect the socket destroy for tethered interface.
testCallback3.expectedInterfaceDestroyedForNetwork(null /* network */);
// There was still a tethered interface, but no callback should be sent once unregistered
testCallback3.expectedNoCallback();
}
private RtNetlinkAddressMessage createNetworkAddressUpdateNetLink(
@@ -528,7 +528,8 @@ public class MdnsSocketProviderTest {
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
mHandler.post(()-> mSocketProvider.unrequestSocket(testCallback));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback.expectedInterfaceDestroyedForNetwork(TEST_NETWORK);
// No callback sent when unregistered
testCallback.expectedNoCallback();
verify(mCm, times(1)).unregisterNetworkCallback(any(NetworkCallback.class));
verify(mTm, times(1)).unregisterTetheringEventCallback(any());