Merge "Revert "Send ICMPv6 ping to support IPv6-only network"" into main
diff --git a/netbpfload/loader.cpp b/netbpfload/loader.cpp
index a2fa4b8..52428a3 100644
--- a/netbpfload/loader.cpp
+++ b/netbpfload/loader.cpp
@@ -769,7 +769,7 @@
               .max_entries = max_entries,
               .map_flags = md[i].map_flags,
             };
-            if (isAtLeastKernelVersion(4, 14, 0))
+            if (isAtLeastKernelVersion(4, 15, 0))
                 strlcpy(req.map_name, mapNames[i].c_str(), sizeof(req.map_name));
             fd.reset(bpf(BPF_MAP_CREATE, req));
             saved_errno = errno;
@@ -1012,7 +1012,7 @@
               .log_size = static_cast<__u32>(log_buf.size()),
               .expected_attach_type = cs[i].expected_attach_type,
             };
-            if (isAtLeastKernelVersion(4, 14, 0))
+            if (isAtLeastKernelVersion(4, 15, 0))
                 strlcpy(req.prog_name, cs[i].name.c_str(), sizeof(req.prog_name));
             fd.reset(bpf(BPF_PROG_LOAD, req));
 
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 5ff19ca..eb85110 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
@@ -97,6 +97,8 @@
     @NonNull
     private final Looper mLooper;
     @NonNull
+    private final Dependencies mDeps;
+    @NonNull
     private final String[] mDeviceHostname;
     @NonNull
     private final MdnsFeatureFlags mMdnsFeatureFlags;
@@ -111,6 +113,7 @@
             @NonNull String[] deviceHostname, @NonNull MdnsFeatureFlags mdnsFeatureFlags) {
         mDeviceHostname = deviceHostname;
         mLooper = looper;
+        mDeps = deps;
         mMdnsFeatureFlags = mdnsFeatureFlags;
     }
 
@@ -127,6 +130,10 @@
         public Enumeration<InetAddress> getInterfaceInetAddresses(@NonNull NetworkInterface iface) {
             return iface.getInetAddresses();
         }
+
+        public long elapsedRealTime() {
+            return SystemClock.elapsedRealtime();
+        }
     }
 
     private static class RecordInfo<T extends MdnsRecord> {
@@ -585,7 +592,7 @@
      */
     @Nullable
     public MdnsReplyInfo getReply(MdnsPacket packet, InetSocketAddress src) {
-        final long now = SystemClock.elapsedRealtime();
+        final long now = mDeps.elapsedRealTime();
         final boolean isQuestionOnIpv4 = src.getAddress() instanceof Inet4Address;
 
         // TODO: b/322142420 - Set<RecordInfo<?>> may contain duplicate records wrapped in different
@@ -1326,7 +1333,7 @@
         final ServiceRegistration registration = mServices.get(serviceId);
         if (registration == null) return;
 
-        final long now = SystemClock.elapsedRealtime();
+        final long now = mDeps.elapsedRealTime();
         for (RecordInfo<?> record : registration.allRecords) {
             record.lastSentTimeMs = now;
             record.lastAdvertisedOnIpv4TimeMs = now;
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index ce49533..f9a35fe 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -457,6 +457,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.reflect.Method;
 import java.net.DatagramSocket;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
@@ -19188,6 +19189,25 @@
         verifyClatdStop(null /* inOrder */, MOBILE_IFNAME);
     }
 
-    // Note : adding tests is ConnectivityServiceTest is deprecated, as it is too big for
+    private static final int EXPECTED_TEST_METHOD_COUNT = 332;
+
+    @Test
+    public void testTestMethodCount() {
+        final Class<?> testClass = this.getClass();
+
+        int actualTestMethodCount = 0;
+        for (final Method method : testClass.getDeclaredMethods()) {
+            if (method.isAnnotationPresent(Test.class)) {
+                actualTestMethodCount++;
+            }
+        }
+
+        assertEquals("Adding tests in ConnectivityServiceTest is deprecated, "
+                + "as it is too big for maintenance. Please consider adding new tests "
+                + "in subclasses of CSTest instead.",
+                EXPECTED_TEST_METHOD_COUNT, actualTestMethodCount);
+    }
+
+    // Note : adding tests in ConnectivityServiceTest is deprecated, as it is too big for
     // maintenance. Please consider adding new tests in subclasses of CSTest instead.
 }
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 bdefbf5..f7e0b0e 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
@@ -24,7 +24,6 @@
 import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
 import com.android.server.connectivity.mdns.MdnsInterfaceAdvertiser.CONFLICT_HOST
 import com.android.server.connectivity.mdns.MdnsInterfaceAdvertiser.CONFLICT_SERVICE
-import com.android.server.connectivity.mdns.MdnsProber.ProbingInfo
 import com.android.server.connectivity.mdns.MdnsRecord.TYPE_A
 import com.android.server.connectivity.mdns.MdnsRecord.TYPE_AAAA
 import com.android.server.connectivity.mdns.MdnsRecord.TYPE_PTR
@@ -52,10 +51,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
 
 private const val TEST_SERVICE_ID_1 = 42
 private const val TEST_SERVICE_ID_2 = 43
@@ -132,10 +127,23 @@
     private val deps = object : Dependencies() {
         override fun getInterfaceInetAddresses(iface: NetworkInterface) =
                 Collections.enumeration(TEST_ADDRESSES.map { it.address })
+
+        override fun elapsedRealTime() = now
+
+        fun elapse(duration: Long) {
+            now += duration
+        }
+
+        fun resetElapsedRealTime() {
+            now = 100
+        }
+
+        var now: Long = 100
     }
 
     @Before
     fun setUp() {
+        deps.resetElapsedRealTime();
         thread.start()
     }
 
@@ -1022,13 +1030,14 @@
     }
 
     @Test
