Add MdnsAnyRecord

The record is useful for mDNS questions in mDNS probes.

Bug: 241738458
Test: atest
Change-Id: I0f8e659048b6e1d7c3ae1640fbd2d57d723ea9b1
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsAnyRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsAnyRecord.java
new file mode 100644
index 0000000..fcfe9f7
--- /dev/null
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsAnyRecord.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.net.DnsResolver;
+
+import java.io.IOException;
+
+/**
+ * A mDNS "ANY" record, used in mDNS questions to query for any record type.
+ */
+public class MdnsAnyRecord extends MdnsRecord {
+
+    protected MdnsAnyRecord(String[] name, MdnsPacketReader reader) throws IOException {
+        super(name, TYPE_ANY, reader, true /* isQuestion */);
+    }
+
+    protected MdnsAnyRecord(String[] name, boolean unicast) {
+        super(name, TYPE_ANY, DnsResolver.CLASS_IN /* cls */,
+                0L /* receiptTimeMillis */, unicast /* cacheFlush */, 0L /* ttlMillis */);
+    }
+
+    @Override
+    protected void readData(MdnsPacketReader reader) throws IOException {
+        // No data to read
+    }
+
+    @Override
+    protected void writeData(MdnsPacketWriter writer) throws IOException {
+        // No data to write
+    }
+}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
index 7c802e6..c0481a4 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
@@ -39,6 +39,7 @@
     public static final int TYPE_PTR = 0x000C;
     public static final int TYPE_SRV = 0x0021;
     public static final int TYPE_TXT = 0x0010;
+    public static final int TYPE_ANY = 0x00ff;
 
     private static final int FLAG_CACHE_FLUSH = 0x8000;
 
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
index 9fc4674..9746a35 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTests.java
@@ -79,14 +79,7 @@
         Inet4Address addr = record.getInet4Address();
         assertEquals("/10.1.2.3", addr.toString());
 
-        // Encode
-        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
-        record.write(writer, record.getReceiptTime());
-
-        packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
-        byte[] dataOut = packet.getData();
-
-        String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
+        String dataOutText = toHex(record);
         Log.d(TAG, dataOutText);
 
         assertEquals(dataInText, dataOutText);
@@ -123,14 +116,7 @@
         Inet6Address addr = record.getInet6Address();
         assertEquals("/aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040", addr.toString());
 
-        // Encode
-        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
-        record.write(writer, record.getReceiptTime());
-
-        packet = writer.getPacket(MULTICAST_IPV6_ADDRESS);
-        byte[] dataOut = packet.getData();
-
-        String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
+        String dataOutText = toHex(record);
         Log.d(TAG, dataOutText);
 
         assertEquals(dataInText, dataOutText);
@@ -167,14 +153,7 @@
         Inet4Address addr = record.getInet4Address();
         assertEquals("/16.32.48.64", addr.toString());
 
-        // Encode
-        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
-        record.write(writer, record.getReceiptTime());
-
-        packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
-        byte[] dataOut = packet.getData();
-
-        String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
+        String dataOutText = toHex(record);
         Log.d(TAG, dataOutText);
 
         final byte[] expectedDataIn =
@@ -215,14 +194,7 @@
         assertFalse(record.hasSubtype());
         assertNull(record.getSubtype());
 
-        // Encode
-        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
-        record.write(writer, record.getReceiptTime());
-
-        packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
-        byte[] dataOut = packet.getData();
-
-        String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
+        String dataOutText = toHex(record);
         Log.d(TAG, dataOutText);
 
         assertEquals(dataInText, dataOutText);
@@ -263,14 +235,35 @@
         assertEquals(1, record.getServicePriority());
         assertEquals(255, record.getServiceWeight());
 
-        // Encode
-        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
-        record.write(writer, record.getReceiptTime());
+        String dataOutText = toHex(record);
+        Log.d(TAG, dataOutText);
 
-        packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
-        byte[] dataOut = packet.getData();
+        assertEquals(dataInText, dataOutText);
+    }
 
-        String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
+    @Test
+    public void testAnyRecord() throws IOException {
+        final byte[] dataIn = HexDump.hexStringToByteArray(
+                "047465737407616E64726F696403636F6D0000FF0001000000000000");
+        assertNotNull(dataIn);
+        String dataInText = HexDump.dumpHexString(dataIn, 0, dataIn.length);
+
+        // Decode
+        DatagramPacket packet = new DatagramPacket(dataIn, dataIn.length);
+        MdnsPacketReader reader = new MdnsPacketReader(packet);
+
+        String[] name = reader.readLabels();
+        assertNotNull(name);
+        assertEquals(3, name.length);
+        String fqdn = MdnsRecord.labelsToString(name);
+        assertEquals("test.android.com", fqdn);
+
+        int type = reader.readUInt16();
+        assertEquals(MdnsRecord.TYPE_ANY, type);
+
+        MdnsAnyRecord record = new MdnsAnyRecord(name, reader);
+
+        String dataOutText = toHex(record);
         Log.d(TAG, dataOutText);
 
         assertEquals(dataInText, dataOutText);
@@ -320,19 +313,23 @@
         assertEquals(new TextEntry("b", "1234567890"), entries.get(1));
         assertEquals(new TextEntry("xyz", "!@#$"), entries.get(2));
 
-        // Encode
-        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
-        record.write(writer, record.getReceiptTime());
-
-        packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
-        byte[] dataOut = packet.getData();
-
-        String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
+        String dataOutText = toHex(record);
         Log.d(TAG, dataOutText);
 
         assertEquals(dataInText, dataOutText);
     }
 
+    private static String toHex(MdnsRecord record) throws IOException {
+        MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
+        record.write(writer, record.getReceiptTime());
+
+        // The address does not matter as only the data is used
+        final DatagramPacket packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
+        final byte[] dataOut = packet.getData();
+
+        return HexDump.dumpHexString(dataOut, 0, packet.getLength());
+    }
+
     @Test
     public void textRecord_recordDoesNotHaveDataOfGivenLength_throwsEOFException()
             throws Exception {