diff --git a/framework-t/src/android/net/EthernetConfiguration.java b/framework-t/src/android/net/EthernetConfiguration.java index a736bfc506..473642bc94 100644 --- a/framework-t/src/android/net/EthernetConfiguration.java +++ b/framework-t/src/android/net/EthernetConfiguration.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; @@ -27,6 +28,9 @@ 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. + * The configuration can be set to be either persisted across boot or not. When set to be + * persistent, the Builder will check if all set fields can be persisted, otherwise throws an + * exception. Currently persisting {@link NetworkCapabilities} is not supported. * * - Intended Usage and Scope: * This class implements android.os.Parcelable and resides in the framework JAR. This is @@ -43,42 +47,80 @@ public class EthernetConfiguration implements Parcelable { /** * Static IP configuration data (static IPv4 address, IPv4 gateway, DNS servers, etc.) */ - private final IpConfiguration mIpConfiguration; + @Nullable 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; + @Nullable private final NetworkCapabilities mNetworkCapabilities; - public EthernetConfiguration(@NonNull IpConfiguration ipConfiguration, - @NonNull NetworkCapabilities capabilities) { - Objects.requireNonNull(ipConfiguration); - Objects.requireNonNull(capabilities); + /** + * This configuration is not persisted across boot. + * @hide + */ + public static final int PERSISTENCE_NOT_PERSISTED = 0; + + /** + * This configuration is persisted across boot. + * @hide + */ + public static final int PERSISTENCE_IS_PERSISTED = 1; + + /** + * Indicates whether this ethernet configuration should be persisted across boot for the + * associated user. + * More persistence types will be introduced in the future for multi-user management. + * @hide + */ + @IntDef(prefix = "PERSISTENCE", value = {PERSISTENCE_IS_PERSISTED, PERSISTENCE_NOT_PERSISTED}) + public @interface Persistence {} + + /** + * Indicates whether this ethernet configuration should be persisted across boot for the + * associated user. + * When {@code mPersistence} is set to {@code PERSISTENCE_IS_PERSISTED} and a configuration + * that cannot be persisted is passed in, an exception is thrown. Currently + * {@link NetworkCapabilities} is not allowed to be persisted. + */ + private final @Persistence int mPersistence; + + private EthernetConfiguration(@Nullable IpConfiguration ipConfiguration, + @Nullable NetworkCapabilities capabilities, @Persistence int persistence) { mIpConfiguration = ipConfiguration; mNetworkCapabilities = capabilities; + mPersistence = persistence; } /** - * Get the IpConfiguration object associated with this EthernetConfiguration. + * Get the {@link IpConfiguration} object associated with this EthernetConfiguration, or null. */ - @NonNull + @Nullable public IpConfiguration getIpConfiguration() { - return new IpConfiguration(mIpConfiguration); + return mIpConfiguration == null ? null : new IpConfiguration(mIpConfiguration); } /** - * Get the NetworkCapabilities object associated with this EthernetConfiguration. + * Get the {@link NetworkCapabilities} object associated with this EthernetConfiguration, or + * null. */ - @NonNull + @Nullable public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); + return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities); + } + + /** + * Get whether this ethernet configuration is persisted across boot. + */ + public @Persistence int getPersistence() { + return mPersistence; } @Override public String toString() { - return "IP configurations: " + mIpConfiguration.toString() - + "Network capabilities: " + mNetworkCapabilities.toString(); + return "IP configurations: " + mIpConfiguration + + "Network capabilities: " + mNetworkCapabilities + + ", Is persisted: " + mPersistence; } @Override @@ -93,12 +135,13 @@ public class EthernetConfiguration implements Parcelable { final EthernetConfiguration other = (EthernetConfiguration) o; return Objects.equals(this.mIpConfiguration, other.mIpConfiguration) - && Objects.equals(this.mNetworkCapabilities, other.mNetworkCapabilities); + && Objects.equals(this.mNetworkCapabilities, other.mNetworkCapabilities) + && mPersistence == other.mPersistence; } @Override public int hashCode() { - return Objects.hash(mIpConfiguration, mNetworkCapabilities); + return Objects.hash(mIpConfiguration, mNetworkCapabilities, mPersistence); } /** Implement the Parcelable interface */ @@ -106,6 +149,13 @@ public class EthernetConfiguration implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(mIpConfiguration, flags); dest.writeParcelable(mNetworkCapabilities, flags); + dest.writeInt(mPersistence); + } + + private EthernetConfiguration(Parcel in) { + mIpConfiguration = in.readParcelable(IpConfiguration.class.getClassLoader()); + mNetworkCapabilities = in.readParcelable(NetworkCapabilities.class.getClassLoader()); + mPersistence = in.readInt(); } /** Implement the Parcelable interface */ @@ -113,11 +163,7 @@ public class EthernetConfiguration implements Parcelable { 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); + return new EthernetConfiguration(in); } @Override @@ -131,4 +177,58 @@ public class EthernetConfiguration implements Parcelable { public int describeContents() { return 0; } + + /** + * Builder for {@link EthernetConfiguration}. + */ + public static final class Builder { + @Nullable private IpConfiguration mIpConfiguration; + @Nullable private NetworkCapabilities mNetworkCapabilities; + private @Persistence int mPersistence = PERSISTENCE_NOT_PERSISTED; + + /** + * Set persisted configuration for current ethernet configuration. One of + * {@code PERSISTENCE_IS_PERSISTED}, {@code PERSISTENCE_NOT_PERSISTED}. + * When not set, this field is {@code PERSISTENCE_NOT_PERSISTED} by default. + */ + @NonNull + public Builder setPersistence(@Persistence int persistence) { + switch (persistence) { + case PERSISTENCE_IS_PERSISTED: + case PERSISTENCE_NOT_PERSISTED: + mPersistence = persistence; + return this; + } + throw new IllegalArgumentException( + "Invalid persistence value: " + persistence); + } + + /** Set IP configuration for current ethernet configuration */ + @NonNull + public Builder setIpConfiguration(@Nullable IpConfiguration ipConfiguration) { + mIpConfiguration = ipConfiguration; + return this; + } + + /** Set network capabilities for current ethernet configuration */ + @NonNull + public Builder setNetworkCapabilities(@Nullable NetworkCapabilities capabilities) { + mNetworkCapabilities = capabilities; + return this; + } + + /** Build an EthernetConfiguration object */ + @NonNull + public EthernetConfiguration build() { + if (mIpConfiguration == null && mNetworkCapabilities == null) { + throw new IllegalArgumentException("IP configuration and network capabilities are" + + "both null, cannot construct an empty EthernetConfiguration."); + } + // Persisting NetworkCapabilities is not currently supported. + if (mPersistence == PERSISTENCE_IS_PERSISTED && mNetworkCapabilities != null) { + throw new IllegalArgumentException("Network capabilities cannot be persisted."); + } + return new EthernetConfiguration(mIpConfiguration, mNetworkCapabilities, mPersistence); + } + } } diff --git a/tests/unit/java/android/net/EthernetConfigurationTest.java b/tests/unit/java/android/net/EthernetConfigurationTest.java index 30c0d7c5ed..d602fe7c94 100644 --- a/tests/unit/java/android/net/EthernetConfigurationTest.java +++ b/tests/unit/java/android/net/EthernetConfigurationTest.java @@ -20,6 +20,7 @@ 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 static org.junit.Assert.assertTrue; @@ -87,33 +88,83 @@ public class EthernetConfigurationTest { private void assertNetworkCapabilitiesEqual( NetworkCapabilities source, NetworkCapabilities target) { - assertTrue(source.equalsNetCapabilities(target)); + if (source == null || target == null) { + assertNull(target); + assertNull(source); + } else { + assertTrue(source.equalsNetCapabilities(target)); + } } @Test - public void testConstructor() { - EthernetConfiguration config = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + public void testBuilderNotPersisted() { + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); assertIpConfigurationEqual(config.getIpConfiguration(), mIpConfiguration1); assertNetworkCapabilitiesEqual(config.getNetworkCapabilities(), mNetworkCapabilities); + assertEquals(config.getPersistence(), EthernetConfiguration.PERSISTENCE_NOT_PERSISTED); + } + @Test + public void testBuilderPersisted() { + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setPersistence(EthernetConfiguration.PERSISTENCE_IS_PERSISTED) + .build(); + assertIpConfigurationEqual(config.getIpConfiguration(), mIpConfiguration1); + assertNetworkCapabilitiesEqual(config.getNetworkCapabilities(), null); + assertEquals(config.getPersistence(), EthernetConfiguration.PERSISTENCE_IS_PERSISTED); } @Test - public void testConstructorWithNullIpConfig() { - assertThrows(NullPointerException.class, - () -> new EthernetConfiguration(null, mNetworkCapabilities)); + public void testConstructorIsPersistedNotSet() { + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .build(); + assertEquals(config.getPersistence(), EthernetConfiguration.PERSISTENCE_NOT_PERSISTED); } @Test - public void testConstructorWithNulNetCapabilities() { - assertThrows(NullPointerException.class, - () -> new EthernetConfiguration(mIpConfiguration1, null)); + public void testConstructorWithIpConfigNotSet() { + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(null) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); + assertNull(config.getIpConfiguration()); + } + + @Test + public void testConstructorWithPersistedNonNullNetCapabilities() { + assertThrows("Network capabilities cannot be persisted.", + IllegalArgumentException.class, + () -> new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_IS_PERSISTED) + .build()); + } + + @Test + public void testConstructorWithNullIpConfigAndNullNetCapabilities() { + assertThrows("IP configuration and network capabilities are" + + "both null, cannot construct an empty EthernetConfiguration.", + IllegalArgumentException.class, + () -> new EthernetConfiguration.Builder() + .setPersistence(EthernetConfiguration.PERSISTENCE_IS_PERSISTED) + .build()); } @Test public void testHashCodeConsistency() { - EthernetConfiguration config = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); int hash1 = config.hashCode(); int hash2 = config.hashCode(); assertEquals(hash1, hash2); @@ -121,10 +172,16 @@ public class EthernetConfigurationTest { @Test public void testHashCodeOfDifferentConfig() { - EthernetConfiguration config1 = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); - EthernetConfiguration config2 = - new EthernetConfiguration(mIpConfiguration2, mNetworkCapabilities); + EthernetConfiguration config1 = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); + EthernetConfiguration config2 = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration2) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); int hash1 = config1.hashCode(); int hash2 = config2.hashCode(); assertNotEquals(hash1, hash2); @@ -132,10 +189,16 @@ public class EthernetConfigurationTest { @Test public void testHashCodeOfTheSameConfig() { - EthernetConfiguration config1 = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); - EthernetConfiguration config2 = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + EthernetConfiguration config1 = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); + EthernetConfiguration config2 = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); int hash1 = config1.hashCode(); int hash2 = config2.hashCode(); assertEquals(hash1, hash2); @@ -143,10 +206,13 @@ public class EthernetConfigurationTest { @Test public void testToString() { - EthernetConfiguration config = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); String expect; - // After version V, NOT_BANDWIDTH_CONSTRAINED is added to network capabiltiies by default + // After version V, NOT_BANDWIDTH_CONSTRAINED is added to network capabilities by default // while devices before V do not have this default capability. if (SdkLevel.isAtLeastV()) { expect = "IP configurations: IP assignment: STATIC\n" @@ -155,7 +221,8 @@ public class EthernetConfigurationTest { + "Proxy settings: PAC\n" + "HTTP proxy: [test1] 8888\n" + "Network capabilities: [ Transports: ETHERNET Capabilities: NOT_RESTRICTED" - + "&TRUSTED&NOT_VPN&NOT_BANDWIDTH_CONSTRAINED UnderlyingNetworks: Null]"; + + "&TRUSTED&NOT_VPN&NOT_BANDWIDTH_CONSTRAINED UnderlyingNetworks: Null]" + + ", Is persisted: 0"; } else { expect = "IP configurations: IP assignment: STATIC\n" + "Static configuration: IP address 192.168.1.100/25 Gateway 192.168.1.1 " @@ -163,15 +230,18 @@ public class EthernetConfigurationTest { + "Proxy settings: PAC\n" + "HTTP proxy: [test1] 8888\n" + "Network capabilities: [ Transports: ETHERNET Capabilities: NOT_RESTRICTED" - + "&TRUSTED&NOT_VPN UnderlyingNetworks: Null]"; + + "&TRUSTED&NOT_VPN UnderlyingNetworks: Null], Is persisted: 0"; } assertEquals(config.toString(), expect); } @Test public void testParcel() { - EthernetConfiguration config = - new EthernetConfiguration(mIpConfiguration1, mNetworkCapabilities); + EthernetConfiguration config = new EthernetConfiguration.Builder() + .setIpConfiguration(mIpConfiguration1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED) + .build(); assertParcelingIsLossless(config); } } diff --git a/tests/unit/java/android/net/EthernetPortStateTest.java b/tests/unit/java/android/net/EthernetPortStateTest.java index bb4b22a6c6..d42649ede3 100644 --- a/tests/unit/java/android/net/EthernetPortStateTest.java +++ b/tests/unit/java/android/net/EthernetPortStateTest.java @@ -84,8 +84,12 @@ public class EthernetPortStateTest { mNetworkCapabilities = new NetworkCapabilities.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); - mConfig1 = new EthernetConfiguration(ipConfig1, mNetworkCapabilities); - mConfig2 = new EthernetConfiguration(ipConfig2, mNetworkCapabilities); + mConfig1 = new EthernetConfiguration.Builder().setIpConfiguration(ipConfig1) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED).build(); + mConfig2 = new EthernetConfiguration.Builder().setIpConfiguration(ipConfig2) + .setNetworkCapabilities(mNetworkCapabilities) + .setPersistence(EthernetConfiguration.PERSISTENCE_NOT_PERSISTED).build(); mEthernetPortState1 = new EthernetPortState( mTestInterfaceName1, mTestMacAddress1, mTestInterfaceIndex1, mConfig1, @@ -176,8 +180,8 @@ public class EthernetPortStateTest { + "EthernetManager.STATE_LINK_UP}.", IllegalArgumentException.class, () -> new EthernetPortState( - mTestInterfaceName1, mTestMacAddress1, mTestInterfaceIndex1, mConfig1, - EthernetManager.ROLE_CLIENT, -1)); + mTestInterfaceName1, mTestMacAddress1, mTestInterfaceIndex1, mConfig1, + EthernetManager.ROLE_CLIENT, -1)); } @Test @@ -221,8 +225,8 @@ public class EthernetPortStateTest { + "HTTP proxy: [test1] 8888\n" + "Network capabilities: [ Transports: ETHERNET Capabilities: " + "NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_BANDWIDTH_CONSTRAINED " - + "UnderlyingNetworks: Null], Interface name:eth0, " - + "MAC address:0a:1b:2c:3d:4e:5f, Interface index:1"; + + "UnderlyingNetworks: Null], Is persisted: 0," + + " Interface name:eth0, MAC address:0a:1b:2c:3d:4e:5f, Interface index:1"; } else { expect = "Role:1, State:2, Configurations: IP configurations: " + "IP assignment: STATIC\n" @@ -232,8 +236,8 @@ public class EthernetPortStateTest { + "HTTP proxy: [test1] 8888\n" + "Network capabilities: [ Transports: ETHERNET Capabilities: " + "NOT_RESTRICTED&TRUSTED&NOT_VPN UnderlyingNetworks: Nu" - + "ll], Interface name:eth0, MAC address:0a:1b:2c:3d:4e:5f, Interface index:1"; - + + "ll], Is persisted: 0, Interface name:eth0, " + + "MAC address:0a:1b:2c:3d:4e:5f, Interface index:1"; } assertEquals(mEthernetPortState1.toString(), expect); }