-    fun testGetReply_twoIpv4Queries_theSecondReplyIsThrottled() {
+    fun testGetReply_twoIpv4QueriesInOneSecond_theSecondReplyIsThrottled() {
         val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
         repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, setOf(TEST_SUBTYPE))
         val query = makeQuery(TYPE_PTR to arrayOf("_testservice", "_tcp", "local"))
 
         val srcIpv4 = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353)
         val firstReplyIpv4 = repository.getReply(query, srcIpv4)
+        deps.elapse(500L)
         val secondReply = repository.getReply(query, srcIpv4)
 
         assertNotNull(firstReplyIpv4)
@@ -1039,13 +1048,14 @@
 
 
     @Test
-    fun testGetReply_twoIpv6Queries_theSecondReplyIsThrottled() {
+    fun testGetReply_twoIpv6QueriesInOneSecond_theSecondReplyIsThrottled() {
         val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
         repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, setOf(TEST_SUBTYPE))
         val query = makeQuery(TYPE_PTR to arrayOf("_testservice", "_tcp", "local"))
 
         val srcIpv6 = InetSocketAddress(parseNumericAddress("2001:db8::123"), 5353)
         val firstReplyIpv6 = repository.getReply(query, srcIpv6)
+        deps.elapse(500L)
         val secondReply = repository.getReply(query, srcIpv6)
 
         assertNotNull(firstReplyIpv6)
@@ -1055,6 +1065,48 @@
     }
 
     @Test
+    fun testGetReply_twoIpv4QueriesInMoreThanOneSecond_repliesAreNotThrottled() {
+        val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
+        repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, setOf(TEST_SUBTYPE))
+        val query = makeQuery(TYPE_PTR to arrayOf("_testservice", "_tcp", "local"))
+
+        val srcIpv4 = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353)
+        val firstReplyIpv4 = repository.getReply(query, srcIpv4)
+        // The longest possible interval that may make the reply throttled is
+        // 1000 (MIN_MULTICAST_REPLY_INTERVAL_MS) + 120 (delay for shared name) = 1120
+        deps.elapse(1121L)
+        val secondReplyIpv4 = repository.getReply(query, srcIpv4)
+
+        assertNotNull(firstReplyIpv4)
+        assertEquals(MdnsConstants.getMdnsIPv4Address(), firstReplyIpv4.destination.address)
+        assertEquals(MdnsConstants.MDNS_PORT, firstReplyIpv4.destination.port)
+        assertNotNull(secondReplyIpv4)
+        assertEquals(MdnsConstants.getMdnsIPv4Address(), secondReplyIpv4.destination.address)
+        assertEquals(MdnsConstants.MDNS_PORT, secondReplyIpv4.destination.port)
+    }
+
+    @Test
+    fun testGetReply_twoIpv6QueriesInMoreThanOneSecond_repliesAreNotThrottled() {
+        val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
+        repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1, setOf(TEST_SUBTYPE))
+        val query = makeQuery(TYPE_PTR to arrayOf("_testservice", "_tcp", "local"))
+
+        val srcIpv6 = InetSocketAddress(parseNumericAddress("2001:db8::123"), 5353)
+        val firstReplyIpv6 = repository.getReply(query, srcIpv6)
+        // The longest possible interval that may make the reply throttled is
+        // 1000 (MIN_MULTICAST_REPLY_INTERVAL_MS) + 120 (delay for shared name) = 1120
+        deps.elapse(1121L)
+        val secondReplyIpv6 = repository.getReply(query, srcIpv6)
+
+        assertNotNull(firstReplyIpv6)
+        assertEquals(MdnsConstants.getMdnsIPv6Address(), firstReplyIpv6.destination.address)
+        assertEquals(MdnsConstants.MDNS_PORT, firstReplyIpv6.destination.port)
+        assertNotNull(secondReplyIpv6)
+        assertEquals(MdnsConstants.getMdnsIPv6Address(), secondReplyIpv6.destination.address)
+        assertEquals(MdnsConstants.MDNS_PORT, secondReplyIpv6.destination.port)
+    }
+
+    @Test
     fun testGetConflictingServices() {
         val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
         repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* ttl */)