Merge "Add APIs for discover/resolve on specific networks" am: d61719c422
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1944726 Change-Id: I5d6e69d78a54be962134d62262ec0938280ea8d0
This commit is contained in:
@@ -3,6 +3,7 @@ package android.net.nsd {
|
|||||||
|
|
||||||
public final class NsdManager {
|
public final class NsdManager {
|
||||||
method public void discoverServices(String, int, android.net.nsd.NsdManager.DiscoveryListener);
|
method public void discoverServices(String, int, android.net.nsd.NsdManager.DiscoveryListener);
|
||||||
|
method public void discoverServices(@NonNull String, int, @Nullable android.net.Network, @NonNull android.net.nsd.NsdManager.DiscoveryListener);
|
||||||
method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener);
|
method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener);
|
||||||
method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener);
|
method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener);
|
||||||
method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener);
|
method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener);
|
||||||
@@ -43,12 +44,14 @@ package android.net.nsd {
|
|||||||
method public int describeContents();
|
method public int describeContents();
|
||||||
method public java.util.Map<java.lang.String,byte[]> getAttributes();
|
method public java.util.Map<java.lang.String,byte[]> getAttributes();
|
||||||
method public java.net.InetAddress getHost();
|
method public java.net.InetAddress getHost();
|
||||||
|
method @Nullable public android.net.Network getNetwork();
|
||||||
method public int getPort();
|
method public int getPort();
|
||||||
method public String getServiceName();
|
method public String getServiceName();
|
||||||
method public String getServiceType();
|
method public String getServiceType();
|
||||||
method public void removeAttribute(String);
|
method public void removeAttribute(String);
|
||||||
method public void setAttribute(String, String);
|
method public void setAttribute(String, String);
|
||||||
method public void setHost(java.net.InetAddress);
|
method public void setHost(java.net.InetAddress);
|
||||||
|
method public void setNetwork(@Nullable android.net.Network);
|
||||||
method public void setPort(int);
|
method public void setPort(int);
|
||||||
method public void setServiceName(String);
|
method public void setServiceName(String);
|
||||||
method public void setServiceType(String);
|
method public void setServiceType(String);
|
||||||
|
|||||||
@@ -15,6 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package android.net.cts
|
package android.net.cts
|
||||||
|
|
||||||
|
import android.Manifest.permission.MANAGE_TEST_NETWORKS
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.ConnectivityManager.NetworkCallback
|
||||||
|
import android.net.LinkProperties
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkAgentConfig
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_TEST
|
||||||
|
import android.net.NetworkRequest
|
||||||
|
import android.net.TestNetworkInterface
|
||||||
|
import android.net.TestNetworkManager
|
||||||
|
import android.net.TestNetworkSpecifier
|
||||||
import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStarted
|
import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStarted
|
||||||
import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStopped
|
import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStopped
|
||||||
import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.ServiceFound
|
import android.net.cts.NsdManagerTest.NsdDiscoveryRecord.DiscoveryEvent.ServiceFound
|
||||||
@@ -32,14 +45,27 @@ import android.net.nsd.NsdManager.DiscoveryListener
|
|||||||
import android.net.nsd.NsdManager.RegistrationListener
|
import android.net.nsd.NsdManager.RegistrationListener
|
||||||
import android.net.nsd.NsdManager.ResolveListener
|
import android.net.nsd.NsdManager.ResolveListener
|
||||||
import android.net.nsd.NsdServiceInfo
|
import android.net.nsd.NsdServiceInfo
|
||||||
|
import android.os.HandlerThread
|
||||||
import android.platform.test.annotations.AppModeFull
|
import android.platform.test.annotations.AppModeFull
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import com.android.net.module.util.ArrayTrackRecord
|
import com.android.net.module.util.ArrayTrackRecord
|
||||||
import com.android.net.module.util.TrackRecord
|
import com.android.net.module.util.TrackRecord
|
||||||
|
import com.android.networkstack.apishim.ConstantsShim
|
||||||
|
import com.android.networkstack.apishim.NsdShimImpl
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.SC_V2
|
||||||
|
import com.android.testutils.TestableNetworkAgent
|
||||||
|
import com.android.testutils.TestableNetworkCallback
|
||||||
|
import com.android.testutils.runAsShell
|
||||||
|
import com.android.testutils.tryTest
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Assert.assertArrayEquals
|
import org.junit.Assert.assertArrayEquals
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Assume.assumeTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
@@ -57,12 +83,37 @@ private const val SERVICE_TYPE = "_nmt._tcp"
|
|||||||
private const val TIMEOUT_MS = 2000L
|
private const val TIMEOUT_MS = 2000L
|
||||||
private const val DBG = false
|
private const val DBG = false
|
||||||
|
|
||||||
|
private val nsdShim = NsdShimImpl.newInstance()
|
||||||
|
|
||||||
@AppModeFull(reason = "Socket cannot bind in instant app mode")
|
@AppModeFull(reason = "Socket cannot bind in instant app mode")
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class NsdManagerTest {
|
class NsdManagerTest {
|
||||||
|
// NsdManager is not updatable before S, so tests do not need to be backwards compatible
|
||||||
|
@get:Rule
|
||||||
|
val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = SC_V2)
|
||||||
|
|
||||||
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
|
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
|
||||||
private val nsdManager by lazy { context.getSystemService(NsdManager::class.java) }
|
private val nsdManager by lazy { context.getSystemService(NsdManager::class.java) }
|
||||||
|
|
||||||
|
private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) }
|
||||||
private val serviceName = "NsdTest%09d".format(Random().nextInt(1_000_000_000))
|
private val serviceName = "NsdTest%09d".format(Random().nextInt(1_000_000_000))
|
||||||
|
private val handlerThread = HandlerThread(NsdManagerTest::class.java.simpleName)
|
||||||
|
|
||||||
|
private lateinit var testNetwork1: TestTapNetwork
|
||||||
|
private lateinit var testNetwork2: TestTapNetwork
|
||||||
|
|
||||||
|
private class TestTapNetwork(
|
||||||
|
val iface: TestNetworkInterface,
|
||||||
|
val requestCb: NetworkCallback,
|
||||||
|
val agent: TestableNetworkAgent,
|
||||||
|
val network: Network
|
||||||
|
) {
|
||||||
|
fun close(cm: ConnectivityManager) {
|
||||||
|
cm.unregisterNetworkCallback(requestCb)
|
||||||
|
agent.unregister()
|
||||||
|
iface.fileDescriptor.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private interface NsdEvent
|
private interface NsdEvent
|
||||||
private open class NsdRecord<T : NsdEvent> private constructor(
|
private open class NsdRecord<T : NsdEvent> private constructor(
|
||||||
@@ -163,9 +214,14 @@ class NsdManagerTest {
|
|||||||
add(ServiceLost(si))
|
add(ServiceLost(si))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun waitForServiceDiscovered(serviceName: String): NsdServiceInfo {
|
fun waitForServiceDiscovered(
|
||||||
|
serviceName: String,
|
||||||
|
expectedNetwork: Network? = null
|
||||||
|
): NsdServiceInfo {
|
||||||
return expectCallbackEventually<ServiceFound> {
|
return expectCallbackEventually<ServiceFound> {
|
||||||
it.serviceInfo.serviceName == serviceName
|
it.serviceInfo.serviceName == serviceName &&
|
||||||
|
(expectedNetwork == null ||
|
||||||
|
expectedNetwork == nsdShim.getNetwork(it.serviceInfo))
|
||||||
}.serviceInfo
|
}.serviceInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,6 +244,52 @@ class NsdManagerTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
handlerThread.start()
|
||||||
|
|
||||||
|
runAsShell(MANAGE_TEST_NETWORKS) {
|
||||||
|
testNetwork1 = createTestNetwork()
|
||||||
|
testNetwork2 = createTestNetwork()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTestNetwork(): TestTapNetwork {
|
||||||
|
val tnm = context.getSystemService(TestNetworkManager::class.java)
|
||||||
|
val iface = tnm.createTapInterface()
|
||||||
|
val cb = TestableNetworkCallback()
|
||||||
|
val testNetworkSpecifier = TestNetworkSpecifier(iface.interfaceName)
|
||||||
|
cm.requestNetwork(NetworkRequest.Builder()
|
||||||
|
.removeCapability(NET_CAPABILITY_TRUSTED)
|
||||||
|
.addTransportType(TRANSPORT_TEST)
|
||||||
|
.setNetworkSpecifier(testNetworkSpecifier)
|
||||||
|
.build(), cb)
|
||||||
|
val agent = TestableNetworkAgent(context, handlerThread.looper,
|
||||||
|
NetworkCapabilities().apply {
|
||||||
|
removeCapability(NET_CAPABILITY_TRUSTED)
|
||||||
|
addTransportType(TRANSPORT_TEST)
|
||||||
|
setNetworkSpecifier(testNetworkSpecifier)
|
||||||
|
},
|
||||||
|
LinkProperties().apply {
|
||||||
|
interfaceName = iface.interfaceName
|
||||||
|
},
|
||||||
|
NetworkAgentConfig.Builder().build())
|
||||||
|
val network = agent.register()
|
||||||
|
agent.markConnected()
|
||||||
|
// The network has no INTERNET capability, so will be marked validated immediately
|
||||||
|
cb.expectAvailableThenValidatedCallbacks(network)
|
||||||
|
return TestTapNetwork(iface, cb, agent, network)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
runAsShell(MANAGE_TEST_NETWORKS) {
|
||||||
|
testNetwork1.close(cm)
|
||||||
|
testNetwork2.close(cm)
|
||||||
|
}
|
||||||
|
handlerThread.quitSafely()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNsdManager() {
|
fun testNsdManager() {
|
||||||
val si = NsdServiceInfo()
|
val si = NsdServiceInfo()
|
||||||
@@ -298,6 +400,84 @@ class NsdManagerTest {
|
|||||||
registrationRecord2.expectCallback<ServiceUnregistered>()
|
registrationRecord2.expectCallback<ServiceUnregistered>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNsdManager_DiscoverOnNetwork() {
|
||||||
|
// This tests requires shims supporting T+ APIs (discovering on specific network)
|
||||||
|
assumeTrue(ConstantsShim.VERSION > SC_V2)
|
||||||
|
|
||||||
|
val si = NsdServiceInfo()
|
||||||
|
si.serviceType = SERVICE_TYPE
|
||||||
|
si.serviceName = this.serviceName
|
||||||
|
si.port = 12345 // Test won't try to connect so port does not matter
|
||||||
|
|
||||||
|
val registrationRecord = NsdRegistrationRecord()
|
||||||
|
val registeredInfo = registerService(registrationRecord, si)
|
||||||
|
|
||||||
|
tryTest {
|
||||||
|
val discoveryRecord = NsdDiscoveryRecord()
|
||||||
|
nsdShim.discoverServices(nsdManager, SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
|
||||||
|
testNetwork1.network, discoveryRecord)
|
||||||
|
|
||||||
|
val foundInfo = discoveryRecord.waitForServiceDiscovered(
|
||||||
|
serviceName, testNetwork1.network)
|
||||||
|
assertEquals(testNetwork1.network, nsdShim.getNetwork(foundInfo))
|
||||||
|
|
||||||
|
// Rewind to ensure the service is not found on the other interface
|
||||||
|
discoveryRecord.nextEvents.rewind(0)
|
||||||
|
assertNull(discoveryRecord.nextEvents.poll(timeoutMs = 100L) {
|
||||||
|
it is ServiceFound &&
|
||||||
|
it.serviceInfo.serviceName == registeredInfo.serviceName &&
|
||||||
|
nsdShim.getNetwork(it.serviceInfo) != testNetwork1.network
|
||||||
|
}, "The service should not be found on this network")
|
||||||
|
} cleanup {
|
||||||
|
nsdManager.unregisterService(registrationRecord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNsdManager_ResolveOnNetwork() {
|
||||||
|
// This tests requires shims supporting T+ APIs (NsdServiceInfo.network)
|
||||||
|
assumeTrue(ConstantsShim.VERSION > SC_V2)
|
||||||
|
|
||||||
|
val si = NsdServiceInfo()
|
||||||
|
si.serviceType = SERVICE_TYPE
|
||||||
|
si.serviceName = this.serviceName
|
||||||
|
si.port = 12345 // Test won't try to connect so port does not matter
|
||||||
|
|
||||||
|
val registrationRecord = NsdRegistrationRecord()
|
||||||
|
val registeredInfo = registerService(registrationRecord, si)
|
||||||
|
tryTest {
|
||||||
|
val resolveRecord = NsdResolveRecord()
|
||||||
|
|
||||||
|
val discoveryRecord = NsdDiscoveryRecord()
|
||||||
|
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryRecord)
|
||||||
|
|
||||||
|
val foundInfo1 = discoveryRecord.waitForServiceDiscovered(
|
||||||
|
serviceName, testNetwork1.network)
|
||||||
|
assertEquals(testNetwork1.network, nsdShim.getNetwork(foundInfo1))
|
||||||
|
// Rewind as the service could be found on each interface in any order
|
||||||
|
discoveryRecord.nextEvents.rewind(0)
|
||||||
|
val foundInfo2 = discoveryRecord.waitForServiceDiscovered(
|
||||||
|
serviceName, testNetwork2.network)
|
||||||
|
assertEquals(testNetwork2.network, nsdShim.getNetwork(foundInfo2))
|
||||||
|
|
||||||
|
nsdManager.resolveService(foundInfo1, resolveRecord)
|
||||||
|
val cb = resolveRecord.expectCallback<ServiceResolved>()
|
||||||
|
cb.serviceInfo.let {
|
||||||
|
// Resolved service type has leading dot
|
||||||
|
assertEquals(".$SERVICE_TYPE", it.serviceType)
|
||||||
|
assertEquals(registeredInfo.serviceName, it.serviceName)
|
||||||
|
assertEquals(si.port, it.port)
|
||||||
|
assertEquals(testNetwork1.network, nsdShim.getNetwork(it))
|
||||||
|
}
|
||||||
|
// TODO: check that MDNS packets are sent only on testNetwork1.
|
||||||
|
} cleanupStep {
|
||||||
|
nsdManager.unregisterService(registrationRecord)
|
||||||
|
} cleanup {
|
||||||
|
registrationRecord.expectCallback<ServiceUnregistered>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a service and return its registration record.
|
* Register a service and return its registration record.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.net.Network;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -123,6 +124,7 @@ public class NsdServiceInfoTest {
|
|||||||
fullInfo.setServiceType("_kitten._tcp");
|
fullInfo.setServiceType("_kitten._tcp");
|
||||||
fullInfo.setPort(4242);
|
fullInfo.setPort(4242);
|
||||||
fullInfo.setHost(LOCALHOST);
|
fullInfo.setHost(LOCALHOST);
|
||||||
|
fullInfo.setNetwork(new Network(123));
|
||||||
checkParcelable(fullInfo);
|
checkParcelable(fullInfo);
|
||||||
|
|
||||||
NsdServiceInfo noHostInfo = new NsdServiceInfo();
|
NsdServiceInfo noHostInfo = new NsdServiceInfo();
|
||||||
@@ -172,6 +174,7 @@ public class NsdServiceInfoTest {
|
|||||||
assertEquals(original.getServiceType(), result.getServiceType());
|
assertEquals(original.getServiceType(), result.getServiceType());
|
||||||
assertEquals(original.getHost(), result.getHost());
|
assertEquals(original.getHost(), result.getHost());
|
||||||
assertTrue(original.getPort() == result.getPort());
|
assertTrue(original.getPort() == result.getPort());
|
||||||
|
assertEquals(original.getNetwork(), result.getNetwork());
|
||||||
|
|
||||||
// Assert equality of attribute map.
|
// Assert equality of attribute map.
|
||||||
Map<String, byte[]> originalMap = original.getAttributes();
|
Map<String, byte[]> originalMap = original.getAttributes();
|
||||||
|
|||||||
@@ -218,14 +218,14 @@ public class NsdServiceTest {
|
|||||||
client.discoverServices("a_type", PROTOCOL, listener2);
|
client.discoverServices("a_type", PROTOCOL, listener2);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mDaemon, times(1)).maybeStart();
|
verify(mDaemon, times(1)).maybeStart();
|
||||||
verifyDaemonCommand("discover 3 a_type");
|
verifyDaemonCommand("discover 3 a_type 0");
|
||||||
|
|
||||||
// Client resolve request
|
// Client resolve request
|
||||||
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
|
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
|
||||||
client.resolveService(request, listener3);
|
client.resolveService(request, listener3);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mDaemon, times(1)).maybeStart();
|
verify(mDaemon, times(1)).maybeStart();
|
||||||
verifyDaemonCommand("resolve 4 a_name a_type local.");
|
verifyDaemonCommand("resolve 4 a_name a_type local. 0");
|
||||||
|
|
||||||
// Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
|
// Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
|
||||||
deathRecipient.binderDied();
|
deathRecipient.binderDied();
|
||||||
|
|||||||
Reference in New Issue
Block a user