• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.net.cts
17 
18 import android.Manifest.permission.MANAGE_TEST_NETWORKS
19 import android.Manifest.permission.NETWORK_SETTINGS
20 import android.app.compat.CompatChanges
21 import android.net.ConnectivityManager
22 import android.net.ConnectivityManager.NetworkCallback
23 import android.net.DnsResolver
24 import android.net.InetAddresses.parseNumericAddress
25 import android.net.LocalSocket
26 import android.net.LocalSocketAddress
27 import android.net.MacAddress
28 import android.net.Network
29 import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED
30 import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
31 import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
32 import android.net.NetworkCapabilities.TRANSPORT_TEST
33 import android.net.NetworkRequest
34 import android.net.TestNetworkInterface
35 import android.net.TestNetworkManager
36 import android.net.TestNetworkSpecifier
37 import android.net.connectivity.ConnectivityCompatChanges
38 import android.net.cts.util.CtsNetUtils
39 import android.net.nsd.AdvertisingRequest
40 import android.net.nsd.AdvertisingRequest.FLAG_SKIP_PROBING
41 import android.net.nsd.DiscoveryRequest
42 import android.net.nsd.NsdManager
43 import android.net.nsd.NsdManager.PROTOCOL_DNS_SD
44 import android.net.nsd.NsdServiceInfo
45 import android.net.nsd.OffloadEngine
46 import android.net.nsd.OffloadServiceInfo
47 import android.os.Build
48 import android.os.Handler
49 import android.os.HandlerThread
50 import android.platform.test.annotations.AppModeFull
51 import android.provider.DeviceConfig.NAMESPACE_TETHERING
52 import android.system.OsConstants.ETH_P_IPV6
53 import android.system.OsConstants.IPPROTO_IPV6
54 import android.system.OsConstants.IPPROTO_UDP
55 import android.system.OsConstants.RT_SCOPE_LINK
56 import android.util.Log
57 import androidx.test.filters.SmallTest
58 import androidx.test.platform.app.InstrumentationRegistry
59 import com.android.compatibility.common.util.PollingCheck
60 import com.android.compatibility.common.util.PropertyUtil
61 import com.android.compatibility.common.util.SystemUtil
62 import com.android.modules.utils.build.SdkLevel.isAtLeastU
63 import com.android.net.module.util.DnsPacket
64 import com.android.net.module.util.DnsPacket.ANSECTION
65 import com.android.net.module.util.HexDump
66 import com.android.net.module.util.HexDump.hexStringToByteArray
67 import com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN
68 import com.android.net.module.util.PacketBuilder
69 import com.android.testutils.ConnectivityModuleTest
70 import com.android.testutils.DevSdkIgnoreRule
71 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
72 import com.android.testutils.DevSdkIgnoreRunner
73 import com.android.testutils.DeviceConfigRule
74 import com.android.testutils.NSResponder
75 import com.android.testutils.NsdDiscoveryRecord
76 import com.android.testutils.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStarted
77 import com.android.testutils.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStopped
78 import com.android.testutils.NsdDiscoveryRecord.DiscoveryEvent.ServiceFound
79 import com.android.testutils.NsdDiscoveryRecord.DiscoveryEvent.ServiceLost
80 import com.android.testutils.NsdEvent
81 import com.android.testutils.NsdRecord
82 import com.android.testutils.NsdRegistrationRecord
83 import com.android.testutils.NsdRegistrationRecord.RegistrationEvent.RegistrationFailed
84 import com.android.testutils.NsdRegistrationRecord.RegistrationEvent.ServiceRegistered
85 import com.android.testutils.NsdRegistrationRecord.RegistrationEvent.ServiceUnregistered
86 import com.android.testutils.NsdResolveRecord
87 import com.android.testutils.NsdResolveRecord.ResolveEvent.ResolutionStopped
88 import com.android.testutils.NsdResolveRecord.ResolveEvent.ServiceResolved
89 import com.android.testutils.NsdResolveRecord.ResolveEvent.StopResolutionFailed
90 import com.android.testutils.NsdServiceInfoCallbackRecord
91 import com.android.testutils.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.ServiceUpdated
92 import com.android.testutils.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.ServiceUpdatedLost
93 import com.android.testutils.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.UnregisterCallbackSucceeded
94 import com.android.testutils.PollPacketReader
95 import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
96 import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
97 import com.android.testutils.TestDnsPacket
98 import com.android.testutils.TestableNetworkAgent
99 import com.android.testutils.TestableNetworkCallback
100 import com.android.testutils.assertEmpty
101 import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk30
102 import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk33
103 import com.android.testutils.pollForAdvertisement
104 import com.android.testutils.pollForMdnsPacket
105 import com.android.testutils.pollForProbe
106 import com.android.testutils.pollForQuery
107 import com.android.testutils.pollForReply
108 import com.android.testutils.runAsShell
109 import com.android.testutils.tryTest
110 import com.android.testutils.waitForIdle
111 import java.io.File
112 import java.io.IOException
113 import java.net.Inet6Address
114 import java.net.InetAddress
115 import java.net.NetworkInterface
116 import java.net.ServerSocket
117 import java.nio.ByteBuffer
118 import java.nio.charset.StandardCharsets
119 import java.util.Random
120 import java.util.concurrent.Executor
121 import kotlin.math.min
122 import kotlin.test.assertContentEquals
123 import kotlin.test.assertEquals
124 import kotlin.test.assertFailsWith
125 import kotlin.test.assertNotEquals
126 import kotlin.test.assertNotNull
127 import kotlin.test.assertNull
128 import kotlin.test.fail
129 import org.junit.After
130 import org.junit.Assert.assertArrayEquals
131 import org.junit.Assert.assertFalse
132 import org.junit.Assert.assertTrue
133 import org.junit.Assume.assumeTrue
134 import org.junit.Before
135 import org.junit.Rule
136 import org.junit.Test
137 import org.junit.runner.RunWith
138 
139 private const val TAG = "NsdManagerTest"
140 private const val TIMEOUT_MS = 2000L
141 
142 // Registration may take a long time if there are devices with the same hostname on the network,
143 // as the device needs to try another name and probe again. This is especially true since when using
144 // mdnsresponder the usual hostname is "Android", and on conflict "Android-2", "Android-3", ... are
145 // tried sequentially
146 private const val REGISTRATION_TIMEOUT_MS = 10_000L
147 private const val DBG = false
148 private const val TEST_PORT = 12345
149 private const val MDNS_PORT = 5353.toShort()
150 private const val TYPE_KEY = 25
151 private const val QCLASS_INTERNET = 0x0001
152 private const val NAME_RECORDS_TTL_MILLIS: Long = 120
153 private val multicastIpv6Addr = parseNumericAddress("ff02::fb") as Inet6Address
154 private val testSrcAddr = parseNumericAddress("2001:db8::123") as Inet6Address
155 
156 @AppModeFull(reason = "Socket cannot bind in instant app mode")
157 @RunWith(DevSdkIgnoreRunner::class)
158 @SmallTest
159 @ConnectivityModuleTest
160 @IgnoreUpTo(Build.VERSION_CODES.S_V2)
161 class NsdManagerTest {
162     // Rule used to filter CtsNetTestCasesMaxTargetSdkXX
163     @get:Rule
164     val ignoreRule = DevSdkIgnoreRule()
165 
166     @get:Rule
167     val deviceConfigRule = DeviceConfigRule()
168 
169     private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
170     private val nsdManager by lazy {
171         context.getSystemService(NsdManager::class.java) ?: fail("Could not get NsdManager service")
172     }
173 
174     private val cm by lazy { context.getSystemService(ConnectivityManager::class.java)!! }
175     private val serviceName = "NsdTest%09d".format(Random().nextInt(1_000_000_000))
176     private val serviceName2 = "NsdTest%09d".format(Random().nextInt(1_000_000_000))
177     private val serviceName3 = "NsdTest%09d".format(Random().nextInt(1_000_000_000))
178     private val serviceType = "_nmt%09d._tcp".format(Random().nextInt(1_000_000_000))
179     private val serviceType2 = "_nmt%09d._tcp".format(Random().nextInt(1_000_000_000))
180     private val customHostname = "NsdTestHost%09d".format(Random().nextInt(1_000_000_000))
181     private val customHostname2 = "NsdTestHost%09d".format(Random().nextInt(1_000_000_000))
182     private val publicKey = hexStringToByteArray(
183             "0201030dc141d0637960b98cbc12cfca" +
184                     "221d2879dac26ee5b460e9007c992e19" +
185                     "02d897c391b03764d448f7d0c772fdb0" +
186                     "3b1d9d6d52ff8886769e8e2362513565" +
187                     "270962d3"
188     )
189     private val handlerThread = HandlerThread(NsdManagerTest::class.java.simpleName)
190     private val ctsNetUtils by lazy{ CtsNetUtils(context) }
191 
192     private lateinit var testNetwork1: TestTapNetwork
193     private lateinit var testNetwork2: TestTapNetwork
194 
195     private class TestTapNetwork(
196         val iface: TestNetworkInterface,
197         val requestCb: NetworkCallback,
198         val agent: TestableNetworkAgent,
199         val network: Network
200     ) {
201         fun close(cm: ConnectivityManager) {
202             cm.unregisterNetworkCallback(requestCb)
203             agent.unregister()
204             iface.fileDescriptor.close()
205             agent.waitForIdle(TIMEOUT_MS)
206         }
207     }
208 
209     private class TestNsdOffloadEngine : OffloadEngine,
210         NsdRecord<TestNsdOffloadEngine.OffloadEvent>() {
211         sealed class OffloadEvent : NsdEvent {
212             data class AddOrUpdateEvent(val info: OffloadServiceInfo) : OffloadEvent()
213             data class RemoveEvent(val info: OffloadServiceInfo) : OffloadEvent()
214         }
215 
216         override fun onOffloadServiceUpdated(info: OffloadServiceInfo) {
217             add(OffloadEvent.AddOrUpdateEvent(info))
218         }
219 
220         override fun onOffloadServiceRemoved(info: OffloadServiceInfo) {
221             add(OffloadEvent.RemoveEvent(info))
222         }
223     }
224 
225     @Before
226     fun setUp() {
227         handlerThread.start()
228 
229         runAsShell(MANAGE_TEST_NETWORKS) {
230             testNetwork1 = createTestNetwork()
231             testNetwork2 = createTestNetwork()
232         }
233     }
234 
235     private fun createTestNetwork(): TestTapNetwork {
236         val tnm = context.getSystemService(TestNetworkManager::class.java)!!
237         val iface = tnm.createTapInterface()
238         val cb = TestableNetworkCallback()
239         cm.requestNetwork(
240             TestableNetworkAgent.makeNetworkRequestForInterface(iface.interfaceName),
241             cb
242         )
243         val agent = TestableNetworkAgent.createOnInterface(context, handlerThread.looper,
244             iface.interfaceName, TIMEOUT_MS)
245         val network = agent.network ?: fail("Registered agent should have a network")
246 
247         cb.eventuallyExpect<LinkPropertiesChanged>(TIMEOUT_MS) {
248             it.lp.linkAddresses.isNotEmpty()
249         }
250 
251         // The network has no INTERNET capability, so will be marked validated immediately
252         // It does not matter if validated capabilities come before/after the link addresses change
253         cb.eventuallyExpect<CapabilitiesChanged>(TIMEOUT_MS, from = 0) {
254             it.caps.hasCapability(NET_CAPABILITY_VALIDATED)
255         }
256         return TestTapNetwork(iface, cb, agent, network)
257     }
258 
259     private fun makeTestServiceInfo(network: Network? = null) = NsdServiceInfo().also {
260         it.serviceType = serviceType
261         it.serviceName = serviceName
262         it.network = network
263         it.port = TEST_PORT
264     }
265 
266     private fun makePacketReader(network: TestTapNetwork = testNetwork1) = PollPacketReader(
267             Handler(handlerThread.looper),
268             network.iface.fileDescriptor.fileDescriptor,
269             1500 /* maxPacketSize */
270     ).also {
271         it.startAsyncForTest()
272         handlerThread.waitForIdle(TIMEOUT_MS)
273     }
274 
275     @After
276     fun tearDown() {
277         runAsShell(MANAGE_TEST_NETWORKS) {
278             // Avoid throwing here if initializing failed in setUp
279             if (this::testNetwork1.isInitialized) testNetwork1.close(cm)
280             if (this::testNetwork2.isInitialized) testNetwork2.close(cm)
281         }
282         handlerThread.waitForIdle(TIMEOUT_MS)
283         handlerThread.quitSafely()
284         handlerThread.join()
285     }
286 
287     @Test
288     fun testNsdManager() {
289         val si = NsdServiceInfo()
290         si.serviceType = serviceType
291         si.serviceName = serviceName
292         // Test binary data with various bytes
293         val testByteArray = byteArrayOf(-128, 127, 2, 1, 0, 1, 2)
294         // Test string data with 256 characters (25 blocks of 10 characters + 6)
295         val string256 = "1_________2_________3_________4_________5_________6_________" +
296                 "7_________8_________9_________10________11________12________13________" +
297                 "14________15________16________17________18________19________20________" +
298                 "21________22________23________24________25________123456"
299 
300         // Illegal attributes
301         listOf(
302                 Triple(null, null, "null key"),
303                 Triple("", null, "empty key"),
304                 Triple(string256, null, "key with 256 characters"),
305                 Triple(
306                     "key",
307                     string256.substring(3),
308                         "key+value combination with more than 255 characters"
309                 ),
310                 Triple("key", string256.substring(4), "key+value combination with 255 characters"),
311                 Triple("\u0019", null, "key with invalid character"),
312                 Triple("=", null, "key with invalid character"),
313                 Triple("\u007f", null, "key with invalid character")
314         ).forEach {
315             assertFailsWith<IllegalArgumentException>(
316                     "Setting invalid ${it.third} unexpectedly succeeded"
317             ) {
318                 si.setAttribute(it.first, it.second)
319             }
320         }
321 
322         // Allowed attributes
323         si.setAttribute("booleanAttr", null as String?)
324         si.setAttribute("keyValueAttr", "value")
325         si.setAttribute("keyEqualsAttr", "=")
326         si.setAttribute(" whiteSpaceKeyValueAttr ", " value ")
327         si.setAttribute("binaryDataAttr", testByteArray)
328         si.setAttribute("nullBinaryDataAttr", null as ByteArray?)
329         si.setAttribute("emptyBinaryDataAttr", byteArrayOf())
330         si.setAttribute("longkey", string256.substring(9))
331         val socket = ServerSocket(0)
332         val localPort = socket.localPort
333         si.port = localPort
334         if (DBG) Log.d(TAG, "Port = $localPort")
335 
336         val registrationRecord = NsdRegistrationRecord()
337         // Test registering without an Executor
338         nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, registrationRecord)
339         val registeredInfo = registrationRecord.expectCallback<ServiceRegistered>(
340                 REGISTRATION_TIMEOUT_MS
341         ).serviceInfo
342 
343         // Only service name is included in ServiceRegistered callbacks
344         assertNull(registeredInfo.serviceType)
345         assertEquals(si.serviceName, registeredInfo.serviceName)
346 
347         val discoveryRecord = NsdDiscoveryRecord()
348         // Test discovering without an Executor
349         nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord)
350 
351         // Expect discovery started
352         discoveryRecord.expectCallback<DiscoveryStarted>()
353 
354         // Expect a service record to be discovered
355         val foundInfo = discoveryRecord.waitForServiceDiscovered(
356                 registeredInfo.serviceName,
357             serviceType
358         )
359 
360         // Test resolving without an Executor
361         val resolveRecord = NsdResolveRecord()
362         nsdManager.resolveService(foundInfo, resolveRecord)
363         val resolvedService = resolveRecord.expectCallback<ServiceResolved>().serviceInfo
364         assertEquals(".$serviceType", resolvedService.serviceType)
365         assertEquals(registeredInfo.serviceName, resolvedService.serviceName)
366 
367         // Check Txt attributes
368         assertEquals(8, resolvedService.attributes.size)
369         assertTrue(resolvedService.attributes.containsKey("booleanAttr"))
370         assertNull(resolvedService.attributes["booleanAttr"])
371         assertEquals("value", resolvedService.attributes["keyValueAttr"].utf8ToString())
372         assertEquals("=", resolvedService.attributes["keyEqualsAttr"].utf8ToString())
373         assertEquals(
374             " value ",
375                 resolvedService.attributes[" whiteSpaceKeyValueAttr "].utf8ToString()
376         )
377         assertEquals(string256.substring(9), resolvedService.attributes["longkey"].utf8ToString())
378         assertArrayEquals(testByteArray, resolvedService.attributes["binaryDataAttr"])
379         assertTrue(resolvedService.attributes.containsKey("nullBinaryDataAttr"))
380         assertNull(resolvedService.attributes["nullBinaryDataAttr"])
381         assertTrue(resolvedService.attributes.containsKey("emptyBinaryDataAttr"))
382         if (isAtLeastU() || CompatChanges.isChangeEnabled(
383                 ConnectivityCompatChanges.ENABLE_PLATFORM_MDNS_BACKEND
384             )) {
385             assertArrayEquals(byteArrayOf(), resolvedService.attributes["emptyBinaryDataAttr"])
386         } else {
387             assertNull(resolvedService.attributes["emptyBinaryDataAttr"])
388         }
389         assertEquals(localPort, resolvedService.port)
390 
391         // Unregister the service
392         nsdManager.unregisterService(registrationRecord)
393         registrationRecord.expectCallback<ServiceUnregistered>()
394 
395         // Expect a callback for service lost
396         val lostCb = discoveryRecord.expectCallbackEventually<ServiceLost> {
397             it.serviceInfo.serviceName == serviceName
398         }
399         // Lost service types have a dot at the end
400         assertEquals("$serviceType.", lostCb.serviceInfo.serviceType)
401 
402         // Register service again to see if NsdManager can discover it
403         val si2 = NsdServiceInfo()
404         si2.serviceType = serviceType
405         si2.serviceName = serviceName
406         si2.port = localPort
407         val registrationRecord2 = NsdRegistrationRecord()
408         nsdManager.registerService(si2, NsdManager.PROTOCOL_DNS_SD, registrationRecord2)
409         val registeredInfo2 = registrationRecord2.expectCallback<ServiceRegistered>(
410                 REGISTRATION_TIMEOUT_MS
411         ).serviceInfo
412 
413         // Expect a service record to be discovered (and filter the ones
414         // that are unrelated to this test)
415         val foundInfo2 = discoveryRecord.waitForServiceDiscovered(
416                 registeredInfo2.serviceName,
417             serviceType
418         )
419 
420         // Resolve the service
421         val resolveRecord2 = NsdResolveRecord()
422         nsdManager.resolveService(foundInfo2, resolveRecord2)
423         val resolvedService2 = resolveRecord2.expectCallback<ServiceResolved>().serviceInfo
424 
425         // Check that the resolved service doesn't have any TXT records
426         assertEquals(0, resolvedService2.attributes.size)
427 
428         nsdManager.stopServiceDiscovery(discoveryRecord)
429 
430         discoveryRecord.expectCallbackEventually<DiscoveryStopped>()
431 
432         nsdManager.unregisterService(registrationRecord2)
433         registrationRecord2.expectCallback<ServiceUnregistered>()
434     }
435 
436     @Test
437     fun testNsdManager_DiscoverOnNetwork() {
438         val si = makeTestServiceInfo()
439         val registrationRecord = NsdRegistrationRecord()
440         val registeredInfo = registerService(registrationRecord, si)
441 
442         tryTest {
443             val discoveryRecord = NsdDiscoveryRecord()
444             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
445                     testNetwork1.network, Executor { it.run() }, discoveryRecord)
446 
447             val foundInfo = discoveryRecord.waitForServiceDiscovered(
448                     serviceName, serviceType, testNetwork1.network)
449             assertEquals(testNetwork1.network, foundInfo.network)
450 
451             // Rewind to ensure the service is not found on the other interface
452             discoveryRecord.nextEvents.rewind(0)
453             assertNull(discoveryRecord.nextEvents.poll(timeoutMs = 100L) {
454                 it is ServiceFound &&
455                         it.serviceInfo.serviceName == registeredInfo.serviceName &&
456                         it.serviceInfo.network != testNetwork1.network
457             }, "The service should not be found on this network")
458         } cleanup {
459             nsdManager.unregisterService(registrationRecord)
460         }
461     }
462 
463     @Test
464     fun testNsdManager_DiscoverWithNetworkRequest() {
465         val si = makeTestServiceInfo()
466         val handler = Handler(handlerThread.looper)
467         val executor = Executor { handler.post(it) }
468 
469         val registrationRecord = NsdRegistrationRecord(expectedThreadId = handlerThread.threadId)
470         val registeredInfo1 = registerService(registrationRecord, si, executor)
471         val discoveryRecord = NsdDiscoveryRecord(expectedThreadId = handlerThread.threadId)
472 
473         tryTest {
474             val specifier = TestNetworkSpecifier(testNetwork1.iface.interfaceName)
475             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
476                     NetworkRequest.Builder()
477                             .removeCapability(NET_CAPABILITY_TRUSTED)
478                             .addTransportType(TRANSPORT_TEST)
479                             .setNetworkSpecifier(specifier)
480                             .build(),
481                     executor, discoveryRecord)
482 
483             val discoveryStarted = discoveryRecord.expectCallback<DiscoveryStarted>()
484             assertEquals(serviceType, discoveryStarted.serviceType)
485 
486             val serviceDiscovered = discoveryRecord.expectCallback<ServiceFound>()
487             assertEquals(registeredInfo1.serviceName, serviceDiscovered.serviceInfo.serviceName)
488             // Discovered service types have a dot at the end
489             assertEquals("$serviceType.", serviceDiscovered.serviceInfo.serviceType)
490             assertEquals(testNetwork1.network, serviceDiscovered.serviceInfo.network)
491 
492             // Unregister, then register the service back: it should be lost and found again
493             nsdManager.unregisterService(registrationRecord)
494             val serviceLost1 = discoveryRecord.expectCallback<ServiceLost>()
495             assertEquals(registeredInfo1.serviceName, serviceLost1.serviceInfo.serviceName)
496             assertEquals(testNetwork1.network, serviceLost1.serviceInfo.network)
497 
498             registrationRecord.expectCallback<ServiceUnregistered>()
499             val registeredInfo2 = registerService(registrationRecord, si, executor)
500             val serviceDiscovered2 = discoveryRecord.expectCallback<ServiceFound>()
501             assertEquals(registeredInfo2.serviceName, serviceDiscovered2.serviceInfo.serviceName)
502             assertEquals("$serviceType.", serviceDiscovered2.serviceInfo.serviceType)
503             assertEquals(testNetwork1.network, serviceDiscovered2.serviceInfo.network)
504 
505             // Teardown, then bring back up a network on the test interface: the service should
506             // go away, then come back
507             testNetwork1.agent.unregister()
508             val serviceLost = discoveryRecord.expectCallback<ServiceLost>()
509             assertEquals(registeredInfo2.serviceName, serviceLost.serviceInfo.serviceName)
510             assertEquals(testNetwork1.network, serviceLost.serviceInfo.network)
511 
512             val newAgent = runAsShell(MANAGE_TEST_NETWORKS) {
513                 TestableNetworkAgent.createOnInterface(context, handlerThread.looper,
514                     testNetwork1.iface.interfaceName,
515                     TIMEOUT_MS)
516             }
517             val newNetwork = newAgent.network ?: fail("Registered agent should have a network")
518             val serviceDiscovered3 = discoveryRecord.expectCallback<ServiceFound>()
519             assertEquals(registeredInfo2.serviceName, serviceDiscovered3.serviceInfo.serviceName)
520             assertEquals("$serviceType.", serviceDiscovered3.serviceInfo.serviceType)
521             assertEquals(newNetwork, serviceDiscovered3.serviceInfo.network)
522         } cleanupStep {
523             nsdManager.stopServiceDiscovery(discoveryRecord)
524             discoveryRecord.expectCallback<DiscoveryStopped>()
525         } cleanup {
526             nsdManager.unregisterService(registrationRecord)
527         }
528     }
529 
530     @Test
531     fun testNsdManager_DiscoverWithNetworkRequest_NoMatchingNetwork() {
532         val handler = Handler(handlerThread.looper)
533         val executor = Executor { handler.post(it) }
534 
535         val discoveryRecord = NsdDiscoveryRecord(expectedThreadId = handlerThread.threadId)
536         val specifier = TestNetworkSpecifier(testNetwork1.iface.interfaceName)
537 
538         tryTest {
539             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
540                     NetworkRequest.Builder()
541                             .removeCapability(NET_CAPABILITY_TRUSTED)
542                             .addTransportType(TRANSPORT_TEST)
543                             // Specified network does not have this capability
544                             .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)
545                             .setNetworkSpecifier(specifier)
546                             .build(),
547                     executor, discoveryRecord)
548             discoveryRecord.expectCallback<DiscoveryStarted>()
549         } cleanup {
550             nsdManager.stopServiceDiscovery(discoveryRecord)
551             discoveryRecord.expectCallback<DiscoveryStopped>()
552         }
553     }
554 
555     private fun checkAddressScopeId(iface: TestNetworkInterface, address: List<InetAddress>) {
556         val targetSdkVersion = context.packageManager
557             .getTargetSdkVersion(context.applicationInfo.packageName)
558         if (targetSdkVersion <= Build.VERSION_CODES.TIRAMISU) {
559             return
560         }
561         val ifaceIdx = NetworkInterface.getByName(iface.interfaceName).index
562         address.forEach {
563             if (it is Inet6Address && it.isLinkLocalAddress) {
564                 assertEquals(ifaceIdx, it.scopeId)
565             }
566         }
567     }
568 
569     @Test
570     fun testNsdManager_ResolveOnNetwork() {
571         val si = makeTestServiceInfo()
572         val registrationRecord = NsdRegistrationRecord()
573         val registeredInfo = registerService(registrationRecord, si)
574         tryTest {
575             val resolveRecord = NsdResolveRecord()
576 
577             val discoveryRecord = NsdDiscoveryRecord()
578             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord)
579 
580             val foundInfo1 = discoveryRecord.waitForServiceDiscovered(
581                     serviceName, serviceType, testNetwork1.network)
582             assertEquals(testNetwork1.network, foundInfo1.network)
583             // Rewind as the service could be found on each interface in any order
584             discoveryRecord.nextEvents.rewind(0)
585             val foundInfo2 = discoveryRecord.waitForServiceDiscovered(
586                     serviceName, serviceType, testNetwork2.network)
587             assertEquals(testNetwork2.network, foundInfo2.network)
588 
589             nsdManager.resolveService(foundInfo1, Executor { it.run() }, resolveRecord)
590             val cb = resolveRecord.expectCallback<ServiceResolved>()
591             cb.serviceInfo.let {
592                 // Resolved service type has leading dot
593                 assertEquals(".$serviceType", it.serviceType)
594                 assertEquals(registeredInfo.serviceName, it.serviceName)
595                 assertEquals(si.port, it.port)
596                 assertEquals(testNetwork1.network, it.network)
597                 checkAddressScopeId(testNetwork1.iface, it.hostAddresses)
598             }
599             // TODO: check that MDNS packets are sent only on testNetwork1.
600         } cleanupStep {
601             nsdManager.unregisterService(registrationRecord)
602         } cleanup {
603             registrationRecord.expectCallback<ServiceUnregistered>()
604         }
605     }
606 
607     @Test
608     fun testNsdManager_RegisterOnNetwork() {
609         val si = makeTestServiceInfo(testNetwork1.network)
610         // Register service on testNetwork1
611         val registrationRecord = NsdRegistrationRecord()
612         registerService(registrationRecord, si)
613         val discoveryRecord = NsdDiscoveryRecord()
614         val discoveryRecord2 = NsdDiscoveryRecord()
615         val discoveryRecord3 = NsdDiscoveryRecord()
616 
617         tryTest {
618             // Discover service on testNetwork1.
619             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
620                 testNetwork1.network, Executor { it.run() }, discoveryRecord)
621             // Expect that service is found on testNetwork1
622             val foundInfo = discoveryRecord.waitForServiceDiscovered(
623                 serviceName, serviceType, testNetwork1.network)
624             assertEquals(testNetwork1.network, foundInfo.network)
625 
626             // Discover service on testNetwork2.
627             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
628                 testNetwork2.network, Executor { it.run() }, discoveryRecord2)
629             // Expect that discovery is started then no other callbacks.
630             discoveryRecord2.expectCallback<DiscoveryStarted>()
631             discoveryRecord2.assertNoCallback()
632 
633             // Discover service on all networks (not specify any network).
634             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
635                 null as Network? /* network */, Executor { it.run() }, discoveryRecord3)
636             // Expect that service is found on testNetwork1
637             val foundInfo3 = discoveryRecord3.waitForServiceDiscovered(
638                     serviceName, serviceType, testNetwork1.network)
639             assertEquals(testNetwork1.network, foundInfo3.network)
640         } cleanupStep {
641             nsdManager.stopServiceDiscovery(discoveryRecord2)
642             discoveryRecord2.expectCallback<DiscoveryStopped>()
643         } cleanup {
644             nsdManager.unregisterService(registrationRecord)
645         }
646     }
647 
648     @Test
649     fun testNsdManager_RegisterServiceNameWithNonStandardCharacters() {
650         val serviceNames = "^Nsd.Test|Non-#AsCiI\\Characters&\\ufffe テスト 測試"
651         val si = NsdServiceInfo().apply {
652             serviceType = this@NsdManagerTest.serviceType
653             serviceName = serviceNames
654             port = 12345 // Test won't try to connect so port does not matter
655         }
656 
657         // Register the service name which contains non-standard characters.
658         val registrationRecord = NsdRegistrationRecord()
659         nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, registrationRecord)
660         registrationRecord.expectCallback<ServiceRegistered>(REGISTRATION_TIMEOUT_MS)
661 
662         tryTest {
663             // Discover that service name.
664             val discoveryRecord = NsdDiscoveryRecord()
665             nsdManager.discoverServices(
666                 serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord
667             )
668             val foundInfo = discoveryRecord.waitForServiceDiscovered(serviceNames, serviceType)
669 
670             // Expect that resolving the service name works properly even service name contains
671             // non-standard characters.
672             val resolveRecord = NsdResolveRecord()
673             nsdManager.resolveService(foundInfo, resolveRecord)
674             val resolvedCb = resolveRecord.expectCallback<ServiceResolved>()
675             assertEquals(foundInfo.serviceName, resolvedCb.serviceInfo.serviceName)
676         } cleanupStep {
677             nsdManager.unregisterService(registrationRecord)
678         } cleanup {
679             registrationRecord.expectCallback<ServiceUnregistered>()
680         }
681     }
682 
683     @Test
684     fun testRegisterService_twoServicesWithSameNameButDifferentTypes_registeredAndDiscoverable() {
685         val si1 = NsdServiceInfo().also {
686             it.network = testNetwork1.network
687             it.serviceName = serviceName
688             it.serviceType = serviceType
689             it.port = TEST_PORT
690         }
691         val si2 = NsdServiceInfo().also {
692             it.network = testNetwork1.network
693             it.serviceName = serviceName
694             it.serviceType = serviceType2
695             it.port = TEST_PORT + 1
696         }
697         val registrationRecord1 = NsdRegistrationRecord()
698         val registrationRecord2 = NsdRegistrationRecord()
699         val discoveryRecord1 = NsdDiscoveryRecord()
700         val discoveryRecord2 = NsdDiscoveryRecord()
701         tryTest {
702             registerService(registrationRecord1, si1)
703             registerService(registrationRecord2, si2)
704 
705             nsdManager.discoverServices(serviceType,
706                     NsdManager.PROTOCOL_DNS_SD,
707                     testNetwork1.network, Executor { it.run() }, discoveryRecord1)
708             nsdManager.discoverServices(serviceType2,
709                     NsdManager.PROTOCOL_DNS_SD,
710                     testNetwork1.network, Executor { it.run() }, discoveryRecord2)
711 
712             discoveryRecord1.waitForServiceDiscovered(serviceName, serviceType,
713                     testNetwork1.network)
714             discoveryRecord2.waitForServiceDiscovered(serviceName, serviceType2,
715                     testNetwork1.network)
716         } cleanupStep {
717             nsdManager.stopServiceDiscovery(discoveryRecord1)
718             nsdManager.stopServiceDiscovery(discoveryRecord2)
719         } cleanup {
720             nsdManager.unregisterService(registrationRecord1)
721             nsdManager.unregisterService(registrationRecord2)
722         }
723     }
724 
725     fun checkOffloadServiceInfo(serviceInfo: OffloadServiceInfo, si: NsdServiceInfo) {
726         val expectedServiceType = si.serviceType.split(",")[0]
727         assertEquals(si.serviceName, serviceInfo.key.serviceName)
728         assertEquals(expectedServiceType, serviceInfo.key.serviceType)
729         assertEquals(listOf("_subtype"), serviceInfo.subtypes)
730         assertTrue(serviceInfo.hostname.startsWith("Android_"))
731         assertTrue(serviceInfo.hostname.endsWith("local"))
732         // Test service types should not be in the priority list
733         assertEquals(Integer.MAX_VALUE, serviceInfo.priority)
734         assertEquals(OffloadEngine.OFFLOAD_TYPE_REPLY.toLong(), serviceInfo.offloadType)
735         val offloadPayload = serviceInfo.offloadPayload
736         assertNotNull(offloadPayload)
737         val dnsPacket = TestDnsPacket(offloadPayload, dstAddr = multicastIpv6Addr)
738         assertEquals(0x8400, dnsPacket.header.flags)
739         assertEquals(0, dnsPacket.records[DnsPacket.QDSECTION].size)
740         assertTrue(dnsPacket.records[DnsPacket.ANSECTION].size >= 5)
741         assertEquals(0, dnsPacket.records[DnsPacket.NSSECTION].size)
742         assertEquals(0, dnsPacket.records[DnsPacket.ARSECTION].size)
743 
744         val ptrRecord = dnsPacket.records[DnsPacket.ANSECTION][0]
745         assertEquals("$expectedServiceType.local", ptrRecord.dName)
746         assertEquals(0x0C /* PTR */, ptrRecord.nsType)
747         val ptrSubRecord = dnsPacket.records[DnsPacket.ANSECTION][1]
748         assertEquals("_subtype._sub.$expectedServiceType.local", ptrSubRecord.dName)
749         assertEquals(0x0C /* PTR */, ptrSubRecord.nsType)
750         val srvRecord = dnsPacket.records[DnsPacket.ANSECTION][2]
751         assertEquals("${si.serviceName}.$expectedServiceType.local", srvRecord.dName)
752         assertEquals(0x21 /* SRV */, srvRecord.nsType)
753         val txtRecord = dnsPacket.records[DnsPacket.ANSECTION][3]
754         assertEquals("${si.serviceName}.$expectedServiceType.local", txtRecord.dName)
755         assertEquals(0x10 /* TXT */, txtRecord.nsType)
756         val iface = NetworkInterface.getByName(testNetwork1.iface.interfaceName)
757         val allAddress = iface.inetAddresses.toList()
758         for (i in 4 until dnsPacket.records[DnsPacket.ANSECTION].size) {
759             val addressRecord = dnsPacket.records[DnsPacket.ANSECTION][i]
760             assertTrue(addressRecord.dName.startsWith("Android_"))
761             assertTrue(addressRecord.dName.endsWith("local"))
762             assertTrue(addressRecord.nsType in arrayOf(0x1C /* AAAA */, 0x01 /* A */))
763             val rData = addressRecord.rr
764             assertNotNull(rData)
765             val addr = InetAddress.getByAddress(rData)
766             assertTrue(addr in allAddress)
767         }
768     }
769 
770     @Test
771     fun testNsdManager_registerOffloadEngine() {
772         val targetSdkVersion = context.packageManager
773             .getTargetSdkVersion(context.applicationInfo.packageName)
774         // The offload callbacks are only supported with the new backend,
775         // enabled with target SDK U+.
776         assumeTrue(isAtLeastU() || targetSdkVersion > Build.VERSION_CODES.TIRAMISU)
777 
778         // TODO: also have a test that use an executor that runs in a different thread, and pass
779         // in the thread ID NsdServiceInfo to check it
780         val si1 = NsdServiceInfo()
781         si1.serviceType = "$serviceType,_subtype"
782         si1.serviceName = serviceName
783         si1.network = testNetwork1.network
784         si1.port = 23456
785         val record1 = NsdRegistrationRecord()
786 
787         val si2 = NsdServiceInfo()
788         si2.serviceType = "$serviceType,_subtype"
789         si2.serviceName = serviceName2
790         si2.network = testNetwork1.network
791         si2.port = 12345
792         val record2 = NsdRegistrationRecord()
793         val offloadEngine = TestNsdOffloadEngine()
794 
795         tryTest {
796             // Register service before the OffloadEngine is registered.
797             nsdManager.registerService(si1, NsdManager.PROTOCOL_DNS_SD, record1)
798             record1.expectCallback<ServiceRegistered>()
799             runAsShell(NETWORK_SETTINGS) {
800                 nsdManager.registerOffloadEngine(testNetwork1.iface.interfaceName,
801                     OffloadEngine.OFFLOAD_TYPE_REPLY.toLong(),
802                     OffloadEngine.OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK.toLong(),
803                     { it.run() }, offloadEngine)
804             }
805             val addOrUpdateEvent1 = offloadEngine
806                 .expectCallbackEventually<TestNsdOffloadEngine.OffloadEvent.AddOrUpdateEvent> {
807                     it.info.key.serviceName == si1.serviceName
808                 }
809             checkOffloadServiceInfo(addOrUpdateEvent1.info, si1)
810 
811             // Register service after OffloadEngine is registered.
812             nsdManager.registerService(si2, NsdManager.PROTOCOL_DNS_SD, record2)
813             record2.expectCallback<ServiceRegistered>()
814             val addOrUpdateEvent2 = offloadEngine
815                 .expectCallbackEventually<TestNsdOffloadEngine.OffloadEvent.AddOrUpdateEvent> {
816                     it.info.key.serviceName == si2.serviceName
817                 }
818             checkOffloadServiceInfo(addOrUpdateEvent2.info, si2)
819 
820             nsdManager.unregisterService(record2)
821             record2.expectCallback<ServiceUnregistered>()
822             val unregisterEvent = offloadEngine
823                 .expectCallbackEventually<TestNsdOffloadEngine.OffloadEvent.RemoveEvent> {
824                     it.info.key.serviceName == si2.serviceName
825                 }
826             checkOffloadServiceInfo(unregisterEvent.info, si2)
827         } cleanupStep {
828             runAsShell(NETWORK_SETTINGS) {
829                 nsdManager.unregisterOffloadEngine(offloadEngine)
830             }
831         } cleanup {
832             nsdManager.unregisterService(record1)
833             record1.expectCallback<ServiceUnregistered>()
834         }
835     }
836 
837     private fun checkConnectSocketToMdnsd(shouldFail: Boolean) {
838         val discoveryRecord = NsdDiscoveryRecord()
839         val localSocket = LocalSocket()
840         tryTest {
841             // Discover any service from NsdManager to enforce NsdService to start the mdnsd.
842             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord)
843             discoveryRecord.expectCallback<DiscoveryStarted>()
844 
845             // Checks the /dev/socket/mdnsd is created.
846             val socket = File("/dev/socket/mdnsd")
847             val doesSocketExist = PollingCheck.waitFor(
848                 TIMEOUT_MS,
849                 {
850                     socket.exists()
851                 },
852                 { doesSocketExist ->
853                     doesSocketExist
854                 },
855             )
856 
857             // If the socket is not created, then no need to check the access.
858             if (doesSocketExist) {
859                 // Create a LocalSocket and try to connect to mdnsd.
860                 assertFalse("LocalSocket is connected.", localSocket.isConnected)
861                 val address = LocalSocketAddress("mdnsd", LocalSocketAddress.Namespace.RESERVED)
862                 if (shouldFail) {
863                     assertFailsWith<IOException>("Expect fail but socket connected") {
864                         localSocket.connect(address)
865                     }
866                 } else {
867                     localSocket.connect(address)
868                     assertTrue("LocalSocket is not connected.", localSocket.isConnected)
869                 }
870             }
871         } cleanup {
872             localSocket.close()
873             nsdManager.stopServiceDiscovery(discoveryRecord)
874             discoveryRecord.expectCallback<DiscoveryStopped>()
875         }
876     }
877 
878     /**
879      * Starting from Android U, the access to the /dev/socket/mdnsd is blocked by the
880      * sepolicy(b/265364111).
881      */
882     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
883     @Test
884     fun testCannotConnectSocketToMdnsd() {
885         val targetSdkVersion = context.packageManager
886                 .getTargetSdkVersion(context.applicationInfo.packageName)
887         assumeTrue(targetSdkVersion > Build.VERSION_CODES.TIRAMISU)
888         val firstApiLevel = min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel())
889         // The sepolicy is implemented in the vendor image, so the access may not be blocked if
890         // the vendor image is not update to date.
891         assumeTrue(firstApiLevel > Build.VERSION_CODES.TIRAMISU)
892         checkConnectSocketToMdnsd(shouldFail = true)
893     }
894 
895     @Test @CtsNetTestCasesMaxTargetSdk33("mdnsd socket is accessible up to target SDK 33")
896     fun testCanConnectSocketToMdnsd() {
897         checkConnectSocketToMdnsd(shouldFail = false)
898     }
899 
900     // Native mdns powered by Netd is removed after U.
901     @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
902     @Test @CtsNetTestCasesMaxTargetSdk30("Socket is started with the service up to target SDK 30")
903     fun testManagerCreatesLegacySocket() {
904         nsdManager // Ensure the lazy-init member is initialized, so NsdManager is created
905         val socket = File("/dev/socket/mdnsd")
906         val timeout = System.currentTimeMillis() + TIMEOUT_MS
907         while (!socket.exists() && System.currentTimeMillis() < timeout) {
908             Thread.sleep(10)
909         }
910         assertTrue("$socket was not found after $TIMEOUT_MS ms", socket.exists())
911     }
912 
913     // The compat change is part of a connectivity module update that applies to T+
914     @ConnectivityModuleTest @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
915     @Test @CtsNetTestCasesMaxTargetSdk30("Socket is started with the service up to target SDK 30")
916     fun testManagerCreatesLegacySocket_CompatChange() {
917         // The socket may have been already created by some other app, or some other test, in which
918         // case this test cannot verify creation. At least verify that the compat change is
919         // disabled in a process with max SDK 30; unit tests already verify that start is requested
920         // when the compat change is disabled.
921         // Note that before T the compat constant had a different int value.
922         assertFalse(CompatChanges.isChangeEnabled(
923                 ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER
924         ))
925     }
926 
927     @Test
928     fun testStopServiceResolution() {
929         val si = makeTestServiceInfo()
930         val resolveRecord = NsdResolveRecord()
931         // Try to resolve an unknown service then stop it immediately.
932         // Expected ResolutionStopped callback.
933         nsdManager.resolveService(si, { it.run() }, resolveRecord)
934         nsdManager.stopServiceResolution(resolveRecord)
935         val stoppedCb = resolveRecord.expectCallback<ResolutionStopped>()
936         assertEquals(si.serviceName, stoppedCb.serviceInfo.serviceName)
937         assertEquals(si.serviceType, stoppedCb.serviceInfo.serviceType)
938     }
939 
940     @Test
941     fun testRegisterServiceInfoCallback() {
942         val lp = cm.getLinkProperties(testNetwork1.network)
943         assertNotNull(lp)
944         val addresses = lp.addresses
945         assertFalse(addresses.isEmpty())
946 
947         val si = makeTestServiceInfo(testNetwork1.network)
948 
949         // Register service on the network
950         val registrationRecord = NsdRegistrationRecord()
951         registerService(registrationRecord, si)
952 
953         val discoveryRecord = NsdDiscoveryRecord()
954         val cbRecord = NsdServiceInfoCallbackRecord()
955         tryTest {
956             // Discover service on the network.
957             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
958                     testNetwork1.network, Executor { it.run() }, discoveryRecord)
959             val foundInfo = discoveryRecord.waitForServiceDiscovered(
960                     serviceName, serviceType, testNetwork1.network)
961 
962             // Register service callback and check the addresses are the same as network addresses
963             nsdManager.registerServiceInfoCallback(foundInfo, { it.run() }, cbRecord)
964             val serviceInfoCb = cbRecord.expectCallback<ServiceUpdated>()
965             assertEquals(foundInfo.serviceName, serviceInfoCb.serviceInfo.serviceName)
966             val hostAddresses = serviceInfoCb.serviceInfo.hostAddresses
967             assertEquals(addresses.size, hostAddresses.size)
968             for (hostAddress in hostAddresses) {
969                 assertTrue(addresses.contains(hostAddress))
970             }
971             checkAddressScopeId(testNetwork1.iface, serviceInfoCb.serviceInfo.hostAddresses)
972         } cleanupStep {
973             nsdManager.unregisterService(registrationRecord)
974             registrationRecord.expectCallback<ServiceUnregistered>()
975             discoveryRecord.expectCallback<ServiceLost>()
976             cbRecord.expectCallback<ServiceUpdatedLost>()
977         } cleanupStep {
978             // Cancel subscription and check stop callback received.
979             nsdManager.unregisterServiceInfoCallback(cbRecord)
980             cbRecord.expectCallback<UnregisterCallbackSucceeded>()
981         } cleanup {
982             nsdManager.stopServiceDiscovery(discoveryRecord)
983             discoveryRecord.expectCallback<DiscoveryStopped>()
984         }
985     }
986 
987     @Test
988     fun testStopServiceResolutionFailedCallback() {
989         // It's not possible to make ResolutionListener#onStopResolutionFailed callback sending
990         // because it is only sent in very edge-case scenarios when the legacy implementation is
991         // used, and the legacy implementation is never used in the current AOSP builds. Considering
992         // that this callback isn't expected to be sent at all at the moment, and this is just an
993         // interface with no implementation. To verify this callback, just call
994         // onStopResolutionFailed on the record directly then verify it is received.
995         val resolveRecord = NsdResolveRecord()
996         resolveRecord.onStopResolutionFailed(
997                 NsdServiceInfo(),
998             NsdManager.FAILURE_OPERATION_NOT_RUNNING
999         )
1000         val failedCb = resolveRecord.expectCallback<StopResolutionFailed>()
1001         assertEquals(NsdManager.FAILURE_OPERATION_NOT_RUNNING, failedCb.errorCode)
1002     }
1003 
1004     @Test
1005     fun testSubtypeAdvertisingAndDiscovery() {
1006         val si = makeTestServiceInfo(network = testNetwork1.network)
1007         // Test "_type._tcp.local,_subtype" syntax with the registration
1008         si.serviceType = si.serviceType + ",_subtype"
1009 
1010         val registrationRecord = NsdRegistrationRecord()
1011 
1012         val baseTypeDiscoveryRecord = NsdDiscoveryRecord()
1013         val subtypeDiscoveryRecord = NsdDiscoveryRecord()
1014         val otherSubtypeDiscoveryRecord = NsdDiscoveryRecord()
1015         tryTest {
1016             registerService(registrationRecord, si)
1017 
1018             // Test "_subtype._type._tcp.local" syntax with discovery. Note this is not
1019             // "_subtype._sub._type._tcp.local".
1020             nsdManager.discoverServices(serviceType,
1021                     NsdManager.PROTOCOL_DNS_SD,
1022                     testNetwork1.network, Executor { it.run() }, baseTypeDiscoveryRecord)
1023             nsdManager.discoverServices("_othersubtype.$serviceType",
1024                     NsdManager.PROTOCOL_DNS_SD,
1025                     testNetwork1.network, Executor { it.run() }, otherSubtypeDiscoveryRecord)
1026             nsdManager.discoverServices("_subtype.$serviceType",
1027                     NsdManager.PROTOCOL_DNS_SD,
1028                     testNetwork1.network, Executor { it.run() }, subtypeDiscoveryRecord)
1029 
1030             subtypeDiscoveryRecord.waitForServiceDiscovered(
1031                     serviceName, serviceType, testNetwork1.network)
1032             baseTypeDiscoveryRecord.waitForServiceDiscovered(
1033                     serviceName, serviceType, testNetwork1.network)
1034             otherSubtypeDiscoveryRecord.expectCallback<DiscoveryStarted>()
1035             // The subtype callback was registered later but called, no need for an extra delay
1036             otherSubtypeDiscoveryRecord.assertNoCallback(timeoutMs = 0)
1037         } cleanupStep {
1038             nsdManager.stopServiceDiscovery(baseTypeDiscoveryRecord)
1039             nsdManager.stopServiceDiscovery(subtypeDiscoveryRecord)
1040             nsdManager.stopServiceDiscovery(otherSubtypeDiscoveryRecord)
1041 
1042             baseTypeDiscoveryRecord.expectCallback<DiscoveryStopped>()
1043             subtypeDiscoveryRecord.expectCallback<DiscoveryStopped>()
1044             otherSubtypeDiscoveryRecord.expectCallback<DiscoveryStopped>()
1045         } cleanup {
1046             nsdManager.unregisterService(registrationRecord)
1047         }
1048     }
1049 
1050     @Test
1051     fun testSubtypeAdvertisingAndDiscovery_withSetSubtypesApi() {
1052         runSubtypeAdvertisingAndDiscoveryTest(useLegacySpecifier = false)
1053     }
1054 
1055     @Test
1056     fun testSubtypeAdvertisingAndDiscovery_withSetSubtypesApiAndLegacySpecifier() {
1057         runSubtypeAdvertisingAndDiscoveryTest(useLegacySpecifier = true)
1058     }
1059 
1060     private fun runSubtypeAdvertisingAndDiscoveryTest(useLegacySpecifier: Boolean) {
1061         val si = makeTestServiceInfo(network = testNetwork1.network)
1062         if (useLegacySpecifier) {
1063             si.subtypes = setOf("_subtype1")
1064 
1065             // Test "_type._tcp.local,_subtype" syntax with the registration
1066             si.serviceType = si.serviceType + ",_subtype2"
1067         } else {
1068             si.subtypes = setOf("_subtype1", "_subtype2")
1069         }
1070 
1071         val registrationRecord = NsdRegistrationRecord()
1072 
1073         val baseTypeDiscoveryRecord = NsdDiscoveryRecord()
1074         val subtype1DiscoveryRecord = NsdDiscoveryRecord()
1075         val subtype2DiscoveryRecord = NsdDiscoveryRecord()
1076         val otherSubtypeDiscoveryRecord = NsdDiscoveryRecord()
1077         tryTest {
1078             registerService(registrationRecord, si)
1079 
1080             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
1081                     testNetwork1.network, Executor { it.run() }, baseTypeDiscoveryRecord)
1082 
1083             // Test "<subtype>._type._tcp.local" syntax with discovery. Note this is not
1084             // "<subtype>._sub._type._tcp.local".
1085             nsdManager.discoverServices("_othersubtype.$serviceType",
1086                     NsdManager.PROTOCOL_DNS_SD,
1087                     testNetwork1.network, Executor { it.run() }, otherSubtypeDiscoveryRecord)
1088             nsdManager.discoverServices("_subtype1.$serviceType",
1089                     NsdManager.PROTOCOL_DNS_SD,
1090                     testNetwork1.network, Executor { it.run() }, subtype1DiscoveryRecord)
1091 
1092             nsdManager.discoverServices(
1093                     DiscoveryRequest.Builder(serviceType).setSubtype("_subtype2")
1094                             .setNetwork(testNetwork1.network).build(),
1095                     Executor { it.run() }, subtype2DiscoveryRecord)
1096 
1097             val info1 = subtype1DiscoveryRecord.waitForServiceDiscovered(
1098                     serviceName, serviceType, testNetwork1.network)
1099             assertTrue(info1.subtypes.contains("_subtype1"))
1100             val info2 = subtype2DiscoveryRecord.waitForServiceDiscovered(
1101                     serviceName, serviceType, testNetwork1.network)
1102             assertTrue(info2.subtypes.contains("_subtype2"))
1103             baseTypeDiscoveryRecord.waitForServiceDiscovered(
1104                     serviceName, serviceType, testNetwork1.network)
1105             otherSubtypeDiscoveryRecord.expectCallback<DiscoveryStarted>()
1106             // The subtype callback was registered later but called, no need for an extra delay
1107             otherSubtypeDiscoveryRecord.assertNoCallback(timeoutMs = 0)
1108         } cleanupStep {
1109             nsdManager.stopServiceDiscovery(baseTypeDiscoveryRecord)
1110             nsdManager.stopServiceDiscovery(subtype1DiscoveryRecord)
1111             nsdManager.stopServiceDiscovery(subtype2DiscoveryRecord)
1112             nsdManager.stopServiceDiscovery(otherSubtypeDiscoveryRecord)
1113 
1114             baseTypeDiscoveryRecord.expectCallback<DiscoveryStopped>()
1115             subtype1DiscoveryRecord.expectCallback<DiscoveryStopped>()
1116             subtype2DiscoveryRecord.expectCallback<DiscoveryStopped>()
1117             otherSubtypeDiscoveryRecord.expectCallback<DiscoveryStopped>()
1118         } cleanup {
1119             nsdManager.unregisterService(registrationRecord)
1120         }
1121     }
1122 
1123     @Test
1124     fun testMultipleSubTypeAdvertisingAndDiscovery_withUpdate() {
1125         val si1 = makeTestServiceInfo(network = testNetwork1.network).apply {
1126             serviceType += ",_subtype1"
1127         }
1128         val si2 = makeTestServiceInfo(network = testNetwork1.network).apply {
1129             serviceType += ",_subtype2"
1130         }
1131         val registrationRecord = NsdRegistrationRecord()
1132         val subtype3DiscoveryRecord = NsdDiscoveryRecord()
1133         tryTest {
1134             registerService(registrationRecord, si1)
1135             updateService(registrationRecord, si2)
1136             nsdManager.discoverServices("_subtype2.$serviceType",
1137                     NsdManager.PROTOCOL_DNS_SD, testNetwork1.network,
1138                     { it.run() }, subtype3DiscoveryRecord)
1139             subtype3DiscoveryRecord.waitForServiceDiscovered(serviceName,
1140                     serviceType, testNetwork1.network)
1141         } cleanupStep {
1142             nsdManager.stopServiceDiscovery(subtype3DiscoveryRecord)
1143             subtype3DiscoveryRecord.expectCallback<DiscoveryStopped>()
1144         } cleanup {
1145             nsdManager.unregisterService(registrationRecord)
1146         }
1147     }
1148 
1149     @Test
1150     fun testSubtypeAdvertisingAndDiscovery_nonAlphanumericalSubtypes() {
1151         // All non-alphanumerical characters between 0x20 and 0x7e, with a leading underscore
1152         val nonAlphanumSubtype = "_ !\"#\$%&'()*+-/:;<=>?@[\\]^_`{|}"
1153         // Test both legacy syntax and the subtypes setter, on different networks
1154         val si1 = makeTestServiceInfo(network = testNetwork1.network).apply {
1155             serviceType = "$serviceType,_test1,$nonAlphanumSubtype"
1156         }
1157         val si2 = makeTestServiceInfo(network = testNetwork2.network).apply {
1158             subtypes = setOf("_test2", nonAlphanumSubtype)
1159         }
1160 
1161         val registrationRecord1 = NsdRegistrationRecord()
1162         val registrationRecord2 = NsdRegistrationRecord()
1163         val subtypeDiscoveryRecord1 = NsdDiscoveryRecord()
1164         val subtypeDiscoveryRecord2 = NsdDiscoveryRecord()
1165         tryTest {
1166             registerService(registrationRecord1, si1)
1167             registerService(registrationRecord2, si2)
1168             nsdManager.discoverServices(DiscoveryRequest.Builder(serviceType)
1169                 .setSubtype(nonAlphanumSubtype)
1170                 .setNetwork(testNetwork1.network)
1171                 .build(), { it.run() }, subtypeDiscoveryRecord1)
1172             nsdManager.discoverServices("$nonAlphanumSubtype.$serviceType",
1173                 NsdManager.PROTOCOL_DNS_SD, testNetwork2.network, { it.run() },
1174                 subtypeDiscoveryRecord2)
1175 
1176             val discoveredInfo1 = subtypeDiscoveryRecord1.waitForServiceDiscovered(serviceName,
1177                 serviceType, testNetwork1.network)
1178             val discoveredInfo2 = subtypeDiscoveryRecord2.waitForServiceDiscovered(serviceName,
1179                 serviceType, testNetwork2.network)
1180             assertTrue(discoveredInfo1.subtypes.contains(nonAlphanumSubtype))
1181             assertTrue(discoveredInfo2.subtypes.contains(nonAlphanumSubtype))
1182         } cleanupStep {
1183             nsdManager.stopServiceDiscovery(subtypeDiscoveryRecord1)
1184             subtypeDiscoveryRecord1.expectCallback<DiscoveryStopped>()
1185         } cleanupStep {
1186             nsdManager.stopServiceDiscovery(subtypeDiscoveryRecord2)
1187             subtypeDiscoveryRecord2.expectCallback<DiscoveryStopped>()
1188         } cleanup {
1189             nsdManager.unregisterService(registrationRecord1)
1190             nsdManager.unregisterService(registrationRecord2)
1191         }
1192     }
1193 
1194     @Test
1195     fun testSubtypeDiscovery_typeMatchButSubtypeNotMatch_notDiscovered() {
1196         val si1 = makeTestServiceInfo(network = testNetwork1.network).apply {
1197             serviceType += ",_subtype1"
1198         }
1199         val registrationRecord = NsdRegistrationRecord()
1200         val subtype2DiscoveryRecord = NsdDiscoveryRecord()
1201         tryTest {
1202             registerService(registrationRecord, si1)
1203             val request = DiscoveryRequest.Builder(serviceType)
1204                     .setSubtype("_subtype2").setNetwork(testNetwork1.network).build()
1205             nsdManager.discoverServices(request, { it.run() }, subtype2DiscoveryRecord)
1206             subtype2DiscoveryRecord.expectCallback<DiscoveryStarted>()
1207             subtype2DiscoveryRecord.assertNoCallback(timeoutMs = 2000)
1208         } cleanupStep {
1209             nsdManager.stopServiceDiscovery(subtype2DiscoveryRecord)
1210             subtype2DiscoveryRecord.expectCallback<DiscoveryStopped>()
1211         } cleanup {
1212             nsdManager.unregisterService(registrationRecord)
1213         }
1214     }
1215 
1216     @Test
1217     fun testSubtypeAdvertising_tooManySubtypes_returnsFailureBadParameters() {
1218         val si = makeTestServiceInfo(network = testNetwork1.network)
1219         // Sets 101 subtypes in total
1220         val seq = generateSequence(1) { it + 1}
1221         si.subtypes = seq.take(100).toList().map {it -> "_subtype" + it}.toSet()
1222         si.serviceType = si.serviceType + ",_subtype"
1223 
1224         val record = NsdRegistrationRecord()
1225         nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, Executor { it.run() }, record)
1226 
1227         val failedCb = record.expectCallback<RegistrationFailed>(REGISTRATION_TIMEOUT_MS)
1228         assertEquals(NsdManager.FAILURE_BAD_PARAMETERS, failedCb.errorCode)
1229     }
1230 
1231     @Test
1232     fun testSubtypeAdvertising_emptySubtypeLabel_returnsFailureBadParameters() {
1233         val si = makeTestServiceInfo(network = testNetwork1.network)
1234         si.subtypes = setOf("")
1235 
1236         val record = NsdRegistrationRecord()
1237         nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, Executor { it.run() }, record)
1238 
1239         val failedCb = record.expectCallback<RegistrationFailed>(REGISTRATION_TIMEOUT_MS)
1240         assertEquals(NsdManager.FAILURE_BAD_PARAMETERS, failedCb.errorCode)
1241     }
1242 
1243     @Test
1244     fun testRegisterWithConflictDuringProbing() {
1245         // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
1246         assumeTrue(TestUtils.shouldTestTApis())
1247 
1248         val si = makeTestServiceInfo(testNetwork1.network)
1249         val packetReader = makePacketReader()
1250 
1251         // Register service on testNetwork1
1252         val registrationRecord = NsdRegistrationRecord()
1253         nsdManager.registerService(
1254             si,
1255             NsdManager.PROTOCOL_DNS_SD,
1256             { it.run() },
1257                 registrationRecord
1258         )
1259 
1260         tryTest {
1261             assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
1262                     "Did not find a probe for the service")
1263             packetReader.sendResponse(buildConflictingAnnouncement())
1264 
1265             // Registration must use an updated name to avoid the conflict
1266             val cb = registrationRecord.expectCallback<ServiceRegistered>(REGISTRATION_TIMEOUT_MS)
1267             cb.serviceInfo.serviceName.let {
1268                 assertTrue("Unexpected registered name: $it",
1269                         it.startsWith(serviceName) && it != serviceName)
1270             }
1271         } cleanupStep {
1272             nsdManager.unregisterService(registrationRecord)
1273             registrationRecord.expectCallback<ServiceUnregistered>()
1274         } cleanup {
1275             packetReader.handler.post { packetReader.stop() }
1276             handlerThread.waitForIdle(TIMEOUT_MS)
1277         }
1278     }
1279 
1280     @Test
1281     fun testRegisterServiceWithCustomHostAndAddresses_conflictDuringProbing_hostRenamed() {
1282         val si = makeTestServiceInfo(testNetwork1.network).apply {
1283             hostname = customHostname
1284             hostAddresses = listOf(
1285                     parseNumericAddress("192.0.2.24"),
1286                     parseNumericAddress("2001:db8::3"))
1287         }
1288 
1289         val packetReader = makePacketReader()
1290 
1291         // Register service on testNetwork1
1292         val registrationRecord = NsdRegistrationRecord()
1293         nsdManager.registerService(
1294             si,
1295             NsdManager.PROTOCOL_DNS_SD,
1296             { it.run() },
1297                 registrationRecord
1298         )
1299 
1300         tryTest {
1301             assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
1302                     "Did not find a probe for the service")
1303             packetReader.sendResponse(buildConflictingAnnouncementForCustomHost())
1304 
1305             // Registration must use an updated hostname to avoid the conflict
1306             val cb = registrationRecord.expectCallback<ServiceRegistered>(REGISTRATION_TIMEOUT_MS)
1307             // Service name is not renamed because there's no conflict on the service name.
1308             assertEquals(serviceName, cb.serviceInfo.serviceName)
1309             val hostname = cb.serviceInfo.hostname ?: fail("Missing hostname")
1310             hostname.let {
1311                 assertTrue("Unexpected registered hostname: $it",
1312                         it.startsWith(customHostname) && it != customHostname)
1313             }
1314         } cleanupStep {
1315             nsdManager.unregisterService(registrationRecord)
1316             registrationRecord.expectCallback<ServiceUnregistered>()
1317         } cleanup {
1318             packetReader.handler.post { packetReader.stop() }
1319             handlerThread.waitForIdle(TIMEOUT_MS)
1320         }
1321     }
1322 
1323     @Test
1324     fun testRegisterServiceWithCustomHostNoAddresses_noConflictDuringProbing_notRenamed() {
1325         val si = makeTestServiceInfo(testNetwork1.network).apply {
1326             hostname = customHostname
1327         }
1328 
1329         val packetReader = makePacketReader()
1330 
1331         // Register service on testNetwork1
1332         val registrationRecord = NsdRegistrationRecord()
1333         nsdManager.registerService(
1334             si,
1335             NsdManager.PROTOCOL_DNS_SD,
1336             { it.run() },
1337                 registrationRecord
1338         )
1339 
1340         tryTest {
1341             assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
1342                     "Did not find a probe for the service")
1343             // Not a conflict because no record is registered for the hostname
1344             packetReader.sendResponse(buildConflictingAnnouncementForCustomHost())
1345 
1346             // Registration is not renamed because there's no conflict
1347             val cb = registrationRecord.expectCallback<ServiceRegistered>(REGISTRATION_TIMEOUT_MS)
1348             assertEquals(serviceName, cb.serviceInfo.serviceName)
1349             assertEquals(customHostname, cb.serviceInfo.hostname)
1350         } cleanupStep {
1351             nsdManager.unregisterService(registrationRecord)
1352             registrationRecord.expectCallback<ServiceUnregistered>()
1353         } cleanup {
1354             packetReader.handler.post { packetReader.stop() }
1355             handlerThread.waitForIdle(TIMEOUT_MS)
1356         }
1357     }
1358 
1359     @Test
1360     fun testRegisterWithConflictAfterProbing() {
1361         // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
1362         assumeTrue(TestUtils.shouldTestTApis())
1363 
1364         val si = makeTestServiceInfo(testNetwork1.network)
1365 
1366         // Register service on testNetwork1
1367         val registrationRecord = NsdRegistrationRecord()
1368         val discoveryRecord = NsdDiscoveryRecord()
1369         val registeredService = registerService(registrationRecord, si)
1370         val packetReader = makePacketReader()
1371 
1372         tryTest {
1373             assertNotNull(packetReader.pollForAdvertisement(serviceName, serviceType),
1374                     "No announcements sent after initial probing")
1375 
1376             assertEquals(si.serviceName, registeredService.serviceName)
1377 
1378             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
1379                 testNetwork1.network, { it.run() }, discoveryRecord)
1380             discoveryRecord.waitForServiceDiscovered(si.serviceName, serviceType)
1381 
1382             // Send a conflicting announcement
1383             val conflictingAnnouncement = buildConflictingAnnouncement()
1384             packetReader.sendResponse(conflictingAnnouncement)
1385 
1386             // Expect to see probes (RFC6762 9., service is reset to probing state)
1387             assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
1388                     "Probe not received within timeout after conflict")
1389 
1390             // Send the conflicting packet again to reply to the probe
1391             packetReader.sendResponse(conflictingAnnouncement)
1392 
1393             // Note the legacy mdnsresponder would send an exit announcement here (a 0-lifetime
1394             // advertisement just for the PTR record), but not the new advertiser. This probably
1395             // follows RFC 6762 8.4, saying that when a record rdata changed, "In the case of shared
1396             // records, a host MUST send a "goodbye" announcement with RR TTL zero [...] for the old
1397             // rdata, to cause it to be deleted from peer caches, before announcing the new rdata".
1398             //
1399             // This should be implemented by the new advertiser, but in the case of conflicts it is
1400             // not very valuable since an identical PTR record would be used by the conflicting
1401             // service (except for subtypes). In that case the exit announcement may be
1402             // counter-productive as it conflicts with announcements done by the conflicting
1403             // service.
1404 
1405             // Note that before sending the following ServiceRegistered callback for the renamed
1406             // service, the legacy mdnsresponder-based implementation would first send a
1407             // Service*Registered* callback for the original service name being *unregistered*; it
1408             // should have been a ServiceUnregistered callback instead (bug in NsdService
1409             // interpretation of the callback).
1410             val newRegistration = registrationRecord.expectCallbackEventually<ServiceRegistered>(
1411                     REGISTRATION_TIMEOUT_MS) {
1412                 it.serviceInfo.serviceName.startsWith(serviceName) &&
1413                         it.serviceInfo.serviceName != serviceName
1414             }
1415 
1416             discoveryRecord.expectCallbackEventually<ServiceFound> {
1417                 it.serviceInfo.serviceName == newRegistration.serviceInfo.serviceName
1418             }
1419         } cleanupStep {
1420             nsdManager.stopServiceDiscovery(discoveryRecord)
1421             discoveryRecord.expectCallback<DiscoveryStopped>()
1422         } cleanupStep {
1423             nsdManager.unregisterService(registrationRecord)
1424             registrationRecord.expectCallback<ServiceUnregistered>()
1425         } cleanup {
1426             packetReader.handler.post { packetReader.stop() }
1427             handlerThread.waitForIdle(TIMEOUT_MS)
1428         }
1429     }
1430 
1431     @Test
1432     fun testRegisterServiceWithCustomHostAndAddresses_conflictAfterProbing_hostRenamed() {
1433         val si = makeTestServiceInfo(testNetwork1.network).apply {
1434             hostname = customHostname
1435             hostAddresses = listOf(
1436                     parseNumericAddress("192.0.2.24"),
1437                     parseNumericAddress("2001:db8::3"))
1438         }
1439 
1440         // Register service on testNetwork1
1441         val registrationRecord = NsdRegistrationRecord()
1442         val discoveryRecord = NsdDiscoveryRecord()
1443         val registeredService = registerService(registrationRecord, si)
1444         val packetReader = makePacketReader()
1445 
1446         tryTest {
1447             assertNotNull(packetReader.pollForAdvertisement(serviceName, serviceType),
1448                 "No announcements sent after initial probing")
1449 
1450             assertEquals(si.serviceName, registeredService.serviceName)
1451             assertEquals(si.hostname, registeredService.hostname)
1452 
1453             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
1454                     testNetwork1.network, { it.run() }, discoveryRecord)
1455             val discoveredInfo = discoveryRecord.waitForServiceDiscovered(
1456                     si.serviceName, serviceType)
1457 
1458             // Send a conflicting announcement
1459             val conflictingAnnouncement = buildConflictingAnnouncementForCustomHost()
1460             packetReader.sendResponse(conflictingAnnouncement)
1461 
1462             // Expect to see probes (RFC6762 9., service is reset to probing state)
1463             assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
1464                     "Probe not received within timeout after conflict")
1465 
1466             // Send the conflicting packet again to reply to the probe
1467             packetReader.sendResponse(conflictingAnnouncement)
1468 
1469             val newRegistration =
1470                     registrationRecord
1471                             .expectCallbackEventually<ServiceRegistered>(REGISTRATION_TIMEOUT_MS) {
1472                                 it.serviceInfo.serviceName == serviceName &&
1473                                         it.serviceInfo.hostname.let { hostname ->
1474                                     hostname != null &&
1475                                             hostname.startsWith(customHostname) &&
1476                                             hostname != customHostname
1477                                 }
1478                             }
1479 
1480             val resolvedInfo = resolveService(discoveredInfo)
1481             assertEquals(newRegistration.serviceInfo.serviceName, resolvedInfo.serviceName)
1482             assertEquals(newRegistration.serviceInfo.hostname, resolvedInfo.hostname)
1483 
1484             discoveryRecord.assertNoCallback()
1485         } cleanupStep {
1486             nsdManager.stopServiceDiscovery(discoveryRecord)
1487             discoveryRecord.expectCallback<DiscoveryStopped>()
1488         } cleanupStep {
1489             nsdManager.unregisterService(registrationRecord)
1490             registrationRecord.expectCallback<ServiceUnregistered>()
1491         } cleanup {
1492             packetReader.handler.post { packetReader.stop() }
1493             handlerThread.waitForIdle(TIMEOUT_MS)
1494         }
1495     }
1496 
1497     @Test
1498     fun testRegisterServiceWithCustomHostNoAddresses_noConflictAfterProbing_notRenamed() {
1499         val si = makeTestServiceInfo(testNetwork1.network).apply {
1500             hostname = customHostname
1501         }
1502 
1503         // Register service on testNetwork1
1504         val registrationRecord = NsdRegistrationRecord()
1505         val discoveryRecord = NsdDiscoveryRecord()
1506         val registeredService = registerService(registrationRecord, si)
1507         val packetReader = makePacketReader()
1508 
1509         tryTest {
1510             assertNotNull(packetReader.pollForAdvertisement(serviceName, serviceType),
1511                     "No announcements sent after initial probing")
1512 
1513             assertEquals(si.serviceName, registeredService.serviceName)
1514             assertEquals(si.hostname, registeredService.hostname)
1515 
1516             // Send a conflicting announcement
1517             val conflictingAnnouncement = buildConflictingAnnouncementForCustomHost()
1518             packetReader.sendResponse(conflictingAnnouncement)
1519 
1520             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
1521                     testNetwork1.network, { it.run() }, discoveryRecord)
1522 
1523             // The service is not renamed
1524             discoveryRecord.waitForServiceDiscovered(si.serviceName, serviceType)
1525         } cleanupStep {
1526             nsdManager.stopServiceDiscovery(discoveryRecord)
1527             discoveryRecord.expectCallback<DiscoveryStopped>()
1528         } cleanupStep {
1529             nsdManager.unregisterService(registrationRecord)
1530             registrationRecord.expectCallback<ServiceUnregistered>()
1531         } cleanup {
1532             packetReader.handler.post { packetReader.stop() }
1533             handlerThread.waitForIdle(TIMEOUT_MS)
1534         }
1535     }
1536 
1537     // Test that even if only a PTR record is received as a reply when discovering, without the
1538     // SRV, TXT, address records as recommended (but not mandated) by RFC 6763 12, the service can
1539     // still be discovered.
1540     @Test
1541     fun testDiscoveryWithPtrOnlyResponse_ServiceIsFound() {
1542         // Register service on testNetwork1
1543         val discoveryRecord = NsdDiscoveryRecord()
1544         val packetReader = makePacketReader()
1545 
1546         nsdManager.discoverServices(
1547             serviceType,
1548             NsdManager.PROTOCOL_DNS_SD,
1549                 testNetwork1.network,
1550             { it.run() },
1551             discoveryRecord
1552         )
1553 
1554         tryTest {
1555             discoveryRecord.expectCallback<DiscoveryStarted>()
1556             assertNotNull(packetReader.pollForQuery("$serviceType.local", DnsResolver.TYPE_PTR))
1557             /*
1558             Generated with:
1559             scapy.raw(scapy.DNS(rd=0, qr=1, aa=1, qd = None, an =
1560                 scapy.DNSRR(rrname='_nmt123456789._tcp.local', type='PTR', ttl=120,
1561                 rdata='NsdTest123456789._nmt123456789._tcp.local'))).hex()
1562              */
1563             val ptrResponsePayload = HexDump.hexStringToByteArray("0000840000000001000000000d5f6e" +
1564                     "6d74313233343536373839045f746370056c6f63616c00000c000100000078002b104e736454" +
1565                     "6573743132333435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00")
1566 
1567             replaceServiceNameAndTypeWithTestSuffix(ptrResponsePayload)
1568             packetReader.sendResponse(buildMdnsPacket(ptrResponsePayload))
1569 
1570             val serviceFound = discoveryRecord.expectCallback<ServiceFound>()
1571             serviceFound.serviceInfo.let {
1572                 assertEquals(serviceName, it.serviceName)
1573                 // Discovered service types have a dot at the end
1574                 assertEquals("$serviceType.", it.serviceType)
1575                 assertEquals(testNetwork1.network, it.network)
1576                 // ServiceFound does not provide port, address or attributes (only information
1577                 // available in the PTR record is included in that callback, regardless of whether
1578                 // other records exist).
1579                 assertEquals(0, it.port)
1580                 assertEmpty(it.hostAddresses)
1581                 assertEquals(0, it.attributes.size)
1582             }
1583         } cleanupStep {
1584             nsdManager.stopServiceDiscovery(discoveryRecord)
1585             discoveryRecord.expectCallback<DiscoveryStopped>()
1586         } cleanup {
1587             packetReader.handler.post { packetReader.stop() }
1588             handlerThread.waitForIdle(TIMEOUT_MS)
1589         }
1590     }
1591 
1592     // Test RFC 6763 12. "Clients MUST be capable of functioning correctly with DNS servers [...]
1593     // that fail to generate these additional records automatically, by issuing subsequent queries
1594     // for any further record(s) they require"
1595     @Test
1596     fun testResolveWhenServerSendsNoAdditionalRecord() {
1597         // Resolve service on testNetwork1
1598         val resolveRecord = NsdResolveRecord()
1599         val packetReader = makePacketReader()
1600         val si = makeTestServiceInfo(testNetwork1.network)
1601         nsdManager.resolveService(si, { it.run() }, resolveRecord)
1602 
1603         tryTest {
1604             val serviceFullName = "$serviceName.$serviceType.local"
1605             // The query should ask for ANY, since both SRV and TXT are requested. Note legacy
1606             // mdnsresponder will ask for SRV and TXT separately, and will not proceed to asking for
1607             // address records without an answer for both.
1608             val srvTxtQuery = packetReader.pollForQuery(serviceFullName, DnsResolver.TYPE_ANY)
1609             assertNotNull(srvTxtQuery)
1610 
1611             /*
1612             Generated with:
1613             scapy.raw(scapy.dns_compress(scapy.DNS(rd=0, qr=1, aa=1, qd = None, an =
1614                 scapy.DNSRRSRV(rrname='NsdTest123456789._nmt123456789._tcp.local',
1615                     rclass=0x8001, port=31234, target='testhost.local', ttl=120) /
1616                 scapy.DNSRR(rrname='NsdTest123456789._nmt123456789._tcp.local', type='TXT', ttl=120,
1617                     rdata='testkey=testvalue')
1618             ))).hex()
1619              */
1620             val srvTxtResponsePayload = HexDump.hexStringToByteArray(
1621                     "000084000000000200000000104" +
1622                             "e7364546573743132333435363738390d5f6e6d74313233343536373839045f7463" +
1623                             "70056c6f63616c0000218001000000780011000000007a020874657374686f7374c" +
1624                             "030c00c0010000100000078001211746573746b65793d7465737476616c7565"
1625             )
1626             replaceServiceNameAndTypeWithTestSuffix(srvTxtResponsePayload)
1627             packetReader.sendResponse(buildMdnsPacket(srvTxtResponsePayload))
1628 
1629             val testHostname = "testhost.local"
1630             val addressQuery = packetReader.pollForQuery(
1631                     testHostname,
1632                     DnsResolver.TYPE_A,
1633                     DnsResolver.TYPE_AAAA
1634             )
1635             assertNotNull(addressQuery)
1636 
1637             /*
1638             Generated with:
1639             scapy.raw(scapy.dns_compress(scapy.DNS(rd=0, qr=1, aa=1, qd = None, an =
1640                 scapy.DNSRR(rrname='testhost.local', type='A', ttl=120,
1641                     rdata='192.0.2.123') /
1642                 scapy.DNSRR(rrname='testhost.local', type='AAAA', ttl=120,
1643                     rdata='2001:db8::123')
1644             ))).hex()
1645              */
1646             val addressPayload = HexDump.hexStringToByteArray(
1647                     "0000840000000002000000000874657374" +
1648                             "686f7374056c6f63616c0000010001000000780004c000027bc00c001c000100000" +
1649                             "078001020010db8000000000000000000000123"
1650             )
1651             packetReader.sendResponse(buildMdnsPacket(addressPayload))
1652 
1653             val serviceResolved = resolveRecord.expectCallback<ServiceResolved>()
1654             serviceResolved.serviceInfo.let {
1655                 assertEquals(serviceName, it.serviceName)
1656                 assertEquals(".$serviceType", it.serviceType)
1657                 assertEquals(testNetwork1.network, it.network)
1658                 assertEquals(31234, it.port)
1659                 assertEquals(1, it.attributes.size)
1660                 assertArrayEquals("testvalue".encodeToByteArray(), it.attributes["testkey"])
1661             }
1662             assertEquals(
1663                     setOf(parseNumericAddress("192.0.2.123"), parseNumericAddress("2001:db8::123")),
1664                     serviceResolved.serviceInfo.hostAddresses.toSet()
1665             )
1666         } cleanup {
1667             packetReader.handler.post { packetReader.stop() }
1668             handlerThread.waitForIdle(TIMEOUT_MS)
1669         }
1670     }
1671 
1672     @Test
1673     fun testUnicastReplyUsedWhenQueryUnicastFlagSet() {
1674         // The flag may be removed in the future but unicast replies should be enabled by default
1675         // in that case. The rule will reset flags automatically on teardown.
1676         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_unicast_reply_enabled", "1")
1677 
1678         val si = makeTestServiceInfo(testNetwork1.network)
1679 
1680         // Register service on testNetwork1
1681         val registrationRecord = NsdRegistrationRecord()
1682         var nsResponder: NSResponder? = null
1683         val packetReader = makePacketReader()
1684         tryTest {
1685             registerService(registrationRecord, si)
1686             /*
1687             Send a "query unicast" query.
1688             Generated with:
1689             scapy.raw(scapy.DNS(rd=0, qr=0, aa=0, qd =
1690                     scapy.DNSQR(qname='_nmt123456789._tcp.local', qtype='PTR', qclass=0x8001)
1691             )).hex()
1692              */
1693             val mdnsPayload = HexDump.hexStringToByteArray("0000000000010000000000000d5f6e6d74313" +
1694                     "233343536373839045f746370056c6f63616c00000c8001")
1695             replaceServiceNameAndTypeWithTestSuffix(mdnsPayload)
1696 
1697             val testSrcAddr = makeLinkLocalAddressOfOtherDeviceOnPrefix(testNetwork1.network)
1698             nsResponder = NSResponder(packetReader, mapOf(
1699                 testSrcAddr to MacAddress.fromString("01:02:03:04:05:06")
1700             )).apply { start() }
1701 
1702             packetReader.sendResponse(buildMdnsPacket(mdnsPayload, testSrcAddr))
1703             // The reply is sent unicast to the source address. There may be announcements sent
1704             // multicast around this time, so filter by destination address.
1705             val reply = packetReader.pollForMdnsPacket { pkt ->
1706                 pkt.isReplyFor("$serviceType.local", DnsResolver.TYPE_PTR) &&
1707                         pkt.dstAddr == testSrcAddr
1708             }
1709             assertNotNull(reply)
1710         } cleanupStep {
1711             nsResponder?.stop()
1712             nsdManager.unregisterService(registrationRecord)
1713             registrationRecord.expectCallback<ServiceUnregistered>()
1714         } cleanup {
1715             packetReader.handler.post { packetReader.stop() }
1716             handlerThread.waitForIdle(TIMEOUT_MS)
1717         }
1718     }
1719 
1720     @Test
1721     fun testReplyWhenKnownAnswerSuppressionFlagSet() {
1722         // The flag may be removed in the future but known-answer suppression should be enabled by
1723         // default in that case. The rule will reset flags automatically on teardown.
1724         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_known_answer_suppression", "1")
1725         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_unicast_reply_enabled", "1")
1726 
1727         val si = makeTestServiceInfo(testNetwork1.network)
1728 
1729         // Register service on testNetwork1
1730         val registrationRecord = NsdRegistrationRecord()
1731         var nsResponder: NSResponder? = null
1732         val packetReader = makePacketReader()
1733         tryTest {
1734             registerService(registrationRecord, si)
1735             /*
1736             Send a query with a known answer. Expect to receive a response containing TXT record
1737             only.
1738             Generated with:
1739             scapy.raw(scapy.DNS(rd=0, qr=0, aa=0, qd =
1740                     scapy.DNSQR(qname='_nmt123456789._tcp.local', qtype='PTR',
1741                             qclass=0x8001) /
1742                     scapy.DNSQR(qname='NsdTest123456789._nmt123456789._tcp.local', qtype='TXT',
1743                             qclass=0x8001),
1744                     an = scapy.DNSRR(rrname='_nmt123456789._tcp.local', type='PTR', ttl=4500,
1745                             rdata='NsdTest123456789._nmt123456789._tcp.local')
1746             )).hex()
1747              */
1748             val query = HexDump.hexStringToByteArray("0000000000020001000000000d5f6e6d74313233343" +
1749                     "536373839045f746370056c6f63616c00000c8001104e7364546573743132333435363738390" +
1750                     "d5f6e6d74313233343536373839045f746370056c6f63616c00001080010d5f6e6d743132333" +
1751                     "43536373839045f746370056c6f63616c00000c000100001194002b104e73645465737431323" +
1752                     "33435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00")
1753             replaceServiceNameAndTypeWithTestSuffix(query)
1754 
1755             val testSrcAddr = makeLinkLocalAddressOfOtherDeviceOnPrefix(testNetwork1.network)
1756             nsResponder = NSResponder(packetReader, mapOf(
1757                     testSrcAddr to MacAddress.fromString("01:02:03:04:05:06")
1758             )).apply { start() }
1759 
1760             packetReader.sendResponse(buildMdnsPacket(query, testSrcAddr))
1761             // The reply is sent unicast to the source address. There may be announcements sent
1762             // multicast around this time, so filter by destination address.
1763             val reply = packetReader.pollForMdnsPacket { pkt ->
1764                 pkt.isReplyFor("$serviceName.$serviceType.local", DnsResolver.TYPE_TXT) &&
1765                         !pkt.isReplyFor("$serviceType.local", DnsResolver.TYPE_PTR) &&
1766                         pkt.dstAddr == testSrcAddr
1767             }
1768             assertNotNull(reply)
1769 
1770             /*
1771             Send a query with a known answer (TTL is less than half). Expect to receive a response
1772             containing both PTR and TXT records.
1773             Generated with:
1774             scapy.raw(scapy.DNS(rd=0, qr=0, aa=0, qd =
1775                     scapy.DNSQR(qname='_nmt123456789._tcp.local', qtype='PTR',
1776                             qclass=0x8001) /
1777                     scapy.DNSQR(qname='NsdTest123456789._nmt123456789._tcp.local', qtype='TXT',
1778                             qclass=0x8001),
1779                     an = scapy.DNSRR(rrname='_nmt123456789._tcp.local', type='PTR', ttl=2150,
1780                             rdata='NsdTest123456789._nmt123456789._tcp.local')
1781             )).hex()
1782              */
1783             val query2 = HexDump.hexStringToByteArray("0000000000020001000000000d5f6e6d7431323334" +
1784                     "3536373839045f746370056c6f63616c00000c8001104e736454657374313233343536373839" +
1785                     "0d5f6e6d74313233343536373839045f746370056c6f63616c00001080010d5f6e6d74313233" +
1786                     "343536373839045f746370056c6f63616c00000c000100000866002b104e7364546573743132" +
1787                     "333435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00")
1788             replaceServiceNameAndTypeWithTestSuffix(query2)
1789 
1790             packetReader.sendResponse(buildMdnsPacket(query2, testSrcAddr))
1791             // The reply is sent unicast to the source address. There may be announcements sent
1792             // multicast around this time, so filter by destination address.
1793             val reply2 = packetReader.pollForMdnsPacket { pkt ->
1794                 pkt.isReplyFor("$serviceName.$serviceType.local", DnsResolver.TYPE_TXT) &&
1795                         pkt.isReplyFor("$serviceType.local", DnsResolver.TYPE_PTR) &&
1796                         pkt.dstAddr == testSrcAddr
1797             }
1798             assertNotNull(reply2)
1799         } cleanupStep {
1800             nsResponder?.stop()
1801             nsdManager.unregisterService(registrationRecord)
1802             registrationRecord.expectCallback<ServiceUnregistered>()
1803         } cleanup {
1804             packetReader.handler.post { packetReader.stop() }
1805             handlerThread.waitForIdle(TIMEOUT_MS)
1806         }
1807     }
1808 
1809     @Test
1810     fun testReplyWithMultipacketWhenKnownAnswerSuppressionFlagSet() {
1811         // The flag may be removed in the future but known-answer suppression should be enabled by
1812         // default in that case. The rule will reset flags automatically on teardown.
1813         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_known_answer_suppression", "1")
1814         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_unicast_reply_enabled", "1")
1815 
1816         val si = makeTestServiceInfo(testNetwork1.network)
1817 
1818         // Register service on testNetwork1
1819         val registrationRecord = NsdRegistrationRecord()
1820         var nsResponder: NSResponder? = null
1821         val packetReader = makePacketReader()
1822         tryTest {
1823             registerService(registrationRecord, si)
1824             /*
1825             Send a query with truncated bit set.
1826             Generated with:
1827             scapy.raw(scapy.DNS(rd=0, qr=0, aa=0, tc=1, qd=
1828                     scapy.DNSQR(qname='_nmt123456789._tcp.local', qtype='PTR',
1829                             qclass=0x8001) /
1830                     scapy.DNSQR(qname='NsdTest123456789._nmt123456789._tcp.local', qtype='TXT',
1831                             qclass=0x8001)
1832             )).hex()
1833              */
1834             val query = HexDump.hexStringToByteArray("0000020000020000000000000d5f6e6d74313233343" +
1835                     "536373839045f746370056c6f63616c00000c8001104e7364546573743132333435363738390" +
1836                     "d5f6e6d74313233343536373839045f746370056c6f63616c0000108001")
1837             replaceServiceNameAndTypeWithTestSuffix(query)
1838             /*
1839             Send a known answer packet (other service) with truncated bit set.
1840             Generated with:
1841             scapy.raw(scapy.DNS(rd=0, qr=0, aa=0, tc=1, qd=None,
1842                     an = scapy.DNSRR(rrname='_test._tcp.local', type='PTR', ttl=4500,
1843                             rdata='NsdTest._test._tcp.local')
1844             )).hex()
1845              */
1846             val knownAnswer1 = HexDump.hexStringToByteArray("000002000000000100000000055f74657374" +
1847                     "045f746370056c6f63616c00000c000100001194001a074e736454657374055f74657374045f" +
1848                     "746370056c6f63616c00")
1849             replaceServiceNameAndTypeWithTestSuffix(knownAnswer1)
1850             /*
1851             Send a known answer packet.
1852             Generated with:
1853             scapy.raw(scapy.DNS(rd=0, qr=0, aa=0, qd=None,
1854                     an = scapy.DNSRR(rrname='_nmt123456789._tcp.local', type='PTR', ttl=4500,
1855                             rdata='NsdTest123456789._nmt123456789._tcp.local')
1856             )).hex()
1857              */
1858             val knownAnswer2 = HexDump.hexStringToByteArray("0000000000000001000000000d5f6e6d7431" +
1859                     "3233343536373839045f746370056c6f63616c00000c000100001194002b104e736454657374" +
1860                     "3132333435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00")
1861             replaceServiceNameAndTypeWithTestSuffix(knownAnswer2)
1862 
1863             val testSrcAddr = makeLinkLocalAddressOfOtherDeviceOnPrefix(testNetwork1.network)
1864             nsResponder = NSResponder(packetReader, mapOf(
1865                     testSrcAddr to MacAddress.fromString("01:02:03:04:05:06")
1866             )).apply { start() }
1867 
1868             packetReader.sendResponse(buildMdnsPacket(query, testSrcAddr))
1869             packetReader.sendResponse(buildMdnsPacket(knownAnswer1, testSrcAddr))
1870             packetReader.sendResponse(buildMdnsPacket(knownAnswer2, testSrcAddr))
1871             // The reply is sent unicast to the source address. There may be announcements sent
1872             // multicast around this time, so filter by destination address.
1873             val reply = packetReader.pollForMdnsPacket { pkt ->
1874                 pkt.isReplyFor("$serviceName.$serviceType.local", DnsResolver.TYPE_TXT) &&
1875                         !pkt.isReplyFor("$serviceType.local", DnsResolver.TYPE_PTR) &&
1876                         pkt.dstAddr == testSrcAddr
1877             }
1878             assertNotNull(reply)
1879         } cleanupStep {
1880             nsResponder?.stop()
1881             nsdManager.unregisterService(registrationRecord)
1882             registrationRecord.expectCallback<ServiceUnregistered>()
1883         } cleanup {
1884             packetReader.handler.post { packetReader.stop() }
1885             handlerThread.waitForIdle(TIMEOUT_MS)
1886         }
1887     }
1888 
1889     @Test
1890     fun testQueryWhenKnownAnswerSuppressionFlagSet() {
1891         // The flag may be removed in the future but known-answer suppression should be enabled by
1892         // default in that case. The rule will reset flags automatically on teardown.
1893         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_query_with_known_answer", "1")
1894 
1895         // Register service on testNetwork1
1896         val discoveryRecord = NsdDiscoveryRecord()
1897         val packetReader = makePacketReader()
1898 
1899         nsdManager.discoverServices(
1900             serviceType,
1901             NsdManager.PROTOCOL_DNS_SD,
1902                 testNetwork1.network,
1903             { it.run() },
1904             discoveryRecord
1905         )
1906 
1907         tryTest {
1908             discoveryRecord.expectCallback<DiscoveryStarted>()
1909             assertNotNull(packetReader.pollForQuery("$serviceType.local", DnsResolver.TYPE_PTR))
1910             /*
1911             Generated with:
1912             scapy.raw(scapy.DNS(rd=0, qr=1, aa=1, qd = None, an =
1913                 scapy.DNSRR(rrname='_nmt123456789._tcp.local', type='PTR', ttl=120,
1914                 rdata='NsdTest123456789._nmt123456789._tcp.local'))).hex()
1915              */
1916             val ptrResponsePayload = HexDump.hexStringToByteArray("0000840000000001000000000d5f6e" +
1917                     "6d74313233343536373839045f746370056c6f63616c00000c000100000078002b104e736454" +
1918                     "6573743132333435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00")
1919 
1920             replaceServiceNameAndTypeWithTestSuffix(ptrResponsePayload)
1921             packetReader.sendResponse(buildMdnsPacket(ptrResponsePayload))
1922 
1923             val serviceFound = discoveryRecord.expectCallback<ServiceFound>()
1924             serviceFound.serviceInfo.let {
1925                 assertEquals(serviceName, it.serviceName)
1926                 // Discovered service types have a dot at the end
1927                 assertEquals("$serviceType.", it.serviceType)
1928                 assertEquals(testNetwork1.network, it.network)
1929                 // ServiceFound does not provide port, address or attributes (only information
1930                 // available in the PTR record is included in that callback, regardless of whether
1931                 // other records exist).
1932                 assertEquals(0, it.port)
1933                 assertEmpty(it.hostAddresses)
1934                 assertEquals(0, it.attributes.size)
1935             }
1936 
1937             // Expect the second query with a known answer
1938             val query = packetReader.pollForMdnsPacket { pkt ->
1939                 pkt.isQueryFor("$serviceType.local", DnsResolver.TYPE_PTR) &&
1940                         pkt.isReplyFor("$serviceType.local", DnsResolver.TYPE_PTR)
1941             }
1942             assertNotNull(query)
1943         } cleanupStep {
1944             nsdManager.stopServiceDiscovery(discoveryRecord)
1945             discoveryRecord.expectCallback<DiscoveryStopped>()
1946         } cleanup {
1947             packetReader.handler.post { packetReader.stop() }
1948             handlerThread.waitForIdle(TIMEOUT_MS)
1949         }
1950     }
1951 
1952     private fun makeLinkLocalAddressOfOtherDeviceOnPrefix(network: Network): Inet6Address {
1953         val lp = cm.getLinkProperties(network) ?: fail("No LinkProperties for net $network")
1954         // Expect to have a /64 link-local address
1955         val linkAddr = lp.linkAddresses.firstOrNull {
1956             it.isIPv6 && it.scope == RT_SCOPE_LINK && it.prefixLength == 64
1957         } ?: fail("No /64 link-local address found in ${lp.linkAddresses} for net $network")
1958 
1959         // Add one to the device address to simulate the address of another device on the prefix
1960         val addrBytes = linkAddr.address.address
1961         addrBytes[IPV6_ADDR_LEN - 1]++
1962         return Inet6Address.getByAddress(addrBytes) as Inet6Address
1963     }
1964 
1965     @Test
1966     fun testAdvertisingAndDiscovery_servicesWithCustomHost_customHostAddressesFound() {
1967         val hostAddresses1 = listOf(
1968                 parseNumericAddress("192.0.2.23"),
1969                 parseNumericAddress("2001:db8::1"),
1970                 parseNumericAddress("2001:db8::2")
1971         )
1972         val hostAddresses2 = listOf(
1973                 parseNumericAddress("192.0.2.24"),
1974                 parseNumericAddress("2001:db8::3")
1975         )
1976         val si1 = NsdServiceInfo().also {
1977             it.network = testNetwork1.network
1978             it.serviceName = serviceName
1979             it.serviceType = serviceType
1980             it.port = TEST_PORT
1981             it.hostname = customHostname
1982             it.hostAddresses = hostAddresses1
1983         }
1984         val si2 = NsdServiceInfo().also {
1985             it.network = testNetwork1.network
1986             it.serviceName = serviceName2
1987             it.serviceType = serviceType
1988             it.port = TEST_PORT + 1
1989             it.hostname = customHostname2
1990             it.hostAddresses = hostAddresses2
1991         }
1992         val registrationRecord1 = NsdRegistrationRecord()
1993         val registrationRecord2 = NsdRegistrationRecord()
1994 
1995         val discoveryRecord1 = NsdDiscoveryRecord()
1996         val discoveryRecord2 = NsdDiscoveryRecord()
1997         tryTest {
1998             registerService(registrationRecord1, si1)
1999 
2000             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
2001                     testNetwork1.network, Executor { it.run() }, discoveryRecord1)
2002 
2003             val discoveredInfo = discoveryRecord1.waitForServiceDiscovered(
2004                     serviceName, serviceType, testNetwork1.network)
2005             val resolvedInfo = resolveService(discoveredInfo)
2006 
2007             assertEquals(TEST_PORT, resolvedInfo.port)
2008             assertEquals(si1.hostname, resolvedInfo.hostname)
2009             assertAddressEquals(hostAddresses1, resolvedInfo.hostAddresses)
2010 
2011             registerService(registrationRecord2, si2)
2012             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
2013                     testNetwork1.network, Executor { it.run() }, discoveryRecord2)
2014 
2015             val discoveredInfo2 = discoveryRecord2.waitForServiceDiscovered(
2016                     serviceName2, serviceType, testNetwork1.network)
2017             val resolvedInfo2 = resolveService(discoveredInfo2)
2018 
2019             assertEquals(TEST_PORT + 1, resolvedInfo2.port)
2020             assertEquals(si2.hostname, resolvedInfo2.hostname)
2021             assertAddressEquals(hostAddresses2, resolvedInfo2.hostAddresses)
2022         } cleanupStep {
2023             nsdManager.stopServiceDiscovery(discoveryRecord1)
2024             nsdManager.stopServiceDiscovery(discoveryRecord2)
2025 
2026             discoveryRecord1.expectCallbackEventually<DiscoveryStopped>()
2027             discoveryRecord2.expectCallbackEventually<DiscoveryStopped>()
2028         } cleanup {
2029             nsdManager.unregisterService(registrationRecord1)
2030             nsdManager.unregisterService(registrationRecord2)
2031         }
2032     }
2033 
2034     @Test
2035     fun testAdvertisingAndDiscovery_multipleRegistrationsForSameCustomHost_hostRenamed() {
2036         val hostAddresses1 = listOf(
2037                 parseNumericAddress("192.0.2.23"),
2038                 parseNumericAddress("2001:db8::1"),
2039                 parseNumericAddress("2001:db8::2")
2040         )
2041         val hostAddresses2 = listOf(
2042                 parseNumericAddress("192.0.2.24"),
2043                 parseNumericAddress("2001:db8::3")
2044         )
2045         val si1 = NsdServiceInfo().also {
2046             it.network = testNetwork1.network
2047             it.hostname = customHostname
2048             it.hostAddresses = hostAddresses1
2049         }
2050         val si2 = NsdServiceInfo().also {
2051             it.network = testNetwork1.network
2052             it.serviceName = serviceName
2053             it.serviceType = serviceType
2054             it.port = TEST_PORT
2055             it.hostname = customHostname
2056             it.hostAddresses = hostAddresses2
2057         }
2058 
2059         val registrationRecord1 = NsdRegistrationRecord()
2060         val registrationRecord2 = NsdRegistrationRecord()
2061 
2062         val discoveryRecord = NsdDiscoveryRecord()
2063         tryTest {
2064             registerService(registrationRecord1, si1)
2065             registerService(registrationRecord2, si2)
2066 
2067             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
2068                     testNetwork1.network, Executor { it.run() }, discoveryRecord)
2069 
2070             val discoveredInfo = discoveryRecord.waitForServiceDiscovered(
2071                     serviceName, serviceType, testNetwork1.network)
2072             val resolvedInfo = resolveService(discoveredInfo)
2073 
2074             assertEquals(TEST_PORT, resolvedInfo.port)
2075             assertNotEquals(si1.hostname, resolvedInfo.hostname)
2076             assertAddressEquals(hostAddresses2, resolvedInfo.hostAddresses)
2077         } cleanupStep {
2078             nsdManager.stopServiceDiscovery(discoveryRecord)
2079 
2080             discoveryRecord.expectCallbackEventually<DiscoveryStopped>()
2081         } cleanup {
2082             nsdManager.unregisterService(registrationRecord1)
2083             nsdManager.unregisterService(registrationRecord2)
2084         }
2085     }
2086 
2087     @Test
2088     fun testAdvertisingAndDiscovery_servicesWithTheSameCustomHostAddressOmitted_addressesFound() {
2089         val hostAddresses = listOf(
2090                 parseNumericAddress("192.0.2.23"),
2091                 parseNumericAddress("2001:db8::1"),
2092                 parseNumericAddress("2001:db8::2")
2093         )
2094         val si1 = NsdServiceInfo().also {
2095             it.network = testNetwork1.network
2096             it.serviceType = serviceType
2097             it.serviceName = serviceName
2098             it.port = TEST_PORT
2099             it.hostname = customHostname
2100             it.hostAddresses = hostAddresses
2101         }
2102         val si2 = NsdServiceInfo().also {
2103             it.network = testNetwork1.network
2104             it.serviceType = serviceType
2105             it.serviceName = serviceName2
2106             it.port = TEST_PORT + 1
2107             it.hostname = customHostname
2108         }
2109 
2110         val registrationRecord1 = NsdRegistrationRecord()
2111         val registrationRecord2 = NsdRegistrationRecord()
2112 
2113         val discoveryRecord = NsdDiscoveryRecord()
2114         tryTest {
2115             registerService(registrationRecord1, si1)
2116 
2117             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
2118                     testNetwork1.network, Executor { it.run() }, discoveryRecord)
2119 
2120             val discoveredInfo1 = discoveryRecord.waitForServiceDiscovered(
2121                     serviceName, serviceType, testNetwork1.network)
2122             val resolvedInfo1 = resolveService(discoveredInfo1)
2123 
2124             assertEquals(serviceName, discoveredInfo1.serviceName)
2125             assertEquals(TEST_PORT, resolvedInfo1.port)
2126             assertEquals(si1.hostname, resolvedInfo1.hostname)
2127             assertAddressEquals(hostAddresses, resolvedInfo1.hostAddresses)
2128 
2129             registerService(registrationRecord2, si2)
2130 
2131             val discoveredInfo2 = discoveryRecord.waitForServiceDiscovered(
2132                     serviceName2, serviceType, testNetwork1.network)
2133             val resolvedInfo2 = resolveService(discoveredInfo2)
2134 
2135             assertEquals(serviceName2, discoveredInfo2.serviceName)
2136             assertEquals(TEST_PORT + 1, resolvedInfo2.port)
2137             assertEquals(si2.hostname, resolvedInfo2.hostname)
2138             assertAddressEquals(hostAddresses, resolvedInfo2.hostAddresses)
2139         } cleanupStep {
2140             nsdManager.stopServiceDiscovery(discoveryRecord)
2141 
2142             discoveryRecord.expectCallback<DiscoveryStopped>()
2143         } cleanup {
2144             nsdManager.unregisterService(registrationRecord1)
2145             nsdManager.unregisterService(registrationRecord2)
2146         }
2147     }
2148 
2149     @Test
2150     fun testRegisterService_registerImmediatelyAfterUnregister_serviceFound() {
2151         val info1 = makeTestServiceInfo(network = testNetwork1.network).apply {
2152             serviceName = "service11111"
2153             port = 11111
2154         }
2155         val info2 = makeTestServiceInfo(network = testNetwork1.network).apply {
2156             serviceName = "service22222"
2157             port = 22222
2158         }
2159         val registrationRecord1 = NsdRegistrationRecord()
2160         val discoveryRecord1 = NsdDiscoveryRecord()
2161         val registrationRecord2 = NsdRegistrationRecord()
2162         val discoveryRecord2 = NsdDiscoveryRecord()
2163         tryTest {
2164             registerService(registrationRecord1, info1)
2165             nsdManager.discoverServices(serviceType,
2166                     NsdManager.PROTOCOL_DNS_SD, testNetwork1.network, { it.run() },
2167                     discoveryRecord1)
2168             discoveryRecord1.waitForServiceDiscovered(info1.serviceName,
2169                     serviceType, testNetwork1.network)
2170             nsdManager.stopServiceDiscovery(discoveryRecord1)
2171 
2172             nsdManager.unregisterService(registrationRecord1)
2173             registerService(registrationRecord2, info2)
2174             nsdManager.discoverServices(serviceType,
2175                     NsdManager.PROTOCOL_DNS_SD, testNetwork1.network, { it.run() },
2176                     discoveryRecord2)
2177             val infoDiscovered = discoveryRecord2.waitForServiceDiscovered(info2.serviceName,
2178                     serviceType, testNetwork1.network)
2179             val infoResolved = resolveService(infoDiscovered)
2180             assertEquals(22222, infoResolved.port)
2181         } cleanupStep {
2182             nsdManager.stopServiceDiscovery(discoveryRecord2)
2183             discoveryRecord2.expectCallback<DiscoveryStopped>()
2184         } cleanup {
2185             nsdManager.unregisterService(registrationRecord2)
2186         }
2187     }
2188 
2189     @Test
2190     fun testAdvertisingAndDiscovery_reregisterCustomHostWithDifferentAddresses_newAddressesFound() {
2191         val si1 = NsdServiceInfo().also {
2192             it.network = testNetwork1.network
2193             it.hostname = customHostname
2194             it.hostAddresses = listOf(
2195                     parseNumericAddress("192.0.2.23"),
2196                     parseNumericAddress("2001:db8::1"))
2197         }
2198         val si2 = NsdServiceInfo().also {
2199             it.network = testNetwork1.network
2200             it.serviceName = serviceName
2201             it.serviceType = serviceType
2202             it.hostname = customHostname
2203             it.port = TEST_PORT
2204         }
2205         val si3 = NsdServiceInfo().also {
2206             it.network = testNetwork1.network
2207             it.hostname = customHostname
2208             it.hostAddresses = listOf(
2209                     parseNumericAddress("192.0.2.24"),
2210                     parseNumericAddress("2001:db8::2"))
2211         }
2212 
2213         val registrationRecord1 = NsdRegistrationRecord()
2214         val registrationRecord2 = NsdRegistrationRecord()
2215         val registrationRecord3 = NsdRegistrationRecord()
2216 
2217         val discoveryRecord = NsdDiscoveryRecord()
2218 
2219         tryTest {
2220             registerService(registrationRecord1, si1)
2221             registerService(registrationRecord2, si2)
2222 
2223             nsdManager.unregisterService(registrationRecord1)
2224             registrationRecord1.expectCallback<ServiceUnregistered>()
2225 
2226             registerService(registrationRecord3, si3)
2227 
2228             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
2229                     testNetwork1.network, Executor { it.run() }, discoveryRecord)
2230             val discoveredInfo = discoveryRecord.waitForServiceDiscovered(
2231                     serviceName, serviceType, testNetwork1.network)
2232             val resolvedInfo = resolveService(discoveredInfo)
2233 
2234             assertEquals(serviceName, discoveredInfo.serviceName)
2235             assertEquals(TEST_PORT, resolvedInfo.port)
2236             assertEquals(customHostname, resolvedInfo.hostname)
2237             assertAddressEquals(
2238                     listOf(parseNumericAddress("192.0.2.24"), parseNumericAddress("2001:db8::2")),
2239                     resolvedInfo.hostAddresses)
2240         } cleanupStep {
2241             nsdManager.stopServiceDiscovery(discoveryRecord)
2242             discoveryRecord.expectCallbackEventually<DiscoveryStopped>()
2243         } cleanup {
2244             nsdManager.unregisterService(registrationRecord2)
2245             nsdManager.unregisterService(registrationRecord3)
2246         }
2247     }
2248 
2249     @Test
2250     fun testAdvertising_registerServiceAndPublicKey_keyAnnounced() {
2251         val si = NsdServiceInfo().also {
2252             it.network = testNetwork1.network
2253             it.serviceType = serviceType
2254             it.serviceName = serviceName
2255             it.port = TEST_PORT
2256             it.publicKey = publicKey
2257         }
2258         val packetReader = makePacketReader()
2259         val registrationRecord = NsdRegistrationRecord()
2260         val discoveryRecord = NsdDiscoveryRecord()
2261         tryTest {
2262             registerService(registrationRecord, si)
2263 
2264             val announcement = packetReader.pollForReply(
2265                 "$serviceName.$serviceType.local",
2266                 TYPE_KEY
2267             )
2268             assertNotNull(announcement)
2269             val keyRecords = announcement.records[ANSECTION].filter { it.nsType == TYPE_KEY }
2270             assertEquals(1, keyRecords.size)
2271             val actualRecord = keyRecords.get(0)
2272             assertEquals(TYPE_KEY, actualRecord.nsType)
2273             assertEquals("$serviceName.$serviceType.local", actualRecord.dName)
2274             assertEquals(NAME_RECORDS_TTL_MILLIS, actualRecord.ttl)
2275             assertArrayEquals(publicKey, actualRecord.rr)
2276 
2277             nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
2278                     testNetwork1.network, Executor { it.run() }, discoveryRecord)
2279 
2280             val discoveredInfo1 = discoveryRecord.waitForServiceDiscovered(
2281                     serviceName, serviceType, testNetwork1.network)
2282             val resolvedInfo1 = resolveService(discoveredInfo1)
2283 
2284             assertEquals(serviceName, discoveredInfo1.serviceName)
2285             assertEquals(TEST_PORT, resolvedInfo1.port)
2286         } cleanupStep {
2287             nsdManager.stopServiceDiscovery(discoveryRecord)
2288 
2289             discoveryRecord.expectCallback<DiscoveryStopped>()
2290         } cleanupStep {
2291             nsdManager.unregisterService(registrationRecord)
2292         } cleanup {
2293             packetReader.handler.post { packetReader.stop() }
2294             handlerThread.waitForIdle(TIMEOUT_MS)
2295         }
2296     }
2297 
2298     @Test
2299     fun testAdvertising_registerCustomHostAndPublicKey_keyAnnounced() {
2300         val si = NsdServiceInfo().also {
2301             it.network = testNetwork1.network
2302             it.hostname = customHostname
2303             it.hostAddresses = listOf(
2304                     parseNumericAddress("192.0.2.23"),
2305                     parseNumericAddress("2001:db8::1"),
2306                     parseNumericAddress("2001:db8::2"))
2307             it.publicKey = publicKey
2308         }
2309         val packetReader = makePacketReader()
2310         val registrationRecord = NsdRegistrationRecord()
2311         tryTest {
2312             registerService(registrationRecord, si)
2313 
2314             val announcement = packetReader.pollForReply("$customHostname.local", TYPE_KEY)
2315             assertNotNull(announcement)
2316             val keyRecords = announcement.records[ANSECTION].filter { it.nsType == TYPE_KEY }
2317             assertEquals(1, keyRecords.size)
2318             val actualRecord = keyRecords.get(0)
2319             assertEquals(TYPE_KEY, actualRecord.nsType)
2320             assertEquals("$customHostname.local", actualRecord.dName)
2321             assertEquals(NAME_RECORDS_TTL_MILLIS, actualRecord.ttl)
2322             assertArrayEquals(publicKey, actualRecord.rr)
2323 
2324             // This test case focuses on key announcement so we don't check the details of the
2325             // announcement of the custom host addresses.
2326             val addressRecords = announcement.records[ANSECTION].filter {
2327                 it.nsType == DnsResolver.TYPE_AAAA ||
2328                         it.nsType == DnsResolver.TYPE_A
2329             }
2330             assertEquals(3, addressRecords.size)
2331         } cleanupStep {
2332             nsdManager.unregisterService(registrationRecord)
2333         } cleanup {
2334             packetReader.handler.post { packetReader.stop() }
2335             handlerThread.waitForIdle(TIMEOUT_MS)
2336         }
2337     }
2338 
2339     @Test
2340     fun testAdvertising_registerTwoServicesWithSameCustomHostAndPublicKey_keyAnnounced() {
2341         val si1 = NsdServiceInfo().also {
2342             it.network = testNetwork1.network
2343             it.serviceType = serviceType
2344             it.serviceName = serviceName
2345             it.port = TEST_PORT
2346             it.hostname = customHostname
2347             it.hostAddresses = listOf(
2348                 parseNumericAddress("192.0.2.23"),
2349                 parseNumericAddress("2001:db8::1"),
2350                 parseNumericAddress("2001:db8::2"))
2351             it.publicKey = publicKey
2352         }
2353         val si2 = NsdServiceInfo().also {
2354             it.network = testNetwork1.network
2355             it.serviceType = serviceType2
2356             it.serviceName = serviceName2
2357             it.port = TEST_PORT + 1
2358             it.hostname = customHostname
2359             it.hostAddresses = listOf()
2360             it.publicKey = publicKey
2361         }
2362         val packetReader = makePacketReader()
2363         val registrationRecord1 = NsdRegistrationRecord()
2364         val registrationRecord2 = NsdRegistrationRecord()
2365         tryTest {
2366             registerService(registrationRecord1, si1)
2367 
2368             var announcement =
2369                 packetReader.pollForReply("$serviceName.$serviceType.local", TYPE_KEY)
2370             assertNotNull(announcement)
2371             var keyRecords = announcement.records[ANSECTION].filter { it.nsType == TYPE_KEY }
2372             assertEquals(2, keyRecords.size)
2373             assertTrue(keyRecords.any { it.dName == "$serviceName.$serviceType.local" })
2374             assertTrue(keyRecords.any { it.dName == "$customHostname.local" })
2375             assertTrue(keyRecords.all { it.ttl == NAME_RECORDS_TTL_MILLIS })
2376             assertTrue(keyRecords.all { it.rr.contentEquals(publicKey) })
2377 
2378             // This test case focuses on key announcement so we don't check the details of the
2379             // announcement of the custom host addresses.
2380             val addressRecords = announcement.records[ANSECTION].filter {
2381                 it.nsType == DnsResolver.TYPE_AAAA ||
2382                         it.nsType == DnsResolver.TYPE_A
2383             }
2384             assertEquals(3, addressRecords.size)
2385 
2386             registerService(registrationRecord2, si2)
2387 
2388             announcement = packetReader.pollForReply("$serviceName2.$serviceType2.local", TYPE_KEY)
2389             assertNotNull(announcement)
2390             keyRecords = announcement.records[ANSECTION].filter { it.nsType == TYPE_KEY }
2391             assertEquals(2, keyRecords.size)
2392             assertTrue(keyRecords.any { it.dName == "$serviceName2.$serviceType2.local" })
2393             assertTrue(keyRecords.any { it.dName == "$customHostname.local" })
2394             assertTrue(keyRecords.all { it.ttl == NAME_RECORDS_TTL_MILLIS })
2395             assertTrue(keyRecords.all { it.rr.contentEquals(publicKey) })
2396         } cleanupStep {
2397             nsdManager.unregisterService(registrationRecord1)
2398             nsdManager.unregisterService(registrationRecord2)
2399         } cleanup {
2400             packetReader.handler.post { packetReader.stop() }
2401             handlerThread.waitForIdle(TIMEOUT_MS)
2402         }
2403     }
2404 
2405     @Test
2406     fun testServiceTypeClientRemovedAfterSocketDestroyed() {
2407         val si = makeTestServiceInfo(testNetwork1.network)
2408         // Register service on testNetwork1
2409         val registrationRecord = NsdRegistrationRecord()
2410         registerService(registrationRecord, si)
2411         // Register multiple discovery requests.
2412         val discoveryRecord1 = NsdDiscoveryRecord()
2413         val discoveryRecord2 = NsdDiscoveryRecord()
2414         val discoveryRecord3 = NsdDiscoveryRecord()
2415         nsdManager.discoverServices(
2416             "_test1._tcp",
2417             NsdManager.PROTOCOL_DNS_SD,
2418                 testNetwork1.network,
2419             { it.run() },
2420             discoveryRecord1
2421         )
2422         nsdManager.discoverServices(
2423             "_test2._tcp",
2424             NsdManager.PROTOCOL_DNS_SD,
2425                 testNetwork1.network,
2426             { it.run() },
2427             discoveryRecord2
2428         )
2429         nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord3)
2430 
2431         tryTest {
2432             discoveryRecord1.expectCallback<DiscoveryStarted>()
2433             discoveryRecord2.expectCallback<DiscoveryStarted>()
2434             discoveryRecord3.expectCallback<DiscoveryStarted>()
2435             val foundInfo = discoveryRecord3.waitForServiceDiscovered(
2436                     serviceName, serviceType, testNetwork1.network)
2437             assertEquals(testNetwork1.network, foundInfo.network)
2438             // Verify that associated ServiceTypeClients has been created for testNetwork1.
2439             assertTrue("No serviceTypeClients for testNetwork1.",
2440                     hasServiceTypeClientsForNetwork(
2441                             getServiceTypeClients(), testNetwork1.network))
2442 
2443             // Disconnect testNetwork1
2444             runAsShell(MANAGE_TEST_NETWORKS) {
2445                 testNetwork1.close(cm)
2446             }
2447 
2448             // Verify that no ServiceTypeClients for testNetwork1.
2449             discoveryRecord3.expectCallback<ServiceLost>()
2450             assertFalse("Still has serviceTypeClients for testNetwork1.",
2451                     hasServiceTypeClientsForNetwork(
2452                             getServiceTypeClients(), testNetwork1.network))
2453         } cleanupStep {
2454             nsdManager.stopServiceDiscovery(discoveryRecord1)
2455             nsdManager.stopServiceDiscovery(discoveryRecord2)
2456             nsdManager.stopServiceDiscovery(discoveryRecord3)
2457             discoveryRecord1.expectCallback<DiscoveryStopped>()
2458             discoveryRecord2.expectCallback<DiscoveryStopped>()
2459             discoveryRecord3.expectCallback<DiscoveryStopped>()
2460         } cleanup {
2461             nsdManager.unregisterService(registrationRecord)
2462             registrationRecord.expectCallback<ServiceUnregistered>()
2463         }
2464     }
2465 
2466     @Test
2467     fun testAdvertiseServiceWithNoAttributes_TxtRecordIstNotEmpty() {
2468         deviceConfigRule.setConfig(
2469             NAMESPACE_TETHERING,
2470             "test_nsd_avoid_advertising_empty_txt_records",
2471             "1"
2472         )
2473         val packetReader = makePacketReader()
2474 
2475         // Test behavior described in RFC6763 6.1: empty TXT records are not allowed, but TXT
2476         // records with a zero length string are equivalent.
2477         val si = makeTestServiceInfo(testNetwork1.network)
2478         // Register service on testNetwork1
2479         val registrationRecord = NsdRegistrationRecord()
2480         registerService(registrationRecord, si)
2481 
2482         tryTest {
2483             val announcement =
2484                 packetReader.pollForReply("$serviceName.$serviceType.local", DnsResolver.TYPE_TXT)
2485             assertNotNull(announcement)
2486             val txtRecords = announcement.records[ANSECTION].filter {
2487                 it.nsType == DnsResolver.TYPE_TXT
2488             }
2489             assertEquals(1, txtRecords.size)
2490             // The TXT record should contain as single zero
2491             assertContentEquals(byteArrayOf(0), txtRecords[0].rr)
2492         } cleanupStep {
2493             nsdManager.unregisterService(registrationRecord)
2494             registrationRecord.expectCallback<ServiceUnregistered>()
2495         } cleanup {
2496             packetReader.handler.post { packetReader.stop() }
2497             handlerThread.waitForIdle(TIMEOUT_MS)
2498         }
2499     }
2500 
2501     private fun verifyCachedServicesRemoval(isCachedServiceRemoved: Boolean) {
2502         val si = makeTestServiceInfo(testNetwork1.network)
2503         // Register service on testNetwork1
2504         val registrationRecord = NsdRegistrationRecord()
2505         registerService(registrationRecord, si)
2506         // Register a discovery request.
2507         val discoveryRecord = NsdDiscoveryRecord()
2508         val packetReader = makePacketReader()
2509 
2510         tryTest {
2511             nsdManager.discoverServices(
2512                     serviceType,
2513                     NsdManager.PROTOCOL_DNS_SD,
2514                     testNetwork1.network,
2515                     { it.run() },
2516                     discoveryRecord
2517             )
2518 
2519             discoveryRecord.expectCallback<DiscoveryStarted>()
2520             val foundInfo = discoveryRecord.waitForServiceDiscovered(
2521                     serviceName, serviceType, testNetwork1.network)
2522             assertEquals(testNetwork1.network, foundInfo.network)
2523             // Verify that the service is not in the cache (a query is sent).
2524             assertNotNull(packetReader.pollForQuery(
2525                     "$serviceType.local", DnsResolver.TYPE_PTR, timeoutMs = 0L))
2526 
2527             // Stop discovery to trigger the cached services removal process.
2528             nsdManager.stopServiceDiscovery(discoveryRecord)
2529             discoveryRecord.expectCallback<DiscoveryStopped>()
2530 
2531             val serviceFullName = "$serviceName.$serviceType.local"
2532             if (isCachedServiceRemoved) {
2533                 Thread.sleep(100L)
2534                 resolveService(foundInfo)
2535                 // Verify the resolution query will send because cached services are remove after
2536                 // exceeding the retention time.
2537                 assertNotNull(packetReader.pollForQuery(
2538                         serviceFullName, DnsResolver.TYPE_ANY, timeoutMs = 0L))
2539             } else {
2540                 resolveService(foundInfo)
2541                 // Verify the resolution query will not be sent because services are still cached.
2542                 assertNull(packetReader.pollForQuery(
2543                         serviceFullName, DnsResolver.TYPE_ANY, timeoutMs = 0L))
2544             }
2545         } cleanupStep {
2546             nsdManager.unregisterService(registrationRecord)
2547             registrationRecord.expectCallback<ServiceUnregistered>()
2548         } cleanup {
2549             packetReader.handler.post { packetReader.stop() }
2550             handlerThread.waitForIdle(TIMEOUT_MS)
2551         }
2552     }
2553 
2554     @Test
2555     fun testRemoveCachedServices() {
2556         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_cached_services_removal", "1")
2557         verifyCachedServicesRemoval(isCachedServiceRemoved = false)
2558     }
2559 
2560     @Test
2561     fun testRemoveCachedServices_ShortRetentionTime() {
2562         deviceConfigRule.setConfig(NAMESPACE_TETHERING, "test_nsd_cached_services_removal", "1")
2563         deviceConfigRule.setConfig(
2564                 NAMESPACE_TETHERING,
2565                 "test_nsd_cached_services_retention_time",
2566                 "1"
2567         )
2568         verifyCachedServicesRemoval(isCachedServiceRemoved = true)
2569     }
2570 
2571     @Test
2572     fun testSkipProbing() {
2573         val si = makeTestServiceInfo(testNetwork1.network)
2574         val request = AdvertisingRequest.Builder(si)
2575             .setFlags(FLAG_SKIP_PROBING)
2576             .build()
2577         assertEquals(FLAG_SKIP_PROBING, request.flags)
2578         assertEquals(PROTOCOL_DNS_SD, request.protocolType)
2579         assertEquals(si.serviceName, request.serviceInfo.serviceName)
2580 
2581         // Register service on testNetwork1
2582         val registrationRecord = NsdRegistrationRecord()
2583         nsdManager.registerService(request, { it.run() }, registrationRecord)
2584         registrationRecord.expectCallback<ServiceRegistered>()
2585         val packetReader = makePacketReader()
2586 
2587         tryTest {
2588             val srvRecordName = "$serviceName.$serviceType.local"
2589             // Look for either announcements or probes
2590             val packet = packetReader.pollForMdnsPacket {
2591                 it.isProbeFor(srvRecordName) || it.isReplyFor(srvRecordName)
2592             }
2593             assertNotNull(packet, "Probe or announcement not received within timeout")
2594             // The first packet should be an announcement, not a probe.
2595             assertTrue("Found initial probes with NSD_ADVERTISING_SKIP_PROBING enabled",
2596                 packet.isReplyFor(srvRecordName))
2597 
2598             // Force a conflict now that the service is getting announced
2599             val conflictingAnnouncement = buildConflictingAnnouncement()
2600             packetReader.sendResponse(conflictingAnnouncement)
2601 
2602             // Expect to see probes now (RFC6762 9., service is reset to probing state)
2603             assertNotNull(packetReader.pollForProbe(serviceName, serviceType),
2604                 "Probe not received within timeout after conflict")
2605         } cleanupStep {
2606             nsdManager.unregisterService(registrationRecord)
2607             registrationRecord.expectCallback<ServiceUnregistered>()
2608         } cleanup {
2609             packetReader.handler.post { packetReader.stop() }
2610             handlerThread.waitForIdle(TIMEOUT_MS)
2611         }
2612     }
2613 
2614     private fun hasServiceTypeClientsForNetwork(clients: List<String>, network: Network): Boolean {
2615         return clients.any { client -> client.substring(
2616                 client.indexOf("network=") + "network=".length,
2617                 client.indexOf("interfaceIndex=") - 1) == network.getNetId().toString()
2618         }
2619     }
2620 
2621     /**
2622      * Get ServiceTypeClient logs from the system dump servicediscovery section.
2623      *
2624      * The sample output:
2625      *     ServiceTypeClient: Type{_nmt079019787._tcp.local} \
2626      *         SocketKey{ network=116 interfaceIndex=68 } with 1 listeners.
2627      *     ServiceTypeClient: Type{_nmt079019787._tcp.local} \
2628      *         SocketKey{ network=115 interfaceIndex=67 } with 1 listeners.
2629      */
2630     private fun getServiceTypeClients(): List<String> {
2631         return SystemUtil.runShellCommand(
2632                 InstrumentationRegistry.getInstrumentation(),
2633             "dumpsys servicediscovery"
2634         )
2635                 .split("\n").mapNotNull { line ->
2636                     line.indexOf("ServiceTypeClient:").let { idx ->
2637                         if (idx == -1) {
2638                             null
2639                         } else {
2640                             line.substring(idx)
2641                         }
2642                     }
2643                 }
2644     }
2645 
2646     private fun buildConflictingAnnouncement(): ByteBuffer {
2647         /*
2648         Generated with:
2649         scapy.raw(scapy.DNS(rd=0, qr=1, aa=1, qd = None, an =
2650                 scapy.DNSRRSRV(rrname='NsdTest123456789._nmt123456789._tcp.local',
2651                     rclass=0x8001, port=31234, target='conflict.local', ttl=120)
2652         )).hex()
2653          */
2654         val mdnsPayload = HexDump.hexStringToByteArray(
2655             "000084000000000100000000104e736454657" +
2656                 "3743132333435363738390d5f6e6d74313233343536373839045f746370056c6f63616c00002" +
2657                 "18001000000780016000000007a0208636f6e666c696374056c6f63616c00"
2658         )
2659         replaceServiceNameAndTypeWithTestSuffix(mdnsPayload)
2660 
2661         return buildMdnsPacket(mdnsPayload)
2662     }
2663 
2664     private fun buildConflictingAnnouncementForCustomHost(): ByteBuffer {
2665         /*
2666         Generated with scapy:
2667         raw(DNS(rd=0, qr=1, aa=1, qd = None, an =
2668             DNSRR(rrname='NsdTestHost123456789.local', type=28, rclass=1, ttl=120,
2669                     rdata='2001:db8::321')
2670         )).hex()
2671          */
2672         val mdnsPayload = HexDump.hexStringToByteArray(
2673             "000084000000000100000000144e7364" +
2674                 "54657374486f7374313233343536373839056c6f63616c00001c000100000078001020010db80000" +
2675                 "00000000000000000321"
2676         )
2677         replaceCustomHostnameWithTestSuffix(mdnsPayload)
2678 
2679         return buildMdnsPacket(mdnsPayload)
2680     }
2681 
2682     /**
2683      * Replaces occurrences of "NsdTest123456789" and "_nmt123456789" in mDNS payload with the
2684      * actual random name and type that are used by the test.
2685      */
2686     private fun replaceServiceNameAndTypeWithTestSuffix(mdnsPayload: ByteArray) {
2687         // Test service name and types have consistent length and are always ASCII
2688         val testPacketName = "NsdTest123456789".encodeToByteArray()
2689         val testPacketTypePrefix = "_nmt123456789".encodeToByteArray()
2690         val encodedServiceName = serviceName.encodeToByteArray()
2691         val encodedTypePrefix = serviceType.split('.')[0].encodeToByteArray()
2692 
2693         val packetBuffer = ByteBuffer.wrap(mdnsPayload)
2694         replaceAll(packetBuffer, testPacketName, encodedServiceName)
2695         replaceAll(packetBuffer, testPacketTypePrefix, encodedTypePrefix)
2696     }
2697 
2698     /**
2699      * Replaces occurrences of "NsdTestHost123456789" in mDNS payload with the
2700      * actual random host name that are used by the test.
2701      */
2702     private fun replaceCustomHostnameWithTestSuffix(mdnsPayload: ByteArray) {
2703         // Test custom hostnames have consistent length and are always ASCII
2704         val testPacketName = "NsdTestHost123456789".encodeToByteArray()
2705         val encodedHostname = customHostname.encodeToByteArray()
2706 
2707         val packetBuffer = ByteBuffer.wrap(mdnsPayload)
2708         replaceAll(packetBuffer, testPacketName, encodedHostname)
2709     }
2710 
2711     private tailrec fun replaceAll(buffer: ByteBuffer, source: ByteArray, replacement: ByteArray) {
2712         assertEquals(source.size, replacement.size)
2713         val index = buffer.array().indexOf(source)
2714         if (index < 0) return
2715 
2716         val origPosition = buffer.position()
2717         buffer.position(index)
2718         buffer.put(replacement)
2719         buffer.position(origPosition)
2720         replaceAll(buffer, source, replacement)
2721     }
2722 
2723     private fun buildMdnsPacket(
2724         mdnsPayload: ByteArray,
2725         srcAddr: Inet6Address = testSrcAddr
2726     ): ByteBuffer {
2727         val packetBuffer = PacketBuilder.allocate(
2728             true /* hasEther */,
2729             IPPROTO_IPV6,
2730                 IPPROTO_UDP,
2731             mdnsPayload.size
2732         )
2733         val packetBuilder = PacketBuilder(packetBuffer)
2734         // Multicast ethernet address for IPv6 to ff02::fb
2735         val multicastEthAddr = MacAddress.fromBytes(
2736                 byteArrayOf(0x33, 0x33, 0, 0, 0, 0xfb.toByte())
2737         )
2738         packetBuilder.writeL2Header(
2739                 MacAddress.fromBytes(byteArrayOf(1, 2, 3, 4, 5, 6)) /* srcMac */,
2740                 multicastEthAddr,
2741                 ETH_P_IPV6.toShort()
2742         )
2743         packetBuilder.writeIpv6Header(
2744                 0x60000000, // version=6, traffic class=0x0, flowlabel=0x0
2745                 IPPROTO_UDP.toByte(),
2746                 64 /* hop limit */,
2747                 srcAddr,
2748                 multicastIpv6Addr /* dstIp */
2749         )
2750         packetBuilder.writeUdpHeader(MDNS_PORT /* srcPort */, MDNS_PORT /* dstPort */)
2751         packetBuffer.put(mdnsPayload)
2752         return packetBuilder.finalizePacket()
2753     }
2754 
2755     /**
2756      * Register a service and return its registration record.
2757      */
2758     private fun registerService(
2759         record: NsdRegistrationRecord,
2760         si: NsdServiceInfo,
2761         executor: Executor = Executor { it.run() }
2762     ): NsdServiceInfo {
2763         nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, executor, record)
2764         // We may not always get the name that we tried to register;
2765         // This events tells us the name that was registered.
2766         val cb = record.expectCallback<ServiceRegistered>(REGISTRATION_TIMEOUT_MS)
2767         return cb.serviceInfo
2768     }
2769 
2770     /**
2771      * Update a service.
2772      */
2773     private fun updateService(
2774             record: NsdRegistrationRecord,
2775             si: NsdServiceInfo,
2776             executor: Executor = Executor { it.run() }
2777     ) {
2778         nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, executor, record)
2779         // TODO: add the callback check for the update.
2780     }
2781 
2782     private fun resolveService(discoveredInfo: NsdServiceInfo): NsdServiceInfo {
2783         val record = NsdResolveRecord()
2784         nsdManager.resolveService(discoveredInfo, Executor { it.run() }, record)
2785         val resolvedCb = record.expectCallback<ServiceResolved>()
2786         assertEquals(discoveredInfo.serviceName, resolvedCb.serviceInfo.serviceName)
2787 
2788         return resolvedCb.serviceInfo
2789     }
2790 }
2791 
ByteArraynull2792 private fun ByteArray.indexOf(sub: ByteArray): Int {
2793     var subIndex = 0
2794     forEachIndexed { i, b ->
2795         when (b) {
2796             // Still matching: continue comparing with next byte
2797             sub[subIndex] -> {
2798                 subIndex++
2799                 if (subIndex == sub.size) {
2800                     return i - sub.size + 1
2801                 }
2802             }
2803             // Not matching next byte but matches first byte: continue comparing with 2nd byte
2804             sub[0] -> subIndex = 1
2805             // No matches: continue comparing from first byte
2806             else -> subIndex = 0
2807         }
2808     }
2809     return -1
2810 }
2811 
utf8ToStringnull2812 private fun ByteArray?.utf8ToString(): String {
2813     if (this == null) return ""
2814     return String(this, StandardCharsets.UTF_8)
2815 }
2816 
assertAddressEqualsnull2817 private fun assertAddressEquals(expected: List<InetAddress>, actual: List<InetAddress>) {
2818     // No duplicate addresses in the actual address list
2819     assertEquals(actual.toSet().size, actual.size)
2820     assertEquals(expected.toSet(), actual.toSet())
2821 }
2822