diff options
author | Benedict Wong <benedictwong@google.com> | 2020-08-10 17:54:33 -0700 |
---|---|---|
committer | Benedict Wong <benedictwong@google.com> | 2020-12-16 17:51:58 -0800 |
commit | 264973663ce84e73a0a88aeff6b6ec1a7971afb0 (patch) | |
tree | d2cfae9d8cde431d1d7313554f95693a59f22510 | |
parent | ad3271875a1e1c083bf390d2f8cf960f5b8f297c (diff) |
Implement basic VcnConfig and VcnGatewayConnectionConfig
This change adds some of the basic fields in VcnConfig and
VcnGatewayConnectionConfig, plus adds a persistability layer to ensure
all VcnConfig(s) are disk-stable.
Bug: 163602123
Bug: 163594033
Test: New tests added, passing
Change-Id: I2e632532809e7768b284be376f2b0a77f634fef5
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | core/java/android/net/vcn/VcnConfig.java | 109 | ||||
-rw-r--r-- | core/java/android/net/vcn/VcnGatewayConnectionConfig.java | 401 | ||||
-rw-r--r-- | services/core/java/com/android/server/vcn/Android.bp | 4 | ||||
-rw-r--r-- | tests/vcn/java/android/net/vcn/VcnConfigTest.java | 83 | ||||
-rw-r--r-- | tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java | 143 | ||||
-rw-r--r-- | tests/vcn/java/com/android/server/VcnManagementServiceTest.java | 8 |
7 files changed, 726 insertions, 23 deletions
diff --git a/Android.bp b/Android.bp index 26e716530426..4b3c22da5c7c 100644 --- a/Android.bp +++ b/Android.bp @@ -314,6 +314,7 @@ filegroup { ":framework-telecomm-sources", ":framework-telephony-common-sources", ":framework-telephony-sources", + ":framework-vcn-util-sources", ":framework-wifi-annotations", ":framework-wifi-non-updatable-sources", ":PacProcessor-aidl-sources", diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java index 148acf130857..d4a3fa7411b1 100644 --- a/core/java/android/net/vcn/VcnConfig.java +++ b/core/java/android/net/vcn/VcnConfig.java @@ -15,30 +15,104 @@ */ package android.net.vcn; +import static com.android.internal.annotations.VisibleForTesting.Visibility; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; +import android.util.ArraySet; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; /** * This class represents a configuration for a Virtual Carrier Network. * + * <p>Each {@link VcnGatewayConnectionConfig} instance added represents a connection that will be + * brought up on demand based on active {@link NetworkRequest}(s). + * + * @see VcnManager for more information on the Virtual Carrier Network feature * @hide */ public final class VcnConfig implements Parcelable { @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); - private VcnConfig() { + private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; + @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs; + + private VcnConfig(@NonNull Set<VcnGatewayConnectionConfig> tunnelConfigs) { + mGatewayConnectionConfigs = Collections.unmodifiableSet(tunnelConfigs); + validate(); } - // TODO: Implement getters, validators, etc /** - * Validates this configuration. + * Deserializes a VcnConfig from a PersistableBundle. * * @hide */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnConfig(@NonNull PersistableBundle in) { + final PersistableBundle gatewayConnectionConfigsBundle = + in.getPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY); + mGatewayConnectionConfigs = + new ArraySet<>( + PersistableBundleUtils.toList( + gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new)); + + validate(); + } + private void validate() { - // TODO: implement validation logic + Preconditions.checkCollectionNotEmpty( + mGatewayConnectionConfigs, "gatewayConnectionConfigs"); + } + + /** Retrieves the set of configured tunnels. */ + @NonNull + public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() { + return Collections.unmodifiableSet(mGatewayConnectionConfigs); + } + + /** + * Serializes this object to a PersistableBundle. + * + * @hide + */ + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + final PersistableBundle gatewayConnectionConfigsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mGatewayConnectionConfigs), + VcnGatewayConnectionConfig::toPersistableBundle); + result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash(mGatewayConnectionConfigs); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof VcnConfig)) { + return false; + } + + final VcnConfig rhs = (VcnConfig) other; + return mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs); } // Parcelable methods @@ -49,15 +123,16 @@ public final class VcnConfig implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) {} + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(toPersistableBundle(), flags); + } @NonNull public static final Parcelable.Creator<VcnConfig> CREATOR = new Parcelable.Creator<VcnConfig>() { @NonNull public VcnConfig createFromParcel(Parcel in) { - // TODO: Ensure all methods are pulled from the parcels - return new VcnConfig(); + return new VcnConfig((PersistableBundle) in.readParcelable(null)); } @NonNull @@ -68,7 +143,23 @@ public final class VcnConfig implements Parcelable { /** This class is used to incrementally build {@link VcnConfig} objects. */ public static class Builder { - // TODO: Implement this builder + @NonNull + private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>(); + + /** + * Adds a configuration for an individual gateway connection. + * + * @param gatewayConnectionConfig the configuration for an individual gateway connection + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder addGatewayConnectionConfig( + @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { + Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null"); + + mGatewayConnectionConfigs.add(gatewayConnectionConfig); + return this; + } /** * Builds and validates the VcnConfig. @@ -77,7 +168,7 @@ public final class VcnConfig implements Parcelable { */ @NonNull public VcnConfig build() { - return new VcnConfig(); + return new VcnConfig(mGatewayConnectionConfigs); } } } diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index 8160edc87440..039360a69a3a 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,7 +15,27 @@ */ package android.net.vcn; +import static android.net.NetworkCapabilities.NetCapability; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.NetworkCapabilities; +import android.os.PersistableBundle; +import android.util.ArraySet; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; /** * This class represents a configuration for a connection to a Virtual Carrier Network gateway. @@ -49,38 +69,399 @@ import android.annotation.NonNull; * <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX} * </ul> * + * <p>The meteredness and roaming of the VCN {@link Network} will be determined by that of the + * underlying Network(s). + * * @hide */ public final class VcnGatewayConnectionConfig { - private VcnGatewayConnectionConfig() { + // TODO: Use MIN_MTU_V6 once it is public, @hide + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int MIN_MTU_V6 = 1280; + + private static final Set<Integer> ALLOWED_CAPABILITIES; + + static { + Set<Integer> allowedCaps = new ArraySet<>(); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET); + allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX); + + ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps); + } + + private static final int DEFAULT_MAX_MTU = 1500; + + /** + * The maximum number of retry intervals that may be specified. + * + * <p>Limited to ensure an upper bound on config sizes. + */ + private static final int MAX_RETRY_INTERVAL_COUNT = 10; + + /** + * The minimum allowable repeating retry interval + * + * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater + * than this value. + * + * @see {@link Builder#setRetryInterval()} + */ + private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); + + private static final long[] DEFAULT_RETRY_INTERVALS_MS = + new long[] { + TimeUnit.SECONDS.toMillis(1), + TimeUnit.SECONDS.toMillis(2), + TimeUnit.SECONDS.toMillis(5), + TimeUnit.SECONDS.toMillis(30), + TimeUnit.MINUTES.toMillis(1), + TimeUnit.MINUTES.toMillis(5), + TimeUnit.MINUTES.toMillis(15) + }; + + private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; + @NonNull private final Set<Integer> mExposedCapabilities; + + private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; + @NonNull private final Set<Integer> mUnderlyingCapabilities; + + // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig + + private static final String MAX_MTU_KEY = "mMaxMtu"; + private final int mMaxMtu; + + private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; + @NonNull private final long[] mRetryIntervalsMs; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnGatewayConnectionConfig( + @NonNull Set<Integer> exposedCapabilities, + @NonNull Set<Integer> underlyingCapabilities, + @NonNull long[] retryIntervalsMs, + @IntRange(from = MIN_MTU_V6) int maxMtu) { + mExposedCapabilities = exposedCapabilities; + mUnderlyingCapabilities = underlyingCapabilities; + mRetryIntervalsMs = retryIntervalsMs; + mMaxMtu = maxMtu; + + validate(); + } + + /** @hide */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) { + final PersistableBundle exposedCapsBundle = + in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); + final PersistableBundle underlyingCapsBundle = + in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); + + mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); + mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); + mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); + mMaxMtu = in.getInt(MAX_MTU_KEY); + validate(); } - // TODO: Implement getters, validators, etc + private void validate() { + Preconditions.checkArgument( + mExposedCapabilities != null && !mExposedCapabilities.isEmpty(), + "exposedCapsBundle was null or empty"); + for (Integer cap : getAllExposedCapabilities()) { + checkValidCapability(cap); + } + + Preconditions.checkArgument( + mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(), + "underlyingCapabilities was null or empty"); + for (Integer cap : getAllUnderlyingCapabilities()) { + checkValidCapability(cap); + } + + Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null"); + validateRetryInterval(mRetryIntervalsMs); + + Preconditions.checkArgument( + mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); + } + + private static void checkValidCapability(int capability) { + Preconditions.checkArgument( + ALLOWED_CAPABILITIES.contains(capability), + "NetworkCapability " + capability + "out of range"); + } + + private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) { + Preconditions.checkArgument( + retryIntervalsMs != null + && retryIntervalsMs.length > 0 + && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT, + "retryIntervalsMs was null, empty or exceed max interval count"); + + final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1]; + if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) { + throw new IllegalArgumentException( + "Repeating retry interval was too short, must be a minimum of 15 minutes: " + + repeatingInterval); + } + } /** - * Validates this configuration + * Returns all exposed capabilities. * * @hide */ - private void validate() { - // TODO: implement validation logic + @NonNull + public Set<Integer> getAllExposedCapabilities() { + return Collections.unmodifiableSet(mExposedCapabilities); + } + + /** + * Checks if this config is configured to support/expose a specific capability. + * + * @param capability the capability to check for + */ + public boolean hasExposedCapability(@NetCapability int capability) { + checkValidCapability(capability); + + return mExposedCapabilities.contains(capability); + } + + /** + * Returns all capabilities required of underlying networks. + * + * @hide + */ + @NonNull + public Set<Integer> getAllUnderlyingCapabilities() { + return Collections.unmodifiableSet(mUnderlyingCapabilities); } - // Parcelable methods + /** + * Checks if this config requires an underlying network to have the specified capability. + * + * @param capability the capability to check for + */ + public boolean requiresUnderlyingCapability(@NetCapability int capability) { + checkValidCapability(capability); + + return mUnderlyingCapabilities.contains(capability); + } - /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects */ + /** Retrieves the configured retry intervals. */ + @NonNull + public long[] getRetryIntervalsMs() { + return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); + } + + /** Retrieves the maximum MTU allowed for this Gateway Connection. */ + @IntRange(from = MIN_MTU_V6) + public int getMaxMtu() { + return mMaxMtu; + } + + /** + * Converts this config to a PersistableBundle. + * + * @hide + */ + @NonNull + @VisibleForTesting(visibility = Visibility.PROTECTED) + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + final PersistableBundle exposedCapsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mExposedCapabilities), + PersistableBundleUtils.INTEGER_SERIALIZER); + final PersistableBundle underlyingCapsBundle = + PersistableBundleUtils.fromList( + new ArrayList<>(mUnderlyingCapabilities), + PersistableBundleUtils.INTEGER_SERIALIZER); + + result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); + result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); + result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); + result.putInt(MAX_MTU_KEY, mMaxMtu); + + return result; + } + + @Override + public int hashCode() { + return Objects.hash( + mExposedCapabilities, + mUnderlyingCapabilities, + Arrays.hashCode(mRetryIntervalsMs), + mMaxMtu); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof VcnGatewayConnectionConfig)) { + return false; + } + + final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; + return mExposedCapabilities.equals(rhs.mExposedCapabilities) + && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities) + && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) + && mMaxMtu == rhs.mMaxMtu; + } + + /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ public static class Builder { - // TODO: Implement this builder + @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet(); + @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet(); + @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; + private int mMaxMtu = DEFAULT_MAX_MTU; + + // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent. + // Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS + // when on Cell. + + /** + * Add a capability that this VCN Gateway Connection will support. + * + * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway + * Connection (i.e., the capabilities that this VCN Gateway Connection will support). + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway + * Connection + */ + public Builder addExposedCapability(@NetCapability int exposedCapability) { + checkValidCapability(exposedCapability); + + mExposedCapabilities.add(exposedCapability); + return this; + } + + /** + * Remove a capability that this VCN Gateway Connection will support. + * + * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway + * Connection (i.e., the capabilities that this VCN Gateway Connection will support) + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway + * Connection + */ + public Builder removeExposedCapability(@NetCapability int exposedCapability) { + checkValidCapability(exposedCapability); + + mExposedCapabilities.remove(exposedCapability); + return this; + } + + /** + * Require a capability for Networks underlying this VCN Gateway Connection. + * + * @param underlyingCapability the capability that a network MUST have in order to be an + * underlying network for this VCN Gateway Connection. + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying + * networks + */ + public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + checkValidCapability(underlyingCapability); + + mUnderlyingCapabilities.add(underlyingCapability); + return this; + } + + /** + * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection. + * + * <p>Calling this method will allow Networks that do NOT have this capability to be + * selected as an underlying network for this VCN Gateway Connection. However, underlying + * networks MAY still have the removed capability. + * + * @param underlyingCapability the capability that a network DOES NOT need to have in order + * to be an underlying network for this VCN Gateway Connection. + * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying + * networks + */ + public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + checkValidCapability(underlyingCapability); + + mUnderlyingCapabilities.remove(underlyingCapability); + return this; + } + + /** + * Set the retry interval between VCN establishment attempts upon successive failures. + * + * <p>The last retry interval will be repeated until safe mode is entered, or a connection + * is successfully established, at which point the retry timers will be reset. For power + * reasons, the last (repeated) retry interval MUST be at least 15 minutes. + * + * <p>Retry intervals MAY be subject to system power saving modes. That is to say that if + * the system enters a power saving mode, the retry may not occur until the device leaves + * the specified power saving mode. Intervals are sequential, and intervals will NOT be + * skipped if system power saving results in delaying retries (even if it exceed multiple + * retry intervals). + * + * <p>Each Gateway Connection will retry according to the retry intervals configured, but if + * safe mode is enabled, all Gateway Connection(s) will be disabled. + * + * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which + * the VCN will attempt to retry a session initiation. The last (repeating) retry + * interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m, + * 15m]} + * @return this {@link Builder} instance, for chaining + * @see VcnManager for additional discussion on fail-safe mode + */ + @NonNull + public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) { + validateRetryInterval(retryIntervalsMs); + + mRetryIntervalsMs = retryIntervalsMs; + return this; + } + + /** + * Sets the maximum MTU allowed for this VCN Gateway Connection. + * + * <p>This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the + * MTU of the virtualized network. + * + * <p>The system may reduce the MTU below the maximum specified based on signals such as the + * MTU of the underlying networks (and adjusted for Gateway Connection overhead). + * + * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than + * the IPv6 minimum MTU of 1280. Defaults to 1500. + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { + Preconditions.checkArgument( + maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)"); + + mMaxMtu = maxMtu; + return this; + } /** - * Builds and validates the VcnGatewayConnectionConfig + * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance */ @NonNull public VcnGatewayConnectionConfig build() { - return new VcnGatewayConnectionConfig(); + return new VcnGatewayConnectionConfig( + mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu); } } } diff --git a/services/core/java/com/android/server/vcn/Android.bp b/services/core/java/com/android/server/vcn/Android.bp new file mode 100644 index 000000000000..5ed204fd7640 --- /dev/null +++ b/services/core/java/com/android/server/vcn/Android.bp @@ -0,0 +1,4 @@ +filegroup { + name: "framework-vcn-util-sources", + srcs: ["util/**/*.java"], +}
\ No newline at end of file diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java new file mode 100644 index 000000000000..77944deb26f1 --- /dev/null +++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 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.vcn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnConfigTest { + private static final Set<VcnGatewayConnectionConfig> GATEWAY_CONNECTION_CONFIGS = + Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig()); + + // Public visibility for VcnManagementServiceTest + public static VcnConfig buildTestConfig() { + VcnConfig.Builder builder = new VcnConfig.Builder(); + + for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) { + builder.addGatewayConnectionConfig(gatewayConnectionConfig); + } + + return builder.build(); + } + + @Test + public void testBuilderRequiresGatewayConnectionConfig() { + try { + new VcnConfig.Builder().build(); + fail("Expected exception due to no VcnGatewayConnectionConfigs provided"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderAndGetters() { + final VcnConfig config = buildTestConfig(); + + assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs()); + } + + @Test + public void testPersistableBundle() { + final VcnConfig config = buildTestConfig(); + + assertEquals(config, new VcnConfig(config.toPersistableBundle())); + } + + @Test + public void testParceling() { + final VcnConfig config = buildTestConfig(); + + Parcel parcel = Parcel.obtain(); + config.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + assertEquals(config, VcnConfig.CREATOR.createFromParcel(parcel)); + } +} diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java new file mode 100644 index 000000000000..e98b6ef2b3a6 --- /dev/null +++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020 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.vcn; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.net.NetworkCapabilities; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionConfigTest { + private static final int[] EXPOSED_CAPS = + new int[] { + NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS + }; + private static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; + private static final long[] RETRY_INTERVALS_MS = + new long[] { + TimeUnit.SECONDS.toMillis(5), + TimeUnit.SECONDS.toMillis(30), + TimeUnit.MINUTES.toMillis(1), + TimeUnit.MINUTES.toMillis(5), + TimeUnit.MINUTES.toMillis(15), + TimeUnit.MINUTES.toMillis(30) + }; + private static final int MAX_MTU = 1360; + + // Package protected for use in VcnConfigTest + static VcnGatewayConnectionConfig buildTestConfig() { + final VcnGatewayConnectionConfig.Builder builder = + new VcnGatewayConnectionConfig.Builder() + .setRetryInterval(RETRY_INTERVALS_MS) + .setMaxMtu(MAX_MTU); + + for (int caps : EXPOSED_CAPS) { + builder.addExposedCapability(caps); + } + + for (int caps : UNDERLYING_CAPS) { + builder.addRequiredUnderlyingCapability(caps); + } + + return builder.build(); + } + + @Test + public void testBuilderRequiresNonEmptyExposedCaps() { + try { + new VcnGatewayConnectionConfig.Builder() + .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + + fail("Expected exception due to invalid exposed capabilities"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresNonEmptyUnderlyingCaps() { + try { + new VcnGatewayConnectionConfig.Builder() + .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + + fail("Expected exception due to invalid required underlying capabilities"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresNonNullRetryInterval() { + try { + new VcnGatewayConnectionConfig.Builder().setRetryInterval(null); + fail("Expected exception due to invalid retryIntervalMs"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresNonEmptyRetryInterval() { + try { + new VcnGatewayConnectionConfig.Builder().setRetryInterval(new long[0]); + fail("Expected exception due to invalid retryIntervalMs"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderRequiresValidMtu() { + try { + new VcnGatewayConnectionConfig.Builder() + .setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1); + fail("Expected exception due to invalid mtu"); + } catch (IllegalArgumentException e) { + } + } + + @Test + public void testBuilderAndGetters() { + final VcnGatewayConnectionConfig config = buildTestConfig(); + + for (int cap : EXPOSED_CAPS) { + config.hasExposedCapability(cap); + } + for (int cap : UNDERLYING_CAPS) { + config.requiresUnderlyingCapability(cap); + } + + assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); + assertEquals(MAX_MTU, config.getMaxMtu()); + } + + @Test + public void testPersistableBundle() { + final VcnGatewayConnectionConfig config = buildTestConfig(); + + assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); + } +} diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 633cf64bc274..876e07fbce0f 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.net.ConnectivityManager; -import android.net.vcn.VcnConfig; +import android.net.vcn.VcnConfigTest; import android.os.ParcelUuid; import android.os.Process; import android.os.UserHandle; @@ -120,7 +120,7 @@ public class VcnManagementServiceTest { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); fail("Expected IllegalStateException exception for system server"); } catch (IllegalStateException expected) { } @@ -133,7 +133,7 @@ public class VcnManagementServiceTest { .getBinderCallingUid(); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); fail("Expected security exception for non system user"); } catch (SecurityException expected) { } @@ -144,7 +144,7 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, new VcnConfig.Builder().build()); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig()); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } |