From 2474cc54e30188d9fcc9067ed356df27a020a93b Mon Sep 17 00:00:00 2001 From: Jimi Chen Date: Wed, 4 Jun 2025 13:54:44 +0000 Subject: [PATCH] Use multicast socket for group membership Replace `ip addr` command with `multicastSocket` to join multicast groups. This change improves robustness and directly leverages Java's networking capabilities for multicast management. Flag: EXEMPT mainline Bug: 419423721 Test: atest CtsConnectivityMultiDevicesTestCases:ApfV6Test Change-Id: I2c941594985d98f86a4a91c9c9cd425eb75e8e97 --- tests/cts/multidevices/apfv6_test.py | 18 ++----- .../ConnectivityMultiDevicesSnippet.kt | 51 +++++++++++++++++++ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/tests/cts/multidevices/apfv6_test.py b/tests/cts/multidevices/apfv6_test.py index 6b71c48bd3..4512c2d3fe 100644 --- a/tests/cts/multidevices/apfv6_test.py +++ b/tests/cts/multidevices/apfv6_test.py @@ -147,14 +147,8 @@ class ApfV6Test(apf_test_base.ApfTestBase): expected_echo_reply, ) - def is_running_as_root(self): - uid = adb_utils.adb_shell(self.clientDevice, 'id -u') - return uid == '0' - @apf_utils.at_least_B() def test_igmpv3_general_query_offload(self): - if not self.is_running_as_root(): - return # use unicast to replace multicast ether dst to prevent flaky due to DTIM skip ether = Ether(src=self.server_mac_address, dst=self.client_mac_address) ip = IP( @@ -167,11 +161,9 @@ class ApfV6Test(apf_test_base.ApfTestBase): mcast_addrs = ['239.0.0.1', '239.0.0.2', '239.0.0.3'] + self.client.createMulticastSocket(self.client_iface_name) for addr in mcast_addrs: - adb_utils.adb_shell( - self.clientDevice, - f'ip addr add {addr}/32 dev {self.client_iface_name} autojoin', - ) + self.client.joinMulticastGroup(addr) ether = Ether(src=self.client_mac_address, dst='01:00:5e:00:00:16') ip = IP( @@ -196,10 +188,8 @@ class ApfV6Test(apf_test_base.ApfTestBase): ) finally: for addr in mcast_addrs: - adb_utils.adb_shell( - self.clientDevice, - f'ip addr del {addr}/32 dev {self.client_iface_name}', - ) + self.client.leaveMulticastGroup(addr) + self.client.destroyMulticastSocket() @apf_utils.at_least_B() @apf_utils.apf_ram_at_least(3000) diff --git a/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt b/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt index feea1247fd..9f01abaf4f 100644 --- a/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt +++ b/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt @@ -47,6 +47,10 @@ import com.android.testutils.TestableNetworkCallback.Event.CapabilitiesChanged import com.android.testutils.runAsShell import com.google.android.mobly.snippet.Snippet import com.google.android.mobly.snippet.rpc.Rpc +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.MulticastSocket +import java.net.NetworkInterface import org.junit.Rule class ConnectivityMultiDevicesSnippet : Snippet { @@ -60,6 +64,7 @@ class ConnectivityMultiDevicesSnippet : Snippet { private val cbHelper = NetworkCallbackHelper() private val ctsTetheringUtils = CtsTetheringUtils(context) private var oldSoftApConfig: SoftApConfiguration? = null + private var multicastSocket: MulticastSocket? = null override fun shutdown() { cbHelper.unregisterAll() @@ -215,4 +220,50 @@ class ConnectivityMultiDevicesSnippet : Snippet { } } } + + @Rpc(description = "Create multicast socket") + fun createMulticastSocket(ifname: String) { + if (multicastSocket != null) { + throw IllegalStateException("multicast socket is not null") + } + + multicastSocket = MulticastSocket() + multicastSocket?.networkInterface = NetworkInterface.getByName(ifname) + } + + @Rpc(description = "Destroy multicast socket") + fun destroyMulticastSocket() { + if (multicastSocket == null) { + throw IllegalStateException("multicast socket is null") + } + + multicastSocket?.close() + multicastSocket = null + } + + @Rpc(description = "Join multicast group") + fun joinMulticastGroup(multicastGroup: String) { + if (multicastSocket == null) { + throw IllegalStateException("multicast socket is null") + } + + val groupToJoin = InetAddress.getByName(multicastGroup) + multicastSocket?.joinGroup( + InetSocketAddress(groupToJoin, 0), + multicastSocket?.networkInterface + ) + } + + @Rpc(description = "Leave multicast group") + fun leaveMulticastGroup(multicastGroup: String) { + if (multicastSocket == null) { + throw IllegalStateException("multicast socket is null") + } + + val groupToLeave = InetAddress.getByName(multicastGroup) + multicastSocket?.leaveGroup( + InetSocketAddress(groupToLeave, 0), + multicastSocket?.networkInterface + ) + } }