Merge changes I987ab866,I73fa9ca7 am: e4407fb469 am: 09a2116456
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2468385
Change-Id: I8cb16e0b654a3c98c4cb67148bd9ac9b1fd20348
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 2078c42..37c2c33 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -525,31 +525,6 @@
clientInfo.mClientIdForServiceUpdates = 0;
}
- /**
- * Check the given service type is valid and construct it to a service type
- * which can use for discovery / resolution service.
- *
- * <p> The valid service type should be 2 labels, or 3 labels if the query is for a
- * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
- * underscore; they are alphanumerical characters or dashes or underscore, except the
- * last one that is just alphanumerical. The last label must be _tcp or _udp.
- *
- * @param serviceType the request service type for discovery / resolution service
- * @return constructed service type or null if the given service type is invalid.
- */
- @Nullable
- private String constructServiceType(String serviceType) {
- if (TextUtils.isEmpty(serviceType)) return null;
-
- final Pattern serviceTypePattern = Pattern.compile(
- "^(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\.)?"
- + "(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\._(?:tcp|udp))$");
- final Matcher matcher = serviceTypePattern.matcher(serviceType);
- if (!matcher.matches()) return null;
- return matcher.group(1) == null
- ? serviceType
- : matcher.group(1) + "_sub." + matcher.group(2);
- }
/**
* Truncate a service name to up to 63 UTF-8 bytes.
@@ -574,6 +549,12 @@
return new String(out.array(), 0, out.position(), utf8);
}
+ private void stopDiscoveryManagerRequest(ClientRequest request, int clientId, int id,
+ ClientInfo clientInfo) {
+ clientInfo.unregisterMdnsListenerFromRequest(request);
+ removeRequestMap(clientId, id, clientInfo);
+ }
+
@Override
public boolean processMessage(Message msg) {
final ClientInfo clientInfo;
@@ -661,11 +642,7 @@
// point, so this needs to check the type of the original request to
// unregister instead of looking at the flag value.
if (request instanceof DiscoveryManagerRequest) {
- final MdnsListener listener =
- ((DiscoveryManagerRequest) request).mListener;
- mMdnsDiscoveryManager.unregisterListener(
- listener.getListenedServiceType(), listener);
- removeRequestMap(clientId, id, clientInfo);
+ stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onStopDiscoverySucceeded(clientId);
} else {
removeRequestMap(clientId, id, clientInfo);
@@ -836,15 +813,22 @@
break;
}
id = request.mGlobalId;
- removeRequestMap(clientId, id, clientInfo);
- if (stopResolveService(id)) {
+ // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
+ // point, so this needs to check the type of the original request to
+ // unregister instead of looking at the flag value.
+ if (request instanceof DiscoveryManagerRequest) {
+ stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onStopResolutionSucceeded(clientId);
} else {
- clientInfo.onStopResolutionFailed(
- clientId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
+ removeRequestMap(clientId, id, clientInfo);
+ if (stopResolveService(id)) {
+ clientInfo.onStopResolutionSucceeded(clientId);
+ } else {
+ clientInfo.onStopResolutionFailed(
+ clientId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
+ }
+ clientInfo.mResolvedService = null;
}
- clientInfo.mResolvedService = null;
- // TODO: Implement the stop resolution with MdnsDiscoveryManager.
break;
}
case NsdManager.REGISTER_SERVICE_CALLBACK:
@@ -1197,10 +1181,7 @@
Log.wtf(TAG, "non-DiscoveryManager request in DiscoveryManager event");
break;
}
- final MdnsListener listener = ((DiscoveryManagerRequest) request).mListener;
- mMdnsDiscoveryManager.unregisterListener(
- listener.getListenedServiceType(), listener);
- removeRequestMap(clientId, transactionId, clientInfo);
+ stopDiscoveryManagerRequest(request, clientId, transactionId, clientInfo);
break;
}
default:
@@ -1260,6 +1241,34 @@
return sb.toString();
}
+ /**
+ * Check the given service type is valid and construct it to a service type
+ * which can use for discovery / resolution service.
+ *
+ * <p> The valid service type should be 2 labels, or 3 labels if the query is for a
+ * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
+ * underscore; they are alphanumerical characters or dashes or underscore, except the
+ * last one that is just alphanumerical. The last label must be _tcp or _udp.
+ *
+ * @param serviceType the request service type for discovery / resolution service
+ * @return constructed service type or null if the given service type is invalid.
+ */
+ @Nullable
+ public static String constructServiceType(String serviceType) {
+ if (TextUtils.isEmpty(serviceType)) return null;
+
+ final Pattern serviceTypePattern = Pattern.compile(
+ "^(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\.)?"
+ + "(_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]\\._(?:tcp|udp))"
+ // Drop '.' at the end of service type that is compatible with old backend.
+ + "\\.?$");
+ final Matcher matcher = serviceTypePattern.matcher(serviceType);
+ if (!matcher.matches()) return null;
+ return matcher.group(1) == null
+ ? matcher.group(2)
+ : matcher.group(1) + "_sub." + matcher.group(2);
+ }
+
@VisibleForTesting
NsdService(Context ctx, Handler handler, long cleanupDelayMs) {
this(ctx, handler, cleanupDelayMs, new Dependencies());
@@ -1780,6 +1789,13 @@
mIsPreSClient = true;
}
+ private void unregisterMdnsListenerFromRequest(ClientRequest request) {
+ final MdnsListener listener =
+ ((DiscoveryManagerRequest) request).mListener;
+ mMdnsDiscoveryManager.unregisterListener(
+ listener.getListenedServiceType(), listener);
+ }
+
// Remove any pending requests from the global map when we get rid of a client,
// and send cancellations to the daemon.
private void expungeAllRequests() {
@@ -1795,10 +1811,7 @@
}
if (request instanceof DiscoveryManagerRequest) {
- final MdnsListener listener =
- ((DiscoveryManagerRequest) request).mListener;
- mMdnsDiscoveryManager.unregisterListener(
- listener.getListenedServiceType(), listener);
+ unregisterMdnsListenerFromRequest(request);
continue;
}
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index db27594..bdf8c04 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -21,6 +21,7 @@
import static android.net.nsd.NsdManager.FAILURE_INTERNAL_ERROR;
import static android.net.nsd.NsdManager.FAILURE_OPERATION_NOT_RUNNING;
+import static com.android.server.NsdService.constructServiceType;
import static com.android.testutils.ContextUtils.mockService;
import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
@@ -1200,6 +1201,50 @@
argThat(info -> matches(info, new NsdServiceInfo(regInfo.getServiceName(), null))));
}
+ @Test
+ public void testStopServiceResolutionWithMdnsDiscoveryManager() {
+ setMdnsDiscoveryManagerEnabled();
+
+ final NsdManager client = connectClient(mService);
+ final ResolveListener resolveListener = mock(ResolveListener.class);
+ final Network network = new Network(999);
+ final String serviceType = "_nsd._service._tcp";
+ final String constructedServiceType = "_nsd._sub._service._tcp.local";
+ final ArgumentCaptor<MdnsServiceBrowserListener> listenerCaptor =
+ ArgumentCaptor.forClass(MdnsServiceBrowserListener.class);
+ final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, serviceType);
+ request.setNetwork(network);
+ client.resolveService(request, resolveListener);
+ waitForIdle();
+ verify(mSocketProvider).startMonitoringSockets();
+ verify(mDiscoveryManager).registerListener(eq(constructedServiceType),
+ listenerCaptor.capture(), argThat(options -> network.equals(options.getNetwork())));
+
+ client.stopServiceResolution(resolveListener);
+ waitForIdle();
+
+ // Verify the listener has been unregistered.
+ verify(mDiscoveryManager, timeout(TIMEOUT_MS))
+ .unregisterListener(eq(constructedServiceType), eq(listenerCaptor.getValue()));
+ verify(resolveListener, timeout(TIMEOUT_MS)).onResolutionStopped(argThat(ns ->
+ request.getServiceName().equals(ns.getServiceName())
+ && request.getServiceType().equals(ns.getServiceType())));
+ verify(mSocketProvider, timeout(CLEANUP_DELAY_MS + TIMEOUT_MS)).requestStopWhenInactive();
+ }
+
+ @Test
+ public void testConstructServiceType() {
+ final String serviceType1 = "test._tcp";
+ final String serviceType2 = "_test._quic";
+ final String serviceType3 = "_123._udp.";
+ final String serviceType4 = "_TEST._999._tcp.";
+
+ assertEquals(null, constructServiceType(serviceType1));
+ assertEquals(null, constructServiceType(serviceType2));
+ assertEquals("_123._udp", constructServiceType(serviceType3));
+ assertEquals("_TEST._sub._999._tcp", constructServiceType(serviceType4));
+ }
+
private void waitForIdle() {
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
}