From e0e89ef66fe78ff815340542950e06acf6fcdc67 Mon Sep 17 00:00:00 2001 From: Chuwei He Date: Mon, 24 Mar 2025 16:49:13 +0900 Subject: [PATCH] Add EthernetConfiguration class This patch adds EthernetConfiguration class which represents a static configuration and network capabilities of a configured ethernet network interface. EthernetConfiguration is used ONLY internally to store and track ethernet configurations, and serves different functionality as EthernetNetworkUpdateRequest. Bug: 397536853 Test: atest ConnectivityCoverageTests Flag: EXEMPT mainline Change-Id: Ib175347096db25b9f2180a2e526746f1f3cf6ceb --- .../android/net/EthernetConfiguration.java | 134 +++++++++++++ .../net/EthernetConfigurationTest.java | 177 ++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 framework-t/src/android/net/EthernetConfiguration.java create mode 100644 tests/unit/java/android/net/EthernetConfigurationTest.java diff --git a/framework-t/src/android/net/EthernetConfiguration.java b/framework-t/src/android/net/EthernetConfiguration.java new file mode 100644 index 0000000000..a736bfc506 --- /dev/null +++ b/framework-t/src/android/net/EthernetConfiguration.java @@ -0,0 +1,134 @@ +/* + * 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 java.util.Objects; + +/** + * This class represents the static IP configuration data such as IP configuration (static IPv4 + * address, IPv4 gateway, DNS servers, etc.) and network capabilities for a configured ethernet + * network interface. + * + * - Intended Usage and Scope: + * This class implements android.os.Parcelable and resides in the framework JAR. This is + * necessary for being used as an AIDL object to share code with EthernetPortInfo and + * EthernetNetworkUpdateRequest. + * + * - Future Evolution: + * This class is meant to progressively replace EthernetNetworkUpdateRequest in EthernetManager's + * {@code @SystemApi} and be exposed through {@code @SystemApi} getters as well. + * + * @hide + */ +public class EthernetConfiguration implements Parcelable { + /** + * Static IP configuration data (static IPv4 address, IPv4 gateway, DNS servers, etc.) + */ + private final IpConfiguration mIpConfiguration; + + /** + * This is only for the requestable bits of NetworkCapabilities that an external caller can + * pass through a EthernetNetworkUpdateRequest. + */ + private final NetworkCapabilities mNetworkCapabilities; + + public EthernetConfiguration(@NonNull IpConfiguration ipConfiguration, + @NonNull NetworkCapabilities capabilities) { + Objects.requireNonNull(ipConfiguration); + Objects.requireNonNull(capabilities); + mIpConfiguration = ipConfiguration; + mNetworkCapabilities = capabilities; + } + + /** + * Get the IpConfiguration object associated with this EthernetConfiguration. + */ + @NonNull + public IpConfiguration getIpConfiguration() { + return new IpConfiguration(mIpConfiguration); + } + + /** + * Get the NetworkCapabilities object associated with this EthernetConfiguration. + */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return new NetworkCapabilities(mNetworkCapabilities); + } + + @Override + public String toString() { + return "IP configurations: " + mIpConfiguration.toString() + + "Network capabilities: " + mNetworkCapabilities.toString(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof EthernetConfiguration)) { + return false; + } + + final EthernetConfiguration other = (EthernetConfiguration) o; + return Objects.equals(this.mIpConfiguration, other.mIpConfiguration) + && Objects.equals(this.mNetworkCapabilities, other.mNetworkCapabilities); + } + + @Override + public int hashCode() { + return Objects.hash(mIpConfiguration, mNetworkCapabilities); + } + + /** Implement the Parcelable interface */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mIpConfiguration, flags); + dest.writeParcelable(mNetworkCapabilities, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public EthernetConfiguration createFromParcel(Parcel in) { + final IpConfiguration config = in.readParcelable( + IpConfiguration.class.getClassLoader()); + final NetworkCapabilities capabilities = in.readParcelable( + NetworkCapabilities.class.getClassLoader()); + return new EthernetConfiguration(config, capabilities); + } + + @Override + public EthernetConfiguration[] newArray(int size) { + return new EthernetConfiguration[size]; + } + }; + + /** Implement the Parcelable interface */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/tests/unit/java/android/net/EthernetConfigurationTest.java b/tests/unit/java/android/net/EthernetConfigurationTest.java new file mode 100644 index 0000000000..30c0d7c5ed --- /dev/null +++ b/tests/unit/java/android/net/EthernetConfigurationTest.java @@ -0,0 +1,177 @@ +/* + * 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.assertThrows; +import static org.junit.Assert.assertTrue; + +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.modules.utils.build.SdkLevel; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.ArrayList; + +@SmallTest +@IgnoreUpTo(Build.VERSION_CODES.S_V2) +@RunWith(DevSdkIgnoreRunner.class) +public class EthernetConfigurationTest { + // Setup 2 different IP configurations for building different ethernet configurations. + private IpConfiguration mIpConfiguration1; + private IpConfiguration mIpConfiguration2; + private NetworkCapabilities mNetworkCapabilities; + + @Before + public void setUp() { + LinkAddress linkAddr = new LinkAddress("192.168.1.100/25"); + InetAddress gateway = InetAddresses.parseNumericAddress("192.168.1.1"); + InetAddress dns1 = InetAddresses.parseNumericAddress("8.8.8.8"); + InetAddress dns2 = InetAddresses.parseNumericAddress("8.8.4.4"); + ArrayList dnsServers = new ArrayList<>(); + dnsServers.add(dns1); + dnsServers.add(dns2); + StaticIpConfiguration staticIpConfig = new StaticIpConfiguration.Builder() + .setIpAddress(linkAddr) + .setGateway(gateway) + .setDnsServers(dnsServers) + .build(); + ProxyInfo proxy1 = ProxyInfo.buildDirectProxy("test1", 8888); + ProxyInfo proxy2 = ProxyInfo.buildDirectProxy("test2", 8888); + + mIpConfiguration1 = new IpConfiguration.Builder() + .setStaticIpConfiguration(staticIpConfig) + .setHttpProxy(proxy1) + .build(); + mIpConfiguration2 = new IpConfiguration.Builder() + .setStaticIpConfiguration(staticIpConfig) + .setHttpProxy(proxy2) + .build(); + + mNetworkCapabilities = new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .build(); + } + + private void assertIpConfigurationEqual(IpConfiguration source, IpConfiguration target) { + assertEquals(source.getIpAssignment(), target.getIpAssignment()); + assertEquals(source.getProxySettings(), target.getProxySettings()); + assertEquals(source.getHttpProxy(), target.getHttpProxy()); + assertEquals(source.getStaticIpConfiguration(), target.getStaticIpConfiguration()); + } + + private void assertNetworkCapabilitiesEqual( + NetworkCapabilities source, NetworkCapabilities target) { + assertTrue(source.equalsNetCapabilities(target)); + } + + @Test + public void testConstructor() { + EthernetConfiguration config = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + assertIpConfigurationEqual(config.getIpConfiguration(), mIpConfiguration1); + assertNetworkCapabilitiesEqual(config.getNetworkCapabilities(), mNetworkCapabilities); + } + + @Test + public void testConstructorWithNullIpConfig() { + assertThrows(NullPointerException.class, + () -> new EthernetConfiguration(null, mNetworkCapabilities)); + } + + @Test + public void testConstructorWithNulNetCapabilities() { + assertThrows(NullPointerException.class, + () -> new EthernetConfiguration(mIpConfiguration1, null)); + } + + @Test + public void testHashCodeConsistency() { + EthernetConfiguration config = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + int hash1 = config.hashCode(); + int hash2 = config.hashCode(); + assertEquals(hash1, hash2); + } + + @Test + public void testHashCodeOfDifferentConfig() { + EthernetConfiguration config1 = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + EthernetConfiguration config2 = + new EthernetConfiguration(mIpConfiguration2, mNetworkCapabilities); + int hash1 = config1.hashCode(); + int hash2 = config2.hashCode(); + assertNotEquals(hash1, hash2); + } + + @Test + public void testHashCodeOfTheSameConfig() { + EthernetConfiguration config1 = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + EthernetConfiguration config2 = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + int hash1 = config1.hashCode(); + int hash2 = config2.hashCode(); + assertEquals(hash1, hash2); + } + + @Test + public void testToString() { + EthernetConfiguration config = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + String expect; + // After version V, NOT_BANDWIDTH_CONSTRAINED is added to network capabiltiies by default + // while devices before V do not have this default capability. + if (SdkLevel.isAtLeastV()) { + expect = "IP configurations: IP assignment: STATIC\n" + + "Static configuration: IP address 192.168.1.100/25 Gateway 192.168.1.1 " + + " DNS servers: [ 8.8.8.8 8.8.4.4 ] Domains \n" + + "Proxy settings: PAC\n" + + "HTTP proxy: [test1] 8888\n" + + "Network capabilities: [ Transports: ETHERNET Capabilities: NOT_RESTRICTED" + + "&TRUSTED&NOT_VPN&NOT_BANDWIDTH_CONSTRAINED UnderlyingNetworks: Null]"; + } else { + expect = "IP configurations: IP assignment: STATIC\n" + + "Static configuration: IP address 192.168.1.100/25 Gateway 192.168.1.1 " + + " DNS servers: [ 8.8.8.8 8.8.4.4 ] Domains \n" + + "Proxy settings: PAC\n" + + "HTTP proxy: [test1] 8888\n" + + "Network capabilities: [ Transports: ETHERNET Capabilities: NOT_RESTRICTED" + + "&TRUSTED&NOT_VPN UnderlyingNetworks: Null]"; + } + assertEquals(config.toString(), expect); + } + + @Test + public void testParcel() { + EthernetConfiguration config = + new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + assertParcelingIsLossless(config); + } +}