Merge "Use case-insensitive matching in discovery/advertising" am: c61c5788fe

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2579727

Change-Id: I0593e891887d6b0fbef30c476e2493e60392c77b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
index cc08ea1..5f27b6a 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -253,8 +253,9 @@
         int getConflictingService(@NonNull NsdServiceInfo info) {
             for (int i = 0; i < mPendingRegistrations.size(); i++) {
                 final NsdServiceInfo other = mPendingRegistrations.valueAt(i).getServiceInfo();
-                if (info.getServiceName().equals(other.getServiceName())
-                        && info.getServiceType().equals(other.getServiceType())) {
+                if (MdnsUtils.equalsIgnoreDnsCase(info.getServiceName(), other.getServiceName())
+                        && MdnsUtils.equalsIgnoreDnsCase(info.getServiceType(),
+                        other.getServiceType())) {
                     return mPendingRegistrations.keyAt(i);
                 }
             }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
index 2281c81..c7b93e5 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -30,6 +30,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.SharedLog;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -56,21 +57,26 @@
 
         public void put(@NonNull String serviceType, @Nullable Network network,
                 @NonNull MdnsServiceTypeClient client) {
-            final Pair<String, Network> perNetworkServiceType = new Pair<>(serviceType, network);
+            final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType);
+            final Pair<String, Network> perNetworkServiceType = new Pair<>(dnsLowerServiceType,
+                    network);
             clients.put(perNetworkServiceType, client);
         }
 
         @Nullable
         public MdnsServiceTypeClient get(@NonNull String serviceType, @Nullable Network network) {
-            final Pair<String, Network> perNetworkServiceType = new Pair<>(serviceType, network);
+            final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType);
+            final Pair<String, Network> perNetworkServiceType = new Pair<>(dnsLowerServiceType,
+                    network);
             return clients.getOrDefault(perNetworkServiceType, null);
         }
 
         public List<MdnsServiceTypeClient> getByServiceType(@NonNull String serviceType) {
+            final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType);
             final List<MdnsServiceTypeClient> list = new ArrayList<>();
             for (int i = 0; i < clients.size(); i++) {
                 final Pair<String, Network> perNetworkServiceType = clients.keyAt(i);
-                if (serviceType.equals(perNetworkServiceType.first)) {
+                if (dnsLowerServiceType.equals(perNetworkServiceType.first)) {
                     list.add(clients.valueAt(i));
                 }
             }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java
index 6ec2f99..1239180 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java
@@ -20,6 +20,7 @@
 import android.text.TextUtils;
 
 import com.android.net.module.util.CollectionUtils;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -152,7 +153,8 @@
     @Override
     public int hashCode() {
         return Objects.hash(super.hashCode(),
-                Arrays.hashCode(mNextDomain), Arrays.hashCode(mTypes));
+                Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(mNextDomain)),
+                Arrays.hashCode(mTypes));
     }
 
     @Override
@@ -165,7 +167,8 @@
         }
 
         return super.equals(other)
-                && Arrays.equals(mNextDomain, ((MdnsNsecRecord) other).mNextDomain)
+                && MdnsUtils.equalsDnsLabelIgnoreDnsCase(mNextDomain,
+                ((MdnsNsecRecord) other).mNextDomain)
                 && Arrays.equals(mTypes, ((MdnsNsecRecord) other).mTypes);
     }
 }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java
index c0f9b8b..6879a64 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java
@@ -17,11 +17,11 @@
 package com.android.server.connectivity.mdns;
 
 import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.SocketAddress;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -180,7 +180,7 @@
             int existingOffset = entry.getKey();
             String[] existingLabels = entry.getValue();
 
-            if (Arrays.equals(existingLabels, labels)) {
+            if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(existingLabels, labels)) {
                 writePointer(existingOffset);
                 return;
             } else if (MdnsRecord.labelsAreSuffix(existingLabels, labels)) {
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java
index 2c7b26b..c88ead0 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -60,7 +61,8 @@
     }
 
     public boolean hasSubtype() {
-        return (name != null) && (name.length > 2) && name[1].equals(MdnsConstants.SUBTYPE_LABEL);
+        return (name != null) && (name.length > 2) && MdnsUtils.equalsIgnoreDnsCase(name[1],
+                MdnsConstants.SUBTYPE_LABEL);
     }
 
     public String getSubtype() {
@@ -74,7 +76,7 @@
 
     @Override
     public int hashCode() {
-        return (super.hashCode() * 31) + Arrays.hashCode(pointer);
+        return (super.hashCode() * 31) + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(pointer));
     }
 
     @Override
@@ -86,6 +88,7 @@
             return false;
         }
 
-        return super.equals(other) && Arrays.equals(pointer, ((MdnsPointerRecord) other).pointer);
+        return super.equals(other) && MdnsUtils.equalsDnsLabelIgnoreDnsCase(pointer,
+                ((MdnsPointerRecord) other).pointer);
     }
 }
\ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
index 669b323..ecf846e 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
@@ -21,9 +21,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.CollectionUtils;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -113,7 +113,8 @@
          */
         private static boolean containsName(@NonNull List<MdnsRecord> records,
                 @NonNull String[] name) {
-            return CollectionUtils.any(records, r -> Arrays.equals(name, r.getName()));
+            return CollectionUtils.any(records,
+                    r -> MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, r.getName()));
         }
     }
 
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java
index 19630e3..28bd1b4 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java
@@ -24,6 +24,7 @@
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -136,7 +137,7 @@
         }
 
         for (int i = 0; i < list1.length; ++i) {
-            if (!list1[i].equals(list2[i + offset])) {
+            if (!MdnsUtils.equalsIgnoreDnsCase(list1[i], list2[i + offset])) {
                 return false;
             }
         }
@@ -271,12 +272,13 @@
 
         MdnsRecord otherRecord = (MdnsRecord) other;
 
-        return Arrays.equals(name, otherRecord.name) && (type == otherRecord.type);
+        return MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, otherRecord.name) && (type
+                == otherRecord.type);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(Arrays.hashCode(name), type);
+        return Objects.hash(Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(name)), type);
     }
 
     /**
@@ -297,7 +299,7 @@
 
         public Key(int recordType, String[] recordName) {
             this.recordType = recordType;
-            this.recordName = recordName;
+            this.recordName = MdnsUtils.toDnsLabelsLowerCase(recordName);
         }
 
         @Override
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
index f756459..1375279 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
@@ -30,6 +30,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.HexDump;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.net.Inet4Address;
@@ -329,7 +330,8 @@
     private int getServiceByName(@NonNull String serviceName) {
         for (int i = 0; i < mServices.size(); i++) {
             final ServiceRegistration registration = mServices.valueAt(i);
-            if (serviceName.equals(registration.serviceInfo.getServiceName())) {
+            if (MdnsUtils.equalsIgnoreDnsCase(serviceName,
+                    registration.serviceInfo.getServiceName())) {
                 return mServices.keyAt(i);
             }
         }
@@ -545,7 +547,9 @@
              must match the question qtype unless the qtype is "ANY" (255) or the rrtype is
              "CNAME" (5), and the record rrclass must match the question qclass unless the
              qclass is "ANY" (255) */
-            if (!Arrays.equals(info.record.getName(), question.getName())) continue;
+            if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(info.record.getName(), question.getName())) {
+                continue;
+            }
             hasFullyOwnedNameMatch |= !info.isSharedName;
 
             // The repository does not store CNAME records
@@ -747,7 +751,10 @@
                 // happens. In fact probing is only done for the service name in the SRV record.
                 // This means only SRV and TXT records need to be checked.
                 final RecordInfo<MdnsServiceRecord> srvRecord = registration.srvRecord;
-                if (!Arrays.equals(record.getName(), srvRecord.record.getName())) continue;
+                if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(record.getName(),
+                        srvRecord.record.getName())) {
+                    continue;
+                }
 
                 // As per RFC6762 9., it's fine if the "conflict" is an identical record with same
                 // data.
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
index e0100f6..28aa640 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java
@@ -21,10 +21,10 @@
 import android.net.Network;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -103,7 +103,7 @@
      * pointer record is already present in the response with the same TTL.
      */
     public synchronized boolean addPointerRecord(MdnsPointerRecord pointerRecord) {
-        if (!Arrays.equals(serviceName, pointerRecord.getPointer())) {
+        if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceName, pointerRecord.getPointer())) {
             throw new IllegalArgumentException(
                     "Pointer records for different service names cannot be added");
         }
