From 66fef2ea8e9155a85ca6516c17f3e13dc172bd40 Mon Sep 17 00:00:00 2001 From: Chuwei He Date: Mon, 23 Jun 2025 14:14:11 +0900 Subject: [PATCH] Add EthernetPortSelector class This patch added EthernetPortSelector class that is used to select a specific ethernet port by interface name or MAC address. Bug: 397536853 Test: atest ConnectivityCoverageTests Flag: EXEMPT mainline Change-Id: I050dc1f484115fdedda349cc2e1a44f4c5fda6db --- .../src/android/net/EthernetPortSelector.java | 141 ++++++++++++++++++ .../android/net/EthernetPortSelectorTest.java | 135 +++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 framework-t/src/android/net/EthernetPortSelector.java create mode 100644 tests/unit/java/android/net/EthernetPortSelectorTest.java diff --git a/framework-t/src/android/net/EthernetPortSelector.java b/framework-t/src/android/net/EthernetPortSelector.java new file mode 100644 index 0000000000..5cc6d768e5 --- /dev/null +++ b/framework-t/src/android/net/EthernetPortSelector.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2025 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 android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.util.Objects; + +/** + * A {@link EthernetPortSelector} used to identify ethernet ports. Ports can be identified by + * matching either interface name or MAC address only. + * This selector is different from {@link EthernetNetworkSpecifier} in the way that + * {@link EthernetPortSelector} is used to identify an ethernet network which might include + * network specific configuration, such as authentication etc,. While {@link EthernetPortSelector} + * is solely used to identify an ethernet port which may or may not be connected. + * @hide + */ +public final class EthernetPortSelector implements Parcelable { + /** + * Name of the network port, or null. + */ + @Nullable + private final String mInterfaceName; + + /** + * MAC address of the network port, or null. + */ + @Nullable + private final MacAddress mMacAddress; + + /** + * Create a new EthernetPortSelector by interface name. + * @param interfaceName Name of the ethernet interface the specifier refers to. + * @hide + */ + public EthernetPortSelector(@NonNull String interfaceName) { + // Interface name and MAC address cannot be both invalid or both set at the same time. + if (TextUtils.isEmpty(interfaceName)) { + throw new IllegalArgumentException("Interface name cannot be empty."); + } + mInterfaceName = interfaceName; + mMacAddress = null; + } + + /** + * Create a new EthernetPortSelector by MAC address. + * @param macAddress MAC address of the ethernet interface the specifier refers to, or null. + * @hide + */ + public EthernetPortSelector(@NonNull MacAddress macAddress) { + // Interface name and MAC address cannot be both invalid or both set at the same time. + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null."); + } + mInterfaceName = null; + mMacAddress = macAddress; + } + + /** + * Get the name of the ethernet port the selector refers to, or null. + * @hide + */ + @Nullable + public String getInterfaceName() { + return mInterfaceName; + } + + /** + * Get the MAC address of the ethernet port the selector refers to, or null. + * @hide + */ + @Nullable + public MacAddress getMacAddress() { + return mMacAddress; + } + + @Override + public boolean equals(@Nullable Object o) { + return (o instanceof EthernetPortSelector rhs) + && TextUtils.equals(mInterfaceName, rhs.mInterfaceName) + && Objects.equals(mMacAddress, rhs.mMacAddress); + } + + @Override + public int hashCode() { + return Objects.hash(mMacAddress, mInterfaceName); + } + + @Override + public String toString() { + String selectorInfo = mMacAddress != null ? mMacAddress.toString() : mInterfaceName; + return "EthernetPortSelector (" + selectorInfo + ")"; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mInterfaceName); + dest.writeParcelable(mMacAddress, flags); + } + + /** @hide */ + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator<>() { + public EthernetPortSelector createFromParcel(Parcel in) { + final String ifname = in.readString(); + final MacAddress addr = in.readParcelable(MacAddress.class.getClassLoader()); + return ifname == null + ? new EthernetPortSelector(addr) : new EthernetPortSelector(ifname); + + } + + public EthernetPortSelector[] newArray(int size) { + return new EthernetPortSelector[size]; + } + }; +} diff --git a/tests/unit/java/android/net/EthernetPortSelectorTest.java b/tests/unit/java/android/net/EthernetPortSelectorTest.java new file mode 100644 index 0000000000..16ac8bd55a --- /dev/null +++ b/tests/unit/java/android/net/EthernetPortSelectorTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2025 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 android.net; + +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; + +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +@RunWith(DevSdkIgnoreRunner.class) +public class EthernetPortSelectorTest { + private final MacAddress mTestMacAddr = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); + private final String mTestIfaceName1 = "testIface"; + private final String mTestIfaceName2 = "testIfaceTwo"; + + @Test + public void testConstructorWithIface() { + final EthernetPortSelector ns = new EthernetPortSelector(mTestIfaceName1); + assertEquals(mTestIfaceName1, ns.getInterfaceName()); + assertNull(ns.getMacAddress()); + } + + @Test + public void testConstructorWithMacAddress() { + final EthernetPortSelector ns = new EthernetPortSelector(mTestMacAddr); + assertEquals(mTestMacAddr, ns.getMacAddress()); + assertNull(ns.getInterfaceName()); + } + + @Test + public void testConstructorWithNullIface() { + assertThrows("Interface name cannot be empty.", + IllegalArgumentException.class, + () -> new EthernetPortSelector((String) null)); + } + + @Test + public void testConstructorWithNullMacAddr() { + assertThrows("MAC address cannot be null.", + IllegalArgumentException.class, + () -> new EthernetPortSelector((MacAddress) null)); + } + + @Test + public void testEquals() { + final EthernetPortSelector nsOne = + new EthernetPortSelector(mTestIfaceName1); + final EthernetPortSelector nsTwo = + new EthernetPortSelector(mTestIfaceName1); + assertEquals(nsOne, nsTwo); + } + + @Test + public void testNotEquals() { + final EthernetPortSelector nsOne = + new EthernetPortSelector(mTestIfaceName1); + final EthernetPortSelector nsTwo = + new EthernetPortSelector(mTestIfaceName2); + assertNotEquals(nsOne, nsTwo); + } + + @Test + public void testHashCodeOfDifferentSpecifier() { + final EthernetPortSelector nsOne = + new EthernetPortSelector(mTestIfaceName1); + final EthernetPortSelector nsTwo = + new EthernetPortSelector(mTestIfaceName2); + int hash1 = nsOne.hashCode(); + int hash2 = nsTwo.hashCode(); + assertNotEquals(hash1, hash2); + } + + @Test + public void testHashCodeOfTheSameSpecifier() { + final EthernetPortSelector nsOne = + new EthernetPortSelector(mTestIfaceName1); + final EthernetPortSelector nsTwo = + new EthernetPortSelector(mTestIfaceName1); + int hash1 = nsOne.hashCode(); + int hash2 = nsTwo.hashCode(); + assertEquals(hash1, hash2); + } + + @Test + public void testToString() { + final EthernetPortSelector nsOne = + new EthernetPortSelector(mTestIfaceName1); + String expectOne = "EthernetPortSelector (testIface)"; + assertEquals(nsOne.toString(), expectOne); + + final EthernetPortSelector nsTwo = + new EthernetPortSelector(mTestMacAddr); + String expectTwo = "EthernetPortSelector (aa:bb:cc:dd:ee:ff)"; + assertEquals(nsTwo.toString(), expectTwo); + } + + @Test + public void testParcel() { + final EthernetPortSelector nsOne = + new EthernetPortSelector(mTestIfaceName1); + assertParcelingIsLossless(nsOne); + + final EthernetPortSelector nsTwo = + new EthernetPortSelector(mTestMacAddr); + assertParcelingIsLossless(nsTwo); + } +}