Check kernel version for multicast routing support.

Multicast routing is only supported on 14_5.15.0 and onwards. When sdk
version is 34+, thread is supported, if kernel version is e.g.
5.15.144-android13 then multicast routing is not supported so we need to
skip multicast routing tests.

Bug: 328133320

Test: atest ThreadNetworkIntegrationTests:android.net.thread.BorderRoutingTest
Change-Id: I5d67f4558b40ee3ec0569298c7c02726d5d19e98
diff --git a/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java b/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
index d84cd20..ee21405 100644
--- a/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
+++ b/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
@@ -24,6 +24,7 @@
 import static android.net.thread.utils.IntegrationTestUtils.isExpectedIcmpv6Packet;
 import static android.net.thread.utils.IntegrationTestUtils.isFromIpv6Source;
 import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
+import static android.net.thread.utils.IntegrationTestUtils.isMulticastRoutingSupported;
 import static android.net.thread.utils.IntegrationTestUtils.isSimulatedThreadRadioSupported;
 import static android.net.thread.utils.IntegrationTestUtils.isToIpv6Destination;
 import static android.net.thread.utils.IntegrationTestUtils.newPacketReader;
@@ -33,7 +34,6 @@
 
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
-import static com.android.testutils.DeviceInfoUtils.isKernelVersionAtLeast;
 import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
 import static com.android.testutils.TestPermissionUtil.runAsShell;
 
@@ -96,7 +96,6 @@
     private InfraNetworkDevice mInfraDevice;
 
     private static final int NUM_FTD = 2;
-    private static final String KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED = "5.15.0";
     private static final Inet6Address GROUP_ADDR_SCOPE_5 =
             (Inet6Address) InetAddresses.parseNumericAddress("ff05::1234");
     private static final Inet6Address GROUP_ADDR_SCOPE_4 =
@@ -239,7 +238,7 @@
     @Test
     public void multicastRouting_ftdSubscribedMulticastAddress_infraLinkJoinsMulticastGroup()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -261,7 +260,7 @@
     public void
             multicastRouting_ftdSubscribedScope3MulticastAddress_infraLinkNotJoinMulticastGroup()
                     throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -282,7 +281,7 @@
     @Test
     public void multicastRouting_ftdSubscribedMulticastAddress_canPingfromInfraLink()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -304,7 +303,7 @@
     @Test
     public void multicastRouting_inboundForwarding_afterBrRejoinFtdRepliesSubscribedAddress()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
 
         // TODO (b/327311034): Testing bbr state switch from primary mode to secondary mode and back
         // to primary mode requires an additional BR in the Thread network. This is not currently
@@ -314,7 +313,7 @@
     @Test
     public void multicastRouting_ftdSubscribedScope3MulticastAddress_cannotPingfromInfraLink()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -336,7 +335,7 @@
     @Test
     public void multicastRouting_ftdNotSubscribedMulticastAddress_cannotPingFromInfraDevice()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -357,7 +356,7 @@
     @Test
     public void multicastRouting_multipleFtdsSubscribedDifferentAddresses_canPingFromInfraDevice()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -393,7 +392,7 @@
     @Test
     public void multicastRouting_multipleFtdsSubscribedSameAddress_canPingFromInfraDevice()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -427,7 +426,7 @@
 
     @Test
     public void multicastRouting_outboundForwarding_scopeLargerThan3IsForwarded() throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -453,7 +452,7 @@
     @Test
     public void multicastRouting_outboundForwarding_scopeSmallerThan4IsNotForwarded()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -475,7 +474,7 @@
 
     @Test
     public void multicastRouting_outboundForwarding_llaToScope4IsNotForwarded() throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -498,7 +497,7 @@
 
     @Test
     public void multicastRouting_outboundForwarding_mlaToScope4IsNotForwarded() throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -525,7 +524,7 @@
     @Test
     public void multicastRouting_infraNetworkSwitch_ftdRepliesToSubscribedAddress()
             throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
@@ -553,7 +552,7 @@
 
     @Test
     public void multicastRouting_infraNetworkSwitch_outboundPacketIsForwarded() throws Exception {
-        assumeTrue(isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED));
+        assumeTrue(isMulticastRoutingSupported());
         /*
          * <pre>
          * Topology:
diff --git a/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java b/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
index 5f1f76a..3493d9f 100644
--- a/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
+++ b/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
@@ -46,7 +46,6 @@
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
 import android.net.thread.utils.FullThreadDevice;
-import android.net.thread.utils.OtDaemonController;
 import android.net.thread.utils.TapTestNetworkTracker;
 import android.os.HandlerThread;
 
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
index 6e70d24..bb2d973 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
@@ -20,6 +20,7 @@
 import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.testutils.DeviceInfoUtils.isKernelVersionAtLeast;
 
 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
@@ -32,6 +33,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.VintfRuntimeInfo;
 
 import androidx.annotation.NonNull;
 
@@ -63,6 +65,8 @@
 import java.util.concurrent.TimeoutException;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /** Static utility methods relating to Thread integration tests. */
 public final class IntegrationTestUtils {
@@ -75,6 +79,9 @@
     public static final Duration CALLBACK_TIMEOUT = Duration.ofSeconds(1);
     public static final Duration SERVICE_DISCOVERY_TIMEOUT = Duration.ofSeconds(20);
 
+    private static final String KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED = "5.15.0";
+    private static final int KERNEL_ANDROID_VERSION_MULTICAST_ROUTING_SUPPORTED = 14;
+
     private IntegrationTestUtils() {}
 
     /** Returns whether the device supports simulated Thread radio. */
@@ -83,6 +90,24 @@
         return SystemProperties.get("ro.product.model").startsWith("Cuttlefish");
     }
 
+    public static boolean isMulticastRoutingSupported() {
+        return isKernelVersionAtLeast(KERNEL_VERSION_MULTICAST_ROUTING_SUPPORTED)
+                && isKernelAndroidVersionAtLeast(
+                        KERNEL_ANDROID_VERSION_MULTICAST_ROUTING_SUPPORTED);
+    }
+
+    private static boolean isKernelAndroidVersionAtLeast(int n) {
+        final String osRelease = VintfRuntimeInfo.getOsRelease();
+        final Pattern pattern = Pattern.compile("android(\\d+)");
+        Matcher matcher = pattern.matcher(osRelease);
+
+        if (matcher.find()) {
+            int version = Integer.parseInt(matcher.group(1));
+            return (version >= n);
+        }
+        return false;
+    }
+
     /**
      * Waits for the given {@link Supplier} to be true until given timeout.
      *
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java
index 49b002a..9406a2f 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java
@@ -17,7 +17,9 @@
 package com.android.server.thread;
 
 import static com.android.server.thread.ThreadPersistentSettings.THREAD_ENABLED;
+
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
@@ -30,13 +32,13 @@
 import android.content.res.Resources;
 import android.os.PersistableBundle;
 import android.util.AtomicFile;
+
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
+
 import com.android.connectivity.resources.R;
 import com.android.server.connectivity.ConnectivityResources;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -44,6 +46,10 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
 /** Unit tests for {@link ThreadPersistentSettings}. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest