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