@@ -301,13 +301,13 @@
         boolean dropAddressRecords = false;
 
         for (MdnsInetAddressRecord inetAddressRecord : getInet4AddressRecords()) {
-            if (!Arrays.equals(
+            if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(
                     this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
                 dropAddressRecords = true;
             }
         }
         for (MdnsInetAddressRecord inetAddressRecord : getInet6AddressRecords()) {
-            if (!Arrays.equals(
+            if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(
                     this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
                 dropAddressRecords = true;
             }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
index 129db7e..77b5c58 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -23,10 +23,10 @@
 import android.util.ArraySet;
 
 import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.EOFException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
@@ -50,7 +50,7 @@
             List<MdnsResponse> responses, String[] pointer) {
         if (responses != null) {
             for (MdnsResponse response : responses) {
-                if (Arrays.equals(response.getServiceName(), pointer)) {
+                if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(response.getServiceName(), pointer)) {
                     return response;
                 }
             }
@@ -66,7 +66,8 @@
                 if (serviceRecord == null) {
                     continue;
                 }
-                if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) {
+                if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(),
+                        hostName)) {
                     return response;
                 }
             }
@@ -164,11 +165,8 @@
         for (MdnsRecord record : records) {
             if (record instanceof MdnsPointerRecord) {
                 String[] name = record.getName();
-                if ((serviceType == null)
-                        || Arrays.equals(name, serviceType)
-                        || ((name.length == (serviceType.length + 2))
-                        && name[1].equals(MdnsConstants.SUBTYPE_LABEL)
-                        && MdnsRecord.labelsAreSuffix(serviceType, name))) {
+                if ((serviceType == null) || MdnsUtils.typeEqualsOrIsSubtype(
+                        serviceType, name)) {
                     MdnsPointerRecord pointerRecord = (MdnsPointerRecord) record;
                     // Group PTR records that refer to the same service instance name into a single
                     // response.
@@ -296,7 +294,7 @@
             if (serviceRecord == null) {
                 continue;
             }
-            if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) {
+            if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(), hostName)) {
                 if (result == null) {
                     result = new ArrayList<>(/* initialCapacity= */ responses.size());
                 }
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java
index ebd8b77..f851b35 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.util.MdnsUtils;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -142,7 +143,8 @@
     @Override
     public int hashCode() {
         return (super.hashCode() * 31)
-                + Objects.hash(servicePriority, serviceWeight, Arrays.hashCode(serviceHost),
+                + Objects.hash(servicePriority, serviceWeight,
+                Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(serviceHost)),
                 servicePort);
     }
 
@@ -159,7 +161,7 @@
         return super.equals(other)
                 && (servicePriority == otherRecord.servicePriority)
                 && (serviceWeight == otherRecord.serviceWeight)
-                && Arrays.equals(serviceHost, otherRecord.serviceHost)
+                && MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceHost, otherRecord.serviceHost)
                 && (servicePort == otherRecord.servicePort);
     }
 }
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 5cc789f..63d1a50 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
@@ -21,6 +21,9 @@
 import android.net.Network;
 import android.os.Handler;
 
+import com.android.server.connectivity.mdns.MdnsConstants;
+import com.android.server.connectivity.mdns.MdnsRecord;
+
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
@@ -50,6 +53,17 @@
     }
 
     /**
+     * Convert the array of labels to DNS case-insensitive lowercase.
+     */
+    public static String[] toDnsLabelsLowerCase(@NonNull String[] labels) {
+        final String[] outStrings = new String[labels.length];
+        for (int i = 0; i < labels.length; ++i) {
+            outStrings[i] = toDnsLowerCase(labels[i]);
+        }
+        return outStrings;
+    }
+
+    /**
      * Compare two strings by DNS case-insensitive lowercase.
      */
     public static boolean equalsIgnoreDnsCase(@NonNull String a, @NonNull String b) {
@@ -62,6 +76,39 @@
         return true;
     }
 
+    /**
+     * Compare two set of DNS labels by DNS case-insensitive lowercase.
+     */
+    public static boolean equalsDnsLabelIgnoreDnsCase(@NonNull String[] a, @NonNull String[] b) {
+        if (a == b) {
+            return true;
+        }
+        int length = a.length;
+        if (b.length != length) {
+            return false;
+        }
+        for (int i = 0; i < length; i++) {
+            if (!equalsIgnoreDnsCase(a[i], b[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Compare labels a equals b or a is suffix of b.
+     *
+     * @param a the type or subtype.
+     * @param b the base type
+     */
+    public static boolean typeEqualsOrIsSubtype(@NonNull String[] a,
+            @NonNull String[] b) {
+        return MdnsUtils.equalsDnsLabelIgnoreDnsCase(a, b)
+                || ((b.length == (a.length + 2))
+                && MdnsUtils.equalsIgnoreDnsCase(b[1], MdnsConstants.SUBTYPE_LABEL)
+                && MdnsRecord.labelsAreSuffix(a, b));
+    }
+
     private static char toDnsLowerCase(char a) {
         return a >= 'A' && a <= 'Z' ? (char) (a + ('a' - 'A')) : a;
     }
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
index b539fe0..d9acc61 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
@@ -51,6 +51,7 @@
 private const val SERVICE_ID_2 = 2
 private const val LONG_SERVICE_ID_1 = 3
 private const val LONG_SERVICE_ID_2 = 4
+private const val CASE_INSENSITIVE_TEST_SERVICE_ID = 5
 private const val TIMEOUT_MS = 10_000L
 private val TEST_ADDR = parseNumericAddress("2001:db8::123")
 private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */)
@@ -78,6 +79,13 @@
     network = null
 }
 
+private val ALL_NETWORKS_SERVICE_2 =
+    NsdServiceInfo("TESTSERVICENAME", "_ADVERTISERTEST._tcp").apply {
+        port = 12345
+        hostAddresses = listOf(TEST_ADDR)
+        network = null
+    }
+
 private val LONG_ALL_NETWORKS_SERVICE =
     NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply {
         port = 12345
@@ -228,6 +236,9 @@
         postSync { advertiser.addService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE,
                 null /* subtype */) }
 
+        postSync { advertiser.addService(CASE_INSENSITIVE_TEST_SERVICE_ID, ALL_NETWORKS_SERVICE_2,
+                null /* subtype */) }
+
         // Callbacks for matching network and all networks both get the socket
         postSync {
             oneNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR))
@@ -249,6 +260,14 @@
             network = LONG_ALL_NETWORKS_SERVICE.network
         }
 
+        val expectedCaseInsensitiveRenamed = NsdServiceInfo(
+            "${ALL_NETWORKS_SERVICE_2.serviceName} (3)", ALL_NETWORKS_SERVICE_2.serviceType
+        ).apply {
+            port = ALL_NETWORKS_SERVICE_2.port
+            hostAddresses = ALL_NETWORKS_SERVICE_2.hostAddresses
+            network = ALL_NETWORKS_SERVICE_2.network
+        }
+
         val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
         verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
                 eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any()
@@ -261,6 +280,8 @@
                 argThat { it.matches(LONG_SERVICE_1) }, eq(null))
         verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2),
             argThat { it.matches(expectedLongRenamed) }, eq(null))
+        verify(mockInterfaceAdvertiser1).addService(eq(CASE_INSENSITIVE_TEST_SERVICE_ID),
+            argThat { it.matches(expectedCaseInsensitiveRenamed) }, eq(null))
 
         doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
         postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt
index 5c9c294..a545373 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt
@@ -31,7 +31,7 @@
     @Test
     fun testNameCompression() {
         val writer = MdnsPacketWriter(ByteArray(1000))
-        writer.writeLabels(arrayOf("my", "first", "name"))
+        writer.writeLabels(arrayOf("my", "FIRST", "name"))
         writer.writeLabels(arrayOf("my", "second", "name"))
         writer.writeLabels(arrayOf("other", "first", "name"))
         writer.writeLabels(arrayOf("my", "second", "name"))
@@ -41,7 +41,7 @@
                 InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::123"), 123))
 
         // Each label takes length + 1. So "first.name" offset = 3, "name" offset = 9
-        val expected = "my".label() + "first".label() + "name".label() + 0x00.toByte() +
+        val expected = "my".label() + "FIRST".label() + "name".label() + 0x00.toByte() +
                 // "my.second.name" offset = 15
                 "my".label() + "second".label() + byteArrayOf(0xC0.toByte(), 9) +
                 "other".label() + byteArrayOf(0xC0.toByte(), 3) +
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
index 2b5423b..0a8d78d 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
@@ -48,6 +48,7 @@
 
 private val TEST_SERVICE_NAME_1 = arrayOf("testservice", "_nmt", "_tcp", "local")
 private val TEST_SERVICE_NAME_2 = arrayOf("testservice2", "_nmt", "_tcp", "local")
+private val TEST_SERVICE_NAME_3 = arrayOf("Testservice", "_nmt", "_tcp", "local")
 
 @RunWith(DevSdkIgnoreRunner::class)
 @IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -129,6 +130,15 @@
     }
 
     @Test
+    fun testCreateProberCaseInsensitive() {
+        val probeInfo = TestProbeInfo(
+            listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890),
+                makeServiceRecord(TEST_SERVICE_NAME_2, 37890),
+                makeServiceRecord(TEST_SERVICE_NAME_3, 37890)))
+        assertEquals(2, probeInfo.getPacket(0).questions.size)
+    }
+
+    @Test
     fun testProbeMultipleRecords() {
         val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
         val prober = TestProber(thread.looper, replySender, cb)
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
index 4a39b93..0033b5a 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
@@ -43,6 +43,7 @@
 
 private const val TEST_SERVICE_ID_1 = 42
 private const val TEST_SERVICE_ID_2 = 43
+private const val TEST_SERVICE_ID_3 = 44
 private const val TEST_PORT = 12345
 private const val TEST_SUBTYPE = "_subtype"
 private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local")
@@ -63,6 +64,12 @@
     port = TEST_PORT
 }
 
+private val TEST_SERVICE_3 = NsdServiceInfo().apply {
+    serviceType = "_TESTSERVICE._tcp"
+    serviceName = "MyTESTSERVICE"
+    port = TEST_PORT
+}
+
 @RunWith(DevSdkIgnoreRunner::class)
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
 class MdnsRecordRepositoryTest {
@@ -124,6 +131,9 @@
         assertFailsWith(NameConflictException::class) {
             repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1, null /* subtype */)
         }
+        assertFailsWith(NameConflictException::class) {
+            repository.addService(TEST_SERVICE_ID_3, TEST_SERVICE_3, null /* subtype */)
+        }
     }
 
     @Test
@@ -365,6 +375,27 @@
     }
 
     @Test
+    fun testGetReplyCaseInsensitive() {
+        val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
+        repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+        val questionsCaseInSensitive =
+            listOf(MdnsPointerRecord(arrayOf("_TESTSERVICE", "_TCP", "local"),
+                0L /* receiptTimeMillis */,
+                false /* cacheFlush */,
+                // TTL and data is empty for a question
+                0L /* ttlMillis */,
+                null /* pointer */))
+        val queryCaseInsensitive = MdnsPacket(0 /* flags */, questionsCaseInSensitive,
+            listOf() /* answers */, listOf() /* authorityRecords */,
+            listOf() /* additionalRecords */)
+        val src = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353)
+        val replyCaseInsensitive = repository.getReply(queryCaseInsensitive, src)
+        assertNotNull(replyCaseInsensitive)
+        assertEquals(1, replyCaseInsensitive.answers.size)
+        assertEquals(7, replyCaseInsensitive.additionalAnswers.size)
+    }
+
+    @Test
     fun testGetReply() {
         doGetReplyTest(subtype = null)
     }
@@ -490,6 +521,34 @@
     }
 
     @Test
+    fun testGetConflictingServicesCaseInsensitive() {
+        val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
+        repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */)
+        repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */)
+
+        val packet = MdnsPacket(
+            0 /* flags */,
+            emptyList() /* questions */,
+            listOf(
+                MdnsServiceRecord(
+                    arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"),
+                    0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */,
+                    0 /* servicePriority */, 0 /* serviceWeight */,
+                    TEST_SERVICE_1.port + 1,
+                    TEST_HOSTNAME),
+                MdnsTextRecord(
+                    arrayOf("MYOTHERTESTSERVICE", "_TESTSERVICE", "_tcp", "local"),
+                    0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */,
+                    listOf(TextEntry.fromString("somedifferent=entry"))),
+            ) /* answers */,
+            emptyList() /* authorityRecords */,
+            emptyList() /* additionalRecords */)
+
+        assertEquals(setOf(TEST_SERVICE_ID_1, TEST_SERVICE_ID_2),
+            repository.getConflictingServices(packet))
+    }
+
+    @Test
     fun testGetConflictingServices_IdenticalService() {
         val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
         repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */)
@@ -505,7 +564,7 @@
                                 0L /* receiptTimeMillis */, true /* cacheFlush */,
                                 otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */,
                                 TEST_SERVICE_1.port,
-                                TEST_HOSTNAME),
+                                arrayOf("ANDROID_000102030405060708090A0B0C0D0E0F", "local")),
                         MdnsTextRecord(
                                 arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"),
                                 0L /* receiptTimeMillis */, true /* cacheFlush */,
@@ -517,6 +576,35 @@
         // Above records are identical to the actual registrations: no conflict
         assertEquals(emptySet(), repository.getConflictingServices(packet))
     }
