Merge "Move buildMdnsServiceInfoFromResponse to MdnsUtils." into main
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index a5dd536..b0e3ba4 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -20,6 +20,7 @@
 import static com.android.server.connectivity.mdns.MdnsServiceCache.ServiceExpiredCallback;
 import static com.android.server.connectivity.mdns.MdnsServiceCache.findMatchedResponse;
 import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
+import static com.android.server.connectivity.mdns.util.MdnsUtils.buildMdnsServiceInfoFromResponse;
 import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
 
 import android.annotation.NonNull;
@@ -41,10 +42,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.DatagramPacket;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
 import java.net.InetSocketAddress;
-import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -309,57 +307,6 @@
         serviceCache.unregisterServiceExpiredCallback(cacheKey);
     }
 
-    private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(@NonNull MdnsResponse response,
-            @NonNull String[] serviceTypeLabels, long elapsedRealtimeMillis) {
-        String[] hostName = null;
-        int port = 0;
-        if (response.hasServiceRecord()) {
-            hostName = response.getServiceRecord().getServiceHost();
-            port = response.getServiceRecord().getServicePort();
-        }
-
-        final List<String> ipv4Addresses = new ArrayList<>();
-        final List<String> ipv6Addresses = new ArrayList<>();
-        if (response.hasInet4AddressRecord()) {
-            for (MdnsInetAddressRecord inetAddressRecord : response.getInet4AddressRecords()) {
-                final Inet4Address inet4Address = inetAddressRecord.getInet4Address();
-                ipv4Addresses.add((inet4Address == null) ? null : inet4Address.getHostAddress());
-            }
-        }
-        if (response.hasInet6AddressRecord()) {
-            for (MdnsInetAddressRecord inetAddressRecord : response.getInet6AddressRecords()) {
-                final Inet6Address inet6Address = inetAddressRecord.getInet6Address();
-                ipv6Addresses.add((inet6Address == null) ? null : inet6Address.getHostAddress());
-            }
-        }
-        String serviceInstanceName = response.getServiceInstanceName();
-        if (serviceInstanceName == null) {
-            throw new IllegalStateException(
-                    "mDNS response must have non-null service instance name");
-        }
-        List<String> textStrings = null;
-        List<MdnsServiceInfo.TextEntry> textEntries = null;
-        if (response.hasTextRecord()) {
-            textStrings = response.getTextRecord().getStrings();
-            textEntries = response.getTextRecord().getEntries();
-        }
-        Instant now = Instant.now();
-        // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address.
-        return new MdnsServiceInfo(
-                serviceInstanceName,
-                serviceTypeLabels,
-                response.getSubtypes(),
-                hostName,
-                port,
-                ipv4Addresses,
-                ipv6Addresses,
-                textStrings,
-                textEntries,
-                response.getInterfaceIndex(),
-                response.getNetwork(),
-                now.plusMillis(response.getMinRemainingTtl(elapsedRealtimeMillis)));
-    }
-
     private List<MdnsResponse> getExistingServices() {
         return featureFlags.isQueryWithKnownAnswerEnabled()
                 ? serviceCache.getCachedServices(cacheKey) : Collections.emptyList();
diff --git a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
index 8745941..85a8961 100644
--- a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
+++ b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
@@ -30,12 +30,17 @@
 import android.util.Pair;
 
 import com.android.server.connectivity.mdns.MdnsConstants;
+import com.android.server.connectivity.mdns.MdnsInetAddressRecord;
 import com.android.server.connectivity.mdns.MdnsPacket;
 import com.android.server.connectivity.mdns.MdnsPacketWriter;
 import com.android.server.connectivity.mdns.MdnsRecord;
+import com.android.server.connectivity.mdns.MdnsResponse;
+import com.android.server.connectivity.mdns.MdnsServiceInfo;
 
 import java.io.IOException;
 import java.net.DatagramPacket;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
@@ -43,6 +48,7 @@
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.StandardCharsets;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -318,4 +324,62 @@
         }
         return true;
     }
+
+    /**
+     * Build MdnsServiceInfo object from given MdnsResponse, service type labels and current time.
+     *
+     * @param response target service response
+     * @param serviceTypeLabels service type labels
+     * @param elapsedRealtimeMillis current time.
+     */
+    public static MdnsServiceInfo buildMdnsServiceInfoFromResponse(@NonNull MdnsResponse response,
+            @NonNull String[] serviceTypeLabels, long elapsedRealtimeMillis) {
+        String[] hostName = null;
+        int port = 0;
+        if (response.hasServiceRecord()) {
+            hostName = response.getServiceRecord().getServiceHost();
+            port = response.getServiceRecord().getServicePort();
+        }
+
+        final List<String> ipv4Addresses = new ArrayList<>();
+        final List<String> ipv6Addresses = new ArrayList<>();
+        if (response.hasInet4AddressRecord()) {
+            for (MdnsInetAddressRecord inetAddressRecord : response.getInet4AddressRecords()) {
+                final Inet4Address inet4Address = inetAddressRecord.getInet4Address();
+                ipv4Addresses.add((inet4Address == null) ? null : inet4Address.getHostAddress());
+            }
+        }
+        if (response.hasInet6AddressRecord()) {
+            for (MdnsInetAddressRecord inetAddressRecord : response.getInet6AddressRecords()) {
+                final Inet6Address inet6Address = inetAddressRecord.getInet6Address();
+                ipv6Addresses.add((inet6Address == null) ? null : inet6Address.getHostAddress());
+            }
+        }
+        String serviceInstanceName = response.getServiceInstanceName();
+        if (serviceInstanceName == null) {
+            throw new IllegalStateException(
+                    "mDNS response must have non-null service instance name");
+        }
+        List<String> textStrings = null;
+        List<MdnsServiceInfo.TextEntry> textEntries = null;
+        if (response.hasTextRecord()) {
+            textStrings = response.getTextRecord().getStrings();
+            textEntries = response.getTextRecord().getEntries();
+        }
+        Instant now = Instant.now();
+        // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address.
+        return new MdnsServiceInfo(
+                serviceInstanceName,
+                serviceTypeLabels,
+                response.getSubtypes(),
+                hostName,
+                port,
+                ipv4Addresses,
+                ipv6Addresses,
+                textStrings,
+                textEntries,
+                response.getInterfaceIndex(),
+                response.getNetwork(),
+                now.plusMillis(response.getMinRemainingTtl(elapsedRealtimeMillis)));
+    }
 }
\ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
index 5c3ad22..efae244 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
@@ -22,21 +22,27 @@
 import com.android.server.connectivity.mdns.MdnsConstants.FLAG_TRUNCATED
 import com.android.server.connectivity.mdns.MdnsConstants.IPV4_SOCKET_ADDR
 import com.android.server.connectivity.mdns.MdnsConstants.IPV6_SOCKET_ADDR
+import com.android.server.connectivity.mdns.MdnsInetAddressRecord
 import com.android.server.connectivity.mdns.MdnsPacket
 import com.android.server.connectivity.mdns.MdnsPacketReader
 import com.android.server.connectivity.mdns.MdnsPointerRecord
 import com.android.server.connectivity.mdns.MdnsRecord
+import com.android.server.connectivity.mdns.MdnsResponse
+import com.android.server.connectivity.mdns.MdnsServiceInfo
+import com.android.server.connectivity.mdns.MdnsServiceRecord
+import com.android.server.connectivity.mdns.MdnsTextRecord
 import com.android.server.connectivity.mdns.util.MdnsUtils.createQueryDatagramPackets
 import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRunner
-import java.net.DatagramPacket
-import kotlin.test.assertContentEquals
+import org.junit.Assert.assertArrayEquals
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.junit.runner.RunWith
+import java.net.DatagramPacket
+import kotlin.test.assertContentEquals
 
 @RunWith(DevSdkIgnoreRunner::class)
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -157,4 +163,54 @@
         assertFalse(MdnsUtils.checkAllPacketsWithSameAddress(listOf(v6Packet, otherV6Packet)))
         assertFalse(MdnsUtils.checkAllPacketsWithSameAddress(listOf(v4Packet, v6Packet)))
     }
+
+    @Test
+    fun testBuildMdnsServiceInfoFromResponse() {
+        val serviceInstanceName = "MyTestService"
+        val serviceType = "_testservice._tcp.local"
+        val hostName = "Android_000102030405060708090A0B0C0D0E0F.local"
+        val port = 12345
+        val ttlTime = 120000L
+        val testElapsedRealtime = 123L
+        val serviceName = "$serviceInstanceName.$serviceType".split(".").toTypedArray()
+        val v4Address = "192.0.2.1"
+        val v6Address = "2001:db8::1"
+        val interfaceIndex = 99
+        val response = MdnsResponse(0 /* now */, serviceName, interfaceIndex, null /* network */)
+        // Set PTR record
+        response.addPointerRecord(MdnsPointerRecord(serviceType.split(".").toTypedArray(),
+                testElapsedRealtime, false /* cacheFlush */, ttlTime, serviceName))
+        // Set SRV record.
+        response.serviceRecord = MdnsServiceRecord(serviceName, testElapsedRealtime,
+                false /* cacheFlush */, ttlTime, 0 /* servicePriority */, 0 /* serviceWeight */,
+                port, hostName.split(".").toTypedArray())
+        // Set TXT record.
+        response.textRecord = MdnsTextRecord(serviceName,
+                testElapsedRealtime, true /* cacheFlush */, 0L /* ttlMillis */,
+                listOf(MdnsServiceInfo.TextEntry.fromString("somedifferent=entry")))
+        // Set InetAddress record.
+        response.addInet4AddressRecord(MdnsInetAddressRecord(hostName.split(".").toTypedArray(),
+                testElapsedRealtime, true /* cacheFlush */,
+                0L /* ttlMillis */, InetAddresses.parseNumericAddress(v4Address)))
+        response.addInet6AddressRecord(MdnsInetAddressRecord(hostName.split(".").toTypedArray(),
+                testElapsedRealtime, true /* cacheFlush */,
+                0L /* ttlMillis */, InetAddresses.parseNumericAddress(v6Address)))
+
+        // Convert a MdnsResponse to a MdnsServiceInfo
+        val serviceInfo = MdnsUtils.buildMdnsServiceInfoFromResponse(
+                response, serviceType.split(".").toTypedArray(), testElapsedRealtime)
+
+        assertEquals(serviceInstanceName, serviceInfo.serviceInstanceName)
+        assertArrayEquals(serviceType.split(".").toTypedArray(), serviceInfo.serviceType)
+        assertArrayEquals(hostName.split(".").toTypedArray(), serviceInfo.hostName)
+        assertEquals(port, serviceInfo.port)
+        assertEquals(1, serviceInfo.ipv4Addresses.size)
+        assertEquals(v4Address, serviceInfo.ipv4Addresses[0])
+        assertEquals(1, serviceInfo.ipv6Addresses.size)
+        assertEquals(v6Address, serviceInfo.ipv6Addresses[0])
+        assertEquals(interfaceIndex, serviceInfo.interfaceIndex)
+        assertEquals(null, serviceInfo.network)
+        assertEquals(mapOf("somedifferent" to "entry"),
+                serviceInfo.attributes)
+    }
 }