Adjust the notifyNetworkUnrequested on handleRegisterListener

If the MdnsServiceTypeClient was removed when the
SocketCreationCallback#onAllSocketsDestroyed() was called, the
MdnsSocketClientBase#notifyNetworkUnrequested() will not be
called when a listener is unregistered from the
MdnsDiscoveryManager. This is because the serviceTypeClients will
be cleared after the socket is destroyed. However, these dead
listeners will be re-added to the MdnsServiceTypeClient when a
new socket is created. They will then continue to send callbacks
to the NsdService. Therefore, the notifyNetworkUnrequested()
should be moved to the beginning of the handleRegisterListener()
to ensure that the socket unregistration is properly notified.

Bug: 285997766
Test: atest FrameworksNetTests android.net.cts.NsdManagerTest
Change-Id: I31c766305018889f50a7c12c836174c340d01d7f
This commit is contained in:
Paul Hu
2023-06-07 16:21:34 +08:00
parent 1667bfea04
commit c54aa729c9
2 changed files with 44 additions and 2 deletions

View File

@@ -220,6 +220,9 @@ public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback {
private void handleUnregisterListener(
@NonNull String serviceType, @NonNull MdnsServiceBrowserListener listener) {
// Unrequested the network.
socketClient.notifyNetworkUnrequested(listener);
final List<MdnsServiceTypeClient> serviceTypeClients =
perNetworkServiceTypeClients.getByServiceType(serviceType);
if (serviceTypeClients.isEmpty()) {
@@ -237,8 +240,6 @@ public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback {
// No discovery request. Stops the socket client.
socketClient.stopDiscovery();
}
// Unrequested the network.
socketClient.notifyNetworkUnrequested(listener);
}
@Override

View File

@@ -294,6 +294,47 @@ public class MdnsDiscoveryManagerTests {
.processResponse(response, ifIndex, NETWORK_1);
}
@Test
public void testUnregisterListenerAfterSocketDestroyed() throws IOException {
// Create a ServiceTypeClient for SERVICE_TYPE_1
final MdnsSearchOptions network1Options =
MdnsSearchOptions.newBuilder().setNetwork(null /* network */).build();
final SocketCreationCallback callback = expectSocketCreationCallback(
SERVICE_TYPE_1, mockListenerOne, network1Options);
runOnHandler(() -> callback.onSocketCreated(null /* network */));
verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(
mockListenerOne, network1Options);
// Receive a response, it should be processed on the client.
final MdnsPacket response = createMdnsPacket(SERVICE_TYPE_1);
final int ifIndex = 1;
runOnHandler(() -> discoveryManager.onResponseReceived(
response, ifIndex, null /* network */));
verify(mockServiceTypeClientType1NullNetwork).processResponse(
response, ifIndex, null /* network */);
runOnHandler(() -> callback.onAllSocketsDestroyed(null /* network */));
verify(mockServiceTypeClientType1NullNetwork).notifySocketDestroyed();
// Receive a response again, it should not be processed.
runOnHandler(() -> discoveryManager.onResponseReceived(
response, ifIndex, null /* network */));
// Still times(1) as a response was received once previously
verify(mockServiceTypeClientType1NullNetwork, times(1))
.processResponse(response, ifIndex, null /* network */);
// Unregister the listener, notifyNetworkUnrequested should be called but other stop methods
// won't be call because the service type client was unregistered and destroyed. But those
// cleanups were done in notifySocketDestroyed when the socket was destroyed.
runOnHandler(() -> discoveryManager.unregisterListener(SERVICE_TYPE_1, mockListenerOne));
verify(socketClient).notifyNetworkUnrequested(mockListenerOne);
verify(mockServiceTypeClientType1NullNetwork, never()).stopSendAndReceive(any());
// The stopDiscovery() is only used by MdnsSocketClient, which doesn't send
// onAllSocketsDestroyed(). So the socket clients that send onAllSocketsDestroyed() do not
// need to call stopDiscovery().
verify(socketClient, never()).stopDiscovery();
}
private MdnsPacket createMdnsPacket(String serviceType) {
final String[] type = TextUtils.split(serviceType, "\\.");
final ArrayList<String> name = new ArrayList<>(type.length + 1);