+
+    @Test
+    fun testGetConflictingServicesCaseInsensitive_IdenticalService() {
+        val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
+        repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */)
+        repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */)
+
+        val otherTtlMillis = 1234L
+        val packet = MdnsPacket(
+                0 /* flags */,
+                emptyList() /* questions */,
+                listOf(
+                        MdnsServiceRecord(
+                                arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"),
+                                0L /* receiptTimeMillis */, true /* cacheFlush */,
+                                otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */,
+                                TEST_SERVICE_1.port,
+                                TEST_HOSTNAME),
+                        MdnsTextRecord(
+                                arrayOf("MyOtherTestService", "_TESTSERVICE", "_tcp", "local"),
+                                0L /* receiptTimeMillis */, true /* cacheFlush */,
+                                otherTtlMillis, emptyList()),
+                ) /* answers */,
+                emptyList() /* authorityRecords */,
+                emptyList() /* additionalRecords */)
+
+        // Above records are identical to the actual registrations: no conflict
+        assertEquals(emptySet(), repository.getConflictingServices(packet))
+    }
 }
 
 private fun MdnsRecordRepository.initWithService(
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt
new file mode 100644
index 0000000..8f819b7
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.mdns
+
+import android.os.Build
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
+class MdnsRecordTest {
+
+    @Test
+    fun testPointerRecordHasSubType() {
+        val ptrRecord1 = MdnsPointerRecord(
+            arrayOf("_testtype", "_sub", "_tcp", "local"),
+            0L /* receiptTimeMillis */,
+            false /* cacheFlush */,
+            4500000 /* ttlMillis */,
+            arrayOf("testservice", "_testtype", "_tcp", "local")
+        )
+        val ptrRecord2 = MdnsPointerRecord(
+            arrayOf("_testtype", "_SUB", "_tcp", "local"),
+            0L /* receiptTimeMillis */,
+            false /* cacheFlush */,
+            4500000 /* ttlMillis */,
+            arrayOf("testservice", "_testtype", "_tcp", "local")
+        )
+        assertTrue(ptrRecord1.hasSubtype())
+        assertTrue(ptrRecord2.hasSubtype())
+    }
+
+    @Test
+    fun testEqualsCaseInsensitive() {
+        val ptrRecord1 = MdnsPointerRecord(
+            arrayOf("_testtype", "_tcp", "local"),
+            0L /* receiptTimeMillis */,
+            false /* cacheFlush */,
+            4500000 /* ttlMillis */,
+            arrayOf("testservice", "_testtype", "_tcp", "local")
+            )
+        val ptrRecord2 = MdnsPointerRecord(
+            arrayOf("_testType", "_tcp", "local"),
+            0L /* receiptTimeMillis */,
+            false /* cacheFlush */,
+            4500000 /* ttlMillis */,
+            arrayOf("testsErvice", "_testtype", "_Tcp", "local")
+        )
+        assertEquals(ptrRecord1, ptrRecord2)
+        assertEquals(ptrRecord1.hashCode(), ptrRecord2.hashCode())
+
+        val srvRecord1 = MdnsServiceRecord(
+            arrayOf("testservice", "_testtype", "_tcp", "local"),
+            123 /* receiptTimeMillis */,
+            false /* cacheFlush */,
+            2000 /* ttlMillis */,
+            0 /* servicePriority */,
+            0 /* serviceWeight */,
+            80 /* port */,
+            arrayOf("hostname")
+        )
+        val srvRecord2 = MdnsServiceRecord(
+            arrayOf("Testservice", "_testtype", "_tcp", "local"),
+            123 /* receiptTimeMillis */,
+            false /* cacheFlush */,
+            2000 /* ttlMillis */,
+            0 /* servicePriority */,
+            0 /* serviceWeight */,
+            80 /* port */,
+            arrayOf("Hostname")
+        )
+        assertEquals(srvRecord1, srvRecord2)
+        assertEquals(srvRecord1.hashCode(), srvRecord2.hashCode())
+
+        val nsecRecord1 = MdnsNsecRecord(
+            arrayOf("hostname"),
+            0L /* receiptTimeMillis */,
+            true /* cacheFlush */,
+            2000L, /* ttlMillis */
+            arrayOf("hostname"),
+            intArrayOf(1, 2, 3) /* types */
+        )
+        val nsecRecord2 = MdnsNsecRecord(
+            arrayOf("HOSTNAME"),
+            0L /* receiptTimeMillis */,
+            true /* cacheFlush */,
+            2000L, /* ttlMillis */
+            arrayOf("HOSTNAME"),
+            intArrayOf(1, 2, 3) /* types */
+        )
+        assertEquals(nsecRecord1, nsecRecord2)
+        assertEquals(nsecRecord1.hashCode(), nsecRecord2.hashCode())
+    }
+
+    @Test
+    fun testLabelsAreSuffix() {
+        val labels1 = arrayOf("a", "b", "c")
+        val labels2 = arrayOf("B", "C")
+        val labels3 = arrayOf("b", "c")
+        val labels4 = arrayOf("b", "d")
+        assertTrue(MdnsRecord.labelsAreSuffix(labels2, labels1))
+        assertTrue(MdnsRecord.labelsAreSuffix(labels3, labels1))
+        assertFalse(MdnsRecord.labelsAreSuffix(labels4, labels1))
+    }
+}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
index b0a1f18..e16c448 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java
@@ -269,14 +269,9 @@
         assertEquals("st=0", textStrings.get(6));
     }
 
-    @Test
-    public void testDecodeIPv6AnswerPacket() throws IOException {
-        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
-        assertNotNull(data6);
-
-        responses = decode(decoder, data6);
-        assertEquals(1, responses.size());
-        MdnsResponse response = responses.valueAt(0);
+    private void verifyResponse(ArraySet<MdnsResponse> responseArraySet) {
+        assertEquals(1, responseArraySet.size());
+        MdnsResponse response = responseArraySet.valueAt(0);
         assertTrue(response.isComplete());
 
         MdnsInetAddressRecord inet6AddressRecord = response.getInet6AddressRecord();
@@ -290,6 +285,22 @@
     }
 
     @Test
+    public void testDecodeIPv6AnswerPacket() throws IOException {
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
+        assertNotNull(data6);
+        verifyResponse(decode(decoder, data6));
+    }
+
+    @Test
+    public void testDecodeCaseInsensitiveMatch() throws IOException {
+        final String[] castServiceTypeUpperCase =
+                new String[] {"_GOOGLECAST", "_TCP", "LOCAL"};
+        MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, castServiceTypeUpperCase);
+        assertNotNull(data6);
+        verifyResponse(decode(decoder, data6));
+    }
+
+    @Test
     public void testIsComplete() {
         MdnsResponse response = new MdnsResponse(responses.valueAt(0));
         assertTrue(response.isComplete());
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
index 3f5e7a1..dc0e646 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java
@@ -228,6 +228,12 @@
         final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS);
 
         assertFalse(response.addPointerRecord(response.getPointerRecords().get(0)));
+        final String[] serviceName = new String[] { "MYSERVICE", "_TYPE", "_tcp", "local" };
+        final String[] serviceType = new String[] { "_TYPE", "_tcp", "local" };
+        MdnsPointerRecord pointerRecordCaseInsensitive =
+                new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */,
+                        false /* cacheFlush */, TEST_TTL_MS, serviceName);
+        assertFalse(response.addPointerRecord(pointerRecordCaseInsensitive));
         assertFalse(response.addInet6AddressRecord(response.getInet6AddressRecord()));
         assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord()));
         assertFalse(response.setServiceRecord(response.getServiceRecord()));
@@ -270,4 +276,30 @@
         // All records were replaced, not added
         assertEquals(ttlZeroResponse.getRecords().size(), response.getRecords().size());
     }
+
+    @Test
+    public void dropUnmatchedAddressRecords_caseInsensitive() {
+
+        final String[] hostname = new String[] { "MyHostname" };
+        final String[] upperCaseHostName = new String[] { "MYHOSTNAME" };
+        final String[] serviceName = new String[] { "MyService", "_type", "_tcp", "local" };
+        final String[] serviceType = new String[] { "_type", "_tcp", "local" };
+        final MdnsResponse response = new MdnsResponse(/* now= */ 0, serviceName, INTERFACE_INDEX,
+                mNetwork);
+        response.addPointerRecord(new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */,
+                false /* cacheFlush */, TEST_TTL_MS, serviceName));
+        response.setServiceRecord(new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */,
+                true /* cacheFlush */, TEST_TTL_MS, 0 /* servicePriority */,
+                0 /* serviceWeight */, 0 /* servicePort */, hostname));
+        response.setTextRecord(new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */,
+                true /* cacheFlush */, TEST_TTL_MS, emptyList() /* entries */));
+        response.addInet4AddressRecord(new MdnsInetAddressRecord(
+                upperCaseHostName , 0L /* receiptTimeMillis */, true /* cacheFlush */,
+                TEST_TTL_MS, parseNumericAddress("192.0.2.123")));
+        response.addInet6AddressRecord(new MdnsInetAddressRecord(
+                upperCaseHostName, 0L /* receiptTimeMillis */, true /* cacheFlush */,
+                TEST_TTL_MS, parseNumericAddress("2001:db8::123")));
+
+        assertFalse(response.dropUnmatchedAddressRecords());
+    }
 }
\ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
index 4e69f47..42d296b 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -1036,10 +1036,11 @@
         final String otherInstance = "instance2";
         final String ipV4Address = "192.0.2.0";
         final String ipV6Address = "2001:db8::";
+        final String capitalizedRequestInstance = "Instance1";
 
         final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
                 // Use different case in the options
-                .setResolveInstanceName("Instance1").build();
+                .setResolveInstanceName(capitalizedRequestInstance).build();
 
         client.startSendAndReceive(mockListenerOne, resolveOptions);
         client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
@@ -1067,8 +1068,9 @@
                 Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork);
 
         // mockListenerOne gets notified for the requested instance
-        verify(mockListenerOne).onServiceNameDiscovered(matchServiceName(requestedInstance));
-        verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance));
+        verify(mockListenerOne).onServiceNameDiscovered(
+                matchServiceName(capitalizedRequestInstance));
+        verify(mockListenerOne).onServiceFound(matchServiceName(capitalizedRequestInstance));
 
         // ...but does not get any callback for the other instance
         verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
@@ -1079,8 +1081,9 @@
         // mockListenerTwo gets notified for both though
         final InOrder inOrder = inOrder(mockListenerTwo);
         inOrder.verify(mockListenerTwo).onServiceNameDiscovered(
-                matchServiceName(requestedInstance));
-        inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance));
+                matchServiceName(capitalizedRequestInstance));
+        inOrder.verify(mockListenerTwo).onServiceFound(
+                matchServiceName(capitalizedRequestInstance));
 
         inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
         inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
@@ -1179,8 +1182,7 @@
         final String ipV4Address = "192.0.2.0";
 
         final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
-                // Use different case in the options
-                .setResolveInstanceName("Instance1").build();
+                .setResolveInstanceName("instance1").build();
 
         client.startSendAndReceive(mockListenerOne, resolveOptions);
         // Ensure the first task is executed so it schedules a future task
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 61c3a70..f705bcb 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
@@ -17,11 +17,14 @@
 package com.android.server.connectivity.mdns.util
 
 import android.os.Build
+import com.android.server.connectivity.mdns.util.MdnsUtils.equalsDnsLabelIgnoreDnsCase
 import com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase
+import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLabelsLowerCase
 import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase
 import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRunner
+import org.junit.Assert.assertArrayEquals
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -50,6 +53,12 @@
     }
 
     @Test
+    fun testToDnsLabelsLowerCase() {
+        assertArrayEquals(arrayOf("test", "tÉst", "ţést"),
+            toDnsLabelsLowerCase(arrayOf("TeSt", "TÉST", "ţést")))
+    }
+
+    @Test
     fun testEqualsIgnoreDnsCase() {
         assertTrue(equalsIgnoreDnsCase("TEST", "Test"))
         assertTrue(equalsIgnoreDnsCase("TEST", "test"))
@@ -72,4 +81,25 @@
         assertEquals(truncateServiceName("测试abcde", 7), "测试a")
         assertEquals(truncateServiceName("测试abcde", 100), "测试abcde")
     }
+
+    @Test
+    fun testEqualsLabelIgnoreDnsCase() {
+        assertTrue(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "test")))
+        assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test")))
+        assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("Test"), arrayOf("test", "test")))
+        assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "tést")))
+    }
+
+    @Test
+    fun testTypeEqualsOrIsSubtype() {
+        assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"),
+            arrayOf("_type", "_TCP", "local")))
+        assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"),
+            arrayOf("a", "_SUB", "_type", "_TCP", "local")))
+        assertFalse(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_sub", "_type", "_tcp", "local"),
+                arrayOf("_type", "_TCP", "local")))
+        assertFalse(MdnsUtils.typeEqualsOrIsSubtype(
+                arrayOf("a", "_other", "_type", "_tcp", "local"),
+                arrayOf("a", "_SUB", "_type", "_TCP", "local")))
+    }